Commits

nemunemu committed 48f1e94

Tcp Server

Comments (0)

Files changed (6)

 path = require("path")
 ReversiServer = require("./controllers/reversi-server")
 SocketIOConnector = require("./controllers/socketio-connector")
+TcpConnector = require("./controllers/tcp-server")
 
 app = express()
 server = module.exports = http.createServer(app)
   console.log "Express server listening on port " + app.get("port")
 
 revServer = module.exports.revServer = new ReversiServer()
+
 sioConnector = module.exports.sioConnector = new SocketIOConnector(revServer)
 sioConnector.start(sioServer.sockets)
-
+tcpConnector = new TcpConnector(revServer)
+tcpConnector.start(4000)

controllers/reversi-server.coffee

 
     wl = new Array(2)
     if stone.white > stone.black
-      wl = ['win', 'lose']
+      wl = ['Win', 'Lose']
     else if stone.white < stone.black
-      wl = ['lose', 'win']
+      wl = ['Lose', 'Win']
     else
-      wl = ['draw', 'draw']
+      wl = ['Tie', 'Tie']
 
     idx = [ReversiBoard.white, ReversiBoard.black].indexOf(userColor)
       
       nextTurnPlayer: @turnPlayer()
       nextColor: @board.turn
 
+  _gameStartInfo: ->
+    players: @players
+    nextTurnPlayer: @turnPlayer()
+    nextColor: @board.turn
+
   @login: (room, username, callback) ->
     if !room then room = new ReversiRoom
+    success = room._addUser(username)
+    isGameStart = room.startGame()
     status =
-      success: room._addUser(username)
-      gameStart: room.startGame()
-      nextTurnPlayer: room.turnPlayer()
-      nextColor: room.board.turn if room.board
+      success: success 
+      gameStart: isGameStart
+      gameInfo: room._gameStartInfo() if isGameStart
 
     callback(room, status) if callback
 
       state: {type: 'waiting'}
       client: client
       connector: connector
-      options: options
+      options: options || {}
 
   login: (username, roomname) ->
     self = @
     maskedName = @maskName(username)
 
     ReversiRoom.login @_roomList[roomname], username, (room, status) ->
+      console.log status
       self._roomList[roomname] = room
 
       if status.success
         if status.gameStart
           self.requestNoticeToGroup roomname, 'game standby',
             roomname: roomname
-
-          self.requestNotice status.nextTurnPlayer, 'game turn',
-            color: status.nextColor
+            players: status.gameInfo.players
+            nextTurnPlayer: status.gameInfo.nextTurnPlayer
+            nextColor: status.gameInfo.nextColor
         console.log "done/login room: #{roomname}, id: #{username}"
       else
         self.fail(username, 'login failed')
     roomname = info.state.roomname
     ReversiRoom.logout @_roomList[roomname], username, (room, status) ->
       self._roomList[roomname] = room
+      delete self._roomList[roomname] unless room
 
       if status.success
         self._userInfo[username].state =
 
   move: (username, x, y) ->
     info = @_userInfo[username]
+    return @moveResponseNotice(username, false) unless info
     switch info.state.type 
       when 'login'
         roomname = info.state.roomname
 
         if result.success
           @requestNoticeToGroup roomname, 'game update',
-            result.update
+            update: result.update
+            username: username
+            isLastTurn: result.gameEnd
+
+            if result.gameEnd
+              @noticeGameEnd(roomname)
+            else
+              @requestNotice result.nextTurnPlayer, 'game turn',
+                color: result.nextColor
+        else if info.options.loseIlligalMove
+          console.log "lose"
+          # lose
+
+        @moveResponseNotice(username, result.success)
+      else
+        @moveResponseNotice(username, false)
 
-          if result.gameEnd
-            @noticeGameEnd(roomname)
-          else
-            @requestNotice result.nextTurnPlayer, 'game turn',
-              color: result.nextColor
+  pass: (username) ->
+    @moveResponseNotice(username, true)
+
+  moveResponseNotice: (username, success) ->
     @requestNotice username, 'move submitted',
-      success: result.success
+      success: success
 
   fail: (username, msg) ->
     @requestNotice username, msg
 
   requestJoinGroup: (username, groupname) ->
     cinfo = @findConnectInfo(username)
-    cinfo.connector.joinGroup(cinfo.client, groupname)
+    cinfo.connector.joinGroup(username, cinfo.client, groupname)
 
   requestLeaveGroup: (username, groupname) ->
     cinfo = @findConnectInfo(username)
-    cinfo.connector.leaveGroup(cinfo.client, groupname)
+    cinfo.connector.leaveGroup(username, cinfo.client, groupname)
 
   findConnectInfo: (username) ->
     client: @_userInfo[username].client

controllers/socketio-connector.coffee

     socket.on 'request roomlist', () ->
       self.operator.noticeRoomlist username
 
-  joinGroup: (client, groupname) ->
+  joinGroup: (username, client, groupname) ->
     client.join(groupname)
 
-  leaveGroup: (client, groupname) ->
+  leaveGroup: (username, client, groupname) ->
     client.leave(groupname)
 
   noticeAll: (type, data) ->
         client.emit 'game standby',
           name: data.name
 
+        client.socket(data.nextTurnPlayer).emit 'game turn',
+          color: data.nextColor
+
       when 'game cancel'
         client.emit 'game cancel',
           name: data.name
 
       when 'game update'
         client.emit 'game update',
-          data
+          data.update
           # point: data.point
           # color: data.color
           # revPoints: data.revPoints

controllers/tcp-server.coffee

 net = require('net')
+Reversi = require('./reversi')
 
 class TcpConnector
-  constructor: (port) ->
-    server = net.createServer tcpResponse
-    server.listen(port)
-    console.log('listening on port 3000')
+  constructor: (@operator) ->
+    @operator.registerConnector @
+    @groups = {}
+    @clients = {}
+
+  start: (@port) ->
+    self = @
+    @server = net.createServer (client) ->
+      self.tcpResponse(client)
+    @server.listen(@port)
+    console.log("listening on port #{@port}")
+
+  close: ->
+    @server.close()
+
+  tcpResponse: (socket) ->
+    self = @
+    client =
+      socket: socket
+      buffer: ""
+      username: null
 
-  tcpResponse: (client) ->
     console.log 'server -> tcp server created.'
 
-    client.on 'data', (data) ->
-      console.log "server-> #{data}/ from: #{client.remoteAddress}:#{client.remotePort}"
-      client
+    socket.on 'data', (data) ->
+      console.log "server-> #{data}/ from: #{socket.remoteAddress}:#{socket.remotePort}"
+      parseCmd = TcpConnector.parser(client.buffer, data.toString())
+      client.buffer = parseCmd.buffer
+      if parseCmd.success
+        self.doCommand(parseCmd, client)
+
+    socket.on 'close', ->
+      console.log "server-> close connection #{socket.remoteAddress}:#{socket.remotePort}"
+      self.operator.disconnect client.username if client.username
 
-    client.on 'close', ->
-      console.log "server-> close connection #{client.remoteAddress}:#{client.remotePort}"
 
   doCommand: (com, client) ->
     switch com.command
         username = com.args[0]
 
         nameSplit = username.split(",") 
+        console.log nameSplit
         roomname = if nameSplit.length > 1 then roomname = nameSplit[0] else username
 
+        client.username = username
+        @clients[username] = client
+        @operator.register username, client, this,
+          loseIlligalMove: true
+        @operator.login username, roomname 
+
       when 'MOVE'
-        posChar = com.args[0]
-        posCharX = posChar[0]
-        posCharY = posChar[1]
+        if com.args[0] == "PASS"
+          @operator.pass client.username
+        else
+          posChar = com.args[0]
+          posCharX = posChar[0]
+          posCharY = posChar[1]
+
+          charParseArr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+          
+          charIdx = charParseArr.indexOf(posCharX) + 1
+          pos =
+            x: charIdx
+            y: parseInt(posCharY, 10)
+
+          @operator.move client.username, pos.x, pos.y
+
+  joinGroup: (username, client, groupname) ->
+    @groups[groupname] = {} unless @groups[groupname]
+    @groups[groupname][client.username] = client
 
-        charParseArr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+  leaveGroup: (username, client, groupname) ->
+    delete @groups[groupname][client.username]
+
+  noticeAll: (type, data) ->
+    for idx, val of @clients
+      @notice(val, type, data) if val
+
+  noticeToGroup: (groupname, type, data) ->
+    for idx, val of @groups[groupname]
+      @notice(val, type, data) if val
+
+  notice: (client, type, data) ->
+    username = client.username
+
+    switch type
+      when 'game standby'
+        oppPlayer = data.players[1 - data.players.indexOf(username)]
+        if username == data.nextTurnPlayer
+          client.socket.write "START BLACK #{oppPlayer} 60000\n"
+        else
+          client.socket.write "START WHITE #{oppPlayer} 60000\n"
+      when 'game update'
+        unless username == data.username || data.isLastTurn
+          ptstr = TcpConnector.convertPos(data.update.point.x, data.update.point.y)
+          client.socket.write "MOVE #{ptstr}\n"
+      when 'move submitted'
+        if data.success
+          client.socket.write "ACK 60000\n"
+      when 'game end'
+        if data.color == Reversi.black
+          client.socket.write "END #{data.issue} #{data.black} #{data.white} DOUBLE_PASS\n"
+        else
+          client.socket.write "END #{data.issue} #{data.white} #{data.black} DOUBLE_PASS\n"
+        client.socket.write "BYE\n"
         
-        charIdx = charParseArr.indexOf(posCharX) + 1
-        pos =
-          x: charIdx
-          y: parseInt(posCharY, 10)
+  @parser: (buffer, str) ->
+    constr = buffer + str
+    spstr = constr.split("\n")
 
-  @parser: (str) ->
-    strArray = str.split(' ')
+    if spstr.length > 1
+      strArray = spstr[0].split(' ')
 
-    command: strArray[0]
-    args: strArray.slice(1)
+      success: true
+      buffer: spstr[1]
+      command: strArray[0]
+      args: strArray.slice(1)
+    else
+      success: false
+      buffer: constr
 
+  @convertPos: (x, y) ->
+    charParseArr = ['A', 'B', 'C', 'D', 'E', 'F', 'G', 'H']
+    "#{charParseArr[x - 1]}#{y}"
+        
 
-      
+module.exports = TcpConnector
 
       
-      
 

test/controllers/reversi-server-test.coffee

       testClients = [{id: "test1"}, {id: "test2"}] 
       count = 0
 
+      check = ->
+        done() if count++ > 1
+
       testConnector.noticeAllfunc = (type, data) ->
+        console.log arguments
         switch type
           when 'login'
             switch data.username
               when usernames[0]
-                console.log arguments
                 data.roomname.should.be.eql roomname
-                done() if count++ > 2
+                check()
               when usernames[1]
                 data.roomname.should.be.eql roomname
-                done() if count++ > 2
+                check()
 
       testConnector.noticeToGroupfunc = (groupname, type, data) ->
+        console.log arguments
         switch type
           when 'game standby'
             data.roomname.should.eql roomname
-            done() if count++ > 2
-
-      testConnector.noticefunc = (client, type, data) ->
-        type.should.eql 'game turn'
-        data.color.should.eql Reversi.black
-        done() if count++ > 2
+            data.nextColor.should.eql Reversi.black
+            check()
 
       revServer.register(usernames[0], testClients[0], testConnector)
       revServer.register(usernames[1], testClients[1], testConnector)
       roomname = 'testroom'
       testClients = [{id: "test1"}, {id: "test2"}] 
       count = 0
-      turnCount = 0
+
+      check = ->
+        done() if count++ > 1
 
       testConnector.noticeToGroupfunc = (groupname, type, data) ->
         groupname.should.eql(roomname)
         switch type
           when 'game standby'
             data.roomname.should.eql roomname
-            done() if count++ > 1
+            data.nextColor.should.eql Reversi.black
+            revServer.move(data.nextTurnPlayer, 3, 4)
+            check()
           when 'game update'
-            data.point.x.should.eql(3)
-            data.point.y.should.eql(4)
-            data.color.should.eql(Reversi.black)
-            data.revPoints[0].x.should.eql(4)
-            data.revPoints[0].y.should.eql(4)
-            done() if count++ > 1
+            data.update.point.x.should.eql(3)
+            data.update.point.y.should.eql(4)
+            data.update.color.should.eql(Reversi.black)
+            data.update.revPoints[0].x.should.eql(4)
+            data.update.revPoints[0].y.should.eql(4)
+            check()
 
       testConnector.noticefunc = (client, type, data) ->
         switch type
           when 'game turn'
-            if turnCount++ == 0
-              data.color.should.eql Reversi.black
-              idx = if client.id == 'test1' then 0 else 1
-              revServer.move(usernames[idx], 3, 4)
-            else
-              data.color.should.eql Reversi.white
+            data.color.should.eql Reversi.white
           when 'move submitted'
             data.success.should.eql true
-            done() if count++ > 1
+            check()
 
       revServer.register(usernames[0], testClients[0], testConnector)
       revServer.register(usernames[1], testClients[1], testConnector)
       roomname = 'testroom'
       testClients = [{id: "test1"}, {id: "test2"}] 
       count = 0
-      turnCount = 0
 
       turnPlayer = new Array(2)
 
       testConnector.noticeToGroupfunc = (groupname, type, data) ->
         groupname.should.eql(roomname)
         switch type
+          when 'game standby'
+            room = revServer.roomInfo(roomname)
+
+            data.nextColor.should.eql Reversi.black
+            turnPlayer[0] = if data.nextTurnPlayer == 'testuser1' then 0 else 1
+            turnPlayer[1] = 1 - turnPlayer[0]
+
+            room.board.board[5][5] = Reversi.black
+            revServer.move(data.nextTurnPlayer, 3, 4)
           when 'game update'
-            data.point.x.should.eql(3)
-            data.point.y.should.eql(4)
-            data.color.should.eql(Reversi.black)
-            data.revPoints[0].x.should.eql(4)
-            data.revPoints[0].y.should.eql(4)
+            data.update.point.x.should.eql(3)
+            data.update.point.y.should.eql(4)
+            data.update.color.should.eql(Reversi.black)
+            data.update.revPoints[0].x.should.eql(4)
+            data.update.revPoints[0].y.should.eql(4)
             check()
 
       testConnector.noticefunc = (client, type, data) ->
         switch type
           when 'game turn'
-            if turnCount++ == 0
-              room = revServer.roomInfo(roomname)
-
-              data.color.should.eql Reversi.black
-              turnPlayer[0] = if client.id == 'test1' then 0 else 1
-              turnPlayer[1] = 1 - turnPlayer[0]
-              
-              room.board.board[5][5] = Reversi.black
-              revServer.move(usernames[turnPlayer[0]], 3, 4)
-            else
-              data.color.should.eql Reversi.white
+            data.color.should.eql Reversi.white
           when 'game end'
             switch client.id
               when testClients[turnPlayer[0]].id
                 data.color.should.eql Reversi.black
-                data.issue.should.eql 'win'
+                data.issue.should.eql 'Win'
               when testClients[turnPlayer[1]].id
                 data.color.should.eql Reversi.white
-                data.issue.should.eql 'lose'
+                data.issue.should.eql 'Lose'
             data.black.should.eql(5)
             data.white.should.eql(0)
             check()

test/controllers/tcp-connector-test.coffee

+TcpConnector = require('../../controllers/tcp-server')
+net = require('net')
+chai = require('chai')
+chai.should()
+
+class TestOperator
+  registerConnector: ->
+
+  register: ->
+    @registerfunc.apply(@, arguments) if @registerfunc
+
+  login: ->
+    @loginfunc.apply(@, arguments) if @loginfunc
+
+  move: ->
+    @movefunc.apply(@, arguments) if @movefunc
+
+  disconnect: ->
+    @disconnectfunc.apply(@, arguments) if @disconnectfunc
+
+port = 5000
+describe 'TcpConnector', ->
+  connector = null
+  operator = null
+  beforeEach ->
+    operator = new TestOperator()
+    connector = new TcpConnector(operator)
+    connector.start(port)
+
+  afterEach ->
+    connector.close()
+
+  it 'OPEN', (done) ->
+    count = 0
+    testuser = "testuser"
+    
+    check = ->
+      if count++ > 0
+        client.end()
+        done() 
+
+    client = net.createConnection port: port, ->
+      console.log arguments
+      check()
+      client.write("OPEN #{testuser}\n")
+
+    operator.loginfunc = (username, roomname) ->
+      username.should.eql testuser
+      roomname.should.eql testuser
+      check()
+
+  it 'game standby', (done) -> 
+    count = 0
+    testuser = "testuser"
+    
+    check = ->
+      if count++ > 0
+        socket.end()
+        done() 
+
+    socket = net.createConnection port: port, ->
+      client = 
+        socket: socket
+        username: testuser
+      check()
+      socket.write("OPEN #{testuser}\n")
+
+    operator.registerfunc = (username, client) ->
+      connector.notice client, 'game standby',
+        players: ["testuser", "dummyuser"]
+        nextTurnPlayer: "testuser" 
+
+    socket.on 'data', (data) ->
+      console.log data.toString()
+      data.toString().should.eql("START BLACK dummyuser 60000\n")
+      check()
+
+  it 'game update', (done) -> 
+    count = 0
+    testuser = "testuser"
+    
+    check = ->
+      if count++ > 0
+        socket.end()
+        done() 
+
+    socket = net.createConnection port: port, ->
+      client = 
+        socket: socket
+        username: testuser
+      check()
+      socket.write("OPEN #{testuser}\n")
+
+    operator.registerfunc = (username, client) ->
+      connector.notice client, 'game update',
+        username: 'testuser'
+        update: 
+          point:
+            x: 7
+            y: 2
+
+      connector.notice client, 'game update',
+        username: 'dummyuser'
+        update: 
+          point:
+            x: 3
+            y: 5
+
+    socket.on 'data', (data) ->
+      data.toString().should.eql("MOVE C5\n")
+      check()
+    
+
+
+
+
+