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" : 2}, 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 (name) { 106 * console.log('You have successfully created the group `' + name + '`'); 107 * }); 108 */ 109 110 this.emit('newgroup', this.groups[name]); 111 } 112 return this.groups[name]; 113 }; 114 115 /** 116 * @static 117 * @memberOf nowjs 118 * @function 119 * @name initialize 120 121 * @description Returns a reference to the `everyone` object. The 122 * options object, if supplied, will be automatically merged with the 123 * default values. 124 125 * @param {httpServer} server A Node.js http server (such as the one 126 * available in the http module or a module like Express) on which to 127 * run Now. 128 129 * @param {Object} [options={"clientWrite" : true, "autoHost" : true, 130 "host" : undefined, "port" : undefined, "socketio" : {}, 131 "closureTimeout : 30000, "client : {}, "scope" : "window"}] 132 133 * @type Group 134 135 * @example nowjs.initialize(server, {clientWrite: false, socketio: {'log level': 2}); 136 */ 137 Now.prototype.initialize = function (server, options) { 138 // Merge options 139 if (typeof options === 'object') { 140 nowUtil.extend(this.options, options); 141 } else { 142 options = this._readConfigFile(options); 143 if (options) { 144 nowUtil.extend(this.options, options); 145 } 146 } 147 148 this.Group = require('./group').initialize(this); 149 this.User = require('./user').initialize(this); 150 this.Handlers = require('./handlers').initialize(this); 151 this.Support = require('./support').initialize(this); 152 153 var self = this; 154 155 fileServer.wrapServer(server, this.options); 156 this.server = io.listen(server); 157 for (var i in this.options.socketio) { 158 this.server.set(i, this.options.socketio[i]); 159 } 160 161 // Need this to be separate from clientsMap. 162 this.server.sockets.on('connection', function (socket) { 163 var user = new self.User(socket); 164 socket.user = self.users[socket.id] = user; 165 self.getGroup('everyone').addUser(socket.id); 166 socket.emit('rd'); 167 }); 168 169 var everyone = this.getGroup('everyone'); 170 everyone.isSuperGroup = true; 171 172 // Shim for backwards compatibility. 173 this.on('connect', function () { 174 var user = nowUtil.clone(this); 175 user._events = everyone._events; 176 everyone.emit.apply(user, ['connect']); 177 }); 178 179 this.on('disconnect', function () { 180 var user = nowUtil.clone(this); 181 user._events = everyone._events; 182 everyone.emit.apply(user, ['disconnect']); 183 }); 184 185 return everyone; 186 }; 187 188 Now.prototype.addSupportServer = function(host, port){ 189 var server = new this.Support(host, port); 190 return server; 191 } 192 193 exports.Now = Now; 194 195 /** 196 * @name nowjs#connect 197 * @event 198 * @version 0.7.0 199 200 * @description Called in the context of a user when the server first 201 * receives a message from the given user. 202 203 * @example nowjs.on('connect', function () { 204 * this.now.receiveMessage('SERVER', 'Welcome to NowJS.'); 205 * }); 206 */ 207 208 /** 209 * @name nowjs#disconnect 210 * @event 211 * @version 0.7.0 212 213 * @description Called in the context of a user who has just 214 * disconnected from the server. 215 216 * @example nowjs.on('disconnect, function () { 217 * delete myArray[this.user.clientId]; 218 * }); 219 */ 220 221 /** 222 * @name nowjs#groupdel 223 * @event 224 * @version 0.7.0 225 226 * @param {Group} group Actually not quite a group; this parameter 227 * refers to a clone of the group in question that also carries the 228 * fully qualified name (fqn) of the variable to delete. Access the 229 * fqn via `group.fqn`. 230 231 * @description Called when deleting a variable from all members of 232 * the group specified by this function's argument. 233 234 * @example nowjs.on('groupdel', function (group) { 235 * if (group.groupName === 'everyone') { 236 * console.log('Everyone now no longer possesses ' + group.fqn); 237 * } 238 * }); 239 */ 240 241 /** 242 * @name nowjs#grouprv 243 * @event 244 * @version 0.7.0 245 246 * @param {Group} group Similar to {@link nowjs#groupdel}, this is also 247 * a clone of the actual group. In addition to the fully qualified 248 * name, this clone also possesses a serialized form of its target 249 * value, accessible via `group.val`. 250 251 * @description Called when replacing the value of a variable for all 252 * members of the group specified by this function's argument. 253 254 * @example nowjs.on('grouprv', function (group) { 255 * if (group.groupName === 'everyone') { 256 * console.log('Everyone now sees ' + group.fqn + ' as ' + group.val); 257 * } 258 * }); 259 */ 260 261