1 var io = require('socket.io'); 2 var fileServer = require('./fileServer'); 3 var EventEmitter = require('events').EventEmitter; 4 var nowUtil = require('./nowUtil').nowUtil; 5 6 /** 7 * @name nowjs 8 * @constructor 9 * @description The object returned by require('now'). 10 */ 11 var Now = function () { 12 this.closures = {}; 13 this.groups = {}; 14 this.users = {}; 15 this.options = { 16 clientWrite: true, 17 autoHost: true, 18 socketio: {"log level" : 1}, 19 client: {}, 20 scope: 'window', 21 closureTimeout: 30000 22 }; 23 }; 24 25 Now.prototype.__proto__ = EventEmitter.prototype; 26 27 Now.prototype._readConfigFile = function (path) { 28 path = path || process.cwd() + "/nowjs.json"; 29 try { 30 var conf = require('fs').readFileSync(path), parsedConf; 31 try { 32 parsedConf = JSON.parse(conf); 33 } catch (e) { 34 //throw new logging.NowError("Malformed configuration file."); 35 //throw e; 36 } 37 return parsedConf; 38 } catch (err) { 39 //throw e; 40 //logging.log("No configuration file found"); 41 return undefined; 42 } 43 }; 44 45 /** 46 * @memberOf nowjs# 47 * @function 48 * @name getClient 49 50 * @description Retrieves a user from the given client ID and executes 51 * of several actions in the context of that user. 52 53 * @param {String} id The client ID associated with the target user. 54 * @param {Function} callback Takes no arguments. Called in the 55 * context of the user corresponding to the given id. 56 * @example nowjs.getClient('1234567890' function () { 57 * this.now.receiveMessage('SERVER', 'Anything is possible with NowJS.'); 58 * }); 59 */ 60 Now.prototype.getClient = function (id, callback) { 61 callback.apply(this.users[id]); 62 }; 63 64 /** 65 * @memberOf nowjs# 66 * @function 67 * @name getGroups 68 69 * @description Retrieves a list (represented in Javascript as an 70 * array) of all groups that have been created and passes it in to the 71 * supplied callback. 72 73 * @param {Function} callback Takes one argument, an array of all 74 * groups that have been created. 75 76 * @example nowjs.on('connect', function () { 77 * var self = this; 78 * getGroups(function (groups) { 79 * nowjs.getGroup(groups[Math.floor(groups.length * Math.random())]).addUser(self); 80 * }); 81 * }); 82 */ 83 Now.prototype.getGroups = function (callback) { 84 callback(Object.keys(this.groups)); 85 }; 86 87 /** 88 * @memberOf nowjs# 89 * @function 90 * @name getGroup 91 * @description Retrieves and returns a group from its name, creating it if 92 * necessary. 93 * @param {String} name The name of the group to be retrieved. 94 * @type Group 95 * @example var new_group = nowjs.getGroup('a new group'); 96 */ 97 Now.prototype.getGroup = function (name) { 98 if (!nowUtil.hasProperty(this.groups, name)) { 99 this.groups[name] = new this.Group(name); 100 /** 101 * @name nowjs#newgroup 102 * @event 103 * @param {Group} group The group created by {@link nowjs#getGroup}. 104 * @description Called when a new group is created. 105 * @example nowjs.on('newgroup', function (group) { 106 * console.log('You have successfully created the group `' + group.groupName + '`'); 107 * }); 108 */ 109 110 this.emit('newgroup', this.groups[name]); 111 } 112 return this.groups[name]; 113 }; 114 115 /** 116 * @memberOf nowjs# 117 * @function 118 * @name removeGroup 119 * @description Removes all traces of a group. 120 * @param {String} name The name of the group to be retrieved. 121 * @type Group 122 * @example var new_group = nowjs.getGroup('a new group'); 123 */ 124 Now.prototype.removeGroup = function (name) { 125 /** 126 * @name nowjs#removegroup 127 * @event 128 * @param {Group} group The group removed by {@link nowjs#getGroup}. 129 * @description Called when a group is removed. 130 * @example nowjs.on('removegroup', function (group) { 131 * console.log('Group `' + group.groupName + '` eliminated from existence.'); 132 * }); 133 */ 134 this.emit('removegroup', name); 135 }; 136 137 138 /** 139 * @static 140 * @memberOf nowjs 141 * @function 142 * @name initialize 143 144 * @description Returns a reference to the `everyone` object. The 145 * options object, if supplied, will be automatically merged with the 146 * default values. 147 148 * @param {httpServer} server A Node.js http server (such as the one 149 * available in the http module or a module like Express) on which to 150 * run Now. 151 152 * @param {Object} [options={"clientWrite" : true, "autoHost" : true, 153 "host" : undefined, "port" : undefined, "socketio" : {}, 154 "closureTimeout : 30000, "client : {}, "scope" : "window"}] 155 156 * @type Group 157 158 * @example nowjs.initialize(server, {clientWrite: false, socketio: {'log level': 2}); 159 */ 160 Now.prototype.initialize = function (server, options) { 161 // Merge options 162 if (typeof options === 'object') { 163 nowUtil.extend(this.options, options); 164 } else { 165 options = this._readConfigFile(options); 166 if (options) { 167 nowUtil.extend(this.options, options); 168 } 169 } 170 171 this.Group = require('./group').initialize(this); 172 this.User = require('./user').initialize(this); 173 this.Handlers = require('./handlers').initialize(this); 174 this.Support = require('./support').initialize(this); 175 176 var self = this; 177 178 fileServer.wrapServer(server, this.options); 179 this.server = io.listen(server, this.options.socketio); 180 181 // Need this to be separate from clientsMap. 182 this.server.sockets.on('connection', function (socket) { 183 var user = new self.User(socket); 184 socket.user = self.users[socket.id] = user; 185 self.getGroup('everyone').addUser(socket.id); 186 socket.emit('rd'); 187 }); 188 189 var everyone = this.getGroup('everyone'); 190 everyone.isSuperGroup = true; 191 192 // Shim for backwards compatibility. 193 this.on('connect', function () { 194 var user = nowUtil.clone(this); 195 user._events = everyone._events; 196 everyone.emit.apply(user, ['connect']); 197 }); 198 199 this.on('disconnect', function () { 200 var user = nowUtil.clone(this); 201 user._events = everyone._events; 202 everyone.emit.apply(user, ['disconnect']); 203 }); 204 205 return everyone; 206 }; 207 208 Now.prototype.addSupportServer = function(host, port){ 209 var server = new this.Support(host, port); 210 return server; 211 } 212 213 exports.Now = Now; 214 215 /** 216 * @name nowjs#connect 217 * @event 218 * @version 0.7.0 219 220 * @description Called in the context of a user when the server first 221 * receives a message from the given user. 222 223 * @example nowjs.on('connect', function () { 224 * this.now.receiveMessage('SERVER', 'Welcome to NowJS.'); 225 * }); 226 */ 227 228 /** 229 * @name nowjs#disconnect 230 * @event 231 * @version 0.7.0 232 233 * @description Called in the context of a user who has just 234 * disconnected from the server. 235 236 * @example nowjs.on('disconnect, function () { 237 * delete myArray[this.user.clientId]; 238 * }); 239 */ 240 241 /** 242 * @name nowjs#groupdel 243 * @event 244 * @version 0.7.0 245 246 * @param {Group} group Actually not quite a group; this parameter 247 * refers to a clone of the group in question that also carries the 248 * fully qualified name (fqn) of the variable to delete. Access the 249 * fqn via `group.fqn`. 250 251 * @description Called when deleting a variable from all members of 252 * the group specified by this function's argument. 253 254 * @example nowjs.on('groupdel', function (group) { 255 * if (group.groupName === 'everyone') { 256 * console.log('Everyone now no longer possesses ' + group.fqn); 257 * } 258 * }); 259 */ 260 261 /** 262 * @name nowjs#grouprv 263 * @event 264 * @version 0.7.0 265 266 * @param {Group} group Similar to {@link nowjs#groupdel}, this is also 267 * a clone of the actual group. In addition to the fully qualified 268 * name, this clone also possesses a serialized form of its target 269 * value, accessible via `group.val`. 270 271 * @description Called when replacing the value of a variable for all 272 * members of the group specified by this function's argument. 273 274 * @example nowjs.on('grouprv', function (group) { 275 * if (group.groupName === 'everyone') { 276 * console.log('Everyone now sees ' + group.fqn + ' as ' + group.val); 277 * } 278 * }); 279 */ 280 281