gitHub:http://github.com/NetEase/pomelo

Pomelo0.3.3

Pomelo

Expose createApplication().

createApp

Pomelo.createApp()

type: method

Create an pomelo application.

Source

Pomelo.createApp = function (opts) {
  var app = application;
  app.init(opts);
  self.app = app;
  return app;
};

Application

Application prototype.

getBase

Application.getBase()

type: method

Get application base path

// cwd: /home/game/ pomelo start // app.getBase() -> /home/game

Source

Application.getBase = function() {
  return this.get('base') || process.cwd();
};

filter

Application.filter()

type: method

Params

  • filter - provide before and after filter method.

add a filter to before and after filter

Source

Application.filter = function (filter) {
  this.before(filter);
  this.after(filter);
  return this;
};

before

Application.before()

type: method

Params

  • bf - before fileter, bf(msg, session, next)

Add before filter.

Source

Application.before = function (bf) {
  var befores = this.get('__befores__');
  if(!befores) {
    befores = [];
    this.set('__befores__', befores);
  }
  befores.push(bf);
  return this;
};

after

Application.after()

type: method

Params

  • af - after filter, `af(err, msg, session, resp, next)`

Add after filter.

Source

Application.after = function (af) {
  var afters = this.get('__afters__');
  if(!afters) {
    afters = [];
    this.set('__afters__', afters);
  }
  afters.push(af);
  return this;
};

load

Application.load()

type: method

Params

  • name - (optional) name of the component
  • component - component instance or factory function of the component
  • opts - (optional) construct parameters for the factory function

Load component

Source

Application.load = function(name, component, opts) {
  if(typeof name !== 'string') {
    opts = component;
    component = name;
    name = null;
    if(typeof component.name === 'string') {
      name = component.name;
    }
  }

  if(typeof component === 'function') {
    component = component(this, opts);
  }

  if(!name && typeof component.name === 'string') {
    name = component.name;
  }

  if(name && this.components[name]) {
    // ignore duplicat component
    logger.warn('ignore duplicate component: %j', name);
    return;
  }

  this.loaded.push(component);
  if(name) {
    // components with a name would get by name throught app.components later.
    this.components[name] = component;
  }

  return this;
};

loadConfig

Application.loadConfig()

type: method

Params

  • key - environment key
  • val - environment value

Load Configure json file to settings.

Source

Application.loadConfig = function (key, val) {
  var env = this.get('env');
  val = require(val);
  if (val[env]) {
    val = val[env];
  }
  this.set(key, val);
};

route

Application.route()

type: method

Params

  • serverType - server type string
  • routeFunc - route function. routeFunc(session, msg, app, cb)

Set the route function for the specified server type.

Examples:

app.route('area', routeFunc);

var routeFunc = function(session, msg, app, cb) { // all request to area would be route to the first area server var areas = app.getServersByType('area'); cb(null, areas[0].id); };

Source

Application.route = function(serverType, routeFunc) {
  var routes = this.get('__routes__');
  if(!routes) {
    routes = {};
    this.set('__routes__', routes);
  }
  routes[serverType] = routeFunc;
  return this;
};

start

Application.start()

type: method

Params

  • cb - callback function

Start application. It would load the default components and start all the loaded components.

Source

Application.start = function(cb) {
  if(this.state > STATE_INITED) {
    utils.invokeCallback(cb, new Error('application has already start.'));
    return;
  }
  appUtil.loadDefaultComponents(this);
  var self = this;
  appUtil.optComponents(this.loaded, 'start', function(err) {
    self.state = STATE_START;
    if(err) {
      utils.invokeCallback(cb, err);
    } else {
      logger.info('%j enter after start...', self.getServerId());
      self.afterStart(cb);
    }
  });
};

set

Application.set()

type: method

Params

  • setting - the setting of application
  • val - the setting's value
  • attach - whether attach the settings to application

Assign setting to val, or return setting's value.

Example:

app.set('key1', 'value1'); app.get('key1'); // 'value1' app.key1; // undefined

app.set('key2', 'value2', true); app.get('key2'); // 'value2' app.key2; // 'value2'

Source

Application.set = function (setting, val, attach) {
  if (arguments.length === 1) {
    return this.settings[setting];
  }
  this.settings[setting] = val;
  if(attach) {
    this[setting] = val;
  }
  return this;
};

get

Application.get()

type: method

Params

  • setting - application setting

Get property from setting

Source

Application.get = function (setting) {
  return this.settings[setting];
};

enabled

Application.enabled()

type: method

Params

  • setting - application setting

Check if setting is enabled.

Source

Application.enabled = function (setting) {
  return !!this.get(setting);
};

disabled

Application.disabled()

type: method

Params

  • setting - application setting

Check if setting is disabled.

Source

Application.disabled = function (setting) {
  return !this.get(setting);
};

enable

Application.enable()

type: method

Params

  • setting - application setting

Enable setting.

Source

Application.enable = function (setting) {
  return this.set(setting, true);
};

disable

Application.disable()

type: method

Params

  • setting - application setting

Disable setting.

Source

Application.disable = function (setting) {
  return this.set(setting, false);
};

configure

Application.configure()

type: method

Params

  • env - application environment
  • fn - callback function
  • type - server type

Configure callback for the specified env and server type. When no env is specified that callback will be invoked for all environments and when no type is specified that callback will be invoked for all server types.

Examples:

app.configure(function(){ // executed for all envs and server types });

app.configure('development', function(){ // executed development env });

app.configure('development', 'connector', function(){ // executed for development env and connector server type });

Source

Application.configure = function (env, type, fn) {
  var args = [].slice.call(arguments);
  fn = args.pop();
  env = 'all';
  type = 'all';

  if(args.length > 0) {
    env = args[0];
  }
  if(args.length > 1) {
    type = args[1];
  }

  if (env === 'all' || env.indexOf(this.settings.env) >= 0) {
    if (type === 'all' || type.indexOf(this.settings.serverType) >= 0) {
      fn.call(this);
    }
  }
  return this;
};

registerAdmin

Application.registerAdmin()

type: method

Params

  • module - (optional) module id or provoided by module.moduleId
  • module - module object or factory function for module
  • opts - construct parameter for module

Register admin modules. Admin modules is the extends point of the monitor system.

Source

Application.registerAdmin = function(moduleId, module, opts){
  var modules = this.get('__modules__');
  if(!modules) {
    modules = [];
    this.set('__modules__', modules);
  }

  if(typeof moduleId !== 'string') {
    opts = module;
    module = moduleId;
    moduleId = module.moduleId;
  }

  modules.push({moduleId: moduleId, module: module, opts: opts});
};

getMaster

Application.getMaster()

type: method

Get master server info.

Source

Application.getMaster = function() {
  return this.master;
};

getCurServer

Application.getCurServer()

type: method

Get current server info.

Source

Application.getCurServer = function() {
  return this.curServer;
};

getServerId

Application.getServerId()

type: method

Get current server id.

Source

Application.getServerId = function() {
  return this.serverId;
};

getServerType

Application.getServerType()

type: method

Get current server type.

Source

Application.getServerType = function() {
  return this.serverType;
};

getServers

Application.getServers()

type: method

Get all the current server infos.

Source

Application.getServers = function() {
  return this.servers;
};

getServersFromConfig

Application.getServersFromConfig()

type: method

Get all server infos from servers.json.

Source

Application.getServersFromConfig = function() {
  return this.get('__serverMap__');
};

getServerTypes

Application.getServerTypes()

type: method

Get all the server type.

Source

Application.getServerTypes = function() {
  return this.serverTypes;
};

getServerById

Application.getServerById()

type: method

Params

  • serverId - server id

Get server info by server id from current server cluster.

Source

Application.getServerById = function(serverId) {
  return this.servers[serverId];
};

getServerFromConfig

Application.getServerFromConfig()

type: method

Params

  • serverId - server id

Get server info by server id from servers.json.

Source

Application.getServerFromConfig = function(serverId) {
  return this.get('__serverMap__')[serverId];
};

getServersByType

Application.getServersByType()

type: method

Params

  • serverType - server type

Get server infos by server type.

Source

Application.getServersByType = function(serverType) {
  return this.serverTypeMaps[serverType];
};

isFrontend

Application.isFrontend()

type: method

Params

  • server - server info. it would check current server

Check the server whether is a frontend server

Source

Application.isFrontend = function(server) {
  server = server || this.getCurServer();
  return !!server && !!server.frontend;
};

isBackend

Application.isBackend()

type: method

Params

  • server - server info. it would check current server

Check the server whether is a backend server

Source

Application.isBackend = function(server) {
  server = server || this.getCurServer();
  return !!server && !server.frontend;
};

isMaster

Application.isMaster()

type: method

Check whether current server is a master server

Source

Application.isMaster = function() {
  return this.serverType === 'master';
};

addServers

Application.addServers()

type: method

Params

  • servers - new server info list

Add new server info to current application in runtime.

Source

Application.addServers = function(servers) {
  if(!servers || !servers.length) {
    return;
  }

  var item, slist;
  for(var i=0, l=servers.length; i<l; i++) {
    item = servers[i];
    // update global server map
    this.servers[item.id] = item;

    // update global server type map
    slist = this.serverTypeMaps[item.serverType];
    if(!slist) {
      this.serverTypeMaps[item.serverType] = slist = [];
    }
    replaceServer(slist, item);

    // update global server type list
    if(this.serverTypes.indexOf(item.serverType) < 0) {
      this.serverTypes.push(item.serverType);
    }
  }
  this.event.emit(events.ADD_SERVERS, servers);
};

removeServers

Application.removeServers()

type: method

Params

  • ids - server id list

Remote server info from current application at runtime.

Source

Application.removeServers = function(ids) {
  if(!ids || !ids.length) {
    return;
  }

  var id, item, slist;
  for(var i=0, l=ids.length; i<l; i++) {
    id = ids[i];
    item = this.servers[id];
    if(!item) {
      continue;
    }
    // clean global server map
    delete this.servers[id];

    // clean global server type map
    slist = this.serverTypeMaps[item.serverType];
    removeServer(slist, id);
    // TODO: should remove the server type if the slist is empty?
  }
  this.event.emit(events.REMOVE_SERVERS, ids);
};

var replaceServer = function(slist, serverInfo) {
  for(var i=0, l=slist.length; i<l; i++) {
    if(slist[i].id === serverInfo.id) {
      slist[i] = serverInfo;
      return;
    }
  }
  slist.push(serverInfo);
};

var removeServer = function(slist, id) {
  if(!slist || !slist.length) {
    return;
  }

  for(var i=0, l=slist.length; i<l; i++) {
    if(slist[i].id === id) {
      slist.splice(i, 1);
      return;
    }
  }
};

SessionService

Session service manages the sessions for each client connection.

Session service is created by session component and is only available in frontend servers. You can access the service by app.get('sessionService') in frontend servers.

kick

SessionService.prototype.kick()

type: method

Params

  • uid - user id asscociated with the session
  • cb - callback function

Kick a user offline by user id.

Source

SessionService.prototype.kick = function(uid, cb) {
  var session = this.getByUid(uid);

  if(session) {
    // notify client
    session.closed('kick');
    process.nextTick(function() {
      utils.invokeCallback(cb);
    });
  } else {
    process.nextTick(function() {
      utils.invokeCallback(cb);
    });
  }
};

kickBySessionId

SessionService.prototype.kickBySessionId()

type: method

Params

  • sid - session id
  • cb - callback function

Kick a user offline by session id.

Source

SessionService.prototype.kickBySessionId = function(sid, cb) {
  var session = this.get(sid);

  if(session) {
    // notify client
    session.closed('kick');
    process.nextTick(function() {
      utils.invokeCallback(cb);
    });
  } else {
    process.nextTick(function() {
      utils.invokeCallback(cb);
    });
  }
};

LocalSessionService

Service that maintains local sessions and the communiation with frontend server.

LocalSessionService would be created in each server process and maintains local sessions for current process and communicates with the relative frontend servers.

LocalSessionService instance could be accessed by app.get('localSessionService').

get

LocalSessionService.prototype.get()

type: method

Params

  • frontendId - frontend server id that session attached
  • sid - session id
  • cb - callback function. args: cb(err, localSession)

Get local session by frontend server id and session id.

Source

LocalSessionService.prototype.get = function(frontendId, sid, cb) {
  var namespace = 'sys';
  var service = 'sessionRemote';
  var method = 'getLocalSessionBySid';
  var args = [sid];
  rpcInvoke(this.app, frontendId, namespace, service, method,
            args, localSessionCB.bind(null, this, cb));

};

getByUid

LocalSessionService.prototype.getByUid()

type: method

Params

  • frontendId - frontend server id that session attached
  • uid - user id binded with the session
  • cb - callback function. args: cb(err, localSession)

Get local session by frontend server id and user id.

Source

LocalSessionService.prototype.getByUid = function(frontendId, uid, cb) {
  var namespace = 'sys';
  var service = 'sessionRemote';
  var method = 'getLocalSessionByUid';
  var args = [uid];
  rpcInvoke(this.app, frontendId, namespace, service, method,
            args, localSessionCB.bind(null, this, cb));
};

kickBySid

LocalSessionService.prototype.kickBySid()

type: method

Params

  • frontendId - cooperating frontend server id
  • sid - session id
  • cb - callback function

Kick a session by session id.

Source

LocalSessionService.prototype.kickBySid = function(frontendId, sid, cb) {
  var namespace = 'sys';
  var service = 'sessionRemote';
  var method = 'kickBySid';
  var args = [sid];
  rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
};

kickByUid

LocalSessionService.prototype.kickByUid()

type: method

Params

  • frontendId - cooperating frontend server id
  • uid - user id
  • cb - callback function

Kick a session by user id.

Source

LocalSessionService.prototype.kickByUid = function(frontendId, uid, cb) {
  var namespace = 'sys';
  var service = 'sessionRemote';
  var method = 'kickByUid';
  var args = [uid];
  rpcInvoke(this.app, frontendId, namespace, service, method, args, cb);
};

LocalSession

LocalSession is the proxy for global session passed to handlers and it helps to keep the key/value pairs for the server local. Global session locates in frontend server and should not be accessed directly.

The mainly operation on local session should be read and any changes happen in local session is local and would be discarded in next request. You have to push the changes to the frontend manually if necessary. Any push would overwrite the last push of the same key silently and the changes would be saw in next request. And you have to make sure the transaction outside if you would push the session concurrently in different processes.

See the api below for more details.

bind

LocalSession.prototype.bind()

type: method

Params

  • uid - user id
  • cb - callback function

Bind current session with the user id. It would push the uid to frontend server and bind uid to the global session.

Source

LocalSession.prototype.bind = function(uid, cb) {
  var self = this;
  this.__sessionService__.bind(this, uid, function(err) {
    if(!err) {
      self.uid = uid;
    }
    cb(err);
  });
};

set

LocalSession.prototype.set()

type: method

Params

  • key - key
  • value - value

Set the key/value into local session.

Source

LocalSession.prototype.set = function(key, value) {
  this.settings[key] = value;
};

get

LocalSession.prototype.get()

type: method

Params

  • key - key

Get the value from local session by key.

Source

LocalSession.prototype.get = function(key) {
  return this.settings[key];
};

push

LocalSession.prototype.push()

type: method

Params

  • key - key
  • cb - callback function

Push the key/value in local session to the global session.

Source

LocalSession.prototype.push = function(key, cb) {
  this.__sessionService__.push(this.frontendId, this.id, key, this.get(key), cb);
};

pushAll

LocalSession.prototype.pushAll()

type: method

Params

  • cb - callback function

Push all the key/values in local session to the global session.

Source

LocalSession.prototype.pushAll = function(cb) {
  this.__sessionService__.pushAll(this.frontendId, this.id, this.settings, cb);
};

ChannelService

Create and maintain channels for server local.

ChannelService is created by channel component which is a default loaded component of pomelo and channel service would be accessed by app.get('channelService').

createChannel

ChannelService.prototype.createChannel()

type: method

Params

  • name - channel's name

Create channel with name.

Source

ChannelService.prototype.createChannel = function(name) {
  if(this.channels[name]) {
    return this.channels[name];
  }

  var c = new Channel(name, this);
  this.channels[name] = c;
  return c;
};

getChannel

ChannelService.prototype.getChannel()

type: method

Params

  • name - channel's name
  • create - if true, create channel

Get channel by name.

Source

ChannelService.prototype.getChannel = function(name, create) {
  var channel = this.channels[name];
  if(!channel && !!create) {
    channel = this.channels[name] = new Channel(name, this);
  }
  return channel;
};

destroyChannel

ChannelService.prototype.destroyChannel()

type: method

Params

  • name - channel name

Destroy channel by name.

Source

ChannelService.prototype.destroyChannel = function(name) {
  delete this.channels[name];
};

pushMessageByUids

ChannelService.prototype.pushMessageByUids()

type: method

Params

  • route - message route
  • msg - message that would be sent to client
  • uids - the receiver info list, [{uid: userId, sid: frontendServerId}]
  • cb - cb(err)

Push message by uids. Group the uids by group. ignore any uid if sid not specified.

Source

ChannelService.prototype.pushMessageByUids = function(route, msg, uids, cb) {
  if(typeof route !== 'string') {
    cb = uids;
    uids = msg;
    msg = route;
    route = msg.route;
  }

  if(!uids || uids.length === 0) {
    utils.invokeCallback(cb, new Error('uids should not be empty'));
    return;
  }
  var groups = {}, record;
  for(var i=0, l=uids.length; i<l; i++) {
    record = uids[i];
    add(record.uid, record.sid, groups);
  }

  sendMessageByGroup(this, route, msg, groups, cb);
};

broadcast

ChannelService.prototype.broadcast()

type: method

Params

  • stype - frontend server type string
  • route - route string
  • msg - message
  • opts - broadcast options. opts.binded: push to binded sessions or all the sessions
  • cb - callback

Broadcast message to all the connected clients.

Source

ChannelService.prototype.broadcast = function(stype, route, msg, opts, cb) {
  var app = this.app;
  var namespace = 'sys';
  var service = 'channelRemote';
  var method = 'broadcast';
  var failIds = [];
  var servers = app.getServersByType(stype);

  if(!servers || servers.length === 0) {
    // server list is empty
    cb();
    return;
  }

  var count = servers.length;
  var successFlag = false;

  var latch = countDownLatch.createCountDownLatch(count, function() {
    if(!successFlag) {
      utils.invokeCallback(cb, new Error('broadcast fails'));
      return;
    }
    utils.invokeCallback(cb, null, failIds);
  });

  var genCB = function(id) {
    return function(err, fails) {
      if(err) {
        logger.error('[broadcast] fail to push message to %j, err:' + err.stack, id);
        latch.done();
        return;
      }
      successFlag = true;
      latch.done();
    };
  };

  for(var i=0, l=count; i<l; i++) {
    app.rpcInvoke(servers[i].id, {namespace: namespace, service: service,
      method: method, args: [route, msg, opts]}, genCB());
  }
};

Channel

Channel maintains the receiver collection for a subject. You can add users into a channel and then broadcast message to them by channel.

add

Channel.prototype.add()

type: method

Params

  • uid - user id
  • sid - frontend server id which user has connected to

Add user to channel.

Source

Channel.prototype.add = function(uid, sid) {
  if(this.state > ST_INITED) {
    return false;
  } else {
    var res = add(uid, sid, this.groups);
    if(res) {
      this.records[uid] = {sid: sid, uid: uid};
    }
    return res;
  }
};

leave

Channel.prototype.leave()

type: method

Params

  • uid - user id
  • sid - frontend server id which user has connected to.

Remove user from channel.

Source

Channel.prototype.leave = function(uid, sid) {
  if(!uid || !sid) {
    return false;
  }
  delete this.records[uid];
  return deleteFrom(uid, sid, this.groups[sid]);
};

getMembers

Channel.prototype.getMembers()

type: method

Get channel members.

Notice: Heavy operation.

Source

Channel.prototype.getMembers = function() {
  var res = [], groups = this.groups;
  var group, i, l;
  for(var sid in this.groups) {
    group = this.groups[sid];
    for(i=0, l=group.length; i<l; i++) {
      res.push(group[i]);
    }
  }
  return res;
};

getMember

Channel.prototype.getMember()

type: method

Params

  • uid - user id

Get Member info.

Source

Channel.prototype.getMember = function(uid) {
  return this.records[uid];
};

destroy

Channel.prototype.destroy()

type: method

Destroy channel.

Source

Channel.prototype.destroy = function() {
  this.state = ST_DESTROYED;
  this.__channelService__.destroyChannel(this.name);
};

pushMessage

Channel.prototype.pushMessage()

type: method

Params

  • route - message route
  • msg - message that would be sent to client
  • cb - callback function

Push message to all the members in the channel

Source

Channel.prototype.pushMessage = function(route, msg, cb) {
  if(this.state !== ST_INITED) {
    utils.invokeCallback(new Error('channel is not running now'));
    return;
  }

  if(typeof route !== 'string') {
    cb = msg;
    msg = route;
    route = msg.route;
  }

  sendMessageByGroup(this.__channelService__, route, msg, this.groups, cb);
};
copyright 2012, NetEase, Inc. All Rights Reserved.