First attempt at fixed-up js library component, inspired by Glitch's emitter pattern in #613.
This commit is contained in:
parent
f0c9128ff8
commit
7fa088c036
1 changed files with 123 additions and 87 deletions
|
|
@ -43,9 +43,6 @@ The client is composed of two parts:
|
||||||
- /server/portal/websocket_client.py - the portal-side component
|
- /server/portal/websocket_client.py - the portal-side component
|
||||||
- this file - the javascript component handling dynamic content
|
- this file - the javascript component handling dynamic content
|
||||||
|
|
||||||
A
|
|
||||||
|
|
||||||
|
|
||||||
messages sent to the client is one of two modes:
|
messages sent to the client is one of two modes:
|
||||||
OOB("func1",args, "func2",args, ...) - OOB command executions, this will
|
OOB("func1",args, "func2",args, ...) - OOB command executions, this will
|
||||||
call unique javascript functions
|
call unique javascript functions
|
||||||
|
|
@ -54,117 +51,152 @@ messages sent to the client is one of two modes:
|
||||||
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
//
|
|
||||||
// Custom OOB functions
|
|
||||||
// functions defined here can be called by name by the server. For
|
|
||||||
// example input OOB{"echo":(args),{kwargs}} will trigger a function named
|
|
||||||
// echo(args, kwargs). The commands the server understands is set by
|
|
||||||
// settings.OOB_PLUGIN_MODULES
|
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var id = 0;
|
var cmdid = 0;
|
||||||
var map = {};
|
var cmdmap = {};
|
||||||
|
|
||||||
var Evennia = {
|
var Evennia = {
|
||||||
debug: true,
|
debug: true,
|
||||||
// called by the frontend to send a command to the backend
|
// Client -> Evennia.
|
||||||
cmd: function (cmd, params, callback) {
|
// Called by the frontend to send a command to Evennia.
|
||||||
var msg = params ? [cmd, [params], {}] : [cmd, [], {}];
|
//
|
||||||
params.id = id++;
|
// Args:
|
||||||
|
// cmdname (str): String identifier to call
|
||||||
log('cmd called with following args:', cmd, params, callback);
|
// kwargs (obj): Data argument for calling as cmdname(kwargs)
|
||||||
|
// callback (func): If given, will be given an eventual return
|
||||||
websocket.send('OOB' + JSON.stringify(msg));
|
// value from the backend.
|
||||||
|
//
|
||||||
|
send: function (cmdname, kwargs, callback) {
|
||||||
|
kwargs.cmdid = cmdid++;
|
||||||
|
var data = kwargs ? [cmdname, kwargs] : [cmdname, {}];
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
if (typeof callback === 'function') {
|
||||||
map[id] = callback;
|
this.cmdmap[cmdid] = callback;
|
||||||
|
}
|
||||||
|
this.connection.send(JSON.stringify(kwargs));
|
||||||
|
|
||||||
|
log('cmd called with following args:', cmd, params, callback);
|
||||||
|
},
|
||||||
|
|
||||||
|
// Evennia -> Client.
|
||||||
|
// Called by the backend to emit an event to the global emitter
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// event (event): Event received from Evennia
|
||||||
|
// data (obj):
|
||||||
|
//
|
||||||
|
emit: function (cmdname, data) {
|
||||||
|
if (data.cmdid) {
|
||||||
|
this.cmdmap[data.cmdid].apply(this, [data]);
|
||||||
|
delete this.cmdmap[cmddata.cmdid];
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
this.emitter.emit(cmdname, data);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
|
||||||
// called by the backend to emit an event to the global emitter
|
// Initializer.
|
||||||
emit: function (event, data) {
|
// startup Evennia emitter and connection.
|
||||||
if (data.id) {
|
//
|
||||||
map[data.id].apply(this, [event, data]);
|
// Args:
|
||||||
delete map[data.id];
|
// opts (obj):
|
||||||
}
|
// emitter - custom emitter. If not given,
|
||||||
Evennia.emitter.emit(event, data);
|
// will use a default emitter. Must have
|
||||||
},
|
// an "emit" function.
|
||||||
|
// connection - This defaults to a WebsocketConnection,
|
||||||
// startup Evennia emitter and connection
|
// but could also be the CometConnection or another
|
||||||
init: function (opts) {
|
// custom protocol. Must have a 'send' method and
|
||||||
opts = opts || {};
|
// make use of Evennia.emit to return data to Client.
|
||||||
Evennia.emitter = opts.emitter || new Emitter();
|
//
|
||||||
Evennia.websocket = new Connection();
|
init: function (kwargs) {
|
||||||
|
kwargs = kwargs || {};
|
||||||
|
this.emitter = kwargs.emitter || new DefaultEmitter();
|
||||||
|
this.connection = kwargs.connection || new WebsocketConnection();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// wrapper for websocket setup
|
// Websocket Connector
|
||||||
var Connection = function () {
|
//
|
||||||
|
var WebsocketConnection = function () {
|
||||||
var websocket = new WebSocket(wsurl);
|
var websocket = new WebSocket(wsurl);
|
||||||
websocket.onopen = function (event) {
|
// Handle Websocket open event
|
||||||
|
this.websocket.onopen = function (event) {
|
||||||
|
log('Websocket connection openened.');
|
||||||
Evennia.emit('socket:open', event);
|
Evennia.emit('socket:open', event);
|
||||||
};
|
};
|
||||||
websocket.onclose = function (event) {
|
// Handle Websocket close event
|
||||||
log('WebSocket connection closed.')
|
this.websocket.onclose = function (event) {
|
||||||
|
log('WebSocket connection closed.');
|
||||||
Evennia.emit('socket:close', event);
|
Evennia.emit('socket:close', event);
|
||||||
};
|
};
|
||||||
websocket.onmessage = function (event) {
|
// Handle websocket errors
|
||||||
if (typeof event.data !== 'string' && event.data.length < 0) {
|
this.websocket.onerror = function (event) {
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
// only acceptable mode is OOB
|
|
||||||
var mode = event.data.substr(0, 3);
|
|
||||||
|
|
||||||
if (mode === 'OOB') {
|
|
||||||
// parse the rest of the response
|
|
||||||
var res = JSON.parse(event.data.substr(3));
|
|
||||||
log(res);
|
|
||||||
var cmd = res[0];
|
|
||||||
var args = res[1];
|
|
||||||
Evennia.emit(cmd, args[0]);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
websocket.onerror = function (event) {
|
|
||||||
log("Websocket error to ", wsurl, event);
|
log("Websocket error to ", wsurl, event);
|
||||||
Evennia.emit('socket:error', data);
|
Evennia.emit('socket:error', data);
|
||||||
};
|
};
|
||||||
|
// Handle incoming websocket data
|
||||||
|
this.websocket.onmessage = function (event) {
|
||||||
|
var data = event.data
|
||||||
|
if (typeof data !== 'string' && data.length < 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
// Parse the incoming data, send to emitter
|
||||||
|
// Incoming data is on the form [cmdname, kwargs]
|
||||||
|
data = JSON.parse(data);
|
||||||
|
Evennia.emit(data[0], data[1]]);
|
||||||
|
};
|
||||||
return websocket;
|
return websocket;
|
||||||
}
|
}
|
||||||
|
|
||||||
// basic emitter, can be overridden in evennia init
|
// AJAX/COMET Connector
|
||||||
var Emitter = function () {
|
//
|
||||||
var map = {};
|
CometConnection = function() {
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
// Basic emitter to distribute data being sent to the client from
|
||||||
|
// the Server. An alternative can be overridden in Evennia.init.
|
||||||
|
//
|
||||||
|
var DefaultEmitter = function () {
|
||||||
|
var cmdmap = {};
|
||||||
|
|
||||||
// emit to listeners of given event
|
// Emit data to all listeners tied to a given cmdname
|
||||||
var emit = function (event, params) {
|
//
|
||||||
log('emit', event, params);
|
// Args:
|
||||||
if (map[event] && map[event] === Array) {
|
// cmdname (str): Name of command, used to find
|
||||||
map[event].forEach(function (val) {
|
// all listeners to this call; each will be
|
||||||
val.apply(this, params);
|
// called as function(kwargs).
|
||||||
});
|
// kwargs (obj): Argument to the listener.
|
||||||
|
//
|
||||||
|
var emit = function (cmdname, kwargs) {
|
||||||
|
log('emit', cmdname, kwargs);
|
||||||
|
|
||||||
|
if (this.cmdmap[cmdname]) {
|
||||||
|
this.cmdmap[cmdname].apply(this, kwargs);
|
||||||
|
};
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// bind listener to event, only allow one instance of handler
|
// Bind listener to event
|
||||||
var on = function (event, handler) {
|
//
|
||||||
if (!map[event]) {
|
// Args:
|
||||||
map[event] = [];
|
// cmdname (str): Name of event to handle.
|
||||||
|
// listener (function): Function taking one argument,
|
||||||
|
// to listen to cmdname events.
|
||||||
|
//
|
||||||
|
var on = function (cmdname, listener) {
|
||||||
|
if typeof(listener === 'function') {
|
||||||
|
this.cmdmap[cmdname] = listener;
|
||||||
}
|
}
|
||||||
if (map[event].indexOf(handler) >= 0) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
map[event].push(handler);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// remove handler from event
|
// remove handling of this cmdname
|
||||||
var off = function (event, handler) {
|
//
|
||||||
if (map[event]) {
|
// Args:
|
||||||
var listener = map[event].indexOf(handler);
|
// cmdname (str): Name of event to handle
|
||||||
if (listener >= 0) {
|
//
|
||||||
map[event].splice(listener, 1);
|
var off = function (cmdname) {
|
||||||
}
|
delete this.cmdmap[cmdname]
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -178,13 +210,17 @@ messages sent to the client is one of two modes:
|
||||||
window.Evennia = Evennia;
|
window.Evennia = Evennia;
|
||||||
})();
|
})();
|
||||||
|
|
||||||
function log() {
|
// helper logging function
|
||||||
|
// Args:
|
||||||
|
// msg (str): Message to log to console.
|
||||||
|
//
|
||||||
|
function log(msg) {
|
||||||
if (Evennia.debug) {
|
if (Evennia.debug) {
|
||||||
console.log(arguments);
|
console.log(msg);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Callback function - called when page has finished loading (kicks the client into gear)
|
// Called when page has finished loading (kicks the client into gear)
|
||||||
$(document).ready(function(){
|
$(document).ready(function(){
|
||||||
// remove the "no javascript" warning, since we obviously have javascript
|
// remove the "no javascript" warning, since we obviously have javascript
|
||||||
$('#noscript').remove();
|
$('#noscript').remove();
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue