Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[POC] Use socket for base save/update | Prevent multiple session #29

Open
wants to merge 2 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 4 additions & 2 deletions client/scripts/BASE.as
Original file line number Diff line number Diff line change
Expand Up @@ -3935,7 +3935,8 @@ package
else
{
// Comment: save route triggered
new URLLoaderApi().load(GLOBAL._baseURL + "save",saveDataList,handleLoadSuccessful,handleLoadError);
// new URLLoaderApi().load(GLOBAL._baseURL + "save",saveDataList,handleLoadSuccessful,handleLoadError);
GLOBAL.SOCKET.send(OPCODES.BASE_SAVE,saveData,handleLoadSuccessful,handleLoadError);
}
if(_saveOver)
{
Expand Down Expand Up @@ -4303,7 +4304,8 @@ package
else
{
// Comment: updatedsaved route triggered
new URLLoaderApi().load(GLOBAL._baseURL + "updatesaved",[["baseid",BASE._loadedBaseID],["version",GLOBAL._version.Get()],["lastupdate",UPDATES._lastUpdateID],["type",tmpMode]],handleLoadSuccessful,handleLoadError);
// new URLLoaderApi().load(GLOBAL._baseURL + "updatesaved",[["baseid",BASE._loadedBaseID],["version",GLOBAL._version.Get()],["lastupdate",UPDATES._lastUpdateID],["type",tmpMode]],handleLoadSuccessful,handleLoadError);
GLOBAL.SOCKET.send(OPCODES.UPDATE_SAVE, {"version": GLOBAL._version.Get(), "lastupdate": UPDATES._lastUpdateID, "type": tmpMode}, handleLoadSuccessful, handleLoadError)
}
}

Expand Down
4 changes: 3 additions & 1 deletion client/scripts/GLOBAL.as
Original file line number Diff line number Diff line change
Expand Up @@ -426,7 +426,8 @@ package
private static var tickables:Vector.<ITickable>;

private static var fastTickables:Vector.<ITickable>;


public static var SOCKET:SOCKET_API = new SOCKET_API();

public function GLOBAL()
{
Expand Down Expand Up @@ -1772,6 +1773,7 @@ package
else if(Timestamp() - _afktimer.Get() > 60 * 10)
{
POPUPS.Timeout();
SOCKET_CONN.disconnect();
}
}
}
Expand Down
1 change: 1 addition & 0 deletions client/scripts/LOGIN.as
Original file line number Diff line number Diff line change
Expand Up @@ -196,6 +196,7 @@ package
GLOBAL.player.picture = serverData.pic_square;
GLOBAL.player.timePlayed = serverData.timeplayed;
GLOBAL.player.email = serverData.email;
GLOBAL.SOCKET.connect(serverData.userid)
_playerID = serverData.userid;
_playerName = serverData.username;
_playerLastName = serverData.last_name;
Expand Down
26 changes: 26 additions & 0 deletions client/scripts/OPCODES.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
package
{
public class OPCODES
{

public static const LOGIN:int = 1;
public static const LOGIN_ERROR:int = 2;

public static const DUPLICATE_SESSION:int = 5;

public static const GET_NEW_MAP:int = 10;

public static const BASE_SAVE:int = 100;
public static const BASE_SAVE_ERROR:int = 101;

public static const UPDATE_SAVE:int = 200;

public static const PING:int = 500;

public function OPCODES()
{

super();
}
}
}
285 changes: 285 additions & 0 deletions client/scripts/SOCKET_API.as
Original file line number Diff line number Diff line change
@@ -0,0 +1,285 @@
package
{
import flash.events.Event;
import flash.events.IOErrorEvent;
import flash.events.ProgressEvent;
import flash.events.TimerEvent;
import flash.net.Socket;
import flash.utils.ByteArray;
import flash.utils.Timer;
import flash.events.SecurityErrorEvent;
import flash.utils.Dictionary;

public class SOCKET_API
{

private var _socket:Socket;

private var _host:String = "192.168.1.2";

private var _port:int = 3002;

private var _successCallbacks:Dictionary;

private var _errorCallbacks:Dictionary;

private var _eventListener:Dictionary;

private var _sendQueue:Array;

private var _instanceID:String;

private var _userid:String;

private const _socketTimeout:int = 4;

private var _pingTimer:Timer;

private var _isSending:Boolean = false;

private var _reconnectAttempts:int = 0;

private const MAX_RECONNECT_ATTEMPTS:int = 3;

private var _connectCallback:Function;

public function SOCKET_API()
{
this._successCallbacks = new Dictionary();
this._errorCallbacks = new Dictionary();
this._sendQueue = [];
super();
_socket = new Socket();
_socket.timeout = _socketTimeout * 1000;
_socket.addEventListener(Event.CONNECT, onConnect);
_socket.addEventListener(IOErrorEvent.IO_ERROR, onIOError);
_socket.addEventListener(Event.CLOSE, onClose);
_socket.addEventListener(ProgressEvent.SOCKET_DATA, onSocketData);
_socket.addEventListener(SecurityErrorEvent.SECURITY_ERROR, onSecurityError);
_pingTimer = new Timer(5000);
_pingTimer.addEventListener(TimerEvent.TIMER, sendPing);
_instanceID = generateInstanceID(32);
}

public function connect(id:String, callback:Function = null):void
{
_userid = id;
_socket.connect(_host, _port);
_connectCallback = callback;
}

private function onConnect(event:Event):void
{
trace("Connected to server");
PLEASEWAIT.Hide();
if (_connectCallback !== null)
{
trace("calling connect callback");
_connectCallback();
_connectCallback = null;
}
send(1, {}, null, onLoginError);
processSendQueue();
_pingTimer.start();
_reconnectAttempts = 0;
}

private function onLoginError(event:IOErrorEvent = null):void
{
cleanup();
GLOBAL.ErrorMessage("SOCKET.LOGIN " + event.text);
}

public function cleanup()
{
_pingTimer.stop();
_reconnectAttempts = MAX_RECONNECT_ATTEMPTS + 1;
clearCallbacks();
_sendQueue = [];
if (_socket.connected)
{
_socket.close();
}
}

public function send(opcode:int, data:Object, successCallback:Function = null, errorCallback:Function = null):void
{
if (_socket.connected)
{
trace("Sending data to server opcode:" + opcode);
data["_instanceid"] = _instanceID;
data["_userid"] = _userid;
_sendQueue.push( {
"opcode": opcode,
"data": data,
"successCallback": successCallback,
"errorCallback": errorCallback
});

processSendQueue();
}
else if (errorCallback != null)
{
var errorMessage:String = "Socket is closed";
var ioErrorEvent:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false, errorMessage);
errorCallback(ioErrorEvent);
}
}

private function processSendQueue():void
{
if (_sendQueue.length > 0 && !_isSending)
{
trace("Processing send queue");
var sendData:Object = _sendQueue.shift();
var opcode:int = int(sendData.opcode);
var jsonData = JSON.encode(sendData.data);
_successCallbacks[opcode] = sendData.successCallback;
_errorCallbacks[opcode] = sendData.errorCallback;
_socket.writeShort(opcode);
_socket.writeInt(jsonData.length);
_socket.writeUTFBytes(jsonData);
_socket.flush();

_socket.addEventListener(Event.COMPLETE, onSendComplete);
}
}

private function onSendComplete(event:Event):void
{
// Remove event listener and reset flag indicating that sending is complete
_socket.removeEventListener(Event.COMPLETE, onSendComplete);
_isSending = false;
}

private function onSocketData(event:ProgressEvent):void
{
var opcode:int = _socket.readShort();

// Extract length of the JSON data from the next two bytes
var dataLength:int = _socket.readInt();
trace("Receive data from server - opcode:" + opcode + " length " + dataLength + "bytes" + _socket.bytesAvailable + ":pending:");
// Extract JSON data from the rest of the ByteArray
var jsonData:String = _socket.readUTFBytes(dataLength);

var responseData:Object = JSON.decode(jsonData);
var successCallback:Function = _successCallbacks[opcode];
var errorCallback:Function = _errorCallbacks[opcode];


if (responseData.hasOwnProperty("__error"))
{
if (errorCallback !== null)
{
var ioErrorEvent:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false, "Request error");
errorCallback(ioErrorEvent);
}
}
else
{
if(_eventListener.hasOwnProperty(opcode)){
var eventCallback = _eventListener(opcode)
eventCallback(responseData)
}
if (successCallback != null)
{
trace("calling callback");
successCallback(responseData);
}
}
clearCallbacks(opcode);
processSendQueue();
}

private function clearCallbacks(opcode:int = -1):void
{
for (var code in _successCallbacks)
{
if (opcode !== -1 && opcode != code)
{
continue;
}
delete _successCallbacks[code];
delete _errorCallbacks[code];
}
}

public function addEventListener(opcode:int, callback:Function):void
{
_eventListener[opcode] = callback;
}

public function removeEventListener(opcode:int):void
{
if (_eventListener.hasOwnProperty(opcode))
{
delete _eventListener[opcode];
}
}

private function sendPing(event:TimerEvent):void
{
send(500, {});
}

private function generateInstanceID(length:uint):String
{
var chars:String = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
var result:String = "";
var i:uint = 0;
while (i < length)
{
var randomIndex:uint = Math.floor(Math.random() * chars.length);
result += chars.charAt(randomIndex);
i++;
}
return result;
}

private function onSecurityError(error:SecurityErrorEvent):void
{
trace("security error", error.text);
reconnect();
}

private function onIOError(event:IOErrorEvent):void
{
trace("Socket error: " + event.text);
reconnect();
}

private function onClose(event:Event):void
{
trace("Socket close: " + event.toString());
reconnect();
}

private function reconnect():void
{
_pingTimer.stop();
trace("reconnecting", _reconnectAttempts);
if (_reconnectAttempts < MAX_RECONNECT_ATTEMPTS)
{
PLEASEWAIT.Show("Reconnecting to server.");
_reconnectAttempts++;
_socket.connect(_host, _port);
}
else
{
for each (var errorCallback:Function in _errorCallbacks)
{
if (errorCallback !== null)
{
var errorMessage:String = "Cannot reconnect to server";
var ioErrorEvent:IOErrorEvent = new IOErrorEvent(IOErrorEvent.IO_ERROR, false, false, errorMessage);
errorCallback(ioErrorEvent);
}
}
clearCallbacks();
PLEASEWAIT.Hide();
PLEASEWAIT.Show();
GLOBAL.ErrorMessage("Socket cannot reconnect, restart game");
}
}
}
}
8 changes: 7 additions & 1 deletion server/example.env
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
# For detailed information on variables see, http://178.32.125.55:25590/monkey-patch/backyard-monsters-refitted/wiki/Server-%26-Database-Setup#server-setup
TCP_HOST=0.0.0.0
PORT=3001
SECRET_KEY=
SESSION_LIFETIME=30d
Expand All @@ -8,4 +9,9 @@ DB_NAME='bym'
DB_HOST='localhost'
DB_PORT=3306
DB_USER='root'
DB_PASSWORD=''
DB_PASSWORD=''
#REDIS
REDIS_HOST=
REDIS_PORT=
REDIS_USER=
REDIS_PASS=
Loading