From db597358586b97afa9601f32390da6b4cfa03531 Mon Sep 17 00:00:00 2001
From: exane <raco0n@gmx.de>
Date: Mon, 15 Jun 2015 21:03:12 +0200
Subject: [PATCH] replace socket.io with socketcluster

---
 .gitignore           |  1 +
 package.json         |  8 ++++-
 public/js/client.js  | 74 ++++++++++++++++++++++++++++++++++++-----
 server/Battle.js     | 35 ++++++++++++++++----
 server/Battleside.js | 13 --------
 server/Card.js       |  3 ++
 server/Npc.js        | 28 ----------------
 server/Room.js       | 67 +++++++++++++++++++++++++------------
 server/Socket.js     |  3 --
 server/User.js       | 28 +++++++++-------
 server/_server.js    |  2 ++
 server/server.js     | 13 +++++++-
 server/store.js      |  4 +++
 server/worker.js     | 78 ++++++++++++++++++++++++++++++++++++++++++++
 14 files changed, 263 insertions(+), 94 deletions(-)
 delete mode 100644 server/Npc.js
 create mode 100644 server/_server.js
 create mode 100644 server/store.js
 create mode 100644 server/worker.js

diff --git a/.gitignore b/.gitignore
index 47e2d23..de30e87 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
 node_modules
 .idea
 build
+test
\ No newline at end of file
diff --git a/package.json b/package.json
index b319e8b..f00b072 100644
--- a/package.json
+++ b/package.json
@@ -4,7 +4,7 @@
   "description": "",
   "main": "gulpfile.js",
   "dependencies": {
-    "socket.io": "^1.3.5",
+    "socket.io": "^1.3.5"
   },
   "devDependencies": {
     "babelify": "^6.1.2",
@@ -17,6 +17,12 @@
     "promise": "^7.0.1",
     "pubsub-js": "^1.5.2",
     "shortid": "^2.2.2",
+    "connect": "3.0.1",
+    "express": "4.12.3",
+    "minimist": "1.1.0",
+    "serve-static": "1.8.0",
+    "socketcluster": "2.2.x",
+    "socketcluster-client": "2.2.x",
     "vinyl-source-stream": "^1.1.0"
   },
   "scripts": {
diff --git a/public/js/client.js b/public/js/client.js
index 59e21d9..1bf1ea9 100644
--- a/public/js/client.js
+++ b/public/js/client.js
@@ -1,4 +1,5 @@
-var io = require("socket.io-client")/*("http://localhost:16918")*/;
+/*("http://localhost:16918")*/
+var socketCluster = require("socketcluster-client");
 var Backbone = require("backbone");
 var Handlebars = require("handlebars");
 var $ = require("jquery");
@@ -22,8 +23,9 @@ Handlebars.registerHelper("health", function(lives, options){
 var Config = {};
 
 Config.Server = {
-  "URL": "http://localhost",
-  "PORT": 16918
+  "hostname": "localhost",
+  "port": 16918,
+  secure: false
 }
 
 var App = Backbone.Router.extend({
@@ -40,14 +42,14 @@ var App = Backbone.Router.extend({
     Backbone.history.start();
   },
   connect: function(){
-    this.socket = io(Config.Server.URL + ":" + Config.Server.PORT);
+    this.socket = socketCluster.connect(Config.Server);
   },
   receive: function(event, cb){
     this.socket.on(event, cb);
-  },
+  }, /*
   receiveOnce: function(event, cb){
     this.socket.once(event, cb);
-  },
+  },*/
   send: function(event, data){
     data = data || null;
     var socket = this.socket;
@@ -141,7 +143,7 @@ var SideView = Backbone.View.extend({
       this.$info.addClass("removeBackground");
     }
 
-    this.$info.find(".passing").html(d.passing?"Passed":"");
+    this.$info.find(".passing").html(d.passing ? "Passed" : "");
 
   },
   renderCloseField: function(){
@@ -219,6 +221,8 @@ var BattleView = Backbone.View.extend({
     this.$hand = this.$el.find(".field-hand");
     this.$preview = this.$el.find(".card-preview");
 
+    /*//this.battleChannel = app.socket.subscribe()
+
     app.receive("update:hand", function(data){
       if(user.get("roomSide") == data._roomSide){
         self.handCards = JSON.parse(data.cards);
@@ -257,13 +261,14 @@ var BattleView = Backbone.View.extend({
       side.field.weather = data.weather;
 
       side.render();
-    })
+    })*/
 
     var interval = setInterval(function(){
       if(!user.get("room")) return;
+      this.setUpBattleEvents(user.get("room"));
       this.app.send("request:gameLoaded", {_roomID: user.get("room")});
       clearInterval(interval);
-    }.bind(this), 100);
+    }.bind(this), 10);
 
     this.render();
 
@@ -346,6 +351,48 @@ var BattleView = Backbone.View.extend({
     this.yourSide.render();
     this.otherSide.render();*/
     return this;
+  },
+  setUpBattleEvents: function(channelName){
+    this.battleChannel = this.app.socket.subscribe(channelName);
+    var self = this;
+    var user = this.user;
+
+    this.battleChannel.watch(function(d){
+      var event = d.event, data = d.data;
+
+      if(event === "update:hand"){
+        if(user.get("roomSide") == data._roomSide){
+          self.handCards = JSON.parse(data.cards);
+          self.render();
+        }
+      }
+      else if(event === "update:info"){
+        var _side = data._roomSide;
+        var infoData = data.info;
+        var leader = data.leader;
+
+        var side = self.yourSide;
+        if(user.get("roomSide") != _side){
+          side = self.otherSide;
+        }
+        side.infoData = infoData;
+        side.leader = leader;
+        side.render();
+      }
+      else if(event === "update:fields"){
+        var _side = data._roomSide;
+
+        var side = self.yourSide;
+        if(user.get("roomSide") != _side){
+          side = self.otherSide;
+        }
+        side.field.close = data.close;
+        side.field.ranged = data.ranged;
+        side.field.siege = data.siege;
+        side.field.weather = data.weather;
+        side.render();
+      }
+    })
   }
 });
 
@@ -357,6 +404,8 @@ var User = Backbone.Model.extend({
     var self = this;
     var app = this.get("app");
 
+    this.listenTo(this.attributes, "change:room", this.subscribeRoom);
+
     app.receive("response:name", function(data){
       self.set("name", data.name);
     });
@@ -364,6 +413,8 @@ var User = Backbone.Model.extend({
     app.receive("init:battle", function(data){
       console.log("opponent found!");
       self.set("roomSide", data.side);
+      /*
+            self.set("channel:battle", app.socket.subscribe(self.get("room")));*/
       app.navigate("battle", {trigger: true});
     })
 
@@ -396,6 +447,11 @@ var User = Backbone.Model.extend({
   joinRoom: function(){
     this.get("app").send("request:joinRoom");
   },
+  subscribeRoom: function(){
+    var room = this.get("room");
+    var app = this.get("app");
+    app.socket.subscribe(room);
+  },
   setName: function(name){
     this.get("app").send("request:name", {name: name});
   }
diff --git a/server/Battle.js b/server/Battle.js
index 65ba397..12ebea7 100644
--- a/server/Battle.js
+++ b/server/Battle.js
@@ -2,12 +2,12 @@ var Battleside = require("./Battleside");
 var PubSub = require("pubsub-js");
 var Card = require("./Card");
 
-var io = global.io;
+/*var io = global.io;*/
 
 var Battle = (function(){
-  var Battle = function(id, p1, p2){
+  var Battle = function(id, p1, p2, socket){
     if(!(this instanceof Battle)){
-      return (new Battle(id, p1, p2));
+      return (new Battle(id, p1, p2, socket));
     }
     /**
      * constructor here
@@ -15,6 +15,8 @@ var Battle = (function(){
     this._id = id;
     this._user1 = p1;
     this._user2 = p2;
+    this.socket = socket;
+    this.channel = {};
   };
   var r = Battle.prototype;
   /**
@@ -29,21 +31,28 @@ var Battle = (function(){
   r._user2 = null;
   r.turn = 0;
 
+  r.socket = null;
+  r.channel = null;
 
   r._id = null;
 
 
   r.init = function(){
     PubSub.subscribe("update", this.update.bind(this));
+
+
+    this.channel = this.socket.subscribe(this._id);
     this.p1 = Battleside(this._user1.getName(), 0, this, this._user1);
     this.p2 = Battleside(this._user2.getName(), 1, this, this._user2);
     this.p1.foe = this.p2;
     this.p2.foe = this.p1;
     this.p1.setUpWeatherFieldWith(this.p2);
 
+
     this.start();
   }
 
+
   r.start = function(){
     this.p1.setLeadercard();
     this.p2.setLeadercard();
@@ -81,7 +90,7 @@ var Battle = (function(){
     var side = this.turn++ % 2 ? this.p1 : this.p2;
 
     if(side.isPassing()){
-      if(__flag) {
+      if(__flag){
         return this.startNextRound();
       }
       return this.switchTurn(1);
@@ -93,7 +102,7 @@ var Battle = (function(){
 
   }
 
-  r.startNextRound = function() {
+  r.startNextRound = function(){
 
   }
 
@@ -119,9 +128,23 @@ var Battle = (function(){
   }
 
   r.send = function(event, data){
-    io.to(this._id).emit(event, data);
+    this.channel.publish({
+      event: event,
+      data: data
+    });
   }
 
+  /*r._setUpChannel = function() {
+    var self = this;
+    this._abilityChannel.watch(function(d) {
+      var event = d.event, data = d.data;
+
+      if(event === "update") {
+        data();
+      }
+    })
+  }*/
+
   return Battle;
 })();
 
diff --git a/server/Battleside.js b/server/Battleside.js
index b0717ea..895a87f 100644
--- a/server/Battleside.js
+++ b/server/Battleside.js
@@ -174,19 +174,6 @@ Battleside = (function(){
   }
 
   r.update = function(){
-    /*
-      this.send("update:info", {
-        info: this.getInfo(),
-        leader: this.field[Card.TYPE.LEADER].get()[0]
-      })
-      this.send("update:hand", {
-        cards: JSON.stringify(this.hand.getCards())
-      });
-      this.send("update:fields", {
-        close: this.field[Card.TYPE.CLOSE_COMBAT],
-        ranged: this.field[Card.TYPE.RANGED],
-        siege: this.field[Card.TYPE.SIEGE]
-      })*/
     PubSub.publish("update");
   }
 
diff --git a/server/Card.js b/server/Card.js
index b4d9655..0941a00 100644
--- a/server/Card.js
+++ b/server/Card.js
@@ -9,6 +9,7 @@ var Card = (function(){
     /**
      * constructor here
      */
+    this.channel = {};
     this._key = key;
     this._data = CardData[key];
     this._boost = 0;
@@ -38,6 +39,8 @@ var Card = (function(){
     WEATHER: 5
   };
 
+  r.channel = null
+
 
   r._init = function(){
     this._id = ++Card.__id;
diff --git a/server/Npc.js b/server/Npc.js
deleted file mode 100644
index bd723c3..0000000
--- a/server/Npc.js
+++ /dev/null
@@ -1,28 +0,0 @@
-var Entity = require("./Entity");
-
-
-var Npc = (function(){
-  var Npc = function(){
-    if(!(this instanceof Npc)){
-      return (new Npc());
-    }
-    Entity.call(this);
-    /**
-     * constructor here
-     */
-
-
-  };
-  Npc.prototype = Object.create(Entity.prototype);
-  var r = Npc.prototype;
-  /**
-   * methods && properties here
-   * r.property = null;
-   * r.getProperty = function() {...}
-   */
-
-
-  return Npc;
-})();
-
-module.exports = Npc;
\ No newline at end of file
diff --git a/server/Room.js b/server/Room.js
index 1b519bf..83fd37e 100644
--- a/server/Room.js
+++ b/server/Room.js
@@ -2,17 +2,28 @@ var shortid = require("shortid");
 var Battle = require("./Battle");
 
 var Room = (function(){
-  var Room = function(){
+  var Room = function(scServer){
     if(!(this instanceof Room)){
-      return (new Room());
+      return (new Room(scServer));
     }
     /**
      * constructor here
      */
 
+    var self = this;
     this._id = shortid.generate();
-    this._room = [];
+    this._users = [];
     this._ready = {};
+    this.socket = scServer.global;
+/*
+    this._channel = this.socket.subscribe(this._id);*/
+
+    /*this._channel.watch(function(data) {
+      *//*self._users.forEach(function(user) {
+
+      })*//*
+    });*/
+
   };
   var r = Room.prototype;
   /**
@@ -21,20 +32,21 @@ var Room = (function(){
    * r.getProperty = function() {...}
    */
   r.MAX_USER = 2;
-  r._room = null;
+  r._users = null;
   r._id = null;
   r._battle = null;
   r._ready = null;
+  r._channel = null;
 
   r.getID = function(){
     return this._id;
   }
 
   r.join = function(user){
-    if(this._room.length >= 2) return;
-    this._room.push(user);
-    user.setRoom(this);
-    user.joinRoom(this.getID());
+    if(this._users.length >= 2) return;
+    this._users.push(user);
+    user.addRoom(this);
+    /*user.joinRoom(this.getID());*/
 
     if(!this.isOpen()){
       this.initBattle();
@@ -42,47 +54,60 @@ var Room = (function(){
   }
 
   r.isOpen = function(){
-    return !(this._room.length >= 2);
+    return !(this._users.length >= 2);
   }
+/*
 
   r.send = function(event, data){
-    io.to(this._id).emit(event, data);
+    */
+/*this.socket.publish(this._id + "|" + event, data);
+    this.socket.publish(this._id, {
+      event: event,
+      data: data
+    });
+    var subs = this.socket.subscriptions();
+    subs.forEach(function(sub) {
+
+    });*//*
+
+    this._channel.publish(event, data);
   }
+*/
 
   r.getPlayers = function(){
-    return this._room;
+    return this._users;
   }
 
   r.initBattle = function(){
     var self = this;
     var side = 0;
-    this._battle = Battle(this._id, this._room[0], this._room[1]);
-    this._room[0].send("init:battle", {side: "p1"});
-    this._room[1].send("init:battle", {side: "p2"});
+    this._battle = Battle(this._id, this._users[0], this._users[1], this.socket);
+    this._users[0].send("init:battle", {side: "p1"});
+    this._users[1].send("init:battle", {side: "p2"});
   }
 
   r.setReady = function(user, b){
     b = typeof b == "undefined" ? true : b;
     this._ready[user.getID()] = b;
-    if(this.bothReady()) {
+    if(this.bothReady()){
       this._battle.init();
     }
     /*
     if(!this.checkIfReady()) return;
 
-    this._room[0].send("init:battle", {side: "p1"});
-    this._room[1].send("init:battle", {side: "p2"});
+    this._users[0].send("init:battle", {side: "p1"});
+    this._users[1].send("init:battle", {side: "p2"});
     if(!this.checkIfReady()) return;
     this._battle.init();*/
   }
 
-  r.bothReady = function() {
-    return !!this._ready[this._room[0].getID()] && !!this._ready[this._room[1].getID()];
+  r.bothReady = function(){
+    return !!this._ready[this._users[0].getID()] && !!this._ready[this._users[1].getID()];
   }
   /*
     r.checkIfReady = function(){
-      for(var i = 0; i < this._room.length; i++) {
-        if(!this._ready[this._room[i].getID()]) return false;
+      for(var i = 0; i < this._users.length; i++) {
+        if(!this._ready[this._users[i].getID()]) return false;
       }
       return true;
     }*/
diff --git a/server/Socket.js b/server/Socket.js
index bbdae9c..a1c7d35 100644
--- a/server/Socket.js
+++ b/server/Socket.js
@@ -6,9 +6,6 @@ var Battle = require("./Battle");
 var Npc = require("./Npc");
 var Room = require("./Room");
 
-/*
-var Matchmaker = require("./Matchmaker");
-*/
 
 var Socket = (function(){
   var Socket = function(){
diff --git a/server/User.js b/server/User.js
index 1436856..7ab70c1 100644
--- a/server/User.js
+++ b/server/User.js
@@ -1,22 +1,18 @@
-var Entity = require("./Entity");
-
-
 var User = (function(){
   var User = function(socket){
     if(!(this instanceof User)){
       return (new User(socket));
     }
-    Entity.call(this);
     /**
      * constructor here
      */
 
 
     this.socket = socket;
+    this._rooms = [];
     this._id = socket.id;
     this.generateName();
   };
-  User.prototype = Object.create(Entity.prototype);
   var r = User.prototype;
   /**
    * methods && properties here
@@ -26,7 +22,7 @@ var User = (function(){
 
   r._id = null;
   r._name = null;
-  r._room = null;
+  r._rooms = null;
   r.socket = null;
 
   r.getID = function(){
@@ -34,7 +30,11 @@ var User = (function(){
   }
 
   r.joinRoom = function(roomid){
-    this.socket.join(roomid);
+    var self = this;
+    /*this.socket.on(roomid, function(d) {
+      var event = d.event, data = d.data;
+      self.socket.on(event, data);
+    });*/
   }
 
   r.send = function(event, data, room){
@@ -43,8 +43,12 @@ var User = (function(){
     if(!room){
       this.socket.emit(event, data);
     }
-    else {
-      this.socket.to(room).emit(event, data);
+    else {/*
+      this.socket.to(room).emit(event, data);*/
+      this.socket.global.publish(room, {
+        event: event,
+        data: data
+      })
     }
   }
 
@@ -63,10 +67,10 @@ var User = (function(){
     return this._name;
   }
   r.getRoom = function() {
-    return this._room;
+    return this._rooms[0];
   }
-  r.setRoom = function(room) {
-    this._room = room;
+  r.addRoom = function(room) {
+    this._rooms.push(room);
   }
 
   r.disconnect = function() {
diff --git a/server/_server.js b/server/_server.js
new file mode 100644
index 0000000..d00d4a7
--- /dev/null
+++ b/server/_server.js
@@ -0,0 +1,2 @@
+var socket = require("./Socket")();
+
diff --git a/server/server.js b/server/server.js
index d00d4a7..e7ea4b7 100644
--- a/server/server.js
+++ b/server/server.js
@@ -1,2 +1,13 @@
-var socket = require("./Socket")();
+var argv = require('minimist')(process.argv.slice(2));
+var SocketCluster = require('socketcluster').SocketCluster;
 
+var socketCluster = new SocketCluster({
+  workers: Number(argv.w) || 1,
+  stores: Number(argv.s) || 1,
+  port: Number(argv.p) || 16918,
+  appName: argv.n || null,
+  workerController: __dirname + '/worker.js',
+  storeController: __dirname + '/store.js',
+  socketChannelLimit: 100,
+  rebootWorkerOnCrash: argv['auto-reboot'] != false
+});
\ No newline at end of file
diff --git a/server/store.js b/server/store.js
new file mode 100644
index 0000000..92effd8
--- /dev/null
+++ b/server/store.js
@@ -0,0 +1,4 @@
+
+module.exports.run = function (store) {
+  console.log('   >> Store PID:', process.pid);
+};
diff --git a/server/worker.js b/server/worker.js
new file mode 100644
index 0000000..177fb2e
--- /dev/null
+++ b/server/worker.js
@@ -0,0 +1,78 @@
+var fs = require('fs');
+var express = require('express');
+var serveStatic = require('serve-static');
+var path = require('path');
+
+var User = require("./User");
+var Connections = require("./Connections");
+var Battle = require("./Battle");
+var Room = require("./Room");
+
+module.exports.run = function(worker){
+  console.log('   >> Worker PID:', process.pid);
+
+  var app = require('express')();
+
+  var httpServer = worker.httpServer;
+  var scServer = worker.scServer;
+
+  app.use(serveStatic(path.resolve(__dirname, 'public')));
+
+  httpServer.on('request', app);
+
+  var connections = Connections();
+  var roomCollection = {};
+
+
+
+  scServer.on('connection', function(socket){
+    var user = User(socket);
+    connections.add(user);
+    console.log("new user ", user.getName());
+
+    socket.on("request:name", function(data){
+      if(data && data.name){
+        user.setName(data.name);
+      }
+      socket.emit("response:name", {name: user.getName()});
+    })
+
+    socket.on("request:gameLoaded", function(data){
+      console.log(data);
+      roomCollection[data._roomID].setReady(user);
+    })
+
+    socket.on("request:createRoom", function(){
+      var room = Room(worker.getSCServer());
+      roomCollection[room.getID()] = room;
+      room.join(user);
+      console.log("room %s created by %s", room.getID(), user.getName());
+      user.send("response:createRoom", room.getID());
+    })
+
+    socket.on("request:joinRoom", function(){
+      console.log("joinroom");
+      var interval = setInterval(function(){
+        for(var key in roomCollection) {
+          var room = roomCollection[key];
+          if(!room.isOpen()) continue;
+          room.join(user);
+          clearInterval(interval);
+          console.log("user %s joined room %s", user.getName(), room.getID());
+          user.send("response:joinRoom", room.getID());
+        }
+      }, 1000);
+    })
+
+    socket.on("request:roomData", function(){
+      var room = user.getRoom();
+      var players = room.getPlayers();
+      user.send("response:roomData", {players: players});
+    })
+
+    socket.on('disconnect', function(){
+      connections.remove(user);
+      user.disconnect();
+    });
+  });
+};
\ No newline at end of file