From 879093836c8c0b529c2dcb0a237d53a24173e4f9 Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 11:31:20 -0400 Subject: [PATCH 1/6] removed getMessage, added setMessageListener, KISSed sendMessage setMessageListener is a new method that is aiming to replace the message queue system. When you call it, you can pass in a set of types. These types describe the kinds of messages that the listener should respond to if received. For example, if you did: CardshifterServerAPI.setMessageListener(function(message) { ... }, ["chat", "userstatus"]); Then, every time a message was received and it's .command is either "chat" or "userstatus", then the function passed in will be called and the received message will be passed in. --- server_interface/server_interface.js | 55 +++++++++------------------- 1 file changed, 18 insertions(+), 37 deletions(-) diff --git a/server_interface/server_interface.js b/server_interface/server_interface.js index 9cfdddd..92ab686 100644 --- a/server_interface/server_interface.js +++ b/server_interface/server_interface.js @@ -236,10 +236,6 @@ var protocolAddon = (wsProtocolFinder.test(server) ? "" : "ws" + secureAddon + "://"); var socket = new WebSocket(protocolAddon + server); - socket.onmessage = function(message) { - self.incomingMessages.push(JSON.parse(message.data)); - } - socket.onopen = onReady; socket.onerror = function() { @@ -250,54 +246,39 @@ this.socket = socket; }, - /** - * Sends a message to the server. - * - * @param message:Message -- The message to send. - * @param onReceive:Function (OPTIONAL) -- A function to run when a message has returned - * @error NotInitializedException -- If the API has not been initialized yet. - * - * This will use websocket setup by `this.init` to send a message to the server. - * - * NOTE: The onReceive function will NOT NECESSARILY be run when the desired request - * is received. However, it is likely. - */ - sendMessage: function(message, onReceive) { + sendMessage: function(message) { var socket = this.socket; var self = this; if(socket) { if(socket.readyState === SOCKET_OPEN) { this.socket.send(JSON.stringify(flatten(message))); - if(onReceive) { - this.socket.onmessage = function(msg) { - onReceive(JSON.parse(msg.data)); - this.onmessage = function(msg2) { - self.incomingMessages.push(JSON.parse(msg2.data)); - } - } - } } else { - throw new SocketNotReadyException("The Websocket is not yet ready to be used", socket.readyState); + throw new SocketNotReadyException("The Websocket is not ready to be used.", socket.readyState); } } else { throw new NotInitializedException("The API has not yet been initialized."); } - }, + } /** - * Gets a message from the recieved message queue. + * Sets an event listener for when the server sends a message and + * the message type is one of the types in types * - * @return Message -- The first message in the incoming messages queue + * @param listener:Function -- The function to fire when a message of types is received + * @param types:[string] (OPTIONAL) -- Only fire the listener when the message type is in this array * - * This will .shift() the incomingMessages queue and return the value. - * This allows the API to handle the messages from the server so the - * main game code can access the messages as it needs to. - * - * Although the function is very simple, the name make is clear what is - * happening. */ - getMessage: function() { - return this.incomingMessages.shift(); + setMessageListener: function(listener, types) { + this.socket.onmessage(message) { + var data = JSON.parse(message.data); + if(types) { + if(data.command in types) { + listener(message); + } + } else { + listener(message); + } + } } }; })(Function("return this")()); \ No newline at end of file From a420b37e77cb000aacb38e160296bc05c3e2e5ed Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 12:06:34 -0400 Subject: [PATCH 2/6] LoginController now conforms to the new API --- login/login_controller.js | 17 ++++++++--------- 1 file changed, 8 insertions(+), 9 deletions(-) diff --git a/login/login_controller.js b/login/login_controller.js index 90a9d55..5ef8eff 100644 --- a/login/login_controller.js +++ b/login/login_controller.js @@ -9,26 +9,25 @@ CardshifterApp.controller("LoginController", function($scope, $location, $rootSc var login = new CardshifterServerAPI.messageTypes.LoginMessage($scope.username); try { - CardshifterServerAPI.sendMessage(login, function(serverResponse) { - if(serverResponse.status === SUCCESS && serverResponse.message === "OK") { - + CardshifterServerAPI.setMessageListener(function(welcome) { + console.log("was a login response"); + console.log(welcome); + if(welcome.status === SUCCESS && welcome.message === "OK") { // taking the easy way out window.currentUser = { username: $scope.username, - id: serverResponse.userId + id: welcome.userId } $rootScope.$apply(function() { $location.path("/lobby"); }); } else { - // I don't actually know what the server will respond with - // notify the user that there was an issue logging in (custom server issue ???) - - console.log("server message: " + serverResponse.message); + console.log("server messsage: " + welcome.message); $scope.loggedIn = false; } - }); + }, ["loginresponse"]); + CardshifterServerAPI.sendMessage(login); } catch(e) { // notify the user that there was an issue logging in (loginmessage issue) From 9eb2aed0c213bb48966e28f217629b4c118c5f0d Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 12:55:44 -0400 Subject: [PATCH 3/6] sends JSON.parse -d data, rather than the entire JSON message --- server_interface/server_interface.js | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/server_interface/server_interface.js b/server_interface/server_interface.js index 92ab686..9900c4d 100644 --- a/server_interface/server_interface.js +++ b/server_interface/server_interface.js @@ -258,7 +258,7 @@ } else { throw new NotInitializedException("The API has not yet been initialized."); } - } + }, /** * Sets an event listener for when the server sends a message and @@ -267,16 +267,17 @@ * @param listener:Function -- The function to fire when a message of types is received * @param types:[string] (OPTIONAL) -- Only fire the listener when the message type is in this array * + * TODO: Maybe a timeout will be needed? Pass in a function and a MS count. */ setMessageListener: function(listener, types) { - this.socket.onmessage(message) { + this.socket.onmessage = function(message) { var data = JSON.parse(message.data); if(types) { - if(data.command in types) { - listener(message); + if(types.indexOf(data.command) !== -1) { // if contains + listener(data); } } else { - listener(message); + listener(data); } } } From ac5137f31732253321cf27222df0f3e3742bf9c1 Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 12:55:58 -0400 Subject: [PATCH 4/6] removed testing logs --- login/login_controller.js | 2 -- 1 file changed, 2 deletions(-) diff --git a/login/login_controller.js b/login/login_controller.js index 5ef8eff..9ae7eb5 100644 --- a/login/login_controller.js +++ b/login/login_controller.js @@ -10,8 +10,6 @@ CardshifterApp.controller("LoginController", function($scope, $location, $rootSc try { CardshifterServerAPI.setMessageListener(function(welcome) { - console.log("was a login response"); - console.log(welcome); if(welcome.status === SUCCESS && welcome.message === "OK") { // taking the easy way out window.currentUser = { From fe56e0521b6719ba12de3e45ad319f307102e516 Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 12:57:56 -0400 Subject: [PATCH 5/6] now conforms to the new API, setup a command map. This command map is an object where the keys are the .command s of messages, and the values are functions. When a message is received, it's command is used to find the function to call that will act on the newly received message. This is definitely much more structured and cleaner than the old lobby controller. --- lobby/lobby_controller.js | 128 +++++++++++++++++++------------------- 1 file changed, 65 insertions(+), 63 deletions(-) diff --git a/lobby/lobby_controller.js b/lobby/lobby_controller.js index 903e2c9..496b571 100644 --- a/lobby/lobby_controller.js +++ b/lobby/lobby_controller.js @@ -1,7 +1,5 @@ -CardshifterApp.controller("LobbyController", function($scope, $interval, $timeout) { +CardshifterApp.controller("LobbyController", function($scope, $timeout) { var CHAT_FEED_LIMIT = 10; - var POLL_FREQ = 2000; - var MESSAGE_DELAY = 3000; var ENTER_KEY = 13; $scope.users = []; @@ -15,54 +13,20 @@ CardshifterApp.controller("LobbyController", function($scope, $interval, $timeou }; $scope.gotInvite = false; - var getUsersMessage = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", ""); - CardshifterServerAPI.sendMessage(getUsersMessage); // get all online users - - $interval(function() { // update chat and users - while(message = CardshifterServerAPI.getMessage()) { - switch(message.command) { - case "userstatus": - // do conditional checking if user is offline - if(message.status === "OFFLINE") { - for(var i = 0, length = $scope.users.length; i < length; i++) { - - if($scope.users[i].userId === message.userId) { - $scope.users.splice(i, 1); // remove that user from the array - } - } - } else { - $scope.users.push(message); - } - - break; - case "chat": - if($scope.chatMessages.length === CHAT_FEED_LIMIT) { - // remove the latest (opposite of earliest) chat message - $scope.chatMessages.shift(); - } - - var now = new Date(); - var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); - var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); - message.timestamp = YMD + " " + HMS; - - $scope.chatMessages.push(message); - break; + var commandMap = { + "userstatus": updateUserList, + "chat": addChatMessage, + "inviteRequest": displayInvite, + "availableMods": displayMods + }; - case "inviteRequest": - console.log("got invite"); - $scope.invite.id = message.id; - $scope.invite.name = message.name; - $scope.invite.type = message.gameType; - $scope.gotInvite = true; + var getUsers = new CardshifterServerAPI.messageTypes.ServerQueryMessage("USERS", ""); + CardshifterServerAPI.sendMessage(getUsers); - break; - case "availableMods": - $scope.mods = message.mods; - break; - } - } - }, POLL_FREQ); + CardshifterServerAPI.setMessageListener(function(message) { + commandMap[message.command](message); + $scope.$apply(); // needs to manually updated since this is an event + }, ["userstatus", "chat", "inviteRequest", "availableMods"]); $scope.sendMessage = function(e) { if(e && e.keyCode !== ENTER_KEY) { // user may hit "enter" key @@ -78,30 +42,68 @@ CardshifterApp.controller("LobbyController", function($scope, $interval, $timeou $scope.sending = false; }, MESSAGE_DELAY); } - $scope.startGame = function() { if($scope.selected_mod && $scope.selected_opponent) { - var startGameMessage = new CardshifterServerAPI.messageTypes.StartGameRequest($scope.selected_opponent, - $scope.selected_mod); - CardshifterServerAPI.sendMessage(startGameMessage, function(returnMessage) { - if(returnMessage.command !== "wait") { - console.log("server didn't like that") - } - }); + console.log("start"); } else { // user needs to choose an opponent and/or a mod console.log("need to choose mod and/or opponent"); } } - $scope.acceptInvite = function(accept) { + console.log("accept"); + } - var inviteResponse = new CardshifterServerAPI.messageTypes.InviteResponse($scope.invite.id, accept); - CardshifterServerAPI.sendMessage(inviteResponse); - $scope.gotInvite = false; - if(accept) { - // switch to game page + // The command map functions: + /** + * Based on the content of message, will add or remove + * a user from the user list. + */ + function updateUserList(message) { + if(message.status === "OFFLINE") { + for(var i = 0, length = $scope.users.length; i < length; i++) { + if($scope.users[i].userId === message.userId) { + $scope.users.splice(i, 1); // remove that user from the array + break; + } + } + } else { + $scope.users.push(message); } } + /** + * Adds a chat message to the message feed. If the message + * feed is at the maximum limit of messages, deletes the oldest + * message. + */ + function addChatMessage(message) { + if($scope.chatMessages.length === CHAT_FEED_LIMIT) { + // remove the oldest chat message + $scope.chatMessages.shift(); + } + + var now = new Date(); + var YMD = now.getFullYear() + "-" + (now.getMonth() + 1) + "-" + now.getDate(); + var HMS = now.getHours() + ":" + now.getMinutes() + ":" + now.getSeconds(); + message.timestamp = YMD + " " + HMS; + + $scope.chatMessages.push(message); + } + /** + * Shows buttons and a message to this client for accepting + * or declining a game request. + */ + function displayInvite(message) { + $scope.invite.id = message.id; + $scope.invite.name = message.name; + $scope.invite.type = message.gameType; + $scope.gotInvite = true; + } + /** + * Shows to the user a list of all available mods. + */ + function displayMods(message) { + $scope.mods = message.mods; + } }); \ No newline at end of file From dfb02ad9b2337857c28984071a42097cb234c040 Mon Sep 17 00:00:00 2001 From: SirPython Date: Sat, 8 Aug 2015 13:37:53 -0400 Subject: [PATCH 6/6] added addEventTypes and removeMessageListener addEventTypes -- add new event types to the event types listener removeMessageListener -- remove the message listener --- server_interface/server_interface.js | 26 +++++++++++++++++++++++--- 1 file changed, 23 insertions(+), 3 deletions(-) diff --git a/server_interface/server_interface.js b/server_interface/server_interface.js index 9900c4d..66ec516 100644 --- a/server_interface/server_interface.js +++ b/server_interface/server_interface.js @@ -36,7 +36,7 @@ window.CardshifterServerAPI = { socket: null, - incomingMessages: [], + eventTypes: [], messageTypes: { /** * Incoming login message. @@ -270,16 +270,36 @@ * TODO: Maybe a timeout will be needed? Pass in a function and a MS count. */ setMessageListener: function(listener, types) { + this.eventTypes = types; this.socket.onmessage = function(message) { var data = JSON.parse(message.data); - if(types) { - if(types.indexOf(data.command) !== -1) { // if contains + if(this.eventTypes) { + if(this.eventTypes.indexOf(data.command) !== -1) { // if contains listener(data); } } else { listener(data); } } + this.eventTypes = types; + console.log(this.eventTypes); + }, + + /** + * Adds types to the types to listen for in the message event listener + * + * @param types:[string] -- The types to add + */ + addEventTypes: function(types) { + this.eventTypes = this.eventTypes.concat(types); + console.log(this.eventTypes); + }, + + /** + * Removes the message event listener + */ + removeMessageListener: function() { + this.socket.onmessage = null; } }; })(Function("return this")()); \ No newline at end of file