beamzer-client
Version:
This wrapper script makes use of the JS polyfill for Server Sent Events OR Server Push
22 lines (20 loc) • 15.6 kB
JavaScript
/*!
* Example:
*
* var beam = new BeamzerClient({
* source:"https://app.beamzer.co/hub",
* params:{
* topic:"https://ww.example.com/job/status"
* },
options:{ interval: 4500, crossdomain: true }
* });
*
* beam.start(function onOpen(e){ }, function onError(e){ }, function onMessage(e){ });
* beam.on("update", function(e){ });
* beam.on("noupdate", function(e){ });
* beam.newClient({source:"https://app.beamzer.co/hub",params:{},options:{}});
* beam.off("update");
* beam.stop(function(e){ });
*
*/
!function(e){if(!e.EventSource||e._eventSourceImportPrefix){function t(e,t){if(!e||"string"!=typeof e)throw new SyntaxError("Not enough arguments");this.URL=e,this.setOptions(t);var n=this;setTimeout(function(){n.poll()},0)}var n=(e._eventSourceImportPrefix||"")+"EventSource";if(t.prototype={CONNECTING:0,OPEN:1,CLOSED:2,defaultOptions:{loggingEnabled:!1,loggingPrefix:"eventsource",interval:500,bufferSizeLimit:262144,silentTimeout:3e5,getArgs:{evs_buffer_size_limit:262144},xhrHeaders:{Accept:"text/event-stream","Cache-Control":"no-cache",Connection:"keep-alive","X-Requested-With":"XMLHttpRequest"}},setOptions:function(e){var t,n=this.defaultOptions;for(t in n)n.hasOwnProperty(t)&&(this[t]=n[t]);for(t in e)t in n&&e.hasOwnProperty(t)&&(this[t]=e[t]);this.getArgs&&this.bufferSizeLimit&&(this.getArgs.evs_buffer_size_limit=this.bufferSizeLimit),"undefined"!=typeof console&&void 0!==console.log||(this.loggingEnabled=!1)},log:function(e){this.loggingEnabled&&console.log("["+this.loggingPrefix+"]:"+e)},poll:function(){try{if(this.readyState==this.CLOSED)return;this.cleanup(),this.readyState=this.CONNECTING,this.cursor=0,this.cache="",this._xhr=new this.XHR(this),this.resetNoActivityTimer()}catch(e){this.log("There were errors inside the pool try-catch"),this.dispatchEvent("error",{type:"error",data:e.message})}},pollAgain:function(e){var t=this;t.readyState=t.CONNECTING,t.dispatchEvent("error",{type:"error",data:"Reconnecting "}),this._pollTimer=setTimeout(function(){t.poll()},e||0)},cleanup:function(){this.log("evs cleaning up"),this._pollTimer&&(clearInterval(this._pollTimer),this._pollTimer=null),this._noActivityTimer&&(clearInterval(this._noActivityTimer),this._noActivityTimer=null),this._xhr&&(this._xhr.abort(),this._xhr=null)},resetNoActivityTimer:function(){if(this.silentTimeout){this._noActivityTimer&&clearInterval(this._noActivityTimer);var e=this;this._noActivityTimer=setTimeout(function(){e.log("Timeout! silentTImeout:"+e.silentTimeout),e.pollAgain()},this.silentTimeout)}},close:function(){this.readyState=this.CLOSED,this.log("Closing connection. readyState: "+this.readyState),this.cleanup()},_onxhrdata:function(){var e=this._xhr;if(e.isReady()&&!e.hasError()){this.resetNoActivityTimer(),this.readyState==this.CONNECTING&&(this.readyState=this.OPEN,this.dispatchEvent("open",{type:"open"}));var t=e.getBuffer();t.length>this.bufferSizeLimit&&(this.log("buffer.length > this.bufferSizeLimit"),this.pollAgain()),0==this.cursor&&0<t.length&&"\ufeff"==t.substring(0,1)&&(this.cursor=1);var n=this.lastMessageIndex(t);if(n[0]>=this.cursor){var r=n[1],i=t.substring(this.cursor,r);this.parseStream(i),this.cursor=r}e.isDone()&&(this.log("request.isDone(). reopening the connection"),this.pollAgain(this.interval))}else this.readyState!==this.CLOSED&&(this.log("this.readyState !== this.CLOSED"),this.pollAgain(this.interval))},parseStream:function(e){var t,n,r,i,o,s,a=(e=this.cache+this.normalizeToLF(e)).split("\n\n");for(t=0;t<a.length-1;t++){for(r="message",i=[],parts=a[t].split("\n"),n=0;n<parts.length;n++)0==(o=this.trimWhiteSpace(parts[n])).indexOf("event")?r=o.replace(/event:?\s*/,""):0==o.indexOf("retry")?(s=parseInt(o.replace(/retry:?\s*/,"")),isNaN(s)||(this.interval=s)):0==o.indexOf("data")?i.push(o.replace(/data:?\s*/,"")):0==o.indexOf("id:")?this.lastEventId=o.replace(/id:?\s*/,""):0==o.indexOf("id")&&(this.lastEventId=null);if(i.length){var l=new u(r,i.join("\n"),window.location.origin,this.lastEventId);this.dispatchEvent(r,l)}}this.cache=a[a.length-1]},dispatchEvent:function(e,t){var n=this["_"+e+"Handlers"];if(n)for(var r=0;r<n.length;r++)n[r].call(this,t);this["on"+e]&&this["on"+e].call(this,t)},addEventListener:function(e,t){this["_"+e+"Handlers"]||(this["_"+e+"Handlers"]=[]),this["_"+e+"Handlers"].push(t)},removeEventListener:function(e,t){var n=this["_"+e+"Handlers"];if(n)for(var r=n.length-1;0<=r;--r)if(n[r]===t){n.splice(r,1);break}},_pollTimer:null,_noactivityTimer:null,_xhr:null,lastEventId:null,cache:"",cursor:0,onerror:null,onmessage:null,onopen:null,readyState:0,urlWithParams:function(e,t){var n=[];if(t){var r,i,o=encodeURIComponent;for(r in t)t.hasOwnProperty(r)&&(i=o(r)+"="+o(t[r]),n.push(i))}return 0<n.length?-1==e.indexOf("?")?e+"?"+n.join("&"):e+"&"+n.join("&"):e},lastMessageIndex:function(e){var t=e.lastIndexOf("\n\n"),n=e.lastIndexOf("\r\r"),r=e.lastIndexOf("\r\n\r\n");return r>Math.max(t,n)?[r,r+4]:[Math.max(t,n),Math.max(t,n)+2]},trimWhiteSpace:function(e){return e.replace(/^(\s|\u00A0)+|(\s|\u00A0)+$/g,"")},normalizeToLF:function(e){return e.replace(/\r\n|\r/g,"\n")}},e.XDomainRequest&&e.XMLHttpRequest&&void 0===(new e.XMLHttpRequest).responseType){t.isPolyfill="IE_8-9";var r=t.prototype.defaultOptions;r.xhrHeaders=null,r.getArgs.evs_preamble=2056,(t.prototype.XHR=function(e){request=new XDomainRequest,this._request=request,request.onprogress=function(){request._ready=!0,e._onxhrdata()},request.onload=function(){this._loaded=!0,e._onxhrdata()},request.onerror=function(){this._failed=!0,e.readyState=e.CLOSED,e.dispatchEvent("error",{type:"error",data:"XDomainRequest error"})},request.ontimeout=function(){this._failed=!0,e.readyState=e.CLOSED,e.dispatchEvent("error",{type:"error",data:"XDomainRequest timed out"})};var t={};if(e.getArgs){var n=e.getArgs;for(var r in n)n.hasOwnProperty(r)&&(t[r]=n[r]);e.lastEventId&&(t.evs_last_event_id=e.lastEventId)}request.open("GET",e.urlWithParams(e.URL,t)),request.send()}).prototype={useXDomainRequest:!0,_request:null,_ready:!1,_loaded:!1,_failed:!1,isReady:function(){return this._request._ready},isDone:function(){return this._request._loaded},hasError:function(){return this._request._failed},getBuffer:function(){var e="";try{e=this._request.responseText||""}catch(e){}return e},abort:function(){this._request&&this._request.abort()}}}else t.isPolyfill="XHR",(t.prototype.XHR=function(e){request=new XMLHttpRequest,this._request=request,e._xhr=this,request.onreadystatechange=function(){1<request.readyState&&e.readyState!=e.CLOSED&&(200==request.status||300<=request.status&&request.status<400?e._onxhrdata():(request._failed=!0,e.readyState=e.CLOSED,e.dispatchEvent("error",{type:"error",data:"The server responded with "+request.status}),e.close()))},request.onprogress=function(){},request.open("GET",e.urlWithParams(e.URL,e.getArgs),!0);var t=e.xhrHeaders;for(var n in t)t.hasOwnProperty(n)&&request.setRequestHeader(n,t[n]);e.lastEventId&&request.setRequestHeader("Last-Event-Id",e.lastEventId),request.send()}).prototype={useXDomainRequest:!1,_request:null,_failed:!1,isReady:function(){return 2<=this._request.readyState},isDone:function(){return 4==this._request.readyState},hasError:function(){return this._failed||400<=this._request.status},getBuffer:function(){var e="";try{e=this._request.responseText||""}catch(e){}return e},abort:function(){this._request&&this._request.abort()}};e[n]=t}function u(e,t,n,r){this.bubbles=!1,this.cancelBubble=!1,this.cancelable=!1,this.data=t||null,this.origin=n||"",this.lastEventId=r||"",this.type=e||"message"}}(this||self),function(e,t){Array.prototype.indexOf=Array.prototype.indexOf||function(e){for(var t=this.length,n=0;n<t;n++)if(e===this[n])return n;return-1},Object.keys=Object.keys||function(e){var t,n=[];for(t in e)e.hasOwnProperty&&e.hasOwnProperty(t)&&n.push(t);return n},"undefined"!=typeof module&&module.exports?module.exports=t():"undefined"!=typeof define&&define.amd?define("BeamzerClient",t):void 0!==e&&e.window===e&&(e.BeamzerClient=t(e))}(this||self,function(s){if(s.EventSource){function t(){}function l(e,t){for(var n in e)v.call(e,n)&&t(e[n],n,e)}function u(){var a={},t={};return{getEvents:function(){return a},getProxy:function(e){return v.call(t,e)?t[e]:null},readyProxyObserver:function(i,o,s){var e;return v.call(t,o)||(t[o]={events:[],callback:function(n){var r=this;n=n||{},l(a,function(e,t){-1<t.indexOf(n.type||i)&&!s&&(t.match(g),1)&&a[t].call(r,n,o)})}}),(e=t[o])&&e.events&&"function"==typeof e.events.push&&e.events.push(i),e.callback},removeGlobalHandler:function(e){return!!v.call(a,e)&&(delete a[e],!0)},addGlobalHandler:function(e){l(e,function(e,t){var n,r="";switch(t){case"open":case"error":case"message":r="on"}n=r+t,v.call(a,n)||"function"==typeof e&&(a[n]=function(n){return function(e,t){e.target.readyState===EventSource.CLOSED?"function"==typeof this.close&&(n.apply(null,[e,t]),s.console&&s.console.log("[BeamzerClient]: Server-Sent Event Stream Closed!")):e.target.readyState===EventSource.CONNECTING&&(s.console&&s.console.log("[BeamzerClient]: Server-Sent Event Stream Connecting..."),n.apply(this,[e,t]))}}(e))})}}}function a(n,i){var o,s=u.getEvents(),a=Object.keys(s);d.call(n.constructor)!==h?l(n,function(n,r){l(s,function(e,t){0===t.indexOf("on")?(o=t.replace("on",""),null===n[t]&&(n[t]=u.readyProxyObserver(o,r,i))):-1==a.indexOf(t)&&n.addEventListener(t,u.readyProxyObserver(t,r,i),!1)})}):l(s,function(e,t){0===t.indexOf("on")?(o=t.replace("on",""),null===n[t]&&(n[t]=u.readyProxyObserver(o,url,i))):-1==s.indexOf(t)&&n.addEventListener(t,u.readyProxyObserver(t,url,i),!1)})}function c(e,t){var r,i=0,o=[],n=1*new Date;return d.call(e.constructor)!==h?l(e,function(t,n){null!==(r=u.getProxy(n))&&l(r.events,function(e){o.push(n),t.removeEventListener(e,r.callback),t.close(),++i})}):t&&null!==(r=u.getProxy(t))&&(o.push(t),-1<r.events.indexOf(event)&&e.removeEventListener(event,r.callback),e.close(),++i),e=null,function(e){"function"==typeof e&&e({type:"closed",timestamp:n,urls:o,closed_connections:i})}}function f(e,t,r){var i=-1==t.indexOf("?")?"?":"";return!e||x(e)?t:(l(e,function(e,t){if(d.call(e)===o)for(var n=0;n<e.length;n++)i+=r+s.encodeURIComponent(t)+"="+s.encodeURIComponent(e[n])+"&";else"string"==typeof e&&(i+=r+s.encodeURIComponent(t)+"="+s.encodeURIComponent(e)+"&")}),t+(i.length<=1)?"":i.replace(/\&$/,""))}var e={},n="https://app.beamzer.co",o="[object Array]",h="[object Function]",p="[object Object]",d=e.toString,v=e.hasOwnProperty,r=s.location,i=!function(e){try{e.setTimeout.apply(e,t)}catch(e){return!0}return!1}(s),y=r.origin+"/"||r.protocol+"//"+r.host+(r.port||"")+"/",g=/^(?:on|)?(?:open|error)/i,m=/^https?\:\/\/(?:([\w]+?)\.){1,2}(?:com?|org|co\.uk|ex|ca|co\.za|net|ng|com\.ng|gov|mil|biz|info|io|me|dev|ng|mobi|name|edu|nti|aero|jobs|museumco\.za)\/?/,S=null,b=null,_=i||"poll"in s.EventSource.prototype&&"function"==typeof s.EventSource.prototype.poll,E={},x=function(e){if("object"!=typeof e)return!1;for(var t in e)if(v.call(e,t))return!1;return!0},O=function(e,t){d.call(e)!==p&&(e={});var n=e.source||"",r=e.params||null,i=e.options||null,o=null;if(""===n)throw new Error("Cannot connect to stream: URL missing");return"[object URL]"===d.call(n)&&(n=n.toString()),m.exec(n)||(n=y+n),_?i.getArgs=r:n=f(r,n,""),String(i.headers)==p&&(n=f(i.headers,n,":")),!0===i.crossdomain&&(i.withCredentials=i.crossdomain,delete i.crossdomain),v.call(E,n)?(o=E[n],!0===t&&(_temp=c(o,n),o=_temp=null,o=new EventSource(n,i),a(o,null===i||!x(i)))):o=new EventSource(n,i),E[n]=o,this===s?new O(e,t):this};O.prototype.disconnect=function(e){var t=c(E);return E={},t(e),null},O.prototype.on=function(e){u.addGlobalHandler(e),a(E)},O.prototype.off=function(e){u.removeGlobalHandler(e||"")};var q=function(e,t){null===S&&(S=new O(e,t||!1))};return w.publicKey=null,w.targets={},w.serviceDiscoveryAndAuth=function(e){e=e||[y];var n=y+"/beamzer/discovery/auth";return new Promise(function(r,t){var i="function"==typeof s.toStaticHTML?new ActiveXObject("Microsoft.XMLHTTP"):new XMLHttpRequest;"function"==typeof i.setRequestHeader&&(i.setRequestHeader("Accept","application/ld+json"),i.setRequestHeader("Cache-Control","no-transform")),i.ontimeout=function(e){t(e)},i.onerror=function(e){t(e)},i.timeout=8100,i.onreadystatechange=function(e){var t=null,n=null;"readystatechange"===e.type&&4===i.readyState&&(200===i.status||300<=i.status&&i.status<400)&&(targetDetails=JSON.parse(i.responseText),"function"==typeof i.getResponseHeader&&(t=i.getResponseHeader("Link")||null,n=i.getResponseHeader("X-Beamzer-Public-Key")||null),null===t&&(t='<https://service.beamzer.co/hub>; rel="mercure"'),w.targets=targetDetails,w.publicKey=n,r({hubUrl:t.match(/<([^>]+)>;\s+rel=(?:mercure|"[^"]*mercure[^"]*")/)[1],topics:w.targets[y]||[]}))},i.open("GET",f(n,{targets:JSON.stringify(e)},""),!0),i.send(null)})},w.pingAuthExpiration=function(){return new Promise(function(t,n){var e=new Image;e.onload=function(e){t(!0)},e.onerror=function(e){n(!1)},e.src=f({publickey:String(w.publicKey)},"https://app.beamzer.co/hub/auth/expire","")})},w.publishToHub=function(e){var i=n+"/hub/publish";return e=e||{target:[y],data:{title:"Activity Stream",body:"A New Text Stream!"},topic:"default",type:"broadcast",retry:3e3,id:"cjld2cjxh0000qzrmn831i7rn"},-1===(w.targets[y]||[]).indexOf(e.topic||"")?Promise.reject(new Error("Invalid Entry: topic `"+e.topic+"` supplied is not available for current target")):new Promise(function(t,n){var r="function"==typeof s.toStaticHTML?new XDomainRequest:new XMLHttpRequest;"function"==typeof r.setRequestHeader?(r.setRequestHeader("Accept","application/ld+json"),r.setRequestHeader("Content-Type","application/x-www-form-urlencoded"),r.setRequestHeader("X-Api-Key",String(w.publicKey))):r.headers={"content-type":"application/x-www-form-urlencoded",accept:"application/ld+json",origin:y.replace(/\/$/,""),"x-api-key":String(w.publicKey)},v.call(r.prototype,"withCredentials")&&(r.withCredentials=!0),r.onerror=function(e){n(e)},r.ontimeout=function(e){n(e)},r.onprogress=function(){},"function"==typeof s.toStaticHTML?r.open("POST",f(r.headers,i,""),!0):r.open("POST",i,!0),r.onreadystatechange=function(e){"readystatechange"===e.type&&4===r.readyState&&(200!==r.status&&201!==r.status||(dispatchDetails=JSON.parse(r.responseText),t({dispatch:dispatchDetails})))},setTimeout(function(){r.send(function(e,r){var i="";return!e||x(e)?_url:(l(e,function(e,t){if("retry"===t&&(e=String(e)),d.call(e)===o||d.call(e)===p)if("target"!==t)i+=r+s.encodeURIComponent(t)+"="+s.encodeURIComponent(JSON.stringify(e))+"&";else{var n=f(e,"","");i+=n.replace("?","")}else"string"==typeof e&&(i+=r+s.encodeURIComponent(t)+"="+s.encodeURIComponent(e)+"&")}),0==i.length?i:i.replace(/\&$/,""))}(e,""))},0)})},w}function w(r){return r=r||{},this.url=r.source||"",null===b&&(b={constructor:w,start:function(e,t,n){q(r),S.on({open:e,error:t,message:n})},on:function(e,t){if(!e.match(g)){if(e=e.replace("on",""),!S)throw new Error("Illegal Invocation: Beamzer connection instance doesn't yet exist. try call `start()` first");S.on({event:t})}},off:function(e){if(!S)throw new Error("Illegal Invocation: Beamzer connection instance doesn't yet exist. try call `start()` first");S.off(e)},newClient:function(e){forceNew="object"==typeof e.params&&!x(e.params),q(e,forceNew)},stop:function(e){if(!S)throw new Error("Illegal Invocation: Beamzer connection instance doesn't yet exist. try call `start()` first");S.disconnect(e)}}),b}});