diff --git a/README.md b/README.md index 751d3a2..9411b3d 100644 --- a/README.md +++ b/README.md @@ -10,6 +10,8 @@ Unified Node/XPCOM/JS client-side real-time communication with underlying implem * [WebSocket](https://en.wikipedia.org/wiki/WebSocket) +**Note** `RT` is not only a simple framework around real-time layer implementations, it is also a small protocol additional to an implementation, which enables optimum performance, e.g by multiplexing multiple requests transparently (where applicable). + **Example API** @@ -48,7 +50,7 @@ var rt_chat = RT({ ' + textify( m.message ) + '\ '; }) - /*.on('open', function( ){ + /*.one('open', function( ){ alert('OPENED'); })*/ .on('close', function( ){ diff --git a/src/RT.BOSH.js b/src/RT.BOSH.js index a6b0cea..4acd90e 100644 --- a/src/RT.BOSH.js +++ b/src/RT.BOSH.js @@ -39,14 +39,14 @@ RT.Client.BOSH[PROTO].$queue$ = null; RT.Client.BOSH[PROTO].$mID$ = null; RT.Client.BOSH[PROTO].dispose = function( ){ var self = this; - if ( self.$bosh$ ) { self.$bosh$.abort( false ); self.$bosh$ = null; } + if ( self.$bosh$ ) { self.$bosh$.abort( ); self.$bosh$ = null; } self.$queue$ = null; self.$mID$ = null; return __super__.dispose.call( self ); }; RT.Client.BOSH[PROTO].abort = function( trigger ){ var self = this; - if ( self.$bosh$ ) { self.$bosh$.abort( true===trigger ); self.$bosh$ = null; } + if ( self.$bosh$ ) { self.$bosh$.abort( ); self.$bosh$ = null; } return __super__.abort.call( self, true===trigger ); }; RT.Client.BOSH[PROTO].send = function( payload ){ @@ -58,6 +58,7 @@ RT.Client.BOSH[PROTO].listen = function( ){ var self = this; var listen = function listen( ) { var headers = { + 'Connection' : 'Keep-Alive', 'Content-Type' : 'application/x-www-form-urlencoded; charset=utf8', 'X-RT--BOSH' : '1', // this uses BOSH 'X-RT--Receive' : '1', // this is the receive channel @@ -79,36 +80,46 @@ RT.Client.BOSH[PROTO].listen = function( ){ //mimeType : 'text/plain; charset=utf8', headers : headers, onError : function( xhr ) { - self.emit('error', xhr.statusText); self.$bosh$ = null; + self.emit( 'error', xhr.statusText ); }, onTimeout : function( xhr ) { + self.$bosh$ = null; setTimeout( listen, 0 ); }, onComplete : function( xhr ) { - var rt_msg = xhr.responseHeader( 'X-RT--Message' ), - rt_close = xhr.responseHeader( 'X-RT--Close' ), - rt_error = xhr.responseHeader( 'X-RT--Error' ), - rt_mID = xhr.responseHeader( 'X-RT--mID' ) + var rt_msg = xhr.getResponseHeader( 'X-RT--Message' ), + rt_close = xhr.getResponseHeader( 'X-RT--Close' ), + rt_error = xhr.getResponseHeader( 'X-RT--Error' ), + rt_mID = xhr.getResponseHeader( 'X-RT--mID' ) ; if ( rt_error ) { + self.$bosh$ = null; return self.emit( 'error', rt_error ); } if ( rt_close ) { + self.$bosh$ = null; return self.close( ); } + + if ( rt_mID ) self.$mID$ = rt_mID; + // message(s) sent + if ( msgs ) self.$queue$.splice( 0, msgs.length ); + if ( rt_msg ) { // at the same time, handle incoming message(s) - var msgs = (xhr.responseText||'').split( rt_msg ), i, l; - for(i=0,l=msgs.length; i 1 ) xhr.send( payload ); - return xhr; - } - else - { - var xhr = XHR( ), trigger_abort = true; - xhr._abort = xhr.abort; - xhr._aborted = false; - xhr.abort = function( and_trigger ){ - if ( xhr._aborted ) return; - if ( false === and_trigger ) trigger_abort = false; - try{ xhr._abort( ); }catch(e){ } - xhr._aborted = true; - trigger_abort = true; - }; - xhr.__headers__ = null; - xhr.responseHeader = function( key ) { - if ( (null == key) || (4/*DONE*/ !== xhr.readyState) ) return null; - return xhr.getResponseHeader( key ); - /*var headers = xhr.getAllResponseHeaders( ) || ''; - if ( null == xhr.__headers__ ) xhr.__headers__ = RT.Util.Header.decode( headers ); - return xhr.__headers__[HAS](key) ? xhr.__headers__[key] : null;*/ - }; - xhr.responseHeaders = function( decoded ) { - if ( 4/*DONE*/ !== xhr.readyState ) return null; - var headers = xhr.getAllResponseHeaders( ) || ''; - if ( null == xhr.__headers__ ) xhr.__headers__ = RT.Util.Header.decode( headers ); - return true===decoded ? xhr.__headers__ : headers; - }; - if ( !o.url ) return xhr; - xhr.open( o.method||'GET', o.url, !o.sync ); - xhr.responseType = o.responseType || 'text'; - if ( o.headers ) RT.Util.Header.encode( o.headers, xhr ); - if ( o.mimeType ) xhr.overrideMimeType( o.mimeType ); - //xhr.setRequestHeader('Content-Type', 'text/plain; charset=utf8'); - //xhr.overrideMimeType('text/plain; charset=utf8'); - xhr.timeout = o.timeout || 30000; // 30 secs default timeout - if ( o.onProgress ) - { - xhr.onprogress = function( ) { - o.onProgress( xhr ); - }; - } - if ( o.onLoadStart ) - { - xhr.onloadstart = function( ) { - o.onLoadStart( xhr ); - }; + if ( !o.url ) return null; + var url = '[object Object]' === toString.call(o.url) ? o.url : require('url').parse( o.url ), + $hr$, xhr, + options = { + method : o.method || 'GET', + agent : false, + protocol : url.protocol, + host : url.hostname, + hostname : url.hostname, + port : url.port || 80, + path : (url.pathname||'/')+(url.query?('?'+url.query):'') } - if ( o.onLoadEnd ) + ; + + xhr = new RT.XHR( + function( payload ) { + if ( null != payload ) { - xhr.onloadend = function( ) { - o.onLoadEnd( xhr ); - }; + payload = String( payload ); + $hr$.setHeader( 'Content-Length', payload.length.toString() ); + $hr$.write( payload ); } - if ( !o.sync && o.onStateChange ) - { - xhr.onreadystatechange = function( ) { - o.onStateChange( xhr ); - }; - } - xhr.onload = function( ) { - if ( (4/*DONE*/ === xhr.readyState) ) + $hr$.end( ); + }, + function( ) { + $hr$.abort( ); + }); + + $hr$ = ('https:'===options.protocol?require('https').request:require('http').request)(options, function( response ) { + var xdata = '', data_sent = 0; + + xhr.readyState = RT.XHR.OPENED; + if ( o.onStateChange ) o.onStateChange( xhr ); + + xhr.readyState = RT.XHR.HEADERS_RECEIVED; + xhr._rawHeaders = response.rawHeaders.join("\r\n"); + xhr._headers = response.headers; + xhr.responseURL = response.url || null; + xhr.status = response.statusCode || null; + xhr.statusText = response.statusMessage || null; + if ( o.onStateChange ) o.onStateChange( xhr ); + + response.on('data', function( chunk ){ + xdata += chunk.toString( ); + if ( !data_sent ) + { + data_sent = 1; + xhr.readyState = RT.XHR.LOADING; + if ( o.onStateChange ) o.onStateChange( xhr ); + if ( o.onLoadStart ) o.onLoadStart( xhr ); + } + if ( o.onProgress ) o.onProgress( xhr ); + }); + + response.on('end', function( ){ + xhr.readyState = RT.XHR.DONE; + xhr.responseType = 'text'; + xhr.response = xhr.responseText = xdata; + + if ( o.onStateChange ) o.onStateChange( xhr ); + if ( o.onLoadEnd ) o.onLoadEnd( xhr ); + + if ( (RT.XHR.DONE === xhr.readyState) ) { if ( 200 === xhr.status ) { @@ -239,21 +171,125 @@ RT.XHR = { else if ( o.onError ) o.onError( xhr ); } } + }); + + response.on('error', function( ee ){ + xhr.statusText = ee.toString( ); + if ( o.onError ) o.onError( xhr ); + }); + }); + + $hr$.setTimeout(o.timeout || 30000, function( e ){ + if ( o.onTimeout ) o.onTimeout( xhr ); + }); + $hr$.on('abort', function( ee ){ + if ( o.onAbort ) o.onAbort( xhr ); + }); + $hr$.on('error', function( ee ){ + xhr.statusText = ee.toString( ); + if ( o.onError ) o.onError( xhr ); + }); + + if ( o.headers ) RT.Util.Header.encode( o.headers, null, $hr$ ); + //if ( o.mimeType ) $hr$.overrideMimeType( o.mimeType ); + if ( arguments.length > 1 ) xhr.send( payload ); + return xhr; + } + : function( o, payload ) { + o = o || {}; + if ( !o.url ) return null; + var $xhr$ = window.XMLHttpRequest + ? new XMLHttpRequest( ) + : new ActiveXObject( 'Microsoft.XMLHTTP' ) /* or ActiveXObject( 'Msxml2.XMLHTTP' ); ??*/, + + xhr = new RT.XHR( + function( payload ){ + $xhr$.send( payload ); + }, + function( ){ + $xhr$.abort( ); + }), + + update = function( xhr, $xhr$ ) { + xhr.readyState = $xhr$.readyState; + xhr.responseType = $xhr$.responseType; + xhr.responseURL = $xhr$.responseURL; + xhr.response = $xhr$.response; + xhr.responseText = $xhr$.responseText; + xhr.responseXml = $xhr$.responseXml; + xhr.status = $xhr$.status; + xhr.statusText = $xhr$.statusText; + return xhr; + } + ; + xhr.getAllResponseHeaders = function( decoded ){ + var headers = $xhr$.getAllResponseHeaders( ); + return true===decoded ? RT.Util.Header.decode( headers ) : headers; + }; + xhr.getResponseHeader = function( key ){ + return $xhr$.getResponseHeader( key ); + }; + + $xhr$.open( o.method||'GET', o.url, !o.sync ); + xhr.responseType = $xhr$.responseType = o.responseType || 'text'; + $xhr$.timeout = o.timeout || 30000; // 30 secs default timeout + + if ( o.onProgress ) + { + $xhr$.onprogress = function( ) { + update( xhr, $xhr$ ); + o.onProgress( xhr ); }; - xhr.onabort = function( ) { - if ( trigger_abort && o.onAbort ) o.onAbort( xhr ); + } + if ( o.onLoadStart ) + { + $xhr$.onloadstart = function( ) { + o.onLoadStart( update( xhr, $xhr$ ) ); }; - xhr.onerror = function( ) { - if ( o.onError ) o.onError( xhr ); + } + if ( o.onLoadEnd ) + { + $xhr$.onloadend = function( ) { + o.onLoadEnd( update( xhr, $xhr$ ) ); }; - xhr.ontimeout = function( ) { - if ( o.onTimeout ) o.onTimeout( xhr ); + } + if ( !o.sync && o.onStateChange ) + { + $xhr$.onreadystatechange = function( ) { + o.onStateChange( update( xhr, $xhr$ ) ); }; - if ( arguments.length > 1 ) xhr.send( payload ); - return xhr; } + $xhr$.onload = function( ) { + update( xhr, $xhr$ ); + if ( (RT.XHR.DONE === $xhr$.readyState) ) + { + if ( 200 === $xhr$.status ) + { + if ( o.onComplete ) o.onComplete( xhr ); + } + else + { + if ( o.onRequestError ) o.onRequestError( xhr ); + else if ( o.onError ) o.onError( xhr ); + } + } + }; + $xhr$.onabort = function( ) { + if ( o.onAbort ) o.onAbort( update( xhr, $xhr$ ) ); + }; + $xhr$.onerror = function( ) { + if ( o.onError ) o.onError( update( xhr, $xhr$ ) ); + }; + $xhr$.ontimeout = function( ) { + if ( o.onTimeout ) o.onTimeout( update( xhr, $xhr$ ) ); + }; + + if ( o.headers ) RT.Util.Header.encode( o.headers, $xhr$ ); + if ( o.mimeType ) $xhr$.overrideMimeType( o.mimeType ); + if ( arguments.length > 1 ) xhr.send( payload ); + return xhr; } -}; +; RT.UUID = function( PREFIX, SUFFIX ) { return (PREFIX||'') + (++UUID) + '_' + (Date.now()) + '_' + Math.floor((1000*Math.random())) + (SUFFIX||''); diff --git a/src/RT.min..js b/src/RT.min..js index 9e5bcbc..9674aad 100644 --- a/src/RT.min..js +++ b/src/RT.min..js @@ -6,4 +6,4 @@ * https://github.com/foo123/RT * **/ -!function(e,t,n){"use strict";"object"==typeof exports?module.exports=n():(e[t]=n())&&"function"==typeof define&&define.amd&&define(function(){return e[t]})}(this,"RT",function(){"use strict";function e(t){t=t||{};var r=(t.use||t.rt_type||"default").toLowerCase();return e.Client.Impl[n](r)?new e.Client.Impl[r](t):new e.Client(t)}var t="prototype",n="hasOwnProperty",r=Object.keys,o=Object[t].toString,i="undefined"!=typeof global&&"[object global]"===o.call(global),a=String.fromCharCode,s=/^\s+|\s+$/g,u=String[t].trim?function(e){return e.trim()}:function(e){return e.replace(s,"")},l=/[^A-Za-z0-9\+\/\=]/g,c=/\x0d\x0a/g,d=i?null:window.XMLHttpRequest?function(){return new XMLHttpRequest}:function(){return new ActiveXObject("Microsoft.XMLHTTP")},f=0;return e.VERSION="1.0.0",e.Platform={Node:i},e.XHR={create:function(t,r){if(t=t||{},i){if(!t.url)return null;var a="[object Object]"===o.call(t.url)?t.url:require("url").parse(t.url),s={method:t.method||"GET",agent:!1,protocol:a.protocol,host:a.hostname,hostname:a.hostname,port:a.port||80,path:(a.pathname||"/")+(a.query?"?"+a.query:"")},u="https:"===s.protocol?require("https").request:require("http").request,l={readyState:0,status:null,statusText:null,responseType:t.responseType||"text",responseURL:null,response:null,responseText:null,responseXml:null,headers:null,__headers__:null,send:function(e){null!=e&&(e=String(e),c.setHeader("Content-Length",e.length.toString()),c.write(e)),c.end()},abort:function(){c.abort()},getAllResponseHeaders:function(){return l.headers},getResponseHeader:function(e){if(null==e||4!==l.readyState)return null;var t=l.__headers__||{};return t[n](e)?t[e]:null},responseHeader:function(e){return l.getResponseHeader(e)},responseHeaders:function(e){return 4!==l.readyState?null:!0===e?l.__headers__:l.headers}},c=u(s,function(e){var n="",r=0;l.readyState=1,t.onStateChange&&t.onStateChange(l),l.headers=e.rawHeaders.join("\r\n"),l.__headers__=e.headers,l.responseURL=e.url||null,l.readyState=2,l.status=e.statusCode||null,l.statusText=e.statusMessage||null,t.onStateChange&&t.onStateChange(l),e.on("data",function(e){n+=e.toString(),r||(r=1,l.readyState=3,t.onStateChange&&t.onStateChange(l),t.onLoadStart&&t.onLoadStart(l)),t.onProgress&&t.onProgress(l)}),e.on("end",function(){l.readyState=4,l.responseType="text",l.response=l.responseText=n,t.onStateChange&&t.onStateChange(l),t.onLoadEnd&&t.onLoadEnd(l),4===l.readyState&&(200===l.status?t.onComplete&&t.onComplete(l):t.onRequestError?t.onRequestError(l):t.onError&&t.onError(l))}),e.on("error",function(e){l.statusText=e.toString(),t.onError&&t.onError(l)})});return c.setTimeout(t.timeout||3e4,function(e){t.onTimeout&&t.onTimeout(l)}),c.on("abort",function(e){t.onAbort&&t.onAbort(l)}),c.on("error",function(e){l.statusText=e.toString(),t.onError&&t.onError(l)}),t.headers&&e.Util.Header.encode(t.headers,null,c),c.setHeader("Connection","Keep-Alive"),arguments.length>1&&l.send(r),l}var l=d(),f=!0;return l._abort=l.abort,l._aborted=!1,l.abort=function(e){if(!l._aborted){!1===e&&(f=!1);try{l._abort()}catch(t){}l._aborted=!0,f=!0}},l.__headers__=null,l.responseHeader=function(e){return null==e||4!==l.readyState?null:l.getResponseHeader(e)},l.responseHeaders=function(t){if(4!==l.readyState)return null;var n=l.getAllResponseHeaders()||"";return null==l.__headers__&&(l.__headers__=e.Util.Header.decode(n)),!0===t?l.__headers__:n},t.url?(l.open(t.method||"GET",t.url,!t.sync),l.responseType=t.responseType||"text",t.headers&&e.Util.Header.encode(t.headers,l),t.mimeType&&l.overrideMimeType(t.mimeType),l.timeout=t.timeout||3e4,t.onProgress&&(l.onprogress=function(){t.onProgress(l)}),t.onLoadStart&&(l.onloadstart=function(){t.onLoadStart(l)}),t.onLoadEnd&&(l.onloadend=function(){t.onLoadEnd(l)}),!t.sync&&t.onStateChange&&(l.onreadystatechange=function(){t.onStateChange(l)}),l.onload=function(){4===l.readyState&&(200===l.status?t.onComplete&&t.onComplete(l):t.onRequestError?t.onRequestError(l):t.onError&&t.onError(l))},l.onabort=function(){f&&t.onAbort&&t.onAbort(l)},l.onerror=function(){t.onError&&t.onError(l)},l.ontimeout=function(){t.onTimeout&&t.onTimeout(l)},arguments.length>1&&l.send(r),l):l}},e.UUID=function(e,t){return(e||"")+ ++f+"_"+Date.now()+"_"+Math.floor(1e3*Math.random())+(t||"")},e.Const={BASE64:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",CRLF:"\r\n",CRLF_RE:/(\r\n)|\r|\n/g,COOKIE_RE:/([^=]+)(?:=(.*))?/},e.Util={String:{trim:u},Utf8:{encode:function(e){e=e.replace(c,"\n");var t,n,r,o="";for(t=0,n=e.length;n>t;t++)r=e.charCodeAt(t),o+=128>r?a(r):r>127&&2048>r?a(r>>6|192)+a(63&r|128):a(r>>12|224)+a(r>>6&63|128)+a(63&r|128);return o},decode:function(e){for(var t="",n=0,r=c1=c2=0,o=e.length;o>n;)r=e.charCodeAt(n),128>r?(t+=a(r),n++):r>191&&224>r?(c2=e.charCodeAt(n+1),t+=a((31&r)<<6|63&c2),n+=2):(c2=e.charCodeAt(n+1),c3=e.charCodeAt(n+2),t+=a((15&r)<<12|(63&c2)<<6|63&c3),n+=3);return t}},Base64:{encode:function(t){t=e.Util.Utf8.encode(t);for(var n,r,o,i,a,s,u,l="",c=0,d=t.length,f=e.Const.BASE64;d>c;)n=t.charCodeAt(c++),r=t.charCodeAt(c++),o=t.charCodeAt(c++),i=n>>2,a=(3&n)<<4|r>>4,s=(15&r)<<2|o>>6,u=63&o,isNaN(r)?s=u=64:isNaN(o)&&(u=64),l=l+f.charAt(i)+f.charAt(a)+f.charAt(s)+f.charAt(u);return l},decode:function(t){t=t.replace(l,"");for(var n,r,o,i,s,u,c,d="",f=0,h=t.length;h>f;)i=keyString.indexOf(t.charAt(f++)),s=keyString.indexOf(t.charAt(f++)),u=keyString.indexOf(t.charAt(f++)),c=keyString.indexOf(t.charAt(f++)),n=i<<2|s>>4,r=(15&s)<<4|u>>2,o=(3&u)<<6|c,d+=a(n),64!=u&&(d+=a(r)),64!=c&&(d+=a(o));return d=e.Util.Utf8.decode(d)}},Json:{encode:JSON.stringify,decode:JSON.parse},Url:{create:function(t){if(!t)return"";var n,i,a,s,u,l,c,d,f,h=[],p=r(t),g=p.length,C=e.Util.Url.encode;for(s=0,n=g>s?[[i=p[s++],t[i]]]:[];n.length;){if(u=n.shift(),i=u[0],a=u[1],f=o.call(a),"[object Array]"===f)for(i+="[]",l=0,c=a.length;c>l;l++)n.unshift([i,a[l]]);else if("[object Object]"===f)for(d=r(a),l=0,c=d.length;c>l;l++)n.unshift([i+"["+d[l]+"]",a[d[l]]]);else h.push(C(i)+"="+C(a));!n.length&&g>s&&n.unshift([i=p[s++],t[i]])}return h.join("&")},rawencode:function(e){return encodeURIComponent(""+e).split("!").join("%21").split("'").join("%27").split("(").join("%28").split(")").join("%29").split("*").join("%2A")},rawdecode:function(e){return decodeURIComponent(""+e)},encode:function(t){return e.Util.Url.rawencode(t).split("%20").join("+")},decode:function(t){return e.Util.Url.rawdecode((""+t).split("+").join("%20"))}},Cookie:{create:function(e,t,n,r,o,i,a){var s=arguments.length;return{name:s>0?e:"",value:s>1?t:"",domain:s>2?n:"",path:s>3?r:"/",expires:s>4?o:new Date(Date.now()+31536e6),secure:s>5?!!i:!1,httponly:s>6?!!a:!1}},encode:function(e){if(e&&e.name){var t=String(e.name)+"="+String(e.value);return t+="; Domain="+String(e.domain),t+="; Path="+String(e.path),t+="; Expires="+String(e.expires),e.secure&&(t+="; Secure"),e.httponly&&(t+="; HttpOnly"),t}},decode:function(t){var r,o,i,a,s=e.Util.Cookie.create(),u=e.Const.COOKIE_RE,l=String(t).split("; ");if(null!=(r=l.shift().match(u))){for(s.name=r[1],s.value=r[2],i=0,a=l.length;a>i;i++)r=l[i].match(u),null!=r&&r.length&&(o=r[1].toLowerCase(),s[n](o)&&(s[o]="string"==typeof r[2]?r[2]:!0));return"string"==typeof s.expires&&(s.expires=new Date(s.expires)),s}}},Header:{encode:function(t,n,i){var a="";if(!t)return xhr?xhr:a;var s,u,l,c,d,f=r(t),h=e.Const.CRLF;if(i){for(u=0,l=f.length;l>u;u++)s=f[u],i.setHeader(s,t[s]);return i}if(n){for(u=0,l=f.length;l>u;u++)if(s=f[u],"[object Array]"===o.call(t[s]))for(c=0,d=t[s].length;d>c;c++)n.setRequestHeader(s,t[s][c]);else n.setRequestHeader(s,t[s]);return n}for(u=0,l=f.length;l>u;u++)if(s=f[u],"[object Array]"===o.call(t[s]))for(c=0,d=t[s].length;d>c;c++)a+=h+String(t[s][c]);else a.length&&(a+=h),a+=s+": "+String(t[s]);return a},decode:function(t,r){var o,i,a,s,l={},c=null,d=e.Const.CRLF;if(t)for(r=!0===r,t=t.split(d),i=0,a=t.length;a>i;i++)s=t[i],o=s.split(":"),o.length>1?(c=u(o.shift()),r&&(c=c.toLowerCase()),l[n](c)?("string"==typeof l[c]&&(l[c]=[l[c]]),l[c].push(u(o.join(":")))):l[c]=u(o.join(":"))):o[0].length&&c&&(l[c]=d+o[0]);return l}}},e.Client=function h(t){var n=this;return n instanceof h?(n.$cfg$=t||{},n.$event$={},void(n.status=e.Client.CREATED)):new h(t)},e.Client.Impl={},e.Client.CREATED=1,e.Client.DESTROYED=0,e.Client.OPENED=2,e.Client.CLOSED=4,e.Client.PENDING=8,e.Client.ABORTED=16,e.Client[t]={constructor:e.Client,status:e.Client.CREATED,$cfg$:null,$event$:null,dispose:function(){var t=this;return t.status=e.Client.DESTROYED,t.$cfg$=null,t.$event$=null,t},config:function(e,t){var n=this,r=n.$cfg$;return e?arguments.length>1?(r[e]=t,n):r[e]:void 0},on:function(e,t,r){var o=this;return e&&t?(o.$event$[n](e)?o.$event$[e].push([t,!0===r,0]):o.$event$[e]=[[t,!0===r,0]],o):o},one:function(e,t){return this.on(e,t,!0)},off:function(e,t){var r=this;if(!e||!r.$event$[n](e))return r;if(null==t)delete r.$event$[e];else{for(var o=r.$event$[e],i=o.length-1;i>=0;i--)o[i][0]===t&&t.splice(i,1);o.length||delete r.$event$[e]}return r},emit:function(e,t){var r=this;if(!e||!r.$event$[n](e))return r;var o,i,a=r.$event$[e].slice(),s=a.length,u=[],l={event:e,data:t,target:r};for(o=0;s>o;o++)i=a[o],i[1]&&u.push(o),i[1]&&i[2]||(i[2]=1,i[0](l));for(a=r.$event$[e],o=u.length-1;o>=0;o--)a.splice(u[o],1);return a.length||delete r.$event$[e],r},abort:function(t,n){return this.status=e.Client.ABORTED,!0===t?this.emit("abort",n):this},open:function(t){return this.status=e.Client.OPENED,this.emit("open",t)},close:function(t){return this.status=e.Client.CLOSED,this.emit("close",t)},send:function(e){return this},listen:function(){return this},init:function(){var e=this;return setTimeout(function(){e.listen()},40),e}},e.Client[t].addEventListener=e.Client[t].on,e.Client[t].removeEventListener=e.Client[t].off,e.Client[t].trigger=e.Client[t].dispatchEvent=e.Client[t].emit,e}); \ No newline at end of file +!function(e,t,n){"use strict";"object"==typeof exports?module.exports=n():(e[t]=n())&&"function"==typeof define&&define.amd&&define(function(){return e[t]})}(this,"RT",function(){"use strict";function e(t){t=t||{};var r=(t.use||t.rt_type||"default").toLowerCase();return e.Client.Impl[n](r)?new e.Client.Impl[r](t):new e.Client(t)}var t="prototype",n="hasOwnProperty",r=Object.keys,o=Object[t].toString,s="undefined"!=typeof global&&"[object global]"===o.call(global),i=String.fromCharCode,a=/^\s+|\s+$/g,u=String[t].trim?function(e){return e.trim()}:function(e){return e.replace(a,"")},l=/[^A-Za-z0-9\+\/\=]/g,c=/\x0d\x0a/g,d=0;return e.VERSION="1.0.0",e.Platform={Node:s},e.XHR=function f(e,t){var r=this,o=!1;r.readyState=f.UNSENT,r.status=null,r.statusText=null,r.responseType="text",r.responseURL=null,r.response=null,r.responseText=null,r.responseXml=null,r._rawHeaders=null,r._headers=null,r.send=function(t){return o||f.UNSENT!==r.readyState?r:(e&&e(t),r.readyState=f.OPENED,r)},r.abort=function(){return o?void 0:(o=!0,t&&t(),r)},r.getAllResponseHeaders=function(e){return f.DONE!==r.readyState?null:!0===e?r._headers:r._rawHeaders},r.getResponseHeader=function(e){if(null==e||f.DONE!==r.readyState)return null;var t=r._headers||{};return t[n](e)?t[e]:null},r.dispose=function(){return r.readyState=null,r.status=null,r.statusText=null,r.responseType=null,r.responseURL=null,r.response=null,r.responseText=null,r.responseXml=null,r._rawHeaders=null,r._headers=null,r}},e.XHR.UNSENT=0,e.XHR.OPENED=1,e.XHR.HEADERS_RECEIVED=2,e.XHR.LOADING=3,e.XHR.DONE=4,e.XHR.create=s?function(t,n){if(t=t||{},!t.url)return null;var r,s,i="[object Object]"===o.call(t.url)?t.url:require("url").parse(t.url),a={method:t.method||"GET",agent:!1,protocol:i.protocol,host:i.hostname,hostname:i.hostname,port:i.port||80,path:(i.pathname||"/")+(i.query?"?"+i.query:"")};return s=new e.XHR(function(e){null!=e&&(e=String(e),r.setHeader("Content-Length",e.length.toString()),r.write(e)),r.end()},function(){r.abort()}),r=("https:"===a.protocol?require("https").request:require("http").request)(a,function(n){var r="",o=0;s.readyState=e.XHR.OPENED,t.onStateChange&&t.onStateChange(s),s.readyState=e.XHR.HEADERS_RECEIVED,s._rawHeaders=n.rawHeaders.join("\r\n"),s._headers=n.headers,s.responseURL=n.url||null,s.status=n.statusCode||null,s.statusText=n.statusMessage||null,t.onStateChange&&t.onStateChange(s),n.on("data",function(n){r+=n.toString(),o||(o=1,s.readyState=e.XHR.LOADING,t.onStateChange&&t.onStateChange(s),t.onLoadStart&&t.onLoadStart(s)),t.onProgress&&t.onProgress(s)}),n.on("end",function(){s.readyState=e.XHR.DONE,s.responseType="text",s.response=s.responseText=r,t.onStateChange&&t.onStateChange(s),t.onLoadEnd&&t.onLoadEnd(s),e.XHR.DONE===s.readyState&&(200===s.status?t.onComplete&&t.onComplete(s):t.onRequestError?t.onRequestError(s):t.onError&&t.onError(s))}),n.on("error",function(e){s.statusText=e.toString(),t.onError&&t.onError(s)})}),r.setTimeout(t.timeout||3e4,function(e){t.onTimeout&&t.onTimeout(s)}),r.on("abort",function(e){t.onAbort&&t.onAbort(s)}),r.on("error",function(e){s.statusText=e.toString(),t.onError&&t.onError(s)}),t.headers&&e.Util.Header.encode(t.headers,null,r),arguments.length>1&&s.send(n),s}:function(t,n){if(t=t||{},!t.url)return null;var r=window.XMLHttpRequest?new XMLHttpRequest:new ActiveXObject("Microsoft.XMLHTTP"),o=new e.XHR(function(e){r.send(e)},function(){r.abort()}),s=function(e,t){return e.readyState=t.readyState,e.responseType=t.responseType,e.responseURL=t.responseURL,e.response=t.response,e.responseText=t.responseText,e.responseXml=t.responseXml,e.status=t.status,e.statusText=t.statusText,e};return o.getAllResponseHeaders=function(t){var n=r.getAllResponseHeaders();return!0===t?e.Util.Header.decode(n):n},o.getResponseHeader=function(e){return r.getResponseHeader(e)},r.open(t.method||"GET",t.url,!t.sync),o.responseType=r.responseType=t.responseType||"text",r.timeout=t.timeout||3e4,t.onProgress&&(r.onprogress=function(){s(o,r),t.onProgress(o)}),t.onLoadStart&&(r.onloadstart=function(){t.onLoadStart(s(o,r))}),t.onLoadEnd&&(r.onloadend=function(){t.onLoadEnd(s(o,r))}),!t.sync&&t.onStateChange&&(r.onreadystatechange=function(){t.onStateChange(s(o,r))}),r.onload=function(){s(o,r),e.XHR.DONE===r.readyState&&(200===r.status?t.onComplete&&t.onComplete(o):t.onRequestError?t.onRequestError(o):t.onError&&t.onError(o))},r.onabort=function(){t.onAbort&&t.onAbort(s(o,r))},r.onerror=function(){t.onError&&t.onError(s(o,r))},r.ontimeout=function(){t.onTimeout&&t.onTimeout(s(o,r))},t.headers&&e.Util.Header.encode(t.headers,r),t.mimeType&&r.overrideMimeType(t.mimeType),arguments.length>1&&o.send(n),o},e.UUID=function(e,t){return(e||"")+ ++d+"_"+Date.now()+"_"+Math.floor(1e3*Math.random())+(t||"")},e.Const={BASE64:"ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=",CRLF:"\r\n",CRLF_RE:/(\r\n)|\r|\n/g,COOKIE_RE:/([^=]+)(?:=(.*))?/},e.Util={String:{trim:u},Utf8:{encode:function(e){e=e.replace(c,"\n");var t,n,r,o="";for(t=0,n=e.length;n>t;t++)r=e.charCodeAt(t),o+=128>r?i(r):r>127&&2048>r?i(r>>6|192)+i(63&r|128):i(r>>12|224)+i(r>>6&63|128)+i(63&r|128);return o},decode:function(e){for(var t="",n=0,r=c1=c2=0,o=e.length;o>n;)r=e.charCodeAt(n),128>r?(t+=i(r),n++):r>191&&224>r?(c2=e.charCodeAt(n+1),t+=i((31&r)<<6|63&c2),n+=2):(c2=e.charCodeAt(n+1),c3=e.charCodeAt(n+2),t+=i((15&r)<<12|(63&c2)<<6|63&c3),n+=3);return t}},Base64:{encode:function(t){t=e.Util.Utf8.encode(t);for(var n,r,o,s,i,a,u,l="",c=0,d=t.length,f=e.Const.BASE64;d>c;)n=t.charCodeAt(c++),r=t.charCodeAt(c++),o=t.charCodeAt(c++),s=n>>2,i=(3&n)<<4|r>>4,a=(15&r)<<2|o>>6,u=63&o,isNaN(r)?a=u=64:isNaN(o)&&(u=64),l=l+f.charAt(s)+f.charAt(i)+f.charAt(a)+f.charAt(u);return l},decode:function(t){t=t.replace(l,"");for(var n,r,o,s,a,u,c,d="",f=0,h=t.length;h>f;)s=keyString.indexOf(t.charAt(f++)),a=keyString.indexOf(t.charAt(f++)),u=keyString.indexOf(t.charAt(f++)),c=keyString.indexOf(t.charAt(f++)),n=s<<2|a>>4,r=(15&a)<<4|u>>2,o=(3&u)<<6|c,d+=i(n),64!=u&&(d+=i(r)),64!=c&&(d+=i(o));return d=e.Util.Utf8.decode(d)}},Json:{encode:JSON.stringify,decode:JSON.parse},Url:{create:function(t){if(!t)return"";var n,s,i,a,u,l,c,d,f,h=[],p=r(t),g=p.length,C=e.Util.Url.encode;for(a=0,n=g>a?[[s=p[a++],t[s]]]:[];n.length;){if(u=n.shift(),s=u[0],i=u[1],f=o.call(i),"[object Array]"===f)for(s+="[]",l=0,c=i.length;c>l;l++)n.unshift([s,i[l]]);else if("[object Object]"===f)for(d=r(i),l=0,c=d.length;c>l;l++)n.unshift([s+"["+d[l]+"]",i[d[l]]]);else h.push(C(s)+"="+C(i));!n.length&&g>a&&n.unshift([s=p[a++],t[s]])}return h.join("&")},rawencode:function(e){return encodeURIComponent(""+e).split("!").join("%21").split("'").join("%27").split("(").join("%28").split(")").join("%29").split("*").join("%2A")},rawdecode:function(e){return decodeURIComponent(""+e)},encode:function(t){return e.Util.Url.rawencode(t).split("%20").join("+")},decode:function(t){return e.Util.Url.rawdecode((""+t).split("+").join("%20"))}},Cookie:{create:function(e,t,n,r,o,s,i){var a=arguments.length;return{name:a>0?e:"",value:a>1?t:"",domain:a>2?n:"",path:a>3?r:"/",expires:a>4?o:new Date(Date.now()+31536e6),secure:a>5?!!s:!1,httponly:a>6?!!i:!1}},encode:function(e){if(e&&e.name){var t=String(e.name)+"="+String(e.value);return t+="; Domain="+String(e.domain),t+="; Path="+String(e.path),t+="; Expires="+String(e.expires),e.secure&&(t+="; Secure"),e.httponly&&(t+="; HttpOnly"),t}},decode:function(t){var r,o,s,i,a=e.Util.Cookie.create(),u=e.Const.COOKIE_RE,l=String(t).split("; ");if(null!=(r=l.shift().match(u))){for(a.name=r[1],a.value=r[2],s=0,i=l.length;i>s;s++)r=l[s].match(u),null!=r&&r.length&&(o=r[1].toLowerCase(),a[n](o)&&(a[o]="string"==typeof r[2]?r[2]:!0));return"string"==typeof a.expires&&(a.expires=new Date(a.expires)),a}}},Header:{encode:function(t,n,s){var i="";if(!t)return xhr?xhr:i;var a,u,l,c,d,f=r(t),h=e.Const.CRLF;if(s){for(u=0,l=f.length;l>u;u++)a=f[u],s.setHeader(a,t[a]);return s}if(n){for(u=0,l=f.length;l>u;u++)if(a=f[u],"[object Array]"===o.call(t[a]))for(c=0,d=t[a].length;d>c;c++)n.setRequestHeader(a,t[a][c]);else n.setRequestHeader(a,t[a]);return n}for(u=0,l=f.length;l>u;u++)if(a=f[u],"[object Array]"===o.call(t[a]))for(c=0,d=t[a].length;d>c;c++)i+=h+String(t[a][c]);else i.length&&(i+=h),i+=a+": "+String(t[a]);return i},decode:function(t,r){var o,s,i,a,l={},c=null,d=e.Const.CRLF;if(t)for(r=!0===r,t=t.split(d),s=0,i=t.length;i>s;s++)a=t[s],o=a.split(":"),o.length>1?(c=u(o.shift()),r&&(c=c.toLowerCase()),l[n](c)?("string"==typeof l[c]&&(l[c]=[l[c]]),l[c].push(u(o.join(":")))):l[c]=u(o.join(":"))):o[0].length&&c&&(l[c]=d+o[0]);return l}}},e.Client=function h(t){var n=this;return n instanceof h?(n.$cfg$=t||{},n.$event$={},void(n.status=e.Client.CREATED)):new h(t)},e.Client.Impl={},e.Client.CREATED=1,e.Client.DESTROYED=0,e.Client.OPENED=2,e.Client.CLOSED=4,e.Client.PENDING=8,e.Client.ABORTED=16,e.Client[t]={constructor:e.Client,status:e.Client.CREATED,$cfg$:null,$event$:null,dispose:function(){var t=this;return t.status=e.Client.DESTROYED,t.$cfg$=null,t.$event$=null,t},config:function(e,t){var n=this,r=n.$cfg$;return e?arguments.length>1?(r[e]=t,n):r[e]:void 0},on:function(e,t,r){var o=this;return e&&t?(o.$event$[n](e)?o.$event$[e].push([t,!0===r,0]):o.$event$[e]=[[t,!0===r,0]],o):o},one:function(e,t){return this.on(e,t,!0)},off:function(e,t){var r=this;if(!e||!r.$event$[n](e))return r;if(null==t)delete r.$event$[e];else{for(var o=r.$event$[e],s=o.length-1;s>=0;s--)o[s][0]===t&&t.splice(s,1);o.length||delete r.$event$[e]}return r},emit:function(e,t){var r=this;if(!e||!r.$event$[n](e))return r;var o,s,i=r.$event$[e].slice(),a=i.length,u=[],l={event:e,data:t,target:r};for(o=0;a>o;o++)s=i[o],s[1]&&u.push(o),s[1]&&s[2]||(s[2]=1,s[0](l));for(i=r.$event$[e],o=u.length-1;o>=0;o--)i.splice(u[o],1);return i.length||delete r.$event$[e],r},abort:function(t,n){return this.status=e.Client.ABORTED,!0===t?this.emit("abort",n):this},open:function(t){return this.status=e.Client.OPENED,this.emit("open",t)},close:function(t){return this.status=e.Client.CLOSED,this.emit("close",t)},send:function(e){return this},listen:function(){return this},init:function(){var e=this;return setTimeout(function(){e.listen()},40),e}},e.Client[t].addEventListener=e.Client[t].on,e.Client[t].removeEventListener=e.Client[t].off,e.Client[t].trigger=e.Client[t].dispatchEvent=e.Client[t].emit,e}); \ No newline at end of file