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