<commit_before>/*global angular, templateUrlPrefix*/

( function() {'use strict';

    angular.module('em.app', ['angular-carousel', 'em.directives', 'em.filters', 'em.services']);
    angular.module('em.directives', []);
    angular.module('em.filters', []);
    angular.module('em.services', ['em.base64']);

    angular.module('em.app').config(['$locationProvider', '$routeProvider',
    function($locationProvider, $routeProvider) {

      $routeProvider.when('/', {
        templateUrl : 'static/partials/home.html',
        controller : 'HomeController'
      });

      $routeProvider.when('/404', {
        templateUrl : 'static/partials/pageNotFound.html',
        controller : 'PageNotFoundController'
      });

      $routeProvider.when('/login', {
        templateUrl : 'static/partials/login.html',
        controller : 'LoginController'
      });

      $routeProvider.when('/my', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.my;
          }]

        }
      });

      $routeProvider.when('/my/notes', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.notes;
          }]

        }
      });

      $routeProvider.when('/my/notes/context/:uuid', {
        controller : 'ContextController',
        templateUrl : 'static/partials/my/notes/context.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/notes/edit/:uuid', {
        controller : 'NoteEditController',
        templateUrl : 'static/partials/my/notes/edit.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.tasks;
          }]

        }
      });

      $routeProvider.when('/my/tasks/context/:uuid', {
        controller : 'ContextController',
        templateUrl : 'static/partials/my/tasks/context.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks/new/:uuid', {
        controller : 'NewTaskController',
        templateUrl : 'static/partials/my/tasks/new.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks/project/:uuid', {
        controller : 'ProjectController',
        templateUrl : 'static/partials/my/tasks/project.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.otherwise({
        controller : 'PageNotFoundController',
        redirectTo : '404'
      });

      $locationProvider.html5Mode(true);
    }]);

    angular.module('em.app').run(['$document', '$location', '$rootScope', 'userAuthenticate',
    function($document, $location, $rootScope, userAuthenticate) {

      $rootScope.pageAnimation = {
        enter : 'fade-show',
        hide : 'fade-hide'
      };

      $rootScope.$on('event:authenticationRequired', function() {
        userAuthenticate.authenticate();
      });
      $rootScope.$on('event:loginRequired', function() {
        $location.path('/login');
      });
      $rootScope.$on('event:loginSuccess', function() {
        $location.path('/my');
      });
      $rootScope.$on('$viewContentLoaded', function() {
        $rootScope.pageAnimation = {
          enter : 'fade-show',
          hide : 'fade-hide'
        };
      });

    }]);
  }());
<commit_msg>Home page redirects to login page.<commit_after>/*global angular, templateUrlPrefix*/

( function() {'use strict';

    angular.module('em.app', ['angular-carousel', 'em.directives', 'em.filters', 'em.services']);
    angular.module('em.directives', []);
    angular.module('em.filters', []);
    angular.module('em.services', ['em.base64']);

    angular.module('em.app').config(['$locationProvider', '$routeProvider',
    function($locationProvider, $routeProvider) {

      $routeProvider.when('/', {
        redirectTo:'/login'
      });

      $routeProvider.when('/404', {
        templateUrl : 'static/partials/pageNotFound.html',
        controller : 'PageNotFoundController'
      });

      $routeProvider.when('/login', {
        templateUrl : 'static/partials/login.html',
        controller : 'LoginController'
      });

      $routeProvider.when('/my', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.my;
          }]

        }
      });

      $routeProvider.when('/my/notes', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.notes;
          }]

        }
      });

      $routeProvider.when('/my/notes/context/:uuid', {
        controller : 'ContextController',
        templateUrl : 'static/partials/my/notes/context.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/notes/edit/:uuid', {
        controller : 'NoteEditController',
        templateUrl : 'static/partials/my/notes/edit.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks', {
        controller : 'MyPagesController',
        templateUrl : 'static/partials/myPages.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }],
          slideIndex : ['Enum',
          function(Enum) {
            return Enum.my.tasks;
          }]

        }
      });

      $routeProvider.when('/my/tasks/context/:uuid', {
        controller : 'ContextController',
        templateUrl : 'static/partials/my/tasks/context.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks/new/:uuid', {
        controller : 'NewTaskController',
        templateUrl : 'static/partials/my/tasks/new.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.when('/my/tasks/project/:uuid', {
        controller : 'ProjectController',
        templateUrl : 'static/partials/my/tasks/project.html',
        resolve : {
          authenticationRequired : ['$rootScope',
          function($rootScope) {
            $rootScope.$broadcast('event:authenticationRequired');
          }]

        }
      });

      $routeProvider.otherwise({
        controller : 'PageNotFoundController',
        redirectTo : '404'
      });

      $locationProvider.html5Mode(true);
    }]);

    angular.module('em.app').run(['$document', '$location', '$rootScope', 'userAuthenticate',
    function($document, $location, $rootScope, userAuthenticate) {

      $rootScope.pageAnimation = {
        enter : 'fade-show',
        hide : 'fade-hide'
      };

      $rootScope.$on('event:authenticationRequired', function() {
        userAuthenticate.authenticate();
      });
      $rootScope.$on('event:loginRequired', function() {
        $location.path('/login');
      });
      $rootScope.$on('event:loginSuccess', function() {
        $location.path('/my');
      });
      $rootScope.$on('$viewContentLoaded', function() {
        $rootScope.pageAnimation = {
          enter : 'fade-show',
          hide : 'fade-hide'
        };
      });

    }]);
  }());
<|endoftext|>


<commit_before>import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Accordion } from '../Accordion';
import MetaAccordionHeader from './MetaAccordionHeader';
import css from './MetaSection.css';

const propTypes = {
  lastUpdatedDate: PropTypes.string,
  lastUpdatedBy: PropTypes.string,
  createdDate: PropTypes.string,
  createdBy: PropTypes.string,
  id: PropTypes.string,
  contentId: PropTypes.string,
};

class MetaSection extends React.Component { // eslint-disable-line

  constructor(props, context) {
    super(props);
    this.context = context;
    const stripes = context.stripes;
    this.formatDate = stripes.formatDate;
    this.formatTime = stripes.formatTime;
  }

  render() {
    const {
      lastUpdatedDate,
      lastUpdatedBy,
      createdDate,
      createdBy,
    } = this.props;

    return (

        <Accordion
          header={MetaAccordionHeader}
          closedByDefault
          id={this.props.id}
          contentId={this.props.contentId}
          label={<FormattedMessage id="stripes-components.metaSection.recordLastUpdated" values={{ date: this.formatDate(lastUpdatedDate), time: this.formatTime(lastUpdatedDate) }} />}
        >

            {lastUpdatedBy &&

                <FormattedMessage id="stripes-components.metaSection.source" values={{ source: lastUpdatedBy }} />

            }
            { (createdDate || createdBy) && (

                {createdDate &&

                    <FormattedMessage id="stripes-components.metaSection.recordCreated" values={{ date: this.formatDate(createdDate), time: this.formatTime(createdDate) }} />

                }
                {createdBy &&

                    <FormattedMessage id="stripes-components.metaSection.source" values={{ source: createdBy }} />

                }

            )}

        </Accordion>

    );
  }
}

MetaSection.contextTypes = {
  stripes: PropTypes.shape({
    formatDate: PropTypes.func.isRequired,
    formatTime: PropTypes.func.isRequired,
  }).isRequired,
};

MetaSection.propTypes = propTypes;

export default MetaSection;
<commit_msg>Minor<commit_after>import React from 'react';
import PropTypes from 'prop-types';
import { FormattedMessage } from 'react-intl';
import { Accordion } from '../Accordion';
import MetaAccordionHeader from './MetaAccordionHeader';
import css from './MetaSection.css';

const propTypes = {
  lastUpdatedDate: PropTypes.string,
  lastUpdatedBy: PropTypes.string,
  createdDate: PropTypes.string,
  createdBy: PropTypes.string,
  id: PropTypes.string,
  contentId: PropTypes.string,
};

class MetaSection extends React.Component { // eslint-disable-line

  constructor(props, context) {
    super(props);
    this.context = context;
    const stripes = context.stripes;
    this.formatDate = stripes.formatDate;
    this.formatTime = stripes.formatTime;
  }

  render() {
    const {
      lastUpdatedDate,
      lastUpdatedBy,
      createdDate,
      createdBy,
    } = this.props;

    return (

        <Accordion
          header={MetaAccordionHeader}
          closedByDefault
          id={this.props.id}
          contentId={this.props.contentId}
          label={
            <FormattedMessage
              id="stripes-components.metaSection.recordLastUpdated"
              values={{ date: this.formatDate(lastUpdatedDate), time: this.formatTime(lastUpdatedDate) }}
            />
          }
        >

            {lastUpdatedBy &&

                <FormattedMessage
                  id="stripes-components.metaSection.source"
                  values={{ source: lastUpdatedBy }}
                />

            }
            { (createdDate || createdBy) && (

                {createdDate &&

                    <FormattedMessage
                      id="stripes-components.metaSection.recordCreated"
                      values={{ date: this.formatDate(createdDate), time: this.formatTime(createdDate) }}
                    />

                }
                {createdBy &&

                    <FormattedMessage
                      id="stripes-components.metaSection.source"
                      values={{ source: createdBy }}
                    />

                }

            )}

        </Accordion>

    );
  }
}

MetaSection.contextTypes = {
  stripes: PropTypes.shape({
    formatDate: PropTypes.func.isRequired,
    formatTime: PropTypes.func.isRequired,
  }).isRequired,
};

MetaSection.propTypes = propTypes;

export default MetaSection;
<|endoftext|>


<commit_before>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
var util = require('util'),
    EventEmitter = require('events').EventEmitter,
    Router = require('routr'),
    TimeStore = require('./TimeStore'),
    routes = require('../configs/routes'),
    debug = require('debug')('ApplicationStore');

function ApplicationStore(context, initialState) {
    initialState = initialState || {};
    this.page = initialState.page || null;
    this.url = initialState.url || null;
    this.router = new Router(routes);
    this.pages = initialState.pages || [
        {
            name: 'home',
            text: 'Home',
            url: this.router.makePath('home')
        },
        {
            name: 'about',
            text: 'About',
            url: this.router.makePath('about')
        }
    ];
}

ApplicationStore.storeName = 'ApplicationStore';
ApplicationStore.handlers = {
    'NAVIGATE': 'handleNavigate'
};

util.inherits(ApplicationStore, EventEmitter);

ApplicationStore.prototype.setDispatcher = function (dispatcher) {
    this.dispatcher = dispatcher;
};

ApplicationStore.prototype.handleNavigate = function (payload, done) {
    var self = this,
        newPage = null,
        route = this.router.getRoute(payload.path, {navParams: payload.params}),
        timeStore = this.dispatcher.getStore(TimeStore);

    if (route) {
        this.route = route;
        if (route.config.page) {
            this.pages.forEach(function (page) {
                if (route.name === page.name) {
                    newPage = page;
                }
            });
        }
    }
    if (newPage && newPage.name !== self.page ) {
        self.page = newPage.name;
        self.url = newPage.url;
        timeStore.reset(function () {
            debug('page switched to ' + self.page);
            self.emit('update'); // Store may be listening for updates to state
            done();
        });
    } else {
        done(); // Action has been fully handled
    }
};

ApplicationStore.prototype.getState = function () {
    return {
        page: this.page,
        pages: this.pages,
        url: this.url
    };
};

module.exports = ApplicationStore;
<commit_msg>add route to state object<commit_after>/**
 * Copyright 2014, Yahoo! Inc.
 * Copyrights licensed under the New BSD License. See the accompanying LICENSE file for terms.
 */
var util = require('util'),
    EventEmitter = require('events').EventEmitter,
    Router = require('routr'),
    TimeStore = require('./TimeStore'),
    routes = require('../configs/routes'),
    debug = require('debug')('ApplicationStore');

function ApplicationStore(context, initialState) {
    initialState = initialState || {};
    this.page = initialState.page || null;
    this.url = initialState.url || null;
    this.router = new Router(routes);
    this.pages = initialState.pages || [
        {
            name: 'home',
            text: 'Home',
            url: this.router.makePath('home')
        },
        {
            name: 'about',
            text: 'About',
            url: this.router.makePath('about')
        }
    ];
}

ApplicationStore.storeName = 'ApplicationStore';
ApplicationStore.handlers = {
    'NAVIGATE': 'handleNavigate'
};

util.inherits(ApplicationStore, EventEmitter);

ApplicationStore.prototype.setDispatcher = function (dispatcher) {
    this.dispatcher = dispatcher;
};

ApplicationStore.prototype.handleNavigate = function (payload, done) {
    var self = this,
        newPage = null,
        route = this.router.getRoute(payload.path, {navParams: payload.params}),
        timeStore = this.dispatcher.getStore(TimeStore);

    if (route) {
        this.route = route;
        if (route.config.page) {
            this.pages.forEach(function (page) {
                if (route.name === page.name) {
                    newPage = page;
                }
            });
        }
    }
    if (newPage && newPage.name !== self.page ) {
        self.page = newPage.name;
        self.url = newPage.url;
        timeStore.reset(function () {
            debug('page switched to ' + self.page);
            self.emit('update'); // Store may be listening for updates to state
            done();
        });
    } else {
        done(); // Action has been fully handled
    }
};

ApplicationStore.prototype.getState = function () {
    return {
        page: this.page,
        pages: this.pages,
        route: this.route,
        url: this.url
    };
};

module.exports = ApplicationStore;
<|endoftext|>


<commit_before>"use strict"

var f = require('util').format;

// Extend the object
var extend = function(template, fields) {
  var object = {};
  for(var name in template) {
    object[name] = template[name];
  }

  for(var name in fields) {
   object[name] = fields[name];
  }

  return object;
}

exports['Successful reconnect when driver looses touch with entire replicaset'] = {
  metadata: {
    requires: {
      generators: true,
      topology: "single"
    },
    ignore: { travis:true }
  },

  test: function(configuration, test) {
    var ReplSet = configuration.require.ReplSet,
      ObjectId = configuration.require.BSON.ObjectId,
      ReadPreference = configuration.require.ReadPreference,
      Long = configuration.require.BSON.Long,
      co = require('co'),
      mockupdb = require('../../../mock');

    // Contain mock server
    var primaryServer = null;
    var firstSecondaryServer = null;
    var arbiterServer = null;
    var running = true;
    var electionIds = [new ObjectId(), new ObjectId()];
    var die = false;

    // Default message fields
    var defaultFields = {
      "setName": "rs", "setVersion": 1, "electionId": electionIds[0],
      "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000,
      "maxWriteBatchSize" : 1000, "localTime" : new Date(), "maxWireVersion" : 4,
      "minWireVersion" : 0, "ok" : 1, "hosts": ["localhost:32000", "localhost:32001", "localhost:32002"], "arbiters": ["localhost:32002"]
    }

    // Primary server states
    var primary = [extend(defaultFields, {
      "ismaster":true, "secondary":false, "me": "localhost:32000", "primary": "localhost:32000", "tags" : { "loc" : "ny" }
    })];

    // Primary server states
    var firstSecondary = [extend(defaultFields, {
      "ismaster":false, "secondary":true, "me": "localhost:32001", "primary": "localhost:32000", "tags" : { "loc" : "sf" }
    })];

    // Primary server states
    var arbiter = [extend(defaultFields, {
      "ismaster":false, "secondary":false, "arbiterOnly": true, "me": "localhost:32002", "primary": "localhost:32000"
    })];

    // Boot the mock
    co(function*() {
      primaryServer = yield mockupdb.createServer(32000, 'localhost');
      firstSecondaryServer = yield mockupdb.createServer(32001, 'localhost');
      arbiterServer = yield mockupdb.createServer(32002, 'localhost');

      // Primary state machine
      co(function*() {
        while(running) {
          var request = yield primaryServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(primary[0]);
            } else if(doc.insert) {
              request.reply({ "ok" : 1, "n" : 1 });
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // First secondary state machine
      co(function*() {
        while(running) {
          var request = yield firstSecondaryServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(firstSecondary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // Second secondary state machine
      co(function*() {
        while(running) {
          var request = yield arbiterServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(arbiter[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });
    });

    // Attempt to connect
    var server = new ReplSet([
      { host: 'localhost', port: 32000 },
      { host: 'localhost', port: 32001 },
      { host: 'localhost', port: 32002 }], {
        setName: 'rs',
        connectionTimeout: 2000,
        socketTimeout: 5000,
        haInterval: 500,
        size: 500
    });

    server.on('connect', function(e) {
      server.__connected = true;
      // console.log("------------------------------- step 0 ")

      for(var i = 0; i < 100000; i++) {
        // Execute the write
        server.insert(f("%s.inserts", configuration.db), [{a:1}], {
          writeConcern: {w:1}, ordered:true
        }, function(err, results) {
        });
      }

      setTimeout(function() {
        // console.log("------------------------------- step 1 ")
        die = true;

        setTimeout(function() {
          // console.log("------------------------------- step 2 ")
          die = false;

          setTimeout(function() {
            // console.log("------------------------------- step 3 ")
            server.command('admin.$cmd', {ismaster:true}, function(err, r) {
              // console.log("------------------------------- step 4 ")
              // console.dir(err)
              test.equal(null, err);
              test.ok(server.s.replState.primary != null);
              // test.equal(1, server.s.replState.secondaries.length);
              // test.equal(1, server.s.replState.arbiters.length);

              primaryServer.destroy();
              firstSecondaryServer.destroy();
              arbiterServer.destroy();
              server.destroy();
              running = false;

              test.done();
            });
          }, 6000);
        }, 2500);
      }, 2500);
    });

    // Add event listeners
    server.on('fullsetup', function(_server) {});
    // Gives proxies a chance to boot up
    setTimeout(function() {
      server.connect();
    }, 100)
  }
}

exports['Successfully come back from a dead replicaset that has been unavailable for a long time'] = {
  metadata: {
    requires: {
      generators: true,
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var ReplSet = configuration.require.ReplSet,
      ObjectId = configuration.require.BSON.ObjectId,
      ReadPreference = configuration.require.ReadPreference,
      Long = configuration.require.BSON.Long,
      co = require('co'),
      mockupdb = require('../../../mock');

    // Contain mock server
    var primaryServer = null;
    var firstSecondaryServer = null;
    var arbiterServer = null;
    var running = true;
    var electionIds = [new ObjectId(), new ObjectId()];
    var die = false;

    // Default message fields
    var defaultFields = {
      "setName": "rs", "setVersion": 1, "electionId": electionIds[0],
      "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000,
      "maxWriteBatchSize" : 1000, "localTime" : new Date(), "maxWireVersion" : 4,
      "minWireVersion" : 0, "ok" : 1, "hosts": ["localhost:32000", "localhost:32001", "localhost:32002"], "arbiters": ["localhost:32002"]
    }

    // Primary server states
    var primary = [extend(defaultFields, {
      "ismaster":true, "secondary":false, "me": "localhost:32000", "primary": "localhost:32000", "tags" : { "loc" : "ny" }
    })];

    // Primary server states
    var firstSecondary = [extend(defaultFields, {
      "ismaster":false, "secondary":true, "me": "localhost:32001", "primary": "localhost:32000", "tags" : { "loc" : "sf" }
    })];

    // Primary server states
    var arbiter = [extend(defaultFields, {
      "ismaster":false, "secondary":false, "arbiterOnly": true, "me": "localhost:32002", "primary": "localhost:32000"
    })];

    // Boot the mock
    co(function*() {
      primaryServer = yield mockupdb.createServer(32000, 'localhost');
      firstSecondaryServer = yield mockupdb.createServer(32001, 'localhost');
      arbiterServer = yield mockupdb.createServer(32002, 'localhost');

      // Primary state machine
      co(function*() {
        while(running) {
          var request = yield primaryServer.receive();
          if(die) {
            // console.log("------------------ die 1")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(primary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // First secondary state machine
      co(function*() {
        while(running) {
          var request = yield firstSecondaryServer.receive();
          if(die) {
            // console.log("------------------ die 2")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(firstSecondary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // Second secondary state machine
      co(function*() {
        while(running) {
          var request = yield arbiterServer.receive();
          if(die) {
            // console.log("------------------ die 3")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(arbiter[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });
    });

    // Attempt to connect
    var server = new ReplSet([
      { host: 'localhost', port: 32000 },
      { host: 'localhost', port: 32001 },
      { host: 'localhost', port: 32002 }], {
        setName: 'rs',
        connectionTimeout: 5000,
        socketTimeout: 5000,
        haInterval: 1000,
        size: 1
    });

    server.on('connect', function(e) {
      server.__connected = true;

      setTimeout(function() {
        die = true;

        var intervalId = setInterval(function() {
          // console.log("--------------- interval 0")
          server.command('admin.$cmd', {ismaster:true}, function(err, r) {
            // console.log("--------------- interval 1")
            // console.log(err)
            // test.ok(err != null);
          });
        }, 2000);

        setTimeout(function() {
          die = false;
          // console.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ALIVE")

          setTimeout(function() {
            clearInterval(intervalId);

            server.command('admin.$cmd', {ismaster:true}, function(err, r) {
              // console.log("---------------------------------------------------------------")
              // console.dir(err)
              // console.log("server.s.replState.secondaries = " + server.s.replState.secondaries.length)
              // console.log("server.s.replState.arbiters = " + server.s.replState.arbiters.length)
              // console.log("server.s.replState.primary = " + (server.s.replState.primary != null))
              // console.dir(err)
              // console.dir(r.result)

              test.equal(null, err);
              test.ok(server.s.replState.primary != null);
              test.equal(1, server.s.replState.secondaries.length);
              test.equal(1, server.s.replState.arbiters.length);

              primaryServer.destroy();
              firstSecondaryServer.destroy();
              arbiterServer.destroy();
              server.destroy();
              running = false;

              test.done();
            });
          }, 5000);
        }, 25000);
      }, 2500);
    });

    // Add event listeners
    server.on('fullsetup', function(_server) {});
    // Gives proxies a chance to boot up
    setTimeout(function() {
      server.connect();
    }, 100)
  }
}
<commit_msg>test fixes<commit_after>"use strict"

var f = require('util').format;

// Extend the object
var extend = function(template, fields) {
  var object = {};
  for(var name in template) {
    object[name] = template[name];
  }

  for(var name in fields) {
   object[name] = fields[name];
  }

  return object;
}

exports['Successful reconnect when driver looses touch with entire replicaset'] = {
  metadata: {
    requires: {
      generators: true,
      topology: "single"
    },
    ignore: { travis:true }
  },

  test: function(configuration, test) {
    var ReplSet = configuration.require.ReplSet,
      ObjectId = configuration.require.BSON.ObjectId,
      ReadPreference = configuration.require.ReadPreference,
      Long = configuration.require.BSON.Long,
      co = require('co'),
      mockupdb = require('../../../mock');

    // Contain mock server
    var primaryServer = null;
    var firstSecondaryServer = null;
    var arbiterServer = null;
    var running = true;
    var electionIds = [new ObjectId(), new ObjectId()];
    var die = false;

    // Default message fields
    var defaultFields = {
      "setName": "rs", "setVersion": 1, "electionId": electionIds[0],
      "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000,
      "maxWriteBatchSize" : 1000, "localTime" : new Date(), "maxWireVersion" : 4,
      "minWireVersion" : 0, "ok" : 1, "hosts": ["localhost:32000", "localhost:32001", "localhost:32002"], "arbiters": ["localhost:32002"]
    }

    // Primary server states
    var primary = [extend(defaultFields, {
      "ismaster":true, "secondary":false, "me": "localhost:32000", "primary": "localhost:32000", "tags" : { "loc" : "ny" }
    })];

    // Primary server states
    var firstSecondary = [extend(defaultFields, {
      "ismaster":false, "secondary":true, "me": "localhost:32001", "primary": "localhost:32000", "tags" : { "loc" : "sf" }
    })];

    // Primary server states
    var arbiter = [extend(defaultFields, {
      "ismaster":false, "secondary":false, "arbiterOnly": true, "me": "localhost:32002", "primary": "localhost:32000"
    })];

    // Boot the mock
    co(function*() {
      primaryServer = yield mockupdb.createServer(32000, 'localhost');
      firstSecondaryServer = yield mockupdb.createServer(32001, 'localhost');
      arbiterServer = yield mockupdb.createServer(32002, 'localhost');

      // Primary state machine
      co(function*() {
        while(running) {
          var request = yield primaryServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(primary[0]);
            } else if(doc.insert) {
              request.reply({ "ok" : 1, "n" : 1 });
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // First secondary state machine
      co(function*() {
        while(running) {
          var request = yield firstSecondaryServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(firstSecondary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // Second secondary state machine
      co(function*() {
        while(running) {
          var request = yield arbiterServer.receive();
          if(die) {
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(arbiter[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });
    });

    // Attempt to connect
    var server = new ReplSet([
      { host: 'localhost', port: 32000 },
      { host: 'localhost', port: 32001 },
      { host: 'localhost', port: 32002 }], {
        setName: 'rs',
        connectionTimeout: 2000,
        socketTimeout: 2000,
        haInterval: 500,
        size: 500
    });

    server.on('connect', function(e) {
      server.__connected = true;
      // console.log("------------------------------- step 0 ")

      for(var i = 0; i < 100000; i++) {
        // Execute the write
        server.insert(f("%s.inserts", configuration.db), [{a:1}], {
          writeConcern: {w:1}, ordered:true
        }, function(err, results) {
        });
      }

      setTimeout(function() {
        // console.log("------------------------------- step 1 ")
        die = true;

        setTimeout(function() {
          console.log("------------------------------- step 2 ")
          die = false;

          setTimeout(function() {
            // console.log("------------------------------- step 5 : 0")
            // console.dir(server.s.replState.primary)
            // console.log("------------------------------- step 6 : 0")
            // console.dir(server.s.replState.secondaries)
            // console.log("------------------------------- step 7 : 0")
            // console.dir(server.s.replState.arbiters)

            // console.log("------------------------------- step 3 ")
            server.command('admin.$cmd', {ismaster:true}, function(err, r) {
              // console.log("------------------------------- step 4 : 1")
              // console.dir(err)
              // console.log("------------------------------- step 5 : 1")
              // console.dir(server.s.replState.primary)
              // console.log("------------------------------- step 6 : 1")
              // console.dir(server.s.replState.secondaries)
              // console.log("------------------------------- step 7 : 1")
              // console.dir(server.s.replState.arbiters)
              test.equal(null, err);
              test.ok(server.s.replState.primary != null);
              test.equal(1, server.s.replState.secondaries.length);
              test.equal(1, server.s.replState.arbiters.length);

              primaryServer.destroy();
              firstSecondaryServer.destroy();
              arbiterServer.destroy();
              server.destroy();
              running = false;

              test.done();
            });
          }, 6000);
        }, 2500);
      }, 2500);
    });

    // Add event listeners
    server.on('fullsetup', function(_server) {});
    // Gives proxies a chance to boot up
    setTimeout(function() {
      server.connect();
    }, 100)
  }
}

exports['Successfully come back from a dead replicaset that has been unavailable for a long time'] = {
  metadata: {
    requires: {
      generators: true,
      topology: "single"
    }
  },

  test: function(configuration, test) {
    var ReplSet = configuration.require.ReplSet,
      ObjectId = configuration.require.BSON.ObjectId,
      ReadPreference = configuration.require.ReadPreference,
      Long = configuration.require.BSON.Long,
      co = require('co'),
      mockupdb = require('../../../mock');

    // Contain mock server
    var primaryServer = null;
    var firstSecondaryServer = null;
    var arbiterServer = null;
    var running = true;
    var electionIds = [new ObjectId(), new ObjectId()];
    var die = false;

    // Default message fields
    var defaultFields = {
      "setName": "rs", "setVersion": 1, "electionId": electionIds[0],
      "maxBsonObjectSize" : 16777216, "maxMessageSizeBytes" : 48000000,
      "maxWriteBatchSize" : 1000, "localTime" : new Date(), "maxWireVersion" : 4,
      "minWireVersion" : 0, "ok" : 1, "hosts": ["localhost:32000", "localhost:32001", "localhost:32002"], "arbiters": ["localhost:32002"]
    }

    // Primary server states
    var primary = [extend(defaultFields, {
      "ismaster":true, "secondary":false, "me": "localhost:32000", "primary": "localhost:32000", "tags" : { "loc" : "ny" }
    })];

    // Primary server states
    var firstSecondary = [extend(defaultFields, {
      "ismaster":false, "secondary":true, "me": "localhost:32001", "primary": "localhost:32000", "tags" : { "loc" : "sf" }
    })];

    // Primary server states
    var arbiter = [extend(defaultFields, {
      "ismaster":false, "secondary":false, "arbiterOnly": true, "me": "localhost:32002", "primary": "localhost:32000"
    })];

    // Boot the mock
    co(function*() {
      primaryServer = yield mockupdb.createServer(32000, 'localhost');
      firstSecondaryServer = yield mockupdb.createServer(32001, 'localhost');
      arbiterServer = yield mockupdb.createServer(32002, 'localhost');

      // Primary state machine
      co(function*() {
        while(running) {
          var request = yield primaryServer.receive();
          if(die) {
            // console.log("------------------ die 1")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(primary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // First secondary state machine
      co(function*() {
        while(running) {
          var request = yield firstSecondaryServer.receive();
          if(die) {
            // console.log("------------------ die 2")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(firstSecondary[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });

      // Second secondary state machine
      co(function*() {
        while(running) {
          var request = yield arbiterServer.receive();
          if(die) {
            // console.log("------------------ die 3")
            request.connection.destroy();
          } else {
            var doc = request.document;

            if(doc.ismaster) {
              request.reply(arbiter[0]);
            }
          }
        }
      }).catch(function(err) {
        console.log(err.stack);
      });
    });

    // Attempt to connect
    var server = new ReplSet([
      { host: 'localhost', port: 32000 },
      { host: 'localhost', port: 32001 },
      { host: 'localhost', port: 32002 }], {
        setName: 'rs',
        connectionTimeout: 5000,
        socketTimeout: 5000,
        haInterval: 1000,
        size: 1
    });

    server.on('connect', function(e) {
      server.__connected = true;

      setTimeout(function() {
        die = true;

        var intervalId = setInterval(function() {
          // console.log("--------------- interval 0")
          server.command('admin.$cmd', {ismaster:true}, function(err, r) {
            // console.log("--------------- interval 1")
            // console.log(err)
            // test.ok(err != null);
          });
        }, 2000);

        setTimeout(function() {
          die = false;
          // console.log("!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! ALIVE")

          setTimeout(function() {
            clearInterval(intervalId);

            server.command('admin.$cmd', {ismaster:true}, function(err, r) {
              // console.log("---------------------------------------------------------------")
              // console.dir(err)
              // console.log("server.s.replState.secondaries = " + server.s.replState.secondaries.length)
              // console.log("server.s.replState.arbiters = " + server.s.replState.arbiters.length)
              // console.log("server.s.replState.primary = " + (server.s.replState.primary != null))
              // console.dir(err)
              // console.dir(r.result)

              test.equal(null, err);
              test.ok(server.s.replState.primary != null);
              test.equal(1, server.s.replState.secondaries.length);
              test.equal(1, server.s.replState.arbiters.length);

              primaryServer.destroy();
              firstSecondaryServer.destroy();
              arbiterServer.destroy();
              server.destroy();
              running = false;

              test.done();
            });
          }, 5000);
        }, 25000);
      }, 2500);
    });

    // Add event listeners
    server.on('fullsetup', function(_server) {});
    // Gives proxies a chance to boot up
    setTimeout(function() {
      server.connect();
    }, 100)
  }
}
<|endoftext|>


<commit_before>/***
 * Overloading EJS method: this.DeferCascade, this.DeferRender etc.
 ***/

phoxy.OverrideENJS =
{
  _: {},
};

phoxy._.enjs =
{
  OverloadENJSCanvas: function()
    {
      EJS.Canvas.prototype.recursive = 0;
      phoxy.state.RenderCalls = 0;

      phoxy._.internal.Override(EJS.Canvas.prototype, 'RenderCompleted', phoxy._.enjs.RenderCompleted);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'Defer', phoxy._.enjs.Defer);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'CheckIsCompleted', phoxy._.enjs.CheckIsCompleted);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'hook_first', phoxy._.enjs.hook_first);

      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'DeferRender', phoxy._.enjs.DeferRender);
      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'DeferCascade', phoxy._.enjs.DeferCascade);
    }
  ,
  RenderCompleted: function()
    {
      arguments.callee.origin.apply(this);

      // In case of recursive rendering, forbid later using
      // If you losed context from this, and access it with __context
      // Then probably its too late to use this methods:
      delete this.across.Defer;
      delete this.across.DeferRender;
      delete this.across.DeferCascade;

      if (this.recursive)
        return;
      // no one DeferRender was invoked
      // but Canvas.on_completed not prepared
      // So render plan is plain, and we attach CheckIsCompleted in this.Defer queue
      this.recursive++;
      phoxy.state.RenderCalls++;
      this.across.Defer(this.CheckIsCompleted);
    }
  ,
  CheckIsCompleted: function()
    {
      var escape = this.escape();
      if (--escape.recursive === 0)
      {
        escape.log("FireUp");
        escape.fired_up = true;
        for (var k in escape.cascade)
          if (typeof (escape.cascade[k]) === 'function')
              escape.cascade[k].apply(this);
        if (typeof(escape.on_complete) === 'function')
          escape.on_complete();
      }
    }
  ,
  hook_first: function(result)
    {
      var root;
      while (true)
      {
        if (typeof root === 'undefined')
          root = result;
        else
          root = root.nextSibling;

        if (!root)
          break;
        if (root.nodeType !== 1)
          continue;

        if (
          ['defer_render','render'].indexOf(root.tagName) === -1 &&
          root.classList.contains('phoxy_ignore') === false &&
          root.classList.contains('ejs_ancor') === false)
          break;
      }
      return root;
    }
  ,
  DeferRender: function(ejs, data, callback, tag)
    {
      var that = this.escape();
      that.log("DeferRender", ejs, data);
      phoxy._.enjs.AlreadyFiredUp(that);
      that.recursive++;
      phoxy.state.RenderCalls++;

      function CBHook()
      {
        if (typeof callback === 'function')
          callback.call(this); // Local fancy context
        phoxy.state.RenderCalls--;

        that.CheckIsCompleted.call(that.across);
      }

      that.Append(phoxy.DeferRender(ejs, data, CBHook, tag));
      return "<!-- <%= %> IS OBSOLETE. Refactor " + that.name + " -->";
    }
  ,
  Defer: function(callback, time)
    {
      var that = this.escape();
      that.log("Defer", callback, time);
      that.recursive++;
      phoxy._.enjs.AlreadyFiredUp(that);

      function CBHook()
      {
        if (typeof callback === 'function')
          callback.call(that.across);
        that.CheckIsCompleted.call(that.across);
      }

      var OriginDefer = arguments.callee.origin;
      if (phoxy.state.sync_cascade)
        return OriginDefer.call(this, CBHook, time);
      if (typeof that.defer === 'undefined')
        that.defer = [];
      if (typeof time === 'undefined')
        return that.defer.push(CBHook);

      that.defer.push(function()
      {
        return OriginDefer(CBHook, time);
      })
    }
  ,
  DeferCascade: function(callback)
    {
      var that = this.escape();
      that.log("DeferCascade", callback);
      phoxy._.enjs.AlreadyFiredUp(that);

      if (typeof that.cascade === 'undefined')
        that.cascade = [];

      that.cascade.push(callback);
    }
  ,
  AlreadyFiredUp: function(that)
  {
    if (that.fired_up)
    {
      phoxy.Log("You can't invoke this.Defer... methods after rendering finished.\
Because parent cascade callback already executed, and probably you didn't expect new elements on your context.\
Check if you call this.Defer... on DOM(jquery) events? Thats too late. (It mean DOM event exsist -> Render completed).\
In that case use phoxy.Defer methods directly. They context-dependence free.");
      debugger; // already finished
    }
  }
};<commit_msg>Deprecate direct __this.DeferRender. Use __this.CascadeDesign and __this.CascadeRequest instead<commit_after>/***
 * Overloading EJS method: this.DeferCascade, this.DeferRender etc.
 ***/

phoxy.OverrideENJS =
{
  _: {},
};

phoxy._.enjs =
{
  OverloadENJSCanvas: function()
    {
      EJS.Canvas.prototype.recursive = 0;
      phoxy.state.RenderCalls = 0;

      phoxy._.internal.Override(EJS.Canvas.prototype, 'RenderCompleted', phoxy._.enjs.RenderCompleted);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'Defer', phoxy._.enjs.Defer);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'CheckIsCompleted', phoxy._.enjs.CheckIsCompleted);
      phoxy._.internal.Override(EJS.Canvas.prototype, 'hook_first', phoxy._.enjs.hook_first);

      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'DeferRender', phoxy._.enjs.DeferRender);
      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'DeferCascade', phoxy._.enjs.DeferCascade);

      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'CascadeDesign', phoxy._.enjs.CascadeDesign);
      phoxy._.internal.Override(EJS.Canvas.across.prototype, 'CascadeRequest', phoxy._.enjs.CascadeRequest);
    }
  ,
  RenderCompleted: function()
    {
      arguments.callee.origin.apply(this);

      // In case of recursive rendering, forbid later using
      // If you losed context from this, and access it with __context
      // Then probably its too late to use this methods:
      delete this.across.Defer;
      delete this.across.DeferRender;
      delete this.across.DeferCascade;

      if (this.recursive)
        return;
      // no one DeferRender was invoked
      // but Canvas.on_completed not prepared
      // So render plan is plain, and we attach CheckIsCompleted in this.Defer queue
      this.recursive++;
      phoxy.state.RenderCalls++;
      this.across.Defer(this.CheckIsCompleted);
    }
  ,
  CheckIsCompleted: function()
    {
      var escape = this.escape();
      if (--escape.recursive === 0)
      {
        escape.log("FireUp");
        escape.fired_up = true;
        for (var k in escape.cascade)
          if (typeof (escape.cascade[k]) === 'function')
              escape.cascade[k].apply(this);
        if (typeof(escape.on_complete) === 'function')
          escape.on_complete();
      }
    }
  ,
  hook_first: function(result)
    {
      var root;
      while (true)
      {
        if (typeof root === 'undefined')
          root = result;
        else
          root = root.nextSibling;

        if (!root)
          break;
        if (root.nodeType !== 1)
          continue;

        if (
          ['defer_render','render'].indexOf(root.tagName) === -1 &&
          root.classList.contains('phoxy_ignore') === false &&
          root.classList.contains('ejs_ancor') === false)
          break;
      }
      return root;
    }
  ,
  DeferRender: function(ejs, data, callback, tag)
    {
      phoxy.Log(2, "__this.DeferRender is deprecated. Use __this.CascadeDesign or __this.CascadeRequest");

      if (data === undefined || data === null )
        return this.CascadeRequest.call(this, ejs, callback, tag);

      return this.CascadeDesign.apply(this, arguments);
    }
  ,
  CascadeInit: function(across, ejs, data, callback, tag)
    {
      var that = across.escape();
      phoxy._.enjs.AlreadyFiredUp(that);
      that.recursive++;
      phoxy.state.RenderCalls++;

      function CBHook()
      {
        if (typeof callback === 'function')
          callback.call(this); // Local fancy context
        phoxy.state.RenderCalls--;

        that.CheckIsCompleted.call(that.across);
      }

      var ancor = phoxy.DeferRender(ejs, data, CBHook, tag);
      that.Append(ancor);

      return "<!-- <%= %> IS OBSOLETE. Refactor " + that.name + " -->";
    }
  ,
  CascadeDesign: function(ejs, data, callback, tag)
    {
      if (data === undefined || data === null)
        data = {};

      var data_type = typeof data;
      if (data_type !== 'object'
        && data_type !== 'function'
        && data_type !== 'string')
        return phoxy.Log(1, "Are you sure that DATA parameters of CascadeDesign right?");

      var design_type = typeof ejs;
      if (design_type !== 'string'
        && design_type !== 'function')
        return phoxy.Log(1, "Are you sure that EJS parameters of CascadeDesign right?");

      this.escape().log("Design", ejs, data);
      return phoxy._.enjs.CascadeInit(this, ejs, data, callback, tag);
    }
  ,
  CascadeRequest: function(url, callback, tag)
    {
      var url_type = typeof url;

      if (typeof url !== 'string')
        return phoxy.Log(1, "Are you sure that URL parameters of CascadeRequest right?");

      this.escape().log("Request", url);
      return phoxy._.enjs.CascadeInit(this, url, undefined, callback, tag);
    }
  ,
  Defer: function(callback, time)
    {
      var that = this.escape();
      that.log("Defer", callback, time);
      that.recursive++;
      phoxy._.enjs.AlreadyFiredUp(that);

      function CBHook()
      {
        if (typeof callback === 'function')
          callback.call(that.across);
        that.CheckIsCompleted.call(that.across);
      }

      var OriginDefer = arguments.callee.origin;
      if (phoxy.state.sync_cascade)
        return OriginDefer.call(this, CBHook, time);
      if (typeof that.defer === 'undefined')
        that.defer = [];
      if (typeof time === 'undefined')
        return that.defer.push(CBHook);

      that.defer.push(function()
      {
        return OriginDefer(CBHook, time);
      })
    }
  ,
  DeferCascade: function(callback)
    {
      var that = this.escape();
      that.log("DeferCascade", callback);
      phoxy._.enjs.AlreadyFiredUp(that);

      if (typeof that.cascade === 'undefined')
        that.cascade = [];

      that.cascade.push(callback);
    }
  ,
  AlreadyFiredUp: function(that)
  {
    if (that.fired_up)
    {
      phoxy.Log("You can't invoke this.Defer... methods after rendering finished.\
Because parent cascade callback already executed, and probably you didn't expect new elements on your context.\
Check if you call this.Defer... on DOM(jquery) events? Thats too late. (It mean DOM event exsist -> Render completed).\
In that case use phoxy.Defer methods directly. They context-dependence free.");
      debugger; // already finished
    }
  }
};<|endoftext|>


<commit_before>/*eslint no-invalid-this: 0*/ // eslint doesn't understand Promise.coroutine wrapping

// Controls the logic for determining which membership lists should be synced and
// handles the sequence of events until the lists are in sync.
"use strict";

var Promise = require("bluebird");
var promiseutil = require("../promiseutil");
var log = require("../logging").get("MemberListSyncer");

function MemberListSyncer(ircBridge, appServiceBot, server, appServiceUserId, injectJoinFn) {
    this.ircBridge = ircBridge;
    this.appServiceBot = appServiceBot;
    this.server = server;
    this.appServiceUserId = appServiceUserId;
    this.injectJoinFn = injectJoinFn;
    this._syncableRoomsPromise = null;
}

MemberListSyncer.prototype.sync = Promise.coroutine(function*() {
    let server = this.server;
    if (!server.isMembershipListsEnabled()) {
        log.info("%s does not have membership list syncing enabled.", server.domain);
        return;
    }
    if (!server.shouldSyncMembershipToIrc("initial")) {
        log.info("%s shouldn't sync initial memberships to irc.", server.domain);
        return;
    }
    log.info("Checking membership lists for syncing on %s", server.domain);
    let start = Date.now();
    let rooms = yield this._getSyncableRooms(server);
    log.info("Found %s syncable rooms (%sms)", rooms.length, Date.now() - start);
    start = Date.now();
    log.info("Joining Matrix users to IRC channels...");
    yield joinMatrixUsersToChannels(rooms, server, this.injectJoinFn);
    log.info("Joined Matrix users to IRC channels. (%sms)", Date.now() - start);
    // NB: We do not need to explicitly join IRC users to Matrix rooms
    // because we get all of the NAMEs/JOINs as events when we connect to
    // the IRC server. This effectively "injects" the list for us.
    start = Date.now();
    log.info("Leaving IRC users from Matrix rooms (cleanup)...");
    yield leaveIrcUsersFromRooms(rooms, server);
    log.info("Left IRC users from Matrix rooms. (%sms)", Date.now() - start);
});

MemberListSyncer.prototype.getChannelsToJoin = Promise.coroutine(function*() {
    let server = this.server;
    log.debug("getChannelsToJoin => %s", server.domain);
    let rooms = yield this._getSyncableRooms(server);

    // map room IDs to channels on this server.
    let channels = new Set();
    let roomInfoMap = {};
    let roomIds = rooms.map((roomInfo) => {
        roomInfoMap[roomInfo.id] = roomInfo;
        return roomInfo.id;
    });
    yield this.ircBridge.getStore().getIrcChannelsForRoomIds(roomIds).then((roomIdToIrcRoom) => {
        Object.keys(roomIdToIrcRoom).forEach((roomId) => {
            // only interested in rooms for this server
            let ircRooms = roomIdToIrcRoom[roomId].filter((ircRoom) => {
                return ircRoom.server.domain === server.domain;
            });
            ircRooms.forEach((ircRoom) => {
                channels.add(ircRoom.channel);
                log.debug(
                    "%s should be joined because %s real Matrix users are in room %s",
                    ircRoom.channel, roomInfoMap[roomId].realJoinedUsers.length, roomId
                );
                if (roomInfoMap[roomId].realJoinedUsers.length < 5) {
                    log.debug("These are: %s", JSON.stringify(roomInfoMap[roomId].realJoinedUsers));
                }
            });
        })
    });

    let channelsArray = Array.from(channels);
    log.debug(
        "getChannelsToJoin => %s should be synced: %s",
        channelsArray.length, JSON.stringify(channelsArray)
    );
    return channelsArray;
});

// map irc channel to a list of room IDs. If all of those
// room IDs have no real users in them, then part the bridge bot too.
MemberListSyncer.prototype.checkBotPartRoom = Promise.coroutine(function*(ircRoom, req) {
    if (ircRoom.channel.indexOf("#") !== 0) {
        return; // don't leave PM rooms
    }
    let matrixRooms = yield this.ircBridge.getStore().getMatrixRoomsForChannel(
        ircRoom.server, ircRoom.channel
    );

    if (matrixRooms.length === 0) {
        // no mapped rooms, leave the channel.
        yield this.ircBridge.partBot(ircRoom);
        return;
    }

    // At least 1 mapped room - query for the membership list in each room. If there are
    // any real users still left in the room, then do not part the bot from the channel.
    // Query via /$room_id/state rather than /initialSync as the latter can cause
    // the bridge to spin for minutes if the response is large.

    let shouldPart = true;
    for (let i = 0; i < matrixRooms.length; i++) {
        let roomId = matrixRooms[i].getId();
        req.log.debug("checkBotPartRoom: Querying room state in room %s", roomId);
        let res = yield this.appServiceBot.getClient().roomState(roomId);
        let data = getRoomMemberData(ircRoom.server, roomId, res, this.appServiceUserId);
        req.log.debug(
            "checkBotPartRoom: %s Matrix users are in room %s", data.reals.length, roomId
        );
        if (data.reals.length > 0) {
            shouldPart = false;
            break;
        }
    }

    if (shouldPart) {
        yield this.ircBridge.partBot(ircRoom);
    }
});

// grab all rooms the bot knows about which have at least 1 real user in them.
// ignoreCache exists because this function hammers /initialSync and that is expeeeensive,
// so we don't do it unless they need absolutely fresh data. On startup, this can be called
// multiple times, so we cache the first request's promise and return that instead of making
// double hits.
MemberListSyncer.prototype._getSyncableRooms = function(server, ignoreCache) {
    if (!ignoreCache && this._syncableRoomsPromise) {
        log.debug("Returning existing _getSyncableRooms Promise");
        return this._syncableRoomsPromise;
    }

    // hit /initialSync on the bot to pull in room state for all rooms.
    let self = this;
    let fetchRooms = Promise.coroutine(function*() {
        let attempts = 0;
        while (attempts < 10) {
            try {
                // roomDict = { room_id: RoomInfo }
                let roomDict = yield self.appServiceBot.getMemberLists();
                return Object.keys(roomDict).map(function(roomId) {
                    return roomDict[roomId];
                }).filter(function(roomInfo) {
                    // filter out rooms with no real matrix users in them.
                    return roomInfo.realJoinedUsers.length > 0;
                });
            }
            catch (err) {
                log.error("Failed to fetch syncable rooms: " + err.stack);
                attempts += 1;
                yield Promise.delay(attempts * 5000); // wait 5s,10s,15s.. and try again
            }
        }
        log.error("Failed to fetch syncable rooms: Giving up.");
        return [];
    });

    this._syncableRoomsPromise = fetchRooms();
    return this._syncableRoomsPromise;
};

function joinMatrixUsersToChannels(rooms, server, injectJoinFn) {
    var d = promiseutil.defer();

    // filter out rooms listed in the rules
    var filteredRooms = [];
    rooms.forEach(function(roomInfo) {
        if (!server.shouldSyncMembershipToIrc("initial", roomInfo.id)) {
            log.debug(
                "Trimming room %s according to config rules (matrixToIrc=false)",
                roomInfo.id
            );
            if (!roomInfo.realJoinedUsers[0]) {
                return; // no joined users at all
            }
            // trim the list to a single user. We do this rather than filter the
            // room out entirely because otherwise there will be NO matrix users
            // on the IRC-side resulting in no traffic whatsoever.
            roomInfo.realJoinedUsers = [roomInfo.realJoinedUsers[0]];
            log.debug("Trimmed to " + roomInfo.realJoinedUsers);
        }
        filteredRooms.push(roomInfo);
    });

    log.debug("%s rooms passed the config rules", filteredRooms.length);

    // map the filtered rooms to a list of users to join
    // [Room:{reals:[uid,uid]}, ...] => [{uid,roomid}, ...]
    var entries = [];
    filteredRooms.forEach(function(roomInfo) {
        roomInfo.realJoinedUsers.forEach(function(uid, index) {
            entries.push({
                roomId: roomInfo.id,
                userId: uid,
                // Mark the first real matrix user f.e room so we can inject
                // them first to get back up and running more quickly when there
                // is no bot.
                frontier: (index === 0)
            });
        });
    });
    // sort frontier markers to the front of the array
    entries.sort(function(a, b) {
        if (a.frontier && !b.frontier) {
            return -1; // a comes first
        }
        else if (b.frontier && !a.frontier) {
            return 1; // b comes first
        }
        return 0; // don't care
    });

    log.debug("Got %s matrix join events to inject.", entries.length);
    // take the first entry and inject a join event
    function joinNextUser() {
        var entry = entries.shift();
        if (!entry) {
            d.resolve();
            return;
        }
        if (entry.userId.indexOf("@-") === 0) {
            joinNextUser();
            return;
        }
        log.debug(
            "Injecting join event for %s in %s (%s left) is_frontier=%s",
            entry.userId, entry.roomId, entries.length, entry.frontier
        );
        injectJoinFn(entry.roomId, entry.userId, entry.frontier).timeout(
            server.getMemberListFloodDelayMs()
        ).then(() => {
            joinNextUser();
        }, (err) => { // discard error, this will be due to timeouts which we don't want to log
            joinNextUser();
        });
    }

    joinNextUser();

    return d.promise;
}

function leaveIrcUsersFromRooms(rooms, server) {
    return Promise.resolve();
}

function getRoomMemberData(server, roomId, stateEvents, appServiceUserId) {
    stateEvents = stateEvents || [];
    var data = {
        roomId: roomId,
        virtuals: [],
        reals: []
    };
    stateEvents.forEach(function(event) {
        if (event.type !== "m.room.member" || event.content.membership !== "join") {
            return;
        }
        var userId = event.state_key;
        if (userId === appServiceUserId) {
            return;
        }
        if (server.claimsUserId(userId)) {
            data.virtuals.push(userId);
        }
        else if (userId.indexOf("@-") === 0) {
            // Ignore guest user IDs -- TODO: Do this properly by passing them through
        }
        else {
            data.reals.push(userId);
        }
    });
    return data;
}

module.exports = MemberListSyncer;
<commit_msg>Raise how many times we try initial sync<commit_after>/*eslint no-invalid-this: 0*/ // eslint doesn't understand Promise.coroutine wrapping

// Controls the logic for determining which membership lists should be synced and
// handles the sequence of events until the lists are in sync.
"use strict";

var Promise = require("bluebird");
var promiseutil = require("../promiseutil");
var log = require("../logging").get("MemberListSyncer");

function MemberListSyncer(ircBridge, appServiceBot, server, appServiceUserId, injectJoinFn) {
    this.ircBridge = ircBridge;
    this.appServiceBot = appServiceBot;
    this.server = server;
    this.appServiceUserId = appServiceUserId;
    this.injectJoinFn = injectJoinFn;
    this._syncableRoomsPromise = null;
}

MemberListSyncer.prototype.sync = Promise.coroutine(function*() {
    let server = this.server;
    if (!server.isMembershipListsEnabled()) {
        log.info("%s does not have membership list syncing enabled.", server.domain);
        return;
    }
    if (!server.shouldSyncMembershipToIrc("initial")) {
        log.info("%s shouldn't sync initial memberships to irc.", server.domain);
        return;
    }
    log.info("Checking membership lists for syncing on %s", server.domain);
    let start = Date.now();
    let rooms = yield this._getSyncableRooms(server);
    log.info("Found %s syncable rooms (%sms)", rooms.length, Date.now() - start);
    start = Date.now();
    log.info("Joining Matrix users to IRC channels...");
    yield joinMatrixUsersToChannels(rooms, server, this.injectJoinFn);
    log.info("Joined Matrix users to IRC channels. (%sms)", Date.now() - start);
    // NB: We do not need to explicitly join IRC users to Matrix rooms
    // because we get all of the NAMEs/JOINs as events when we connect to
    // the IRC server. This effectively "injects" the list for us.
    start = Date.now();
    log.info("Leaving IRC users from Matrix rooms (cleanup)...");
    yield leaveIrcUsersFromRooms(rooms, server);
    log.info("Left IRC users from Matrix rooms. (%sms)", Date.now() - start);
});

MemberListSyncer.prototype.getChannelsToJoin = Promise.coroutine(function*() {
    let server = this.server;
    log.debug("getChannelsToJoin => %s", server.domain);
    let rooms = yield this._getSyncableRooms(server);

    // map room IDs to channels on this server.
    let channels = new Set();
    let roomInfoMap = {};
    let roomIds = rooms.map((roomInfo) => {
        roomInfoMap[roomInfo.id] = roomInfo;
        return roomInfo.id;
    });
    yield this.ircBridge.getStore().getIrcChannelsForRoomIds(roomIds).then((roomIdToIrcRoom) => {
        Object.keys(roomIdToIrcRoom).forEach((roomId) => {
            // only interested in rooms for this server
            let ircRooms = roomIdToIrcRoom[roomId].filter((ircRoom) => {
                return ircRoom.server.domain === server.domain;
            });
            ircRooms.forEach((ircRoom) => {
                channels.add(ircRoom.channel);
                log.debug(
                    "%s should be joined because %s real Matrix users are in room %s",
                    ircRoom.channel, roomInfoMap[roomId].realJoinedUsers.length, roomId
                );
                if (roomInfoMap[roomId].realJoinedUsers.length < 5) {
                    log.debug("These are: %s", JSON.stringify(roomInfoMap[roomId].realJoinedUsers));
                }
            });
        })
    });

    let channelsArray = Array.from(channels);
    log.debug(
        "getChannelsToJoin => %s should be synced: %s",
        channelsArray.length, JSON.stringify(channelsArray)
    );
    return channelsArray;
});

// map irc channel to a list of room IDs. If all of those
// room IDs have no real users in them, then part the bridge bot too.
MemberListSyncer.prototype.checkBotPartRoom = Promise.coroutine(function*(ircRoom, req) {
    if (ircRoom.channel.indexOf("#") !== 0) {
        return; // don't leave PM rooms
    }
    let matrixRooms = yield this.ircBridge.getStore().getMatrixRoomsForChannel(
        ircRoom.server, ircRoom.channel
    );

    if (matrixRooms.length === 0) {
        // no mapped rooms, leave the channel.
        yield this.ircBridge.partBot(ircRoom);
        return;
    }

    // At least 1 mapped room - query for the membership list in each room. If there are
    // any real users still left in the room, then do not part the bot from the channel.
    // Query via /$room_id/state rather than /initialSync as the latter can cause
    // the bridge to spin for minutes if the response is large.

    let shouldPart = true;
    for (let i = 0; i < matrixRooms.length; i++) {
        let roomId = matrixRooms[i].getId();
        req.log.debug("checkBotPartRoom: Querying room state in room %s", roomId);
        let res = yield this.appServiceBot.getClient().roomState(roomId);
        let data = getRoomMemberData(ircRoom.server, roomId, res, this.appServiceUserId);
        req.log.debug(
            "checkBotPartRoom: %s Matrix users are in room %s", data.reals.length, roomId
        );
        if (data.reals.length > 0) {
            shouldPart = false;
            break;
        }
    }

    if (shouldPart) {
        yield this.ircBridge.partBot(ircRoom);
    }
});

// grab all rooms the bot knows about which have at least 1 real user in them.
// ignoreCache exists because this function hammers /initialSync and that is expeeeensive,
// so we don't do it unless they need absolutely fresh data. On startup, this can be called
// multiple times, so we cache the first request's promise and return that instead of making
// double hits.
MemberListSyncer.prototype._getSyncableRooms = function(server, ignoreCache) {
    if (!ignoreCache && this._syncableRoomsPromise) {
        log.debug("Returning existing _getSyncableRooms Promise");
        return this._syncableRoomsPromise;
    }

    // hit /initialSync on the bot to pull in room state for all rooms.
    let self = this;
    let fetchRooms = Promise.coroutine(function*() {
        let attempts = 0;
        while (attempts < 100) {
            try {
                // roomDict = { room_id: RoomInfo }
                let roomDict = yield self.appServiceBot.getMemberLists();
                return Object.keys(roomDict).map(function(roomId) {
                    return roomDict[roomId];
                }).filter(function(roomInfo) {
                    // filter out rooms with no real matrix users in them.
                    return roomInfo.realJoinedUsers.length > 0;
                });
            }
            catch (err) {
                log.error("Failed to fetch syncable rooms: " + err.stack);
                attempts += 1;
                yield Promise.delay(5000); // wait 5s and try again
            }
        }
        log.error("Failed to fetch syncable rooms: Giving up.");
        return [];
    });

    this._syncableRoomsPromise = fetchRooms();
    return this._syncableRoomsPromise;
};

function joinMatrixUsersToChannels(rooms, server, injectJoinFn) {
    var d = promiseutil.defer();

    // filter out rooms listed in the rules
    var filteredRooms = [];
    rooms.forEach(function(roomInfo) {
        if (!server.shouldSyncMembershipToIrc("initial", roomInfo.id)) {
            log.debug(
                "Trimming room %s according to config rules (matrixToIrc=false)",
                roomInfo.id
            );
            if (!roomInfo.realJoinedUsers[0]) {
                return; // no joined users at all
            }
            // trim the list to a single user. We do this rather than filter the
            // room out entirely because otherwise there will be NO matrix users
            // on the IRC-side resulting in no traffic whatsoever.
            roomInfo.realJoinedUsers = [roomInfo.realJoinedUsers[0]];
            log.debug("Trimmed to " + roomInfo.realJoinedUsers);
        }
        filteredRooms.push(roomInfo);
    });

    log.debug("%s rooms passed the config rules", filteredRooms.length);

    // map the filtered rooms to a list of users to join
    // [Room:{reals:[uid,uid]}, ...] => [{uid,roomid}, ...]
    var entries = [];
    filteredRooms.forEach(function(roomInfo) {
        roomInfo.realJoinedUsers.forEach(function(uid, index) {
            entries.push({
                roomId: roomInfo.id,
                userId: uid,
                // Mark the first real matrix user f.e room so we can inject
                // them first to get back up and running more quickly when there
                // is no bot.
                frontier: (index === 0)
            });
        });
    });
    // sort frontier markers to the front of the array
    entries.sort(function(a, b) {
        if (a.frontier && !b.frontier) {
            return -1; // a comes first
        }
        else if (b.frontier && !a.frontier) {
            return 1; // b comes first
        }
        return 0; // don't care
    });

    log.debug("Got %s matrix join events to inject.", entries.length);
    // take the first entry and inject a join event
    function joinNextUser() {
        var entry = entries.shift();
        if (!entry) {
            d.resolve();
            return;
        }
        if (entry.userId.indexOf("@-") === 0) {
            joinNextUser();
            return;
        }
        log.debug(
            "Injecting join event for %s in %s (%s left) is_frontier=%s",
            entry.userId, entry.roomId, entries.length, entry.frontier
        );
        injectJoinFn(entry.roomId, entry.userId, entry.frontier).timeout(
            server.getMemberListFloodDelayMs()
        ).then(() => {
            joinNextUser();
        }, (err) => { // discard error, this will be due to timeouts which we don't want to log
            joinNextUser();
        });
    }

    joinNextUser();

    return d.promise;
}

function leaveIrcUsersFromRooms(rooms, server) {
    return Promise.resolve();
}

function getRoomMemberData(server, roomId, stateEvents, appServiceUserId) {
    stateEvents = stateEvents || [];
    var data = {
        roomId: roomId,
        virtuals: [],
        reals: []
    };
    stateEvents.forEach(function(event) {
        if (event.type !== "m.room.member" || event.content.membership !== "join") {
            return;
        }
        var userId = event.state_key;
        if (userId === appServiceUserId) {
            return;
        }
        if (server.claimsUserId(userId)) {
            data.virtuals.push(userId);
        }
        else if (userId.indexOf("@-") === 0) {
            // Ignore guest user IDs -- TODO: Do this properly by passing them through
        }
        else {
            data.reals.push(userId);
        }
    });
    return data;
}

module.exports = MemberListSyncer;
<|endoftext|>