More work on the new js lib, added client-side support for ajax/comet, which will be using JSON and OOB commands, same as websocket version.
This commit is contained in:
parent
7fa088c036
commit
da52380b0f
1 changed files with 208 additions and 152 deletions
|
|
@ -25,10 +25,14 @@ functions:
|
||||||
- Evennia.init(options)
|
- Evennia.init(options)
|
||||||
This must be called by the frontend to intialize the library. The
|
This must be called by the frontend to intialize the library. The
|
||||||
argument is an js object with the following possible keys:
|
argument is an js object with the following possible keys:
|
||||||
'connection': Either 'websocket' or 'comet'.
|
'connection': This defaults to Evennia.WebsocketConnection but
|
||||||
|
can also be set to Evennia.CometConnection for backwards
|
||||||
|
compatibility with old browsers. Each connection must have
|
||||||
|
a 'msg(data)' method that should handle the conversion to
|
||||||
|
JSON before sending across the wire.
|
||||||
'cmdhandler': An optional custom command handler for
|
'cmdhandler': An optional custom command handler for
|
||||||
managing outgoing commands from the server. If not
|
managing outgoing commands from the server. If not
|
||||||
supplied, the default will be used. It must have a msg() function.
|
supplied, the default will be used. It must have an emit(data) function.
|
||||||
- Evennia.msg(funcname, [args,...], callback)
|
- Evennia.msg(funcname, [args,...], callback)
|
||||||
Send a command to the server. You can also provide a function
|
Send a command to the server. You can also provide a function
|
||||||
to call with the return of the call (not all commands will return
|
to call with the return of the call (not all commands will return
|
||||||
|
|
@ -37,6 +41,7 @@ functions:
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
Evennia websocket webclient (javascript component)
|
Evennia websocket webclient (javascript component)
|
||||||
|
|
||||||
The client is composed of two parts:
|
The client is composed of two parts:
|
||||||
|
|
@ -52,163 +57,214 @@ messages sent to the client is one of two modes:
|
||||||
*/
|
*/
|
||||||
|
|
||||||
(function() {
|
(function() {
|
||||||
var cmdid = 0;
|
var cmdid = 0;
|
||||||
var cmdmap = {};
|
|
||||||
|
|
||||||
var Evennia = {
|
|
||||||
debug: true,
|
|
||||||
// Client -> Evennia.
|
|
||||||
// Called by the frontend to send a command to Evennia.
|
|
||||||
//
|
|
||||||
// Args:
|
|
||||||
// cmdname (str): String identifier to call
|
|
||||||
// kwargs (obj): Data argument for calling as cmdname(kwargs)
|
|
||||||
// callback (func): If given, will be given an eventual return
|
|
||||||
// value from the backend.
|
|
||||||
//
|
|
||||||
send: function (cmdname, kwargs, callback) {
|
|
||||||
kwargs.cmdid = cmdid++;
|
|
||||||
var data = kwargs ? [cmdname, kwargs] : [cmdname, {}];
|
|
||||||
|
|
||||||
if (typeof callback === 'function') {
|
|
||||||
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);
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// Initializer.
|
|
||||||
// startup Evennia emitter and connection.
|
|
||||||
//
|
|
||||||
// Args:
|
|
||||||
// opts (obj):
|
|
||||||
// emitter - custom emitter. If not given,
|
|
||||||
// will use a default emitter. Must have
|
|
||||||
// an "emit" function.
|
|
||||||
// connection - This defaults to a WebsocketConnection,
|
|
||||||
// but could also be the CometConnection or another
|
|
||||||
// custom protocol. Must have a 'send' method and
|
|
||||||
// make use of Evennia.emit to return data to Client.
|
|
||||||
//
|
|
||||||
init: function (kwargs) {
|
|
||||||
kwargs = kwargs || {};
|
|
||||||
this.emitter = kwargs.emitter || new DefaultEmitter();
|
|
||||||
this.connection = kwargs.connection || new WebsocketConnection();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
// Websocket Connector
|
|
||||||
//
|
|
||||||
var WebsocketConnection = function () {
|
|
||||||
var websocket = new WebSocket(wsurl);
|
|
||||||
// Handle Websocket open event
|
|
||||||
this.websocket.onopen = function (event) {
|
|
||||||
log('Websocket connection openened.');
|
|
||||||
Evennia.emit('socket:open', event);
|
|
||||||
};
|
|
||||||
// Handle Websocket close event
|
|
||||||
this.websocket.onclose = function (event) {
|
|
||||||
log('WebSocket connection closed.');
|
|
||||||
Evennia.emit('socket:close', event);
|
|
||||||
};
|
|
||||||
// Handle websocket errors
|
|
||||||
this.websocket.onerror = function (event) {
|
|
||||||
log("Websocket error to ", wsurl, event);
|
|
||||||
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;
|
|
||||||
}
|
|
||||||
|
|
||||||
// AJAX/COMET Connector
|
|
||||||
//
|
|
||||||
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 = {};
|
var cmdmap = {};
|
||||||
|
|
||||||
// Emit data to all listeners tied to a given cmdname
|
var evennia = {
|
||||||
//
|
|
||||||
// Args:
|
|
||||||
// cmdname (str): Name of command, used to find
|
|
||||||
// all listeners to this call; each will be
|
|
||||||
// called as function(kwargs).
|
|
||||||
// kwargs (obj): Argument to the listener.
|
|
||||||
//
|
|
||||||
var emit = function (cmdname, kwargs) {
|
|
||||||
log('emit', cmdname, kwargs);
|
|
||||||
|
|
||||||
if (this.cmdmap[cmdname]) {
|
debug: true,
|
||||||
this.cmdmap[cmdname].apply(this, kwargs);
|
|
||||||
|
// Initialize.
|
||||||
|
// startup Evennia emitter and connection.
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// opts (obj):
|
||||||
|
// emitter - custom emitter. If not given,
|
||||||
|
// will use a default emitter. Must have
|
||||||
|
// an "emit" function.
|
||||||
|
// connection - This defaults to a WebsocketConnection,
|
||||||
|
// but could also be the CometConnection or another
|
||||||
|
// custom protocol. Must have a 'send' method and
|
||||||
|
// make use of Evennia.emit to return data to Client.
|
||||||
|
//
|
||||||
|
init: function(opts) {
|
||||||
|
opts = opts || {};
|
||||||
|
this.emitter = opts.emitter || new DefaultEmitter();
|
||||||
|
this.connection = opts.connection || new WebsocketConnection();
|
||||||
|
},
|
||||||
|
|
||||||
|
// Client -> Evennia.
|
||||||
|
// Called by the frontend to send a command to Evennia.
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// cmdname (str): String identifier to call
|
||||||
|
// kwargs (obj): Data argument for calling as cmdname(kwargs)
|
||||||
|
// callback (func): If given, will be given an eventual return
|
||||||
|
// value from the backend.
|
||||||
|
//
|
||||||
|
msg: function (cmdname, kwargs, callback) {
|
||||||
|
kwargs.cmdid = cmdid++;
|
||||||
|
var data = kwargs ? [cmdname, kwargs] : [cmdname, {}];
|
||||||
|
|
||||||
|
if (typeof callback === 'function') {
|
||||||
|
this.cmdmap[cmdid] = callback;
|
||||||
|
}
|
||||||
|
this.connection.msg(data);
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
|
||||||
|
}; // end of evennia object
|
||||||
|
|
||||||
|
|
||||||
|
// 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 data to all listeners tied to a given cmdname
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// cmdname (str): Name of command, used to find
|
||||||
|
// all listeners to this call; each will be
|
||||||
|
// 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
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// 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;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
// remove handling of this cmdname
|
||||||
|
//
|
||||||
|
// Args:
|
||||||
|
// cmdname (str): Name of event to handle
|
||||||
|
//
|
||||||
|
var off = function (cmdname) {
|
||||||
|
delete this.cmdmap[cmdname]
|
||||||
|
};
|
||||||
|
return {emit:emit, on:on, off:off}
|
||||||
};
|
};
|
||||||
|
|
||||||
// Bind listener to event
|
// Websocket Connector
|
||||||
//
|
//
|
||||||
// Args:
|
var WebsocketConnection = function () {
|
||||||
// cmdname (str): Name of event to handle.
|
var websocket = new WebSocket(wsurl);
|
||||||
// listener (function): Function taking one argument,
|
// Handle Websocket open event
|
||||||
// to listen to cmdname events.
|
this.websocket.onopen = function (event) {
|
||||||
//
|
log('Websocket connection openened.');
|
||||||
var on = function (cmdname, listener) {
|
Evennia.emit('socket:open', event);
|
||||||
if typeof(listener === 'function') {
|
};
|
||||||
this.cmdmap[cmdname] = listener;
|
// Handle Websocket close event
|
||||||
}
|
this.websocket.onclose = function (event) {
|
||||||
};
|
log('WebSocket connection closed.');
|
||||||
|
Evennia.emit('socket:close', event);
|
||||||
|
};
|
||||||
|
// Handle websocket errors
|
||||||
|
this.websocket.onerror = function (event) {
|
||||||
|
log("Websocket error to ", wsurl, event);
|
||||||
|
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]]);
|
||||||
|
};
|
||||||
|
this.websocket.msg = function(data) {
|
||||||
|
this.websocket.send(JSON.stringify(data));
|
||||||
|
};
|
||||||
|
|
||||||
// remove handling of this cmdname
|
return websocket;
|
||||||
//
|
}
|
||||||
// Args:
|
|
||||||
// cmdname (str): Name of event to handle
|
|
||||||
//
|
|
||||||
var off = function (cmdname) {
|
|
||||||
delete this.cmdmap[cmdname]
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
return {
|
// AJAX/COMET Connector
|
||||||
emit: emit,
|
//
|
||||||
on: on,
|
CometConnection = function() {
|
||||||
off: off
|
var client_hash = '0';
|
||||||
};
|
|
||||||
};
|
var ajaxcomet = {
|
||||||
|
// Send Client -> Evennia. Called by Evennia.send.
|
||||||
|
var msg = function(data) {
|
||||||
|
$.ajax({type: "POST", url: "/webclientdata",
|
||||||
|
async: true, cache: false, timeout: 30000,
|
||||||
|
dataType: "json",
|
||||||
|
data: {mode:'input', msg: data, 'suid': client_hash},
|
||||||
|
success: function(data): {},
|
||||||
|
error: function(req, stat, err): {
|
||||||
|
log("COMET: Server returned error. " + err)
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
window.Evennia = Evennia;
|
// Receive Evennia -> Client. This will start an asynchronous
|
||||||
})();
|
// Long-polling request. It will either timeout or receive data
|
||||||
|
// from the 'webclientdata' url. Either way a new polling request
|
||||||
|
// will immediately be started.
|
||||||
|
var poll = function() {
|
||||||
|
$.ajax({type: "POST", url: "/webclientdata",
|
||||||
|
async: true, cache: false, timeout: 30000,
|
||||||
|
dataType: "json",
|
||||||
|
data = {mode: 'receive', 'suid': client_hash},
|
||||||
|
success: function(data) {
|
||||||
|
Evennia.emit(data[0], data[1])
|
||||||
|
},
|
||||||
|
error: function() {
|
||||||
|
this.poll() // timeout; immediately re-poll
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Initialization will happen when this Connection is created.
|
||||||
|
// We need to store the client id so Evennia knows to separate
|
||||||
|
// the clients.
|
||||||
|
$.ajax({type: "POST", url: "/webclientdata",
|
||||||
|
async: true, cache: false, timeout: 50000,
|
||||||
|
datatype: "json",
|
||||||
|
success: function(data) {
|
||||||
|
this.client_hash = data.suid;
|
||||||
|
this.poll();
|
||||||
|
},
|
||||||
|
error: function(req, stat, err) {
|
||||||
|
log("Connection error: " + err);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
return ajaxcomet;
|
||||||
|
};
|
||||||
|
|
||||||
|
window.Evennia = evennia;
|
||||||
|
|
||||||
|
})(); // end of auto-calling Evennia object defintion
|
||||||
|
|
||||||
// helper logging function
|
// helper logging function
|
||||||
// Args:
|
// Args:
|
||||||
|
|
@ -222,13 +278,13 @@ function log(msg) {
|
||||||
|
|
||||||
// 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
|
|
||||||
$('#noscript').remove();
|
|
||||||
|
|
||||||
|
|
||||||
// a small timeout to stop 'loading' indicator in Chrome
|
// a small timeout to stop 'loading' indicator in Chrome
|
||||||
setTimeout(function () {
|
setTimeout(function () {
|
||||||
log('Evennia initialized...')
|
log('Evennia initialized...')
|
||||||
Evennia.init();
|
Evennia.init()
|
||||||
|
|
||||||
}, 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() {
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue