This commit is contained in:
Matthias Janetschek
2015-06-02 17:17:09 +02:00
parent 44dafd1958
commit e7451b1c59
6 changed files with 495 additions and 206 deletions
@@ -1,111 +1,228 @@
//>>built
define("dojox/socket",["dojo/_base/array","dojo/_base/lang","dojo/_base/xhr","dojo/aspect","dojo/on","dojo/Evented","dojo/_base/url"],function(_1,_2,_3,_4,on,_5,_6){
var _7=window.WebSocket;
var _8=function(_9){
if(typeof _9=="string"){
_9={url:_9};
}
return _7?_8.WebSocket(_9,true):_8.LongPoll(_9);
define("dojox/socket", [
"dojo/_base/array",
"dojo/_base/lang",
"dojo/_base/xhr",
"dojo/aspect",
"dojo/on",
"dojo/Evented",
"dojo/_base/url"
], function(array, lang, xhr, aspect, on, Evented, dBaseUrl) {
var WebSocket = window.WebSocket;
var Socket = function(/*dojo.__XhrArgs*/ argsOrUrl){
// summary:
// Provides a simple socket connection using WebSocket, or alternate
// communication mechanisms in legacy browsers for comet-style communication. This is based
// on the WebSocket API and returns an object that implements the WebSocket interface:
// http://dev.w3.org/html5/websockets/#websocket
// description:
// Provides socket connections. This can be used with virtually any Comet protocol.
// argsOrUrl:
// This uses the same arguments as the other I/O functions in Dojo, or a
// URL to connect to. The URL should be a relative URL in order to properly
// work with WebSockets (it can still be host relative, like //other-site.org/endpoint)
// returns:
// An object that implements the WebSocket API
// example:
// | require(["dojox/socket", "dojo/aspect"], function(socket, aspect) {
// | var sock = socket({"url://comet-server/comet");
// | // we could also add auto-reconnect support
// | // now we can connect to standard HTML5 WebSocket-style events
// | aspect.after(socket, "onmessage", function(event){
// | var message = event.data;
// | // do something with the message
// | });
// | // send something
// | sock.send("hi there");
// | ...
// | });
// You can also use the Reconnect module:
// | require["dojox/socket", "dojox/socket/Reconnect"], function(dxSocket, reconnect){
// | var socket = dxSocket({url:"/comet"});
// | // add auto-reconnect support
// | socket = reconnect(socket);
if(typeof argsOrUrl == "string"){
argsOrUrl = {url: argsOrUrl};
}
return WebSocket ? Socket.WebSocket(argsOrUrl, true) : Socket.LongPoll(argsOrUrl);
};
_8.WebSocket=function(_a,_b){
var _c=document.baseURI||window.location.href;
var ws=new _7(new _6(_c.replace(/^http/i,"ws"),_a.url));
ws.on=function(_d,_e){
ws.addEventListener(_d,_e,true);
Socket.WebSocket = function(args, fallback){
// summary:
// A wrapper for WebSocket, than handles standard args and relative URLs
var baseURI = document.baseURI || window.location.href;
var ws = new WebSocket(new dBaseUrl(baseURI.replace(/^http/i,'ws'), args.url));
ws.on = function(type, listener){
ws.addEventListener(type, listener, true);
};
var opened;
aspect.after(ws, "onopen", function(event){
opened = true;
}, true);
aspect.after(ws, "onclose", function(event){
if(opened){
return;
}
if(fallback){
Socket.replace(ws, Socket.LongPoll(args), true);
}
}, true);
return ws;
};
var _f;
_4.after(ws,"onopen",function(_10){
_f=true;
},true);
_4.after(ws,"onclose",function(_11){
if(_f){
return;
}
if(_b){
_8.replace(ws,_8.LongPoll(_a),true);
}
},true);
return ws;
Socket.replace = function(socket, newSocket, listenForOpen){
// make the original socket a proxy for the new socket
socket.send = lang.hitch(newSocket, "send");
socket.close = lang.hitch(newSocket, "close");
var proxyEvent = function(type){
(newSocket.addEventListener || newSocket.on).call(newSocket, type, function(event){
on.emit(socket, event.type, event);
}, true);
};
if(listenForOpen){
proxyEvent("open");
}
// redirect the events as well
array.forEach(["message", "close", "error"], proxyEvent);
};
_8.replace=function(_12,_13,_14){
_12.send=_2.hitch(_13,"send");
_12.close=_2.hitch(_13,"close");
var _15=function(_16){
(_13.addEventListener||_13.on).call(_13,_16,function(_17){
on.emit(_12,_17.type,_17);
},true);
Socket.LongPoll = function(/*dojo.__XhrArgs*/ args){
// summary:
// Provides a simple long-poll based comet-style socket/connection to a server and returns an
// object implementing the WebSocket interface:
// http://dev.w3.org/html5/websockets/#websocket
// args:
// This uses the same arguments as the other I/O functions in Dojo, with this addition:
// args.interval:
// Indicates the amount of time (in milliseconds) after a response was received
// before another request is made. By default, a request is made immediately
// after getting a response. The interval can be increased to reduce load on the
// server or to do simple time-based polling where the server always responds
// immediately.
// args.transport:
// Provide an alternate transport like dojo.io.script.get
// returns:
// An object that implements the WebSocket API
// example:
// | dojo.require("dojox.socket.LongPoll");
// | var socket = dojox.socket.LongPoll({url:"/comet"});
// or:
// | dojo.require("dojox.socket.LongPoll");
// | dojox.socket.LongPoll.add();
// | var socket = dojox.socket({url:"/comet"});
var cancelled = false,
first = true,
timeoutId,
connections = [];
// create the socket object
var fire, connect;
var socket = {
send: function(data){
// summary:
// Send some data using XHR or provided transport
var sendArgs = lang.delegate(args);
sendArgs.rawBody = data;
clearTimeout(timeoutId);
var deferred = first ? (first = false) || socket.firstRequest(sendArgs) :
socket.transport(sendArgs);
connections.push(deferred);
deferred.then(function(response){
// got a response
socket.readyState = 1;
// remove the current connection
connections.splice(array.indexOf(connections, deferred), 1);
// reconnect to listen for the next message if there are no active connections,
// we queue it up in case one of the onmessage handlers has a message to send
if(!connections.length){
timeoutId = setTimeout(connect, args.interval);
}
if(response){
// now send the message along to listeners
fire("message", {data: response}, deferred);
}
}, function(error){
connections.splice(array.indexOf(connections, deferred), 1);
// an error occurred, fire the appropriate event listeners
if(!cancelled){
fire("error", {error:error}, deferred);
if(!connections.length){
socket.readyState = 3;
fire("close", {wasClean:false}, deferred);
}
}
});
return deferred;
},
close: function(){
// summary:
// Close the connection
socket.readyState = 2;
cancelled = true;
var i;
for(i = 0; i < connections.length; i++){
connections[i].cancel();
}
socket.readyState = 3;
fire("close", {wasClean:true});
},
transport: args.transport || xhr.post,
args: args,
url: args.url,
readyState: 0,
CONNECTING: 0,
OPEN: 1,
CLOSING: 2,
CLOSED: 3,
on: Evented.prototype.on,
firstRequest: function(args){
// summary:
// This allows for special handling for the first request. This is useful for
// providing information to disambiguate between the first request and
// subsequent long-poll requests so the server can properly setup a
// connection on the first connection or reject a request for an expired
// connection if the request is not expecting to be the first for a connection.
// This method can be overriden. The default behavior is to include a Pragma
// header with a value of "start-long-poll"
var headers = (args.headers || (args.headers = {}));
headers.Pragma = "start-long-poll";
try{
return this.transport(args);
}finally{
// cleanup the header so it is not used on subsequent requests
delete headers.Pragma;
}
}
};
fire = function(type, object, deferred){
if(socket["on" + type]){
object.ioArgs = deferred && deferred.ioArgs;
object.type = type;
on.emit(socket, type, object);
}
};
connect = function(){
if(socket.readyState == 0){
// we fire the open event now because we really don't know when the "socket"
// is truly open, and this gives us a to do a send() and get it included in the
// HTTP request
fire("open",{});
}
// make the long-poll connection, to wait for response from the server
if(!connections.length){
socket.send();
}
};
// provide an alias for Dojo's connect method
socket.connect = socket.on;
// do the initial connection
setTimeout(connect);
return socket;
};
if(_14){
_15("open");
}
_1.forEach(["message","close","error"],_15);
};
_8.LongPoll=function(_18){
var _19=false,_1a=true,_1b,_1c=[];
var _1d,_1e;
var _1f={send:function(_20){
var _21=_2.delegate(_18);
_21.rawBody=_20;
clearTimeout(_1b);
var _22=_1a?(_1a=false)||_1f.firstRequest(_21):_1f.transport(_21);
_1c.push(_22);
_22.then(function(_23){
_1f.readyState=1;
_1c.splice(_1.indexOf(_1c,_22),1);
if(!_1c.length){
_1b=setTimeout(_1e,_18.interval);
}
if(_23){
_1d("message",{data:_23},_22);
}
},function(_24){
_1c.splice(_1.indexOf(_1c,_22),1);
if(!_19){
_1d("error",{error:_24},_22);
if(!_1c.length){
_1f.readyState=3;
_1d("close",{wasClean:false},_22);
}
}
});
return _22;
},close:function(){
_1f.readyState=2;
_19=true;
var i;
for(i=0;i<_1c.length;i++){
_1c[i].cancel();
}
_1f.readyState=3;
_1d("close",{wasClean:true});
},transport:_18.transport||_3.post,args:_18,url:_18.url,readyState:0,CONNECTING:0,OPEN:1,CLOSING:2,CLOSED:3,on:_5.prototype.on,firstRequest:function(_25){
var _26=(_25.headers||(_25.headers={}));
_26.Pragma="start-long-poll";
try{
return this.transport(_25);
}
finally{
delete _26.Pragma;
}
}};
_1d=function(_27,_28,_29){
if(_1f["on"+_27]){
_28.ioArgs=_29&&_29.ioArgs;
_28.type=_27;
on.emit(_1f,_27,_28);
}
};
_1e=function(){
if(_1f.readyState==0){
_1d("open",{});
}
if(!_1c.length){
_1f.send();
}
};
_1f.connect=_1f.on;
setTimeout(_1e);
return _1f;
};
return _8;
return Socket;
});
@@ -9,8 +9,13 @@ define([
});
var _updateSocketOpened = false;
var _updateSocket = new Socket({
url: config.hos.deviceRepoUrl + "?onevent=statechanged",
transport: xhr.post });
url: config.hos.deviceRepoUrl,
headers: {
"On-Event": "changes",
"Connection-Timeout": 60000,
"Client-Id": 1234
},
transport: xhr.get });
_updateSocket.on("open", function(event){
_socketOpened = true;
console.log("Socket Opened ", event.message);