1 var net = require('net');
  2 var nowUtil = require('./nowUtil').nowUtil;
  3 
  4 exports.initialize = function(nowjs){
  5   var fn = require('./function').init(nowjs);
  6 
  7   function Support(host, port){
  8     this.socket = net.createConnection(port, host);
  9     this._attachListeners();
 10     this.socket.setNoDelay();
 11     this.availableFunctions = {};
 12   }
 13 
 14   Support.prototype._startHandshake = function(){
 15     this.socket.write(JSON.stringify({type:'new'}));
 16   };
 17 
 18   Support.prototype._attachListeners = function(){
 19     var self = this;
 20     this.socket.on('connect', function(){self._startHandshake();});
 21     this.socket.on('data', function(message){self._handleMessage(message);});
 22   };
 23 
 24   Support.prototype.getRemoteFunction = function(fn) {
 25     var self = this;
 26     if(this.availableFunctions[fn] == undefined){throw new Error("No such function: " + fn);};
 27     return function(){
 28       var args = [];
 29       for (var i = 0, ii = arguments.length; i < ii; i++) {
 30         args[i] = arguments[i];
 31       }
 32       for (i = 0, ii = args.length; i < ii; i++) {
 33         if (typeof args[i] === 'function') {
 34           closureId = 'closure_' + args[i].name + '_' + nowUtil.generateRandomString();
 35           nowjs.closures[closureId] = args[i];
 36           args[i] = {fqn: closureId};
 37           setTimeout(function () {
 38             nowjs.closures[closureId] = nowUtil.noop;
 39           }, nowjs.options.closureTimeout);
 40         }
 41       }
 42 
 43       self.socket.write(JSON.stringify({type: 'rfc',fqn:fn, args:args}));
 44     };
 45   };
 46 
 47   Support.prototype._handleMessage = function(message){
 48     message = JSON.parse(message.toString());
 49     switch(message.type){
 50     case "usercall":
 51       var user = nowjs.users[message.id];
 52       if (user && message.serverId !== nowjs.serverId) {
 53         args = message.args;
 54         // Convert any remote function stubs into remote functions
 55         for (i = 0, ll = args.length; i < ll; i++) {
 56           if (nowUtil.hasProperty(args[i], 'fqn')) {
 57             obj = {host: message.host, port:message.port, fqn: args[i].fqn};
 58             args[i] = fn.closurecall.bind(obj);
 59           }
 60         }
 61         theFunction = user.get(message.fqn);
 62         theFunction.apply({}, args);
 63       } 
 64       break;
 65     case "multicall":
 66       group = nowjs.getGroup(message.groupName);
 67       //group = nowUtil.clone(group, {excludes: message.excludes});
 68       if (group) {
 69         args = message.args;
 70         // Convert any remote function stubs into remote functions
 71         for (i = 0, ll = args.length; i < ll; i++) {
 72           if (nowUtil.hasProperty(args[i], 'fqn')) {
 73             obj = {socket: this.socket, host: message.host, port:message.port, fqn: args[i].fqn};
 74             args[i] = fn.closurecall.bind(obj);
 75           }
 76         }
 77         group = nowUtil.clone(group, {fqn: message.fqn});
 78         nowjs.emit('multicall', group, args);
 79       }
 80       break;
 81     case 'closurecall':
 82       var args = message.args;
 83       // Convert any remote function stubs into remote functions
 84       for (i = 0, ll = args.length; i < ll; i++) {
 85         if (nowUtil.hasProperty(args[i], 'fqn')) {
 86           obj = {socket: this.socket, host: message.host, port:message.port, fqn: args[i].fqn};
 87           args[i] = fn.closurecall.bind(obj);
 88         }
 89       }
 90       theFunction = nowjs.closures[message.fqn];
 91       theFunction.apply({}, args);
 92       break;
 93     case 'functionList':
 94       var funcs = message.functions;
 95       for(var i = 0, ll = funcs.length; i < ll; i++){
 96         this.availableFunctions[funcs[i]] = true;
 97       }
 98     }
 99   };
100 
101 
102   return Support;
103 }