Starting reworking the webclient to use the new oob system format.

This commit is contained in:
Griatch 2015-02-15 08:58:50 +01:00
parent a24b79bb97
commit 850c5effaa
3 changed files with 145 additions and 54 deletions

View file

@ -236,9 +236,9 @@ class TelnetProtocol(Telnet, StatefulTelnetProtocol, Session):
return return
if "oob" in kwargs and "OOB" in self.protocol_flags: if "oob" in kwargs and "OOB" in self.protocol_flags:
# oob is a list of [(cmdname, arg, kwarg), ...] # oob is a list of [(cmdname, arg, kwarg), ...]
for cmdname, args, kwargs in kwargs["oob"]: for cmdname, args, okwargs in kwargs["oob"]:
#print "telnet oob data_out:", cmdname, args, kwargs #print "telnet oob data_out:", cmdname, args, kwargs
self.oob.data_out(cmdname, *args, **kwargs) self.oob.data_out(cmdname, *args, **okwargs)
# parse **kwargs, falling back to ttype if nothing is given explicitly # parse **kwargs, falling back to ttype if nothing is given explicitly
ttype = self.protocol_flags.get('TTYPE', {}) ttype = self.protocol_flags.get('TTYPE', {})

View file

@ -78,27 +78,48 @@ class WebSocketClient(Protocol, Session):
OOB - This is an Out-of-band instruction. If so, OOB - This is an Out-of-band instruction. If so,
the remaining string should be a json-packed the remaining string should be a json-packed
string on the form {oobfuncname: [args, ], ...} string on the form {oobfuncname: [args, ], ...}
any other prefix (or lack of prefix) is considered CMD - plain text data, to be treated like a game
plain text data, to be treated like a game
input command. input command.
""" """
if string[:3] == "OOB": mode = string[:3]
string = string[3:] data = string[3:]
try:
oobdata = json.loads(string) if mode == "OOB":
for (key, args) in oobdata.items(): # an out-of-band command
#print "oob data in:", (key, args) self.decode_json(data)
self.data_in(text=None, oob=(key, make_iter(args))) elif mode == "CMD":
except Exception:
log_trace("Websocket malformed OOB request: %s" % string)
else:
# plain text input # plain text input
self.data_in(text=string) self.data_in(text=data)
def sendLine(self, line): def sendLine(self, line):
"send data to client" "send data to client"
return self.transport.write(line) return self.transport.write(line)
def json_decode(self, data):
"""
Decodes incoming data from the client
[cmdname, [args],{kwargs}] -> cmdname *args **kwargs
"""
try:
cmdname, args, kwargs = json.loads(data)
except Exception:
log_trace("Websocket malformed OOB request: %s" % data)
raise
self.sessionhandler.data_in(oob=(cmdname, args, kwargs))
def json_encode(self, cmdname, *args, **kwargs):
"""
Encode OOB data for sending to client
cmdname *args -> cmdname [json array]
cmdname **kwargs -> cmdname {json object}
"""
cmdtuple = [cmdname, list(args), kwargs]
self.sendLine("OOB" + json.dumps(cmdtuple))
def data_in(self, text=None, **kwargs): def data_in(self, text=None, **kwargs):
""" """
Data Websocket -> Server Data Websocket -> Server
@ -121,9 +142,9 @@ class WebSocketClient(Protocol, Session):
except Exception, e: except Exception, e:
self.sendLine(str(e)) self.sendLine(str(e))
if "oob" in kwargs: if "oob" in kwargs:
oobstruct = self.sessionhandler.oobstruct_parser(kwargs.pop("oob")) for cmdname, args, okwargs in kwargs["oob"]:
#print "oob data_out:", "OOB" + json.dumps(oobstruct) self.encode_json(cmdname, *args, **okwargs)
self.sendLine("OOB" + json.dumps(oobstruct))
raw = kwargs.get("raw", False) raw = kwargs.get("raw", False)
nomarkup = kwargs.get("nomarkup", False) nomarkup = kwargs.get("nomarkup", False)
if "prompt" in kwargs: if "prompt" in kwargs:

View file

@ -36,14 +36,14 @@ function list (args, kwargs) {
function send (args, kwargs) { function send (args, kwargs) {
// show in main window. SEND returns kwargs {name:value}. // show in main window. SEND returns kwargs {name:value}.
for (sendvalue in kwargs) { for (var sendvalue in kwargs) {
doShow("out", sendvalue + " = " + kwargs[sendvalue]);} doShow("out", sendvalue + " = " + kwargs[sendvalue]);}
} }
function report (args, kwargs) { function report (args, kwargs) {
// show in main window. REPORT returns kwargs // show in main window. REPORT returns kwargs
// {attrfieldname:value} // {attrfieldname:value}
for (name in kwargs) { for (var name in kwargs) {
doShow("out", name + " = " + kwargs[name]) } doShow("out", name + " = " + kwargs[name]) }
} }
@ -55,6 +55,8 @@ function err (args, kwargs) {
// display error // display error
doShow("err", args) } doShow("err", args) }
// Map above functions with oob command names
var CMD_MAP = {"ECHO":echo, "LIST":list, "SEND":send, "REPORT":report, "error":err};
// //
// Webclient code // Webclient code
@ -86,34 +88,60 @@ function onClose(evt) {
} }
function onMessage(evt) { function onMessage(evt) {
// called when the Evennia is sending data to client // called when the Evennia is sending data to client.
var inmsg = evt.data // Such data is always prepended by a 3-letter marker
if (inmsg.length > 3 && inmsg.substr(0, 3) == "OOB") { // OOB, PRT or CMD, defining its operation
var inmsg = evt.data;
if (inmsg.length < 4) return;
var mode = inmsg.substr(0, 3);
var message = inmsg.slice(3);
if (mode == "OOB") {
// dynamically call oob methods, if available // dynamically call oob methods, if available
// The variables are come on the form [(cmname, [args], {kwargs}), ...]
var oobcmds = JSON.parse(message);
var errmsg = "";
try { try {
var oobarray = JSON.parse(inmsg.slice(3));} // everything after OOB } if (oobcmds instanceof Array == false) {
catch(err) { errmsg = "oob instruction's outermost level must be an Array.";
// not JSON packed - a normal text throw
doShow('out', inmsg);
return;
} }
if (typeof oobarray != "undefined") { for (var icmd = 0; i < oobcmds.length; icmd++) {
for (var ind in oobarray) { // call each command tuple in turn
try { var cmdname = oobcmds[icmd][0];
window[oobarray[ind][0]](oobarray[ind][1], oobarray[ind][2]) } var args = oobcmds[icmd][1];
catch(err) { var kwargs = oobcmds[icmd][2];
doShow("err", "Could not execute js OOB function '" + oobarray[ind][0] + "(" + oobarray[ind][1] + oobarray[ind][2] + ")'") } // match cmdname with a command existing in the
// CMD_MAP mapping
if (cmdname in CMD_MAP == false) {
errmsg = "oob command " + cmdname + " is not supported by client.";
throw
}
// we have a matching oob command in CMD_MAP.
// Prepare the error message beforehand
errmsg = "Client could not execute OOB function" + "cmdname" + "(" + args + kwargs + ").";
// Execute
CMD_MAP[cmdname](args, kwargs);
} }
} }
} catch(error) {
else if (inmsg.length >= 6 && inmsg.substr(0, 6) == "PROMPT") { if (errmsg) {
// handle prompt doShow("err", errmsg);
var game_prompt = inmsg.slice(6);
doPrompt("prompt", game_prompt);
} }
else { else {
doShow("err", "Client could not execute OOB function in " + oobcmds);
}
}
}
else if (mode == "PRT") {
// handle prompt
doPrompt("prompt", message);
}
else if (mode == "CMD") {
// normal command operation
// normal message // normal message
doShow('out', inmsg); } doShow('out', message);
}
} }
function onError(evt) { function onError(evt) {
@ -123,15 +151,17 @@ function onError(evt) {
function doSend(){ function doSend(){
// relays data from client to Evennia. // relays data from client to Evennia.
// If OOB_debug is set, allows OOB test data on the // If OOB_debug is set, allows OOB test data using the syntax
// form ##OOB{func:args} // ##OOB[funcname, args, kwargs]
outmsg = $("#inputfield").val(); outmsg = $("#inputfield").val();
history_add(outmsg); history_add(outmsg);
HISTORY_POS = 0; HISTORY_POS = 0;
$('#inputform')[0].reset(); // clear input field $('#inputform')[0].reset(); // clear input field
if (OOB_debug && outmsg.length > 4 && outmsg.substr(0, 5) == "##OOB") { if (OOB_debug && outmsg.length > 4 && outmsg.substr(0, 5) == "##OOB") {
if (outmsg == "##OOBUNITTEST") { // OOB direct input
var outmsg = outmsg.slice(5);
if (outmsg == "UNITTEST") {
// unittest mode // unittest mode
doShow("out", "OOB testing mode ..."); doShow("out", "OOB testing mode ...");
doOOB(JSON.parse('{"ECHO":"Echo test"}')); doOOB(JSON.parse('{"ECHO":"Echo test"}'));
@ -144,26 +174,66 @@ function doSend(){
doShow("out", "... OOB testing mode done."); doShow("out", "... OOB testing mode done.");
return return
} }
// test OOB messaging // send a manual OOB instruction
try { try {
doShow("out", "OOB input: " + outmsg.slice(5)); doShow("out", "OOB input: " + outmsg);
if (outmsg.length == 5) { if (outmsg.length == 5) {
doShow("err", "OOB testing syntax: ##OOB{\"cmdname:args, ...}"); } doShow("err", "OOB syntax: ##OOB[\"cmdname\", [args], {kwargs}]"); }
else { else {
doOOB(JSON.parse(outmsg.slice(5))); } } doOOB(JSON.parse(outmsg.slice(5))); }
}
catch(err) { catch(err) {
doShow("err", err) } doShow("err", err)
}
} }
else { else {
// normal output // normal output
websocket.send(outmsg); } websocket.send("CMD" + outmsg); }
} }
function doOOB(oobdict){ function doOOB(cmdstring){
// Send OOB data from client to Evennia. // Send OOB data from client to Evennia.
// Takes input on form {funcname:[args], funcname: [args], ... } // Takes input strings with syntax ["cmdname", args, kwargs]
var oobmsg = JSON.stringify(oobdict); var errmsg = "";
try {
var cmdtuple = JSON.parse(cmdstring);
var oobmsg = "";
if (cmdtuple instanceof Array == false) {
// a single command instruction without arguments
oobmsg = [cmdtuple, (), {}];
}
else if {
switch (cmdtuple.length) {
case 0:
throw;
break;
case 1:
// [cmdname]
oobmsg = [cmdtuple[0], (), {}];
break;
case 2:
// [cmdname, args]
oobmsg = [cmdtuple[0], cmdtuple[1], {}];
break;
case 3:
// [cmdname, args, kwargs]
oobmsg = [cmdtuple[0], cmdtuple[1], cmdtuple[2]];
break;
default:
errmsg = "Malformed OOB instruction:" + cmdstring
}
// convert to string and send it to the server
oobmsg = JSON.stringify(oobmsg);
websocket.send("OOB" + oobmsg); websocket.send("OOB" + oobmsg);
}
catch {
if (errmsg) {
doSend("err", errmsg);
}
else {
doSend("err", "OOB output " + cmdtuple + " is not on the right form.");
}
}
} }
function doShow(type, msg){ function doShow(type, msg){
@ -352,6 +422,6 @@ $(document).ready(function(){
}, 500); }, 500);
// set an idle timer to avoid proxy servers to time out on us (every 3 minutes) // set an idle timer to avoid proxy servers to time out on us (every 3 minutes)
setInterval(function() { setInterval(function() {
websocket.send("idle"); doSend("idle")
}, 60000*3); }, 60000*3);
}); });