sadira
Version:
Web framework
403 lines (294 loc) • 10.7 kB
JavaScript
// Sadira astro-web framework - PG Sprimont <fullmoon@swing.be> (2013) - INAF/IASF Bologna, Italy.
// Do what you want with this file.
/*
Messages handle the data transfer between browser and node in a versatile way.
Messages transiting trough the network are cutted in chunks called datagrams here.
Datagrams can either travel on TCP-IP packets (websockets) or UDP packets (WebRTC).
There are 3 basic datagram types. These should be able to handle any kind of info :
Initiation datagrams
Termination datagrams
stream datagrams
Note that in theory it won't work between different endiannes systems without upgrading the code below
*/
var nodejs= (typeof module !== 'undefined' && module.exports)? true:false; //Checking if we are in Node
var DGM={};
if(nodejs){
DGM=require("./datagram.js");
}else{
DGM.datagram=datagram;
}
var dialog = function (header, mgr){
this.header=null;
if(typeof header != 'undefined')this.set_header(header);
if(typeof mgr != 'undefined')this.mgr=mgr;
console.log("creating dialog " + JSON.stringify(header));
}
dialog.prototype.log = function(msg){
if(typeof this.header.id!='undefined')
console.log("DLG["+this.header.id+"]: "+msg);
else
console.log("DLG[UNDEF]: "+msg);
}
dialog.prototype.send_error = function(error_msg){
this.send_datagram({type: 'error', message : error_msg },null,function(error){
});
}
dialog.prototype.send_info = function(info_msg){
this.send_datagram({type: 'info', message : info_msg },null,function(error){
});
}
dialog.prototype.set_header = function(header){
this.header=header;
}
dialog.prototype.add_serializer=function(srz){
this.serializers[srz.oid]=srz;
for(var s in this.serializers){this.log("srz list after add: "+JSON.stringify(this.serializers[s].oid)); }
}
dialog.prototype.get_serializer=function(oid){
for(var s in this.serializers){console.log("srz ID : "+this.serializers[s].oid); }
return this.serializers[oid];
}
dialog.prototype.srz_request=function(dgram, result_cb){
console.log("NO SERIALIZATION SETUP ON THIS DIALOG!");
result_cb("No serialization setup");
}
dialog.prototype.srz_initiate=function(srz, status_cb){
console.log("Z");
srz.oid=Math.random().toString(36).substring(2);
console.log("Z");
srz_setup(this);
console.log("Z");
this.serializers[srz.oid]=srz;
console.log("Z");
var srz_head={type: 'srz', cmd: 'req', oid: srz.oid, sz : srz.size() };
console.log("Z");
if(typeof srz.header!='undefined')
for(var h in srz.header) srz_head[h]=srz.header[h];
console.log("Z");
this.send_datagram(srz_head,null,function(error){
console.log("Zweeee " + error);
});
console.log("Z");
}
srz_setup=function(dlg){
if(typeof dlg.serializers!='undefined') return;
// var dlg=this;
dlg.serializers={};
dlg.log("srz setup !");
dlg.listen('srz', function(dgram){
var srcmd=dgram.header.cmd;
if(srcmd=='req'){
var status_head={type: 'srz', cmd: 'req_reply'};
try{
var oid=dgram.header.oid;
if(typeof oid=='undefined')
throw "No serializer oid received!!";
status_head.oid=oid;
console.log("SRZ request ID=" + oid + " func is " + typeof dlg.srz_request);
dlg.srz_request(dgram, function(error, srz){
console.log("Ok here... srz = " + typeof srz);
if(error!=null){
status_head.status=false; status_head.error_message= error;
}
else{
console.log("Ok got serializer...");
srz.oid=oid;
status_head.status=true;
dlg.add_serializer(srz);
}
dlg.send_datagram(status_head,null,function(error){});
});
}
catch (e) {
status_head.status=false; status_head.error_message= dump_error(e);
dlg.send_datagram(status_head,null,function(error){});
}
}
else
if(srcmd=='req_reply'){
console.log("request reply !");
var oid=dgram.header.oid;
if(typeof oid=='undefined') throw "No serializer oid received!!";
var srz=dlg.get_serializer(oid);
if(dgram.header.status==true){
srz.on_accept();
var chunk_dgram, ready=true;
while (1){
//console.log("DG");
chunk_dgram=new DGM.datagram({type: 'srz', cmd: 'cnk', oid: oid});
//console.log("DG2");
if(! srz.write_chunk(chunk_dgram) ){
console.log("last chunk written");
delete dlg.serializers[oid];
break;
}
//console.log("DG3");
dlg.send(chunk_dgram, function(error){
if(error) throw "error send chunk " + error;
//console.log("DG4OK");
delete chunk_dgram;
// else
// console.log("chunk written ok");
});
}
}
else
srz.on_error(dgram.header.error_message);
}
else
if(srcmd=='cnk'){ //data chunk
var oid=dgram.header.oid;
if(typeof oid=='undefined') throw "No serializer object id received!!";
var srz=dlg.serializers[oid];
//console.log("received chunk..");
if(!srz.store_chunk(dgram)){
delete dlg.serializers[oid];
}
}
});
}
dialog.prototype.close=function(m){
var hd={type: 'close'};
if(typeof m=='undefined'){ hd.status=true; } else { hd.status=false; hd.error_message=m;}
this.send_datagram(hd,null,function(error){});
if(typeof this.mgr!='undefined')
this.mgr.delete_dialog(this);
}
dialog.prototype.connect = function(result_cb){ //Initiate connexion. In result will be given the dialog object.
var dlg=this;
//console.log("DIALOG connect : header = ["+JSON.stringify(this.header)+"]");
this.listen('hshk',function(dgram){
if(!dgram.header.status){
dlg.log("handshake failed on peer : "+dgram.header.error_message);
result_cb(dgram.header.error_message);
}else result_cb(null,dgram);
});
var init_head={type:'init'};
for(var he in this.header) init_head[he]=this.header[he];
this.send_datagram(init_head, null, function(error){
if(error)
result_cb(error);
});
}
dialog.prototype.read_chunk = function(dgram){
//console.log("Dialog " + this.header.id + " reading chunk " + JSON.stringify(dgram.header));
var dgr_type=dgram.header.type;
if(typeof dgr_type=='undefined')
throw "Datagram type not given on header!";
if(dgr_type=='srz') srz_setup(this);
var listeners=this.listeners[dgr_type];
if(typeof listeners=='undefined'){
throw "No listener for " + dgr_type;
}
for(var l=0;l<listeners.length;l++){
this.listeners[dgr_type][l](dgram);
}
if(typeof dgram.header.close != 'undefined'){
if (dgram.header.close == true){
if(typeof this.mgr!='undefined')
this.mgr.delete_dialog(this);
}
}
}
dialog.prototype.send=function(dgr,status_func){
dgr.header.id=this.header.id;
dgr.send(this.cnx, status_func);
}
dialog.prototype.send_datagram=function(header, data, status_func){
//for(var he in this.header) if(this.header.hasOwnProperty(he)) header[he]=this.header[he];
var dgr=new DGM.datagram(header, data);
this.send(dgr,status_func);
if(typeof dgr.header.close!= 'undefined')
if(dgr.header.close==true){
if(typeof this.mgr!= 'undefined')
this.mgr.delete_dialog(this);
}
}
//dialog.prototype.listeners=[];
dialog.prototype.listen=function(type, callback){
if(typeof this.listeners=='undefined')this.listeners={};
if(typeof this.listeners[type]=='undefined') this.listeners[type]=[];
this.listeners[type].push(callback);
}
var dialog_manager = function(cnx){
this.dialogs={};
this.cnx=cnx;
}
dialog_manager.prototype.delete_dialog=function(dlg){
console.log("!Delete dialog "+JSON.stringify(dlg.header));
delete this.dialogs[dlg.header.id];
//var nd=0;for(var d in this.dialogs){ nd++; console.log("D"+nd+":"+JSON.stringify(this.dialogs[d].header));}
}
dialog_manager.prototype.create_dialog=function(dlg_header){
var dlg = new dialog(dlg_header,this);
dlg.cnx=this.cnx;
dlg.header.id=Math.random().toString(36).substring(2);
this.dialogs[dlg.header.id]=dlg;
//dlg.log("Created from manager");
return dlg;
}
dialog_manager.prototype.process_datagram=function(dgram){
var dmgr=this;
var dlg,header=dgram.header;
if(typeof header=='undefined') throw "datagram has no header!";
var type=header.type;
var dlgid=header.id;
if(typeof type=='undefined')throw "No header type ";
if(typeof dlgid=='undefined') throw "No dialog ID in message header!";
//console.log("DMGR received DGRAM type ["+type+"]for DLG["+dlgid+"]");
//console.log("Header:" + JSON.stringify(header) );
if(type=="init"){ // First chunk of a new dialog -> Initialization of a new dialog object
var hshk_head={type:'hshk'};
var dlg = new dialog(header,this);
dlg.cnx=this.cnx;
try{
var hndl_name=header.handler;
if(typeof hndl_name=='undefined')throw "No handler defined on init datagram ";
var hndl=eval('dialog_handlers.'+hndl_name);
if(typeof hndl=='undefined')throw "No handler found for init datagram handler ["+hndl_name+"]";
hndl(dlg, function(error, hhead, hdata){
var hshk_data=null;
if(typeof error!= 'undefined' && error!=null){
hshk_head.status=false;
hshk_head.close=true;
hshk_head.error_message=error;
//throw "Handshake error : " +error;
dlg.log("Eval handler [" + hndl_name + "] error : " + error);
}else{
hshk_head.status=true;
dlg.log("Eval handler [" + hndl_name + "] OK ");
if(typeof hhead != 'undefined') for (var hh in hhead) hshk_head[hh]=hhead[hh];
if(typeof hdata != 'undefined') hshk_data=hdata;
}
dlg.send_datagram(hshk_head, hshk_data, function(error){
if(error){
dlg.log("Error sending datagram : " + dump_error(error));
}else
dmgr.dialogs[dlgid]=dlg; //Attaching the new dialog to the active hash
} );
});
}
catch(e){
hshk_head.status=false;
hshk_head.close=true;
hshk_head.error_message=e+"";
dlg.log("Init exception " + dump_error(e));
dlg.send_datagram(hshk_head, null, function(error){} );
delete dlg;
}
return;
}
var dlg=this.dialogs[dlgid];
if(typeof dlg!='undefined'){ //Found the dialog
if(type=="close"){ // force close of dialog)
if(!header.status) dlg.log("Closed by peer with error : " + header.error_message);
this.delete_dialog(dlg);
}else
dlg.read_chunk(dgram); //Passing the handling of the datagram to it
}else
throw "Cannot find dialog with id " + dlgid;
}
if(nodejs){
exports.dialog=dialog;
exports.dialog_manager=dialog_manager;
}