(function(){ /** * Bitrix Push & Pull * Pull client * * @package bitrix * @subpackage pull * @copyright 2001-2019 Bitrix */ if(!window.BX){window.BX={}}else if(window.BX.PullClient){return}else if(!window.BX.RestClient){return}const e=window.BX;const t=window.protobuf;const s=19;const n=60;const i=30*60;const o=24*60*60;const r=6e4;const c=10;const a=5e3;const l="bx-pull-session";const h=20;const u={WebSocket:"webSocket",LongPolling:"longPolling"};const d={Online:"online",Offline:"offline",Connecting:"connect"};const f={Unknown:0,Client:1,Backend:2};const g={Server:"server",Client:"client",Online:"online",Status:"status",Revision:"revision"};const p={NORMAL_CLOSURE:1e3,SERVER_DIE:1001,CONFIG_REPLACED:3e3,CHANNEL_EXPIRED:3001,SERVER_RESTARTED:3002,CONFIG_EXPIRED:3003,MANUAL:3004,STUCK:3005,WRONG_CHANNEL_ID:4010};const m={CHANNEL_EXPIRE:"CHANNEL_EXPIRE",CONFIG_EXPIRE:"CONFIG_EXPIRE",SERVER_RESTART:"SERVER_RESTART"};const b={Shared:"shared",Personal:"personal"};const y={api:{},channels:{},publicChannels:{},server:{timeShift:0},clientId:null,jwt:null};const S=t.roots["push-server"]["Response"];const k=t.roots["push-server"]["ResponseBatch"];const C=t.roots["push-server"]["Request"];const I=t.roots["push-server"]["RequestBatch"];const P=t.roots["push-server"]["IncomingMessagesRequest"];const E=t.roots["push-server"]["IncomingMessage"];const v=t.roots["push-server"]["Receiver"];const w="2.0";const R="ping";const T="pong";const _=10;const L={Parse:{code:-32700,message:"Parse error"},InvalidRequest:{code:-32600,message:"Invalid Request"},MethodNotFound:{code:-32601,message:"Method not found"},InvalidParams:{code:-32602,message:"Invalid params"},Internal:{code:-32603,message:"Internal error"}};const M={Publish:"publish",Subscribe:"subscribe"};const x={StatusChange:"internal:user_status"};class O{constructor(t){t=t||{};if(t.restApplication){if(typeof t.configGetMethod==="undefined"){t.configGetMethod="pull.application.config.get"}if(typeof t.skipCheckRevision==="undefined"){t.skipCheckRevision=true}if(typeof t.restApplication==="string"){t.siteId=t.restApplication}t.serverEnabled=true}this._status=d.Offline;this.context="master";this.guestMode=t.guestMode?t.guestMode:typeof e.message!=="undefined"&&e.message.pull_guest_mode?e.message.pull_guest_mode==="Y":false;this.guestUserId=t.guestUserId?t.guestUserId:typeof e.message!=="undefined"&&e.message.pull_guest_user_id?parseInt(e.message.pull_guest_user_id,10):0;if(this.guestMode&&this.guestUserId){this.userId=this.guestUserId}else{this.userId=t.userId?t.userId:typeof e.message!=="undefined"&&e.message.USER_ID?e.message.USER_ID:0}this.siteId=t.siteId?t.siteId:typeof e.message!=="undefined"&&e.message.SITE_ID?e.message.SITE_ID:"none";this.restClient=typeof t.restClient!=="undefined"?t.restClient:new e.RestClient(this.getRestClientOptions());this.enabled=typeof t.serverEnabled!=="undefined"?t.serverEnabled==="Y"||t.serverEnabled===true:typeof e.message!=="undefined"&&e.message.pull_server_enabled==="Y";this.unloading=false;this.starting=false;this.debug=false;this.connectionAttempt=0;this.connectionType=u.WebSocket;this.reconnectTimeout=null;this.restartTimeout=null;this.restoreWebSocketTimeout=null;this.configGetMethod=typeof t.configGetMethod!=="string"?"pull.config.get":t.configGetMethod;this.getPublicListMethod=typeof t.getPublicListMethod!=="string"?"pull.channel.public.list":t.getPublicListMethod;this.skipStorageInit=t.skipStorageInit===true;this.skipCheckRevision=t.skipCheckRevision===true;this._subscribers={};this.watchTagsQueue={};this.watchUpdateInterval=174e4;this.watchForceUpdateInterval=5e3;if(typeof t.configTimestamp!=="undefined"){this.configTimestamp=t.configTimestamp}else if(typeof e.message!=="undefined"&&e.message.pull_config_timestamp){this.configTimestamp=e.message.pull_config_timestamp}else{this.configTimestamp=0}this.session={mid:null,tag:null,time:null,history:{},lastMessageIds:[],messageCount:0};this._connectors={webSocket:null,longPolling:null};this.isSecure=document.location.href.indexOf("https")===0;this.config=null;this.storage=null;if(this.userId&&!this.skipStorageInit){this.storage=new U({userId:this.userId,siteId:this.siteId})}this.sharedConfig=new D({onWebSocketBlockChanged:this.onWebSocketBlockChanged.bind(this),storage:this.storage});this.channelManager=new j({restClient:this.restClient,getPublicListMethod:this.getPublicListMethod});this.notificationPopup=null;this.checkInterval=null;this.offlineTimeout=null;this.pingWaitTimeout=null;this.isManualDisconnect=false;this.loggingEnabled=this.sharedConfig.isLoggingEnabled();this.onPingTimeoutHandler=this.onPingTimeout.bind(this)}get connector(){return this._connectors[this.connectionType]}get status(){return this._status}set status(e){if(this._status===e){return}this._status=e;if(this.offlineTimeout){clearTimeout(this.offlineTimeout);this.offlineTimeout=null}if(e===d.Offline){this.sendPullStatusDelayed(e,a)}else{this.sendPullStatus(e)}}subscribe(e){if(!e){console.error(q.getDateForLog()+": Pull.subscribe: params for subscribe function is invalid. ");return function(){}}if(!q.isPlainObject(e)){return this.attachCommandHandler(e)}e=e||{};e.type=e.type||g.Server;e.command=e.command||null;if(e.type==g.Server||e.type==g.Client){if(typeof this._subscribers[e.type]==="undefined"){this._subscribers[e.type]={}}if(typeof this._subscribers[e.type][e.moduleId]==="undefined"){this._subscribers[e.type][e.moduleId]={callbacks:[],commands:{}}}if(e.command){if(typeof this._subscribers[e.type][e.moduleId]["commands"][e.command]==="undefined"){this._subscribers[e.type][e.moduleId]["commands"][e.command]=[]}this._subscribers[e.type][e.moduleId]["commands"][e.command].push(e.callback);return function(){this._subscribers[e.type][e.moduleId]["commands"][e.command]=this._subscribers[e.type][e.moduleId]["commands"][e.command].filter((t=>t!==e.callback))}.bind(this)}else{this._subscribers[e.type][e.moduleId]["callbacks"].push(e.callback);return function(){this._subscribers[e.type][e.moduleId]["callbacks"]=this._subscribers[e.type][e.moduleId]["callbacks"].filter((t=>t!==e.callback))}.bind(this)}}else{if(typeof this._subscribers[e.type]==="undefined"){this._subscribers[e.type]=[]}this._subscribers[e.type].push(e.callback);return function(){this._subscribers[e.type]=this._subscribers[e.type].filter((t=>t!==e.callback))}.bind(this)}}attachCommandHandler(e){if(typeof e.getModuleId!=="function"||typeof e.getModuleId()!=="string"){console.error(q.getDateForLog()+": Pull.attachCommandHandler: result of handler.getModuleId() is not a string.");return function(){}}let t=g.Server;if(typeof e.getSubscriptionType==="function"){t=e.getSubscriptionType()}return this.subscribe({type:t,moduleId:e.getModuleId(),callback:function(t){let s=null;if(typeof e.getMap==="function"){const n=e.getMap();if(n&&typeof n==="object"){if(typeof n[t.command]==="function"){s=n[t.command].bind(e)}else if(typeof n[t.command]==="string"&&typeof e[n[t.command]]==="function"){s=e[n[t.command]].bind(e)}}}if(!s){const n="handle"+t.command.charAt(0).toUpperCase()+t.command.slice(1);if(typeof e[n]==="function"){s=e[n].bind(e)}}if(s){if(this.debug&&this.context!=="master"){console.warn(q.getDateForLog()+": Pull.attachCommandHandler: receive command",t)}s(t.params,t.extra,t.command)}}.bind(this)})}emit(e){e=e||{};if(e.type==g.Server||e.type==g.Client){if(typeof this._subscribers[e.type]==="undefined"){this._subscribers[e.type]={}}if(typeof this._subscribers[e.type][e.moduleId]==="undefined"){this._subscribers[e.type][e.moduleId]={callbacks:[],commands:{}}}if(this._subscribers[e.type][e.moduleId]["callbacks"].length>0){this._subscribers[e.type][e.moduleId]["callbacks"].forEach((function(t){t(e.data,{type:e.type,moduleId:e.moduleId})}))}if(this._subscribers[e.type][e.moduleId]["commands"][e.data.command]&&this._subscribers[e.type][e.moduleId]["commands"][e.data.command].length>0){this._subscribers[e.type][e.moduleId]["commands"][e.data.command].forEach((function(t){t(e.data.params,e.data.extra,e.data.command,{type:e.type,moduleId:e.moduleId})}))}return true}else{if(typeof this._subscribers[e.type]==="undefined"){this._subscribers[e.type]=[]}if(this._subscribers[e.type].length<=0){return true}this._subscribers[e.type].forEach((function(t){t(e.data,{type:e.type})}));return true}}init(){this._connectors.webSocket=new A({parent:this,onOpen:this.onWebSocketOpen.bind(this),onMessage:this.onIncomingMessage.bind(this),onDisconnect:this.onWebSocketDisconnect.bind(this),onError:this.onWebSocketError.bind(this)});this._connectors.longPolling=new N({parent:this,onOpen:this.onLongPollingOpen.bind(this),onMessage:this.onIncomingMessage.bind(this),onDisconnect:this.onLongPollingDisconnect.bind(this),onError:this.onLongPollingError.bind(this)});this.connectionType=this.isWebSocketAllowed()?u.WebSocket:u.LongPolling;window.addEventListener("beforeunload",this.onBeforeUnload.bind(this));window.addEventListener("offline",this.onOffline.bind(this));window.addEventListener("online",this.onOnline.bind(this));if(e&&e.addCustomEvent){e.addCustomEvent("BXLinkOpened",this.connect.bind(this))}if(e&&e.desktop){e.addCustomEvent("onDesktopReload",(()=>{this.session.mid=null;this.session.tag=null;this.session.time=null}));e.desktop.addCustomEvent("BXLoginSuccess",(()=>this.restart(1e3,"Desktop login")))}this.jsonRpcAdapter=new B({connector:this._connectors.webSocket,handlers:{"incoming.message":this.handleRpcIncomingMessage.bind(this)}})}start(t){let s=true;if(this.isConnected()){return Promise.resolve(true)}if(this.starting&&this._startingPromise){return this._startingPromise}if(!this.userId&&typeof e.message!=="undefined"&&e.message.USER_ID){this.userId=e.message.USER_ID;if(!this.storage){this.storage=new U({userId:this.userId,siteId:this.siteId})}}if(this.siteId==="none"&&typeof e.message!=="undefined"&&e.message.SITE_ID){this.siteId=e.message.SITE_ID}let n=false;if(q.isPlainObject(t)){if(typeof t.skipReconnectToLastSession!=="undefined"){n=!!t.skipReconnectToLastSession;delete t.skipReconnectToLastSession}this.config=t;s=false}if(!this.enabled){return Promise.reject({ex:{error:"PULL_DISABLED",error_description:"Push & Pull server is disabled"}})}const i=(new Date).getTime();let o;if(!n&&this.storage){o=this.storage.get(l)}if(q.isPlainObject(o)&&o.hasOwnProperty("ttl")&&o.ttl>=i){this.session.mid=o.mid}this.starting=true;return new Promise(((e,t)=>{this._startingPromise={resolve:e,reject:t};this.loadConfig().then((n=>{this.setConfig(n,s);this.init();this.updateWatch();this.startCheckConfig();this.connect().then((()=>e(true)),(e=>t(e)))}),(e=>{this.starting=false;this.status=d.Offline;this.stopCheckConfig();console.error(q.getDateForLog()+": Pull: could not read push-server config. ",e);t(e)}))}))}getRestClientOptions(){let e={};if(this.guestMode&&this.guestUserId!==0){e.queryParams={pull_guest_id:this.guestUserId}}return e}setLastMessageId(e){this.session.mid=e}setPublicIds(e){return this.channelManager.setPublicIds(e)}sendMessage(e,t,s,n,i){const o={userList:e,body:{module_id:t,command:s,params:n},expiry:i};if(this.isJsonRpc()){return this.jsonRpcAdapter.executeOutgoingRpcCommand(M.Publish,o)}else{return this.sendMessageBatch([o])}}sendMessageToChannels(e,t,s,n,i){const o={channelList:e,body:{module_id:t,command:s,params:n},expiry:i};if(this.isJsonRpc()){return this.jsonRpcAdapter.executeOutgoingRpcCommand("publish",o)}else{return this.sendMessageBatch([o])}}sendMessageBatch(e){if(!this.isPublishingEnabled()){console.error("Client publishing is not supported or is disabled");return false}if(this.isJsonRpc()){let t=this.jsonRpcAdapter.createPublishRequest(e);return this.connector.send(JSON.stringify(t))}else{let t={};for(let s=0;sthis.connector.send(this.encodeMessageBatch(e,t))))}}encodeMessageBatch(e,t){let s=[];e.forEach((function(e){const n=e.body;let i;if(e.userList){i=this.createMessageReceivers(e.userList,t)}else{i=[]}if(e.channelList){if(!q.isArray(e.channelList)){throw new Error("messageFields.publicChannels must be an array")}e.channelList.forEach(function(e){let t;let s;if(typeof e==="string"&&e.includes(".")){const n=e.toString().split(".");t=n[0];s=n[1]}else if(typeof e==="object"&&"publicId"in e&&"signature"in e){t=e.publicId;s=e.signature}else{throw new Error("Public channel MUST be either a string, formatted like \"{publicId}.{signature}\" or an object with fields 'publicId' and 'signature'")}i.push(v.create({id:this.encodeId(t),signature:this.encodeId(s)}))}.bind(this))}const o=E.create({receivers:i,body:JSON.stringify(n),expiry:e.expiry||0});s.push(o)}),this);const n=I.create({requests:[{incomingMessages:{messages:s}}]});return I.encode(n).finish()}createMessageReceivers(e,t){let s=[];for(let n=0;nthis.restart(e,t)),s)}restart(t,s){if(!t){t=p.NORMAL_CLOSURE}clearTimeout(this.restartTimeout);console.warn(q.getDateForLog()+": Pull: restarting with code "+t);this.disconnect(t,s);if(this.storage){this.storage.remove("bx-pull-config")}this.config=null;this.loadConfig().then((e=>{this.setConfig(e,true);this.updateWatch();this.startCheckConfig();this.connect().catch((e=>console.error(e)))}),(t=>{console.error(q.getDateForLog()+": Pull: could not read push-server config",t);this.status=d.Offline;clearTimeout(this.reconnectTimeout);if(t.status==401||t.status==403){this.stopCheckConfig();if(e&&e.onCustomEvent){e.onCustomEvent(window,"onPullError",["AUTHORIZE_ERROR"])}}}))}loadConfig(){if(!this.config){this.config=Object.assign({},y);let e;if(this.storage){e=this.storage.get("bx-pull-config")}if(this.isConfigActual(e)&&this.checkRevision(e.api.revision_web)){return Promise.resolve(e)}else if(this.storage){this.storage.remove("bx-pull-config")}}else if(this.isConfigActual(this.config)&&this.checkRevision(this.config.api.revision_web)){return Promise.resolve(this.config)}else{this.config=Object.assign({},y)}return new Promise(((e,t)=>{this.restClient.callMethod(this.configGetMethod,{CACHE:"N"}).then((t=>{const s=t.data();let n;n=Math.floor((q.getTimestamp()-new Date(s.serverTime).getTime())/1e3);delete s.serverTime;let i=Object.assign({},s);i.server.timeShift=n;e(i)})).catch((e=>{const s=e.error();if(s.getError().error=="AUTHORIZE_ERROR"||s.getError().error=="WRONG_AUTH_TYPE"){s.status=403}t(s)}))}))}isConfigActual(e){if(!q.isPlainObject(e)){return false}if(e.server.config_timestamp3}isPublishingEnabled(){if(!this.isPublishingSupported()){return false}return this.config&&this.config.server&&this.config.server.publish_enabled===true}isProtobufSupported(){return this.getServerVersion()==4&&!q.browser.IsIe()}isJsonRpc(){return this.getServerVersion()>=5}isSharedMode(){return this.getServerMode()==b.Shared}disconnect(e,t){if(this.connector){this.isManualDisconnect=true;this.connector.disconnect(e,t)}}stop(e,t){this.disconnect(e,t);this.stopCheckConfig()}reconnect(e,t,s){this.disconnect(e,t);s=s||1;this.scheduleReconnect(s)}restoreWebSocketConnection(){if(this.connectionType==u.WebSocket){return true}this._connectors.webSocket.connect()}scheduleReconnect(e){if(!this.enabled){return false}if(!e){if(this.connectionAttempt>3&&this.connectionType===u.WebSocket&&!this.sharedConfig.isLongPollingBlocked()){this.sharedConfig.setWebSocketBlocked(true);this.connectionType=u.LongPolling;this.connectionAttempt=1;e=1}else{e=this.getConnectionAttemptDelay(this.connectionAttempt)}}if(this.reconnectTimeout){clearTimeout(this.reconnectTimeout)}this.logToConsole("Pull: scheduling reconnection in "+e+" seconds; attempt # "+this.connectionAttempt);this.reconnectTimeout=setTimeout((()=>{this.connect().catch((e=>{console.error(e)}))}),e*1e3)}scheduleRestoreWebSocketConnection(){this.logToConsole("Pull: scheduling restoration of websocket connection in "+i+" seconds");if(this.restoreWebSocketTimeout){return}this.restoreWebSocketTimeout=setTimeout((()=>{this.restoreWebSocketTimeout=0;this.restoreWebSocketConnection()}),i*1e3)}connect(){if(!this.enabled){return Promise.reject()}if(this.connector.connected){return Promise.resolve()}if(this.reconnectTimeout){clearTimeout(this.reconnectTimeout)}this.status=d.Connecting;this.connectionAttempt++;return new Promise(((e,t)=>{this._connectPromise={resolve:e,reject:t};this.connector.connect()}))}onIncomingMessage(e){if(this.isJsonRpc()){e===R?this.onJsonRpcPing():this.jsonRpcAdapter.parseJsonRpcMessage(e)}else{const t=this.extractMessages(e);this.handleIncomingEvents(t)}}handleRpcIncomingMessage(e){this.session.mid=e.mid;let t=e.body;if(!e.body.extra){t.extra={}}t.extra.sender=e.sender;if("user_params"in e&&q.isPlainObject(e.user_params)){Object.assign(t.params,e.user_params)}if("dictionary"in e&&q.isPlainObject(e.dictionary)){Object.assign(t.params,e.dictionary)}if(this.checkDuplicate(e.mid)){this.addMessageToStat(t);this.trimDuplicates();this.broadcastMessage(t)}this.connector.send(`mack:${e.mid}`);return{}}onJsonRpcPing(){this.updatePingWaitTimeout();this.connector.send(T)}handleIncomingEvents(e){let t=[];if(e.length===0){this.session.mid=null;return}for(let s=0;sc){this.session.lastMessageIds=this.session.lastMessageIds.slice(-c)}}addMessageToStat(e){if(!this.session.history[e.module_id]){this.session.history[e.module_id]={}}if(!this.session.history[e.module_id][e.command]){this.session.history[e.module_id][e.command]=0}this.session.history[e.module_id][e.command]++;this.session.messageCount++}extractMessages(e){if(e instanceof ArrayBuffer){return this.extractProtobufMessages(e)}else if(q.isNotEmptyString(e)){return this.extractPlainTextMessages(e)}}extractProtobufMessages(e){let t=[];try{let s=k.decode(new Uint8Array(e));for(let e=0;ethis.broadcastMessage(e)))}broadcastMessage(t){const s=t.module_id=t.module_id.toLowerCase();const n=t.command;if(!t.extra){t.extra={}}if(t.extra.server_time_unix){t.extra.server_time_ago=(q.getTimestamp()-t.extra.server_time_unix*1e3)/1e3-(this.config.server.timeShift?this.config.server.timeShift:0);t.extra.server_time_ago=t.extra.server_time_ago>0?t.extra.server_time_ago:0}this.logMessage(t);try{if(t.extra.sender&&t.extra.sender.type===f.Client){if(typeof e.onCustomEvent!=="undefined"){e.onCustomEvent(window,"onPullClientEvent-"+s,[n,t.params,t.extra],true);e.onCustomEvent(window,"onPullClientEvent",[s,n,t.params,t.extra],true)}this.emit({type:g.Client,moduleId:s,data:{command:n,params:q.clone(t.params),extra:q.clone(t.extra)}})}else if(s==="pull"){this.handleInternalPullEvent(n,t)}else if(s=="online"){if(t.extra.server_time_ago<240){if(typeof e.onCustomEvent!=="undefined"){e.onCustomEvent(window,"onPullOnlineEvent",[n,t.params,t.extra],true)}this.emit({type:g.Online,data:{command:n,params:q.clone(t.params),extra:q.clone(t.extra)}})}}else{if(typeof e.onCustomEvent!=="undefined"){e.onCustomEvent(window,"onPullEvent-"+s,[n,t.params,t.extra],true);e.onCustomEvent(window,"onPullEvent",[s,n,t.params,t.extra],true)}this.emit({type:g.Server,moduleId:s,data:{command:n,params:q.clone(t.params),extra:q.clone(t.extra)}})}}catch(s){if(typeof console=="object"){console.warn("\n========= PULL ERROR ===========\n"+"Error type: broadcastMessages execute error\n"+"Error event: ",s,"\n"+"Message: ",t,"\n"+"================================\n");if(typeof e.debug!=="undefined"){e.debug(s)}}}if(t.extra&&t.extra.revision_web){this.checkRevision(t.extra.revision_web)}}logToConsole(e,t){if(this.loggingEnabled||t){console.log(q.getDateForLog()+": "+e)}}logMessage(e){if(!this.debug){return}if(e.extra.sender&&e.extra.sender.type===f.Client){console.info("onPullClientEvent-"+e.module_id,e.command,e.params,e.extra)}else if(e.moduleId=="online"){console.info("onPullOnlineEvent",e.command,e.params,e.extra)}else{console.info("onPullEvent",e.module_id,e.command,e.params,e.extra)}}onLongPollingOpen(){this.unloading=false;this.starting=false;this.connectionAttempt=0;this.isManualDisconnect=false;this.status=d.Online;this.logToConsole("Pull: Long polling connection with push-server opened");if(this.isWebSocketEnabled()){this.scheduleRestoreWebSocketConnection()}if(this._connectPromise){this._connectPromise.resolve()}}onWebSocketBlockChanged(e){const t=e.isWebSocketBlocked;if(t&&this.connectionType===u.WebSocket&&!this.isConnected()){clearTimeout(this.reconnectTimeout);this.connectionAttempt=0;this.connectionType=u.LongPolling;this.scheduleReconnect(1)}else if(!t&&this.connectionType===u.LongPolling){clearTimeout(this.reconnectTimeout);clearTimeout(this.restoreWebSocketTimeout);this.connectionAttempt=0;this.connectionType=u.WebSocket;this.scheduleReconnect(1)}}onWebSocketOpen(){this.unloading=false;this.starting=false;this.connectionAttempt=0;this.isManualDisconnect=false;this.status=d.Online;this.sharedConfig.setWebSocketBlocked(false);this.sharedConfig.setLongPollingBlocked(true);if(this.connectionType==u.LongPolling){this.connectionType=u.WebSocket;this._connectors.longPolling.disconnect()}if(this.restoreWebSocketTimeout){clearTimeout(this.restoreWebSocketTimeout);this.restoreWebSocketTimeout=null}this.logToConsole("Pull: Websocket connection with push-server opened");if(this._connectPromise){this._connectPromise.resolve()}}onWebSocketDisconnect(e){if(this.connectionType===u.WebSocket){this.status=d.Offline}if(!e){e={}}this.logToConsole("Pull: Websocket connection with push-server closed. Code: "+e.code+", reason: "+e.reason,true);if(!this.isManualDisconnect){if(e.code==p.WRONG_CHANNEL_ID){this.scheduleRestart(p.WRONG_CHANNEL_ID,"restarting to reload config")}else{this.scheduleReconnect()}}this.sharedConfig.setLongPollingBlocked(true);this.isManualDisconnect=false;this.clearPingWaitTimeout()}onWebSocketError(e){this.starting=false;if(this.connectionType===u.WebSocket){this.status=d.Offline}console.error(q.getDateForLog()+": Pull: WebSocket connection error",e);this.scheduleReconnect();if(this._connectPromise){this._connectPromise.reject()}this.clearPingWaitTimeout()}onLongPollingDisconnect(e){if(this.connectionType===u.LongPolling){this.status=d.Offline}if(!e){e={}}this.logToConsole("Pull: Long polling connection with push-server closed. Code: "+e.code+", reason: "+e.reason);if(!this.isManualDisconnect){this.scheduleReconnect()}this.isManualDisconnect=false;this.clearPingWaitTimeout()}onLongPollingError(e){this.starting=false;if(this.connectionType===u.LongPolling){this.status=d.Offline}console.error(q.getDateForLog()+": Pull: Long polling connection error",e);this.scheduleReconnect();if(this._connectPromise){this._connectPromise.reject()}this.clearPingWaitTimeout()}isConnected(){return this.connector?this.connector.connected:false}onBeforeUnload(){this.unloading=true;const e=q.clone(this.session);e.ttl=(new Date).getTime()+h*1e3;if(this.storage){try{this.storage.set(l,JSON.stringify(e),h)}catch(e){console.error(q.getDateForLog()+" Pull: Could not save session info in local storage. Error: ",e)}}this.scheduleReconnect(15)}onOffline(){this.disconnect("1000","offline")}onOnline(){this.connect()}handleInternalPullEvent(e,t){switch(e.toUpperCase()){case m.CHANNEL_EXPIRE:{if(t.params.action=="reconnect"){this.config.channels[t.params.channel.type]=t.params.new_channel;this.logToConsole("Pull: new config for "+t.params.channel.type+" channel set:\n",this.config.channels[t.params.channel.type]);this.reconnect(p.CONFIG_REPLACED,"config was replaced")}else{this.restart(p.CHANNEL_EXPIRED,"channel expired")}break}case m.CONFIG_EXPIRE:{this.restart(p.CONFIG_EXPIRED,"config expired");break}case m.SERVER_RESTART:{this.reconnect(p.SERVER_RESTARTED,"server was restarted",15);break}default:}}checkRevision(t){if(this.skipCheckRevision){return true}t=parseInt(t);if(t>0&&t!=s){this.enabled=false;if(typeof e.message!=="undefined"){this.showNotification(e.message("PULL_OLD_REVISION"))}this.disconnect(p.NORMAL_CLOSURE,"check_revision");if(typeof e.onCustomEvent!=="undefined"){e.onCustomEvent(window,"onPullRevisionUp",[t,s])}this.emit({type:g.Revision,data:{server:t,client:s}});this.logToConsole("Pull revision changed from "+s+" to "+t+". Reload required");return false}return true}showNotification(t){if(this.notificationPopup||typeof e.PopupWindow==="undefined"){return}this.notificationPopup=new e.PopupWindow("bx-notifier-popup-confirm",null,{zIndex:200,autoHide:false,closeByEsc:false,overlay:true,content:e.create("div",{props:{className:"bx-messenger-confirm"},html:t}),buttons:[new e.PopupWindowButton({text:e.message("JS_CORE_WINDOW_CLOSE"),className:"popup-window-button-decline",events:{click:()=>{this.notificationPopup.close()}}})],events:{onPopupClose:function(){this.destroy()},onPopupDestroy:()=>{this.notificationPopup=null}}});this.notificationPopup.show()}getRevision(){return this.config&&this.config.api?this.config.api.revision_web:null}getServerVersion(){return this.config&&this.config.server?this.config.server.version:0}getServerMode(){return this.config&&this.config.server?this.config.server.mode:null}getConfig(){return this.config}getDebugInfo(){if(!console||!console.info||!JSON||!JSON.stringify){return false}let e;if(this.config&&this.config.channels){e="ChannelID: "+(this.config.channels.private?this.config.channels.private.id:"n/a")+"\n"+"ChannelDie: "+(this.config.channels.private?this.config.channels.private.end:"n/a")+"\n"+("shared"in this.config.channels?"ChannelDieShared: "+this.config.channels.shared.end:"")}else{e="Config error: config is not loaded"}let t="-";if(this._connectors.webSocket&&this._connectors.webSocket.socket){if(this.isJsonRpc()){t="json-rpc"}else{t=this._connectors.webSocket.socket.url.search("binaryMode=true")!=-1?"protobuf":"text"}}const s=JSON.stringify(this.watchTagsQueue);const n="\n========= PULL DEBUG ===========\n"+"UserId: "+this.userId+" "+(this.userId>0?"":"(guest)")+"\n"+(this.guestMode&&this.guestUserId!==0?"Guest userId: "+this.guestUserId+"\n":"")+"Browser online: "+(navigator.onLine?"Y":"N")+"\n"+"Connect: "+(this.isConnected()?"Y":"N")+"\n"+"Server type: "+(this.isSharedMode()?"cloud":"local")+"\n"+"WebSocket supported: "+(this.isWebSocketSupported()?"Y":"N")+"\n"+"WebSocket connected: "+(this._connectors.webSocket&&this._connectors.webSocket.connected?"Y":"N")+"\n"+"WebSocket mode: "+t+"\n"+"Try connect: "+(this.reconnectTimeout?"Y":"N")+"\n"+"Try number: "+this.connectionAttempt+"\n"+"\n"+"Path: "+(this.connector?this.connector.path:"-")+"\n"+e+"\n"+"\n"+"Last message: "+(this.session.mid>0?this.session.mid:"-")+"\n"+"Session history: "+JSON.stringify(this.session.history)+"\n"+"Watch tags: "+(s=="{}"?"-":s)+"\n"+"================================\n";return console.info(n)}enableLogging(e){if(e===undefined){e=true}e=e===true;this.sharedConfig.setLoggingEnabled(e);this.loggingEnabled=e}capturePullEvent(e){if(e===undefined){e=true}this.debug=e}getConnectionPath(e){let t;let n={};switch(e){case u.WebSocket:t=this.isSecure?this.config.server.websocket_secure:this.config.server.websocket;break;case u.LongPolling:t=this.isSecure?this.config.server.long_pooling_secure:this.config.server.long_polling;break;default:throw new Error("Unknown connection type "+e)}if(!q.isNotEmptyString(t)){return false}if(typeof this.config.jwt=="string"&&this.config.jwt!==""){n["token"]=this.config.jwt}else{let e=[];["private","shared"].forEach((t=>{if(typeof this.config.channels[t]!=="undefined"){e.push(this.config.channels[t].id)}}));if(e.length===0){return false}n["CHANNEL_ID"]=e.join("/")}if(this.isJsonRpc()){n.jsonRpc="true"}else if(this.isProtobufSupported()){n.binaryMode="true"}if(this.isSharedMode()){if(!this.config.clientId){throw new Error("Push-server is in shared mode, but clientId is not set")}n.clientId=this.config.clientId}if(this.session.mid){n.mid=this.session.mid}if(this.session.tag){n.tag=this.session.tag}if(this.session.time){n.time=this.session.time}n.revision=s;return t+"?"+q.buildQueryString(n)}getPublicationPath(){const e=this.isSecure?this.config.server.publish_secure:this.config.server.publish;if(!e){return""}let t=[];for(let e in this.config.channels){if(!this.config.channels.hasOwnProperty(e)){continue}t.push(this.config.channels[e].id)}const s={CHANNEL_ID:t.join("/")};return e+"?"+q.buildQueryString(s)}getConnectionAttemptDelay(e){let t;if(e<1){t=.5}else if(e<3){t=15}else if(e<5){t=45}else if(e<10){t=600}else{t=3600}return t+t*Math.random()*.2}sendPullStatusDelayed(e,t){if(this.offlineTimeout){clearTimeout(this.offlineTimeout)}this.offlineTimeout=setTimeout((()=>{this.offlineTimeout=null;this.sendPullStatus(e)}),t)}sendPullStatus(t){if(this.unloading){return}if(typeof e.onCustomEvent!=="undefined"){e.onCustomEvent(window,"onPullStatus",[t])}this.emit({type:g.Status,data:{status:t}})}extendWatch(e,t){if(!e||this.watchTagsQueue[e]){return false}this.watchTagsQueue[e]=true;if(t){this.updateWatch(t)}}updateWatch(e){clearTimeout(this.watchUpdateTimeout);this.watchUpdateTimeout=setTimeout((()=>{const e=Object.keys(this.watchTagsQueue);if(e.length>0){this.restClient.callMethod("pull.watch.extend",{tags:e},(e=>{if(e.error()){this.updateWatch();return false}const t=e.data();for(let e in t){if(t.hasOwnProperty(e)&&!t[e]){this.clearWatch(e)}}this.updateWatch()}))}else{this.updateWatch()}}),e?this.watchForceUpdateInterval:this.watchUpdateInterval)}clearWatch(e){delete this.watchTagsQueue[e]}updatePingWaitTimeout(){clearTimeout(this.pingWaitTimeout);this.pingWaitTimeout=setTimeout(this.onPingTimeoutHandler,_*2*1e3)}clearPingWaitTimeout(){clearTimeout(this.pingWaitTimeout);this.pingWaitTimeout=null}onPingTimeout(){this.pingWaitTimeout=null;if(!this.enabled||!this.isConnected()){return}console.warn("No pings are received in "+_*2+" seconds. Reconnecting");this.disconnect(p.STUCK,"connection stuck");this.scheduleReconnect()}setPrivateVar(){}returnPrivateVar(){}expireConfig(){}updateChannelID(){}tryConnect(){}tryConnectDelay(){}tryConnectSet(){}updateState(){}setUpdateStateStepCount(){}supportWebSocket(){return this.isWebSocketSupported()}isWebSoketConnected(){return this.isConnected()&&this.connectionType==u.WebSocket}getPullServerStatus(){return this.isConnected()}closeConfirm(){if(this.notificationPopup){this.notificationPopup.destroy()}}}class D{constructor(e){e=e||{};this.storage=e.storage||new U;this.ttl=24*60*60;this.lsKeys={websocketBlocked:"bx-pull-websocket-blocked",longPollingBlocked:"bx-pull-longpolling-blocked",loggingEnabled:"bx-pull-logging-enabled"};this.callbacks={onWebSocketBlockChanged:q.isFunction(e.onWebSocketBlockChanged)?e.onWebSocketBlockChanged:function(){}};if(this.storage){window.addEventListener("storage",this.onLocalStorageSet.bind(this))}}onLocalStorageSet(e){if(this.storage.compareKey(e.key,this.lsKeys.websocketBlocked)&&e.newValue!=e.oldValue){this.callbacks.onWebSocketBlockChanged({isWebSocketBlocked:this.isWebSocketBlocked()})}}isWebSocketBlocked(){if(!this.storage){return false}return this.storage.get(this.lsKeys.websocketBlocked,0)>q.getTimestamp()}setWebSocketBlocked(e){if(!this.storage){return false}try{this.storage.set(this.lsKeys.websocketBlocked,e?q.getTimestamp()+this.ttl:0)}catch(e){console.error(q.getDateForLog()+" Pull: Could not save WS_blocked flag in local storage. Error: ",e)}}isLongPollingBlocked(){if(!this.storage){return false}return this.storage.get(this.lsKeys.longPollingBlocked,0)>q.getTimestamp()}setLongPollingBlocked(e){if(!this.storage){return false}try{this.storage.set(this.lsKeys.longPollingBlocked,e?q.getTimestamp()+this.ttl:0)}catch(e){console.error(q.getDateForLog()+" Pull: Could not save LP_blocked flag in local storage. Error: ",e)}}isLoggingEnabled(){if(!this.storage){return false}return this.storage.get(this.lsKeys.loggingEnabled,0)>q.getTimestamp()}setLoggingEnabled(e){if(!this.storage){return false}try{this.storage.set(this.lsKeys.loggingEnabled,e?q.getTimestamp()+this.ttl:0)}catch(e){console.error("LocalStorage error: ",e);return false}}}class W{_connected=false;connectionType="";disconnectCode="";disconnectReason="";constructor(e){this.parent=e.parent;this.callbacks={onOpen:q.isFunction(e.onOpen)?e.onOpen:function(){},onDisconnect:q.isFunction(e.onDisconnect)?e.onDisconnect:function(){},onError:q.isFunction(e.onError)?e.onError:function(){},onMessage:q.isFunction(e.onMessage)?e.onMessage:function(){}}}get connected(){return this._connected}set connected(e){if(e==this._connected){return}this._connected=e;if(this._connected){this.callbacks.onOpen()}else{this.callbacks.onDisconnect({code:this.disconnectCode,reason:this.disconnectReason})}}get path(){return this.parent.getConnectionPath(this.connectionType)}}class A extends W{constructor(e){super(e);this.connectionType=u.WebSocket;this.socket=null;this.onSocketOpenHandler=this.onSocketOpen.bind(this);this.onSocketCloseHandler=this.onSocketClose.bind(this);this.onSocketErrorHandler=this.onSocketError.bind(this);this.onSocketMessageHandler=this.onSocketMessage.bind(this)}connect(){if(this.socket){if(this.socket.readyState===1){return true}else{this.socket.removeEventListener("open",this.onSocketOpenHandler);this.socket.removeEventListener("close",this.onSocketCloseHandler);this.socket.removeEventListener("error",this.onSocketErrorHandler);this.socket.removeEventListener("message",this.onSocketMessageHandler);this.socket.close();this.socket=null}}this.createSocket()}disconnect(e,t){if(this.socket!==null){this.socket.removeEventListener("open",this.onSocketOpenHandler);this.socket.removeEventListener("close",this.onSocketCloseHandler);this.socket.removeEventListener("error",this.onSocketErrorHandler);this.socket.removeEventListener("message",this.onSocketMessageHandler);this.socket.close(e,t)}this.socket=null;this.disconnectCode=e;this.disconnectReason=t;this.connected=false}createSocket(){if(this.socket){throw new Error("Socket already exists")}if(!this.path){throw new Error("Websocket connection path is not defined")}this.socket=new WebSocket(this.path);this.socket.binaryType="arraybuffer";this.socket.addEventListener("open",this.onSocketOpenHandler);this.socket.addEventListener("close",this.onSocketCloseHandler);this.socket.addEventListener("error",this.onSocketErrorHandler);this.socket.addEventListener("message",this.onSocketMessageHandler)}send(e){if(!this.socket||this.socket.readyState!==1){console.error(q.getDateForLog()+": Pull: WebSocket is not connected");return false}this.socket.send(e);return true}onSocketOpen(){this.connected=true}onSocketClose(e){this.socket=null;this.disconnectCode=e.code;this.disconnectReason=e.reason;this.connected=false}onSocketError(e){this.callbacks.onError(e)}onSocketMessage(e){this.callbacks.onMessage(e.data)}destroy(){if(this.socket){this.socket.close();this.socket=null}}}class N extends W{constructor(e){super(e);this.active=false;this.connectionType=u.LongPolling;this.requestTimeout=null;this.failureTimeout=null;this.xhr=this.createXhr();this.requestAborted=false}createXhr(){const e=new XMLHttpRequest;if(this.parent.isProtobufSupported()&&!this.parent.isJsonRpc()){e.responseType="arraybuffer"}e.addEventListener("readystatechange",this.onXhrReadyStateChange.bind(this));return e}connect(){this.active=true;this.performRequest()}disconnect(e,t){this.active=false;if(this.failureTimeout){clearTimeout(this.failureTimeout);this.failureTimeout=null}if(this.requestTimeout){clearTimeout(this.requestTimeout);this.requestTimeout=null}if(this.xhr){this.requestAborted=true;this.xhr.abort()}this.disconnectCode=e;this.disconnectReason=t;this.connected=false}performRequest(){if(!this.active){return}if(!this.path){throw new Error("Long polling connection path is not defined")}if(this.xhr.readyState!==0&&this.xhr.readyState!==4){return}clearTimeout(this.failureTimeout);clearTimeout(this.requestTimeout);this.failureTimeout=setTimeout((()=>{this.connected=true}),5e3);this.requestTimeout=setTimeout(this.onRequestTimeout.bind(this),n*1e3);this.xhr.open("GET",this.path);this.xhr.send()}onRequestTimeout(){this.requestAborted=true;this.xhr.abort();this.performRequest()}onXhrReadyStateChange(){if(this.xhr.readyState===4){if(!this.requestAborted||this.xhr.status==200){this.onResponse(this.xhr.response)}this.requestAborted=false}}send(e){const t=this.parent.getPublicationPath();if(!t){console.error(q.getDateForLog()+": Pull: publication path is empty");return false}let s=new XMLHttpRequest;s.open("POST",t);s.send(e)}onResponse(e){if(this.failureTimeout){clearTimeout(this.failureTimeout);this.failureTimeout=0}if(this.requestTimeout){clearTimeout(this.requestTimeout);this.requestTimeout=0}if(this.xhr.status==200){this.connected=true;if(q.isNotEmptyString(e)||e instanceof ArrayBuffer){this.callbacks.onMessage(e)}else{this.parent.session.mid=null}this.performRequest()}else if(this.xhr.status==304){this.connected=true;if(this.xhr.getResponseHeader("Expires")==="Thu, 01 Jan 1973 11:11:01 GMT"){const e=this.xhr.getResponseHeader("Last-Message-Id");if(q.isNotEmptyString(e)){this.parent.setLastMessageId(e)}}this.performRequest()}else{this.callbacks.onError("Could not connect to the server");this.connected=false}}}class j{constructor(t){this.publicIds={};this.restClient=typeof t.restClient!=="undefined"?t.restClient:e.rest;this.getPublicListMethod=t.getPublicListMethod}getPublicIds(e){const t=new Date;let s={};let n=[];for(let i=0;it){s[o]=this.publicIds[o]}else{n.push(o)}}if(n.length===0){return Promise.resolve(s)}return new Promise((e=>{this.restClient.callMethod(this.getPublicListMethod,{users:n}).then((t=>{if(t.error()){return e({})}const i=t.data();this.setPublicIds(q.objectValues(i));n.forEach((e=>{s[e]=this.publicIds[e]}));e(s)}))}))}setPublicIds(e){for(let t=0;t{const o=this.createRequest(e,t);if(!this.connector.send(JSON.stringify(o))){i(new F("websocket is not connected"))}const r=setTimeout((()=>{this.rpcResponseAwaiters.delete(o.id);i(new H("no response"))}),s*1e3);this.rpcResponseAwaiters.set(o.id,{resolve:n,reject:i,timeout:r})}))}executeOutgoingRpcBatch(e){let t=[];let s=[];e.forEach((({method:e,params:n,id:i})=>{const o=this.createRequest(e,n,i);t.push(o);s.push(new Promise(((e,t)=>this.rpcResponseAwaiters.set(o.id,{resolve:e,reject:t}))))}));this.connector.send(JSON.stringify(t));return s}processRpcResponse(e){if("id"in e&&this.rpcResponseAwaiters.has(e.id)){const t=this.rpcResponseAwaiters.get(e.id);if("result"in e){t.resolve(e.result)}else if("error"in e){t.reject(e.error)}else{t.reject(new Error("wrong response structure"))}clearTimeout(t.timeout);this.rpcResponseAwaiters.delete(e.id)}else{console.error("Received rpc response with unknown id",e)}}parseJsonRpcMessage(e){let t;try{t=JSON.parse(e)}catch(e){console.error(q.getDateForLog()+": Pull: Could not decode json rpc message",e)}if(q.isArray(t)){return this.executeIncomingRpcBatch(t)}else if(q.isJsonRpcRequest(t)){return this.executeIncomingRpcCommand(t)}else if(q.isJsonRpcResponse(t)){return this.processRpcResponse(t)}else{console.error(q.getDateForLog()+": Pull: unknown rpc packet",t)}}executeIncomingRpcCommand({method:e,params:t}){if(e in this.handlers){return this.handlers[e].call(this,t)}return{error:L.MethodNotFound}}executeIncomingRpcBatch(e){let t=[];for(let s of e){if("jsonrpc"in s){if("method"in s){let e=this.executeIncomingRpcCommand(s);if(e){e["jsonrpc"]=w;e["id"]=s["id"];t.push(e)}}else{this.processRpcResponse(s)}}else{console.error(q.getDateForLog()+": Pull: unknown rpc command in batch",s);t.push({jsonrpc:"2.0",error:L.InvalidRequest})}}return t}nextId(){return++this.idCounter}createPublishRequest(e){let t=e.map((e=>this.createRequest("publish",e)));if(t.length===0){return t[0]}return t}createRequest(e,t,s){if(!s){s=this.nextId()}return{jsonrpc:w,method:e,params:t,id:s}}}class F extends Error{constructor(e){super(e);this.name="ErrorNotConnected"}}class H extends Error{constructor(e){super(e);this.name="ErrorTimeout"}}const q={browser:{IsChrome:function(){return navigator.userAgent.toLowerCase().indexOf("chrome")!=-1},IsFirefox:function(){return navigator.userAgent.toLowerCase().indexOf("firefox")!=-1},IsIe:function(){return navigator.userAgent.match(/(Trident\/|MSIE\/)/)!==null}},getTimestamp:function(){return(new Date).getTime()},errorsToString:function(e){if(!this.isArray(e)){return""}else{return e.reduce((function(e,t){if(e!=""){e+="; "}return e+t.code+": "+t.message}),"")}},isString:function(e){return e===""?true:e?typeof e=="string"||e instanceof String:false},isArray:function(e){return e&&Object.prototype.toString.call(e)=="[object Array]"},isFunction:function(e){return e===null?false:typeof e=="function"||e instanceof Function},isDomNode:function(e){return e&&typeof e=="object"&&"nodeType"in e},isDate:function(e){return e&&Object.prototype.toString.call(e)=="[object Date]"},isPlainObject:function(e){if(!e||typeof e!=="object"||e.nodeType){return false}const t=Object.prototype.hasOwnProperty;try{if(e.constructor&&!t.call(e,"constructor")&&!t.call(e.constructor.prototype,"isPrototypeOf")){return false}}catch(e){return false}let s;for(s in e){}return typeof s==="undefined"||t.call(e,s)},isNotEmptyString:function(e){return this.isString(e)?e.length>0:false},isJsonRpcRequest:function(e){return typeof e==="object"&&e&&"jsonrpc"in e&&q.isNotEmptyString(e.jsonrpc)&&"method"in e&&q.isNotEmptyString(e.method)},isJsonRpcResponse:function(e){return typeof e==="object"&&e&&"jsonrpc"in e&&q.isNotEmptyString(e.jsonrpc)&&"id"in e&&("result"in e||"error"in e)},buildQueryString:function(e){let t="";for(let s in e){if(!e.hasOwnProperty(s)){continue}const n=e[s];if(q.isArray(n)){n.forEach(((e,n)=>{t+=encodeURIComponent(s+"["+n+"]")+"="+encodeURIComponent(e)+"&"}))}else{t+=encodeURIComponent(s)+"="+encodeURIComponent(n)+"&"}}if(t.length>0){t=t.substr(0,t.length-1)}return t},objectValues:function e(t){let s=[];for(let e in t){if(t.hasOwnProperty(e)&&t.propertyIsEnumerable(e)){s.push(t[e])}}return s},clone:function(e,t){let s,n,i;if(t!==false){t=true}if(e===null){return null}if(this.isDomNode(e)){s=e.cloneNode(t)}else if(typeof e=="object"){if(this.isArray(e)){s=[];for(n=0,i=e.length;nt){return e}let n="";for(let i=0;i