From 41daf6d1682d814f6ad9c4f71cfd2deb8d2da4b7 Mon Sep 17 00:00:00 2001 From: Kent Johnson Date: Tue, 30 Oct 2018 17:08:29 -0500 Subject: [PATCH] Changes --- Butterfly.Client.Web/lib/butterfly-client.js | 141 ++++++++------- .../lib/butterfly-client.js.map | 2 +- .../lib/butterfly-client.min.js | 2 +- .../lib/butterfly-client.min.js.map | 2 +- Butterfly.Client.Web/package-lock.json | 30 +--- Butterfly.Client.Web/package.json | 2 +- .../src/array-data-event-handler.js | 168 ++++++++++-------- Butterfly.Core/Database/BaseDatabase.cs | 2 +- Butterfly.Core/Util/WebClientWithTimeout.cs | 20 +++ .../TwilioPhoneTextNotifyMessageSender.cs | 20 +-- 10 files changed, 219 insertions(+), 170 deletions(-) create mode 100644 Butterfly.Core/Util/WebClientWithTimeout.cs diff --git a/Butterfly.Client.Web/lib/butterfly-client.js b/Butterfly.Client.Web/lib/butterfly-client.js index b4f3adfa..a9fe2f1e 100644 --- a/Butterfly.Client.Web/lib/butterfly-client.js +++ b/Butterfly.Client.Web/lib/butterfly-client.js @@ -115,6 +115,10 @@ function _default(config) { var _private = this; var keyFieldNamesByName = {}; + var batchSize = config.batchSize || 250; + var queue = []; + var queueCurrentOffset = 0; + var handleQueueTimeout = null; _private.getKeyValue = function (name, record) { var result = ''; @@ -129,74 +133,87 @@ function _default(config) { return result; }; + _private.handleDataEvent = function (dataEvent) { + //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue); + if (dataEvent.dataEventType === 'InitialEnd') { + if (config.onInitialEnd) config.onInitialEnd(); + } else { + var array = config.arrayMapping[dataEvent.name]; + + if (!array) { + console.error('No mapping for data event \'' + dataEvent.name + '\''); + } else if (dataEvent.dataEventType === 'InitialBegin') { + array.splice(0, array.length); + keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames; + } else if (dataEvent.dataEventType === 'Insert' || dataEvent.dataEventType === 'Initial') { + var keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); + + var index = array.findIndex(function (x) { + return x._keyValue == keyValue; + }); + + if (index >= 0) { + console.error('Duplicate key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); + } else { + dataEvent.record['_keyValue'] = keyValue; + array.splice(array.length, 0, dataEvent.record); + } + } else if (dataEvent.dataEventType === 'Update') { + var _keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); + + var _index = array.findIndex(function (x) { + return x._keyValue == _keyValue; + }); + + if (_index == -1) { + console.error('Could not find key \'' + _keyValue + '\' in table \'' + dataEvent.name + '\''); + } else { + dataEvent.record['_keyValue'] = _keyValue; + array.splice(_index, 1, dataEvent.record); + } + } else if (dataEvent.dataEventType === 'Delete') { + var _keyValue2 = _private.getKeyValue(dataEvent.name, dataEvent.record); + + var _index2 = array.findIndex(function (x) { + return x._keyValue == _keyValue2; + }); + + array.splice(_index2, 1); + } + } + }; + + _private.handleQueue = function () { + if (handleQueueTimeout) clearTimeout(handleQueueTimeout); + + if (queue.length > 0) { + var begin = queueCurrentOffset; + var end = Math.min(begin + batchSize, queue[0].length); + + for (var i = begin; i < end; i++) { + _private.handleDataEvent(queue[0][i]); + } + + if (end === queue[0].length) { + queue.splice(0, 1); + queueCurrentOffset = 0; + } else { + queueCurrentOffset += batchSize; + handleQueueTimeout = setTimeout(_private.handleQueue, 0); + } + } + }; + return function (messageType, data) { - if (messageType == 'RESET') { + if (messageType === 'RESET') { for (var arrayKey in config.arrayMapping) { var array = config.arrayMapping[arrayKey]; if (array) array.splice(0, array.length); } - } else if (messageType == 'DATA-EVENT-TRANSACTION') { - var dataEventTransaction = data; - - for (var i = 0; i < dataEventTransaction.dataEvents.length; i++) { - var dataEvent = dataEventTransaction.dataEvents[i]; //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue); + } else if (messageType === 'DATA-EVENT-TRANSACTION') { + queue.push(data.dataEvents); - if (dataEvent.dataEventType == 'InitialEnd') { - if (config.onInitialEnd) config.onInitialEnd(); - } else { - var _array = config.arrayMapping[dataEvent.name]; - - if (!_array) { - console.error('No mapping for data event \'' + dataEvent.name + '\''); - } else if (dataEvent.dataEventType == 'InitialBegin') { - _array.splice(0, _array.length); - - keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames; - } else if (dataEvent.dataEventType == 'Insert' || dataEvent.dataEventType == 'Initial') { - (function () { - var keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - - var index = _array.findIndex(function (x) { - return x._keyValue == keyValue; - }); - - if (index >= 0) { - console.error('Duplicate key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); - } else { - dataEvent.record['_keyValue'] = keyValue; - - _array.splice(_array.length, 0, dataEvent.record); - } - })(); - } else if (dataEvent.dataEventType == 'Update') { - (function () { - var keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - - var index = _array.findIndex(function (x) { - return x._keyValue == keyValue; - }); - - if (index == -1) { - console.error('Could not find key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); - } else { - dataEvent.record['_keyValue'] = keyValue; - - _array.splice(index, 1, dataEvent.record); - } - })(); - } else if (dataEvent.dataEventType == 'Delete') { - (function () { - var keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - - var index = _array.findIndex(function (x) { - return x._keyValue == keyValue; - }); - - _array.splice(index, 1); - })(); - } - } - } + _private.handleQueue(); } else if (config.onChannelMessage) { config.onChannelMessage(messageType, data); } diff --git a/Butterfly.Client.Web/lib/butterfly-client.js.map b/Butterfly.Client.Web/lib/butterfly-client.js.map index 7e322350..ae81f245 100644 --- a/Butterfly.Client.Web/lib/butterfly-client.js.map +++ b/Butterfly.Client.Web/lib/butterfly-client.js.map @@ -1 +1 @@ -{"version":3,"sources":["webpack://butterfly-client/webpack/universalModuleDefinition","webpack://butterfly-client/webpack/bootstrap","webpack://butterfly-client/./src/array-data-event-handler.js","webpack://butterfly-client/./src/index.js","webpack://butterfly-client/./src/vuex-array-getters.js","webpack://butterfly-client/./src/vuex-array-handler.js","webpack://butterfly-client/./src/vuex-array-mutations.js","webpack://butterfly-client/./src/web-socket-channel-client.js"],"names":["config","_private","keyFieldNamesByName","getKeyValue","name","record","result","keyFieldNames","i","length","value","messageType","data","arrayKey","arrayMapping","array","splice","dataEventTransaction","dataEvents","dataEvent","dataEventType","onInitialEnd","console","error","keyValue","index","findIndex","x","_keyValue","onChannelMessage","arrayName","state","callback","store","getters","start","deleteCount","item","commit","options","_options","url","indexOf","_url","window","location","protocol","host","_state","_stateTimeout","_auth","_subscriptionByChannelKey","debug","onStateChange","_clearStateTimeout","auth","_setState","_connecting","connectingStartMillis","Date","getTime","_webSocket","close","e","hasReconnected","reconnect","elapsedMillis","reconnectEveryMillis","wait","setTimeout","bind","WebSocket","onmessage","_onMessage","onopen","_authenticating","onerror","onclose","text","success","_sendText","authenticateEveryMillis","key","subscription","sent","push","channelKey","vars","JSON","stringify","_markSubscriptionsSent","_connected","_lastSendTextMillis","heartbeatEveryMillis","Math","max","handlers","clearTimeout","send","event","message","parse","_subscribing","disconnect","channel","Array","isArray","handler","_removeSubscription","_addSubscription","onSubscriptionsUpdated","_unsubscribing"],"mappings":"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","file":"butterfly-client.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"butterfly-client\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"butterfly-client\"] = factory();\n\telse\n\t\troot[\"butterfly-client\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/index.js\");\n","export default function(config) {\r\n\tlet _private = this;\r\n\r\n\tlet keyFieldNamesByName = {};\r\n\r\n\t_private.getKeyValue = function (name, record) {\r\n\t\tlet result = '';\r\n\t\tlet keyFieldNames = keyFieldNamesByName[name];\r\n\t\tfor (let i = 0; i < keyFieldNames.length; i++) {\r\n\t\t\tlet value = record[keyFieldNames[i]];\r\n\t\t\tif (!result && result.length > 0) result += ';';\r\n\t\t\tresult += '' + value;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\treturn function (messageType, data) {\r\n\t\tif (messageType == 'RESET') {\r\n\t\t\tfor (let arrayKey in config.arrayMapping) {\r\n\t\t\t\tlet array = config.arrayMapping[arrayKey];\r\n\t\t\t\tif (array) array.splice(0, array.length);\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (messageType == 'DATA-EVENT-TRANSACTION') {\r\n\t\t\tlet dataEventTransaction = data;\r\n\t\t\tfor (let i = 0; i < dataEventTransaction.dataEvents.length; i++) {\r\n\t\t\t\tlet dataEvent = dataEventTransaction.dataEvents[i];\r\n\t\t\t\t//console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue);\r\n\t\t\t\tif (dataEvent.dataEventType == 'InitialEnd') {\r\n\t\t\t\t\tif (config.onInitialEnd) config.onInitialEnd();\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tlet array = config.arrayMapping[dataEvent.name];\r\n\t\t\t\t\tif (!array) {\r\n\t\t\t\t\t\tconsole.error('No mapping for data event \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'InitialBegin') {\r\n\t\t\t\t\t\tarray.splice(0, array.length);\r\n\t\t\t\t\t\tkeyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Insert' || dataEvent.dataEventType == 'Initial') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tif (index >= 0) {\r\n\t\t\t\t\t\t\tconsole.error('Duplicate key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tdataEvent.record['_keyValue'] = keyValue;\r\n\t\t\t\t\t\t\tarray.splice(array.length, 0, dataEvent.record);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Update') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tif (index == -1) {\r\n\t\t\t\t\t\t\tconsole.error('Could not find key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tdataEvent.record['_keyValue'] = keyValue;\r\n\t\t\t\t\t\t\tarray.splice(index, 1, dataEvent.record);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Delete') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tarray.splice(index, 1);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (config.onChannelMessage) {\r\n\t\t\tconfig.onChannelMessage(messageType, data);\r\n\t\t}\r\n\t}\r\n}\r\n","import ArrayDataEventHandler from './array-data-event-handler.js';\nimport VuexArrayGetters from './vuex-array-getters.js';\nimport VuexArrayHandler from './vuex-array-handler.js';\nimport VuexArrayMutations from './vuex-array-mutations.js';\nimport WebSocketChannelClient from './web-socket-channel-client.js';\n\nexport {\n ArrayDataEventHandler,\n VuexArrayGetters,\n VuexArrayHandler,\n VuexArrayMutations,\n WebSocketChannelClient\r\n};\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Length`] = state => state[arrayName].length;\r\n\tresult[`${arrayName}FindIndex`] = state => callback => state[arrayName].findIndex(callback);\r\n\treturn result;\r\n}\r\n","export default function(store, arrayName) {\r\n\treturn {\r\n\t\tget length() { return store.getters[`${arrayName}Length`] },\r\n\t\tfindIndex(callback) { return store.getters[`${arrayName}FindIndex`](callback) },\r\n\t\tsplice(start, deleteCount, item) {\r\n\t\t\treturn store.commit(`${arrayName}Splice`, { start, deleteCount, item });\r\n\t\t},\r\n\t};\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Splice`] = (state, options) => {\r\n\t\tif (options.item) state[arrayName].splice(options.start, options.deleteCount, options.item);\r\n\t\telse state[arrayName].splice(options.start, options.deleteCount);\r\n\t};\r\n\treturn result;\r\n}\r\n","/*\n * States...\n * Disconnected - No WebSocket, no loop running\n * Connecting - Create WebSocket and wait for WebSocket.onopen()\n * Authenticating - Send Authentication and wait for server to send AUTHENTICATED or UNAUTHENTICATED\n * Subscribing - Send subscriptions and transition to Connected\n * Connected - Send heartbeats to server\n */\n\nexport default class {\r\n constructor(options) {\r\n this._options = options;\r\n\r\n let url = this._options.url;\n\r\n if (url.indexOf('://') === -1) {\r\n this._url = (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + window.location.host + url;\r\n }\r\n else {\r\n this._url = url;\r\n }\r\n\r\n this._state = 'Disconnected';\n this._stateTimeout = null;\r\n this._auth = null;\r\n this._subscriptionByChannelKey = {};\r\n }\r\n\r\n _setState(value) {\r\n if (this._state !== value) {\n console.debug(`_setState():value=${value}`);\r\n this._state = value;\r\n if (this._options.onStateChange) this._options.onStateChange(value);\r\n this._clearStateTimeout();\n }\r\n }\r\n\n connect(auth) {\r\n console.debug('WebSocketChannelClient.connect()');\r\n this._auth = auth;\n\r\n this._setState('Connecting');\n this._connecting();\r\n }\r\n\r\n _connecting() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Connecting');\n let connectingStartMillis = new Date().getTime();\n\n if (this._webSocket) {\n try {\n this._webSocket.close();\n }\n catch (e) { }\n this._webSocket = null;\r\n }\n\n let hasReconnected = false;\n let reconnect = error => {\n if (hasReconnected) return;\n hasReconnected = true;\n\n console.debug(`_connecting():reconnect():error=${error}`);\n let elapsedMillis = new Date().getTime() - connectingStartMillis;\n let reconnectEveryMillis = this._options.reconnectEveryMillis || 3000;\n\n if (elapsedMillis > reconnectEveryMillis) {\n this._connecting();\n }\n else {\n let wait = reconnectEveryMillis - elapsedMillis;\n\n this._stateTimeout = setTimeout(this._connecting.bind(this), wait);\r\n }\n };\n\r\n try {\r\n console.debug(`_connecting():new WebSocket(${this._url})`);\r\n this._webSocket = new WebSocket(this._url);\r\n this._webSocket.onmessage = this._onMessage.bind(this);\r\n this._webSocket.onopen = this._authenticating.bind(this);\n this._webSocket.onerror = reconnect.bind(this);\r\n this._webSocket.onclose = reconnect.bind(this);\r\n }\r\n catch (e) {\r\n reconnect(e);\r\n }\r\n }\n\n _authenticating() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Authenticating');\n let text = 'Authorization:' + (this._auth || '');\n let success = this._sendText(text);\n\n if (success) {\n let authenticateEveryMillis = this._options.authenticateEveryMillis || 3000;\n\n this._stateTimeout = setTimeout(this._authenticating.bind(this), authenticateEveryMillis);\n }\r\n }\n\n _subscribing() {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Subscribing');\n\n // Build data\n let data = [];\n\r\n for (let key in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[key];\n\r\n if (!subscription.sent) {\r\n data.push({\r\n channelKey: key,\r\n vars: subscription.vars,\r\n });\r\n }\r\n }\n\n // Subscribe\n let success = true;\n\r\n if (data.length > 0) {\r\n success = this._sendText('Subscribe:' + JSON.stringify(data));\r\n }\n\n if (success) {\n this._markSubscriptionsSent(true);\r\n this._connected();\n }\r\n }\r\n\n _unsubscribing(channelKey) {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Unsubscribing');\n let success = this._sendText('Unsubscribe:' + JSON.stringify(channelKey));\n\n if (success) {\n this._connected();\r\n }\r\n }\n\r\n _connected() {\n this._setState('Connected');\n\n let elapsedMillis = new Date().getTime() - this._lastSendTextMillis;\n let heartbeatEveryMillis = this._options.heartbeatEveryMillis || 3000;\n\n if (elapsedMillis >= heartbeatEveryMillis) {\n this._sendText('!');\n this._connected();\n }\n else {\n let wait = Math.max(0, heartbeatEveryMillis - elapsedMillis);\n\n this._stateTimeout = setTimeout(this._connected.bind(this), wait);\n }\r\n }\n\n disconnect() {\r\n console.debug('WebSocketChannelClient.disconnect()')\r\n this._setState('Disconnected');\r\n if (this._webSocket != null) {\n try {\r\n this._webSocket.close();\n }\n catch (e) { }\r\n this._webSocket = null;\r\n }\n this._clearStateTimeout();\n for (let channelKey in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i]('RESET');\r\n }\r\n }\r\n }\r\n }\r\n\n _clearStateTimeout() {\n if (this._stateTimeout) {\n clearTimeout(this._stateTimeout);\n this._stateTimeout = null;\n }\r\n }\r\n\n _sendText(text) {\n console.debug(`_sendText():text=${text}`);\n try {\n this._webSocket.send(text);\n this._lastSendTextMillis = new Date().getTime();\n return true;\n }\n catch (e) {\n console.error(e);\n this._connecting();\n return false;\r\n }\r\n }\n\n _onMessage(event) {\r\n let message = JSON.parse(event.data);\n\r\n console.debug(`_onMessage():message.messageType=${message.messageType}`);\r\n if (message.channelKey) {\r\n let subscription = this._subscriptionByChannelKey[message.channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i](message.messageType, message.data);\r\n }\r\n }\r\n }\r\n else if (message.messageType === 'AUTHENTICATED') {\n this._markSubscriptionsSent(false);\r\n this._subscribing();\r\n }\r\n else if (message.messageType === 'UNAUTHENTICATED') {\r\n this.disconnect();\r\n }\r\n }\r\n\n _markSubscriptionsSent(value) {\r\n for (let key in this._subscriptionByChannelKey) {\r\n this._subscriptionByChannelKey[key].sent = value;\r\n }\r\n }\r\n\n subscribe(options) {\r\n let channelKey = options.channel || 'default';\n let handlers = Array.isArray(options.handler) ? options.handler : [options.handler];\n let vars = options.vars;\n\r\n // console.debug(`WebSocketChannelClient.subscribe():channelKey=${channelKey}`);\r\n this._removeSubscription(channelKey);\r\n this._addSubscription(channelKey, {\r\n vars,\r\n handlers,\r\n sent: false\r\n });\n if (this._state === 'Connected') {\n this._subscribing();\n }\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n unsubscribe(channelKey) {\r\n // console.debug(`WebSocketChannelClient.unsubscribe():channelKey=${channelKey}`);\r\n if (!channelKey) channelKey = 'default';\r\n this._removeSubscription(channelKey);\r\n this._unsubscribing(channelKey);\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n _addSubscription(channelKey, subscription) {\r\n this._subscriptionByChannelKey[channelKey] = subscription;\r\n }\r\n\r\n _removeSubscription(channelKey) {\r\n delete this._subscriptionByChannelKey[channelKey];\r\n }\r\n\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://butterfly-client/webpack/universalModuleDefinition","webpack://butterfly-client/webpack/bootstrap","webpack://butterfly-client/./src/array-data-event-handler.js","webpack://butterfly-client/./src/index.js","webpack://butterfly-client/./src/vuex-array-getters.js","webpack://butterfly-client/./src/vuex-array-handler.js","webpack://butterfly-client/./src/vuex-array-mutations.js","webpack://butterfly-client/./src/web-socket-channel-client.js"],"names":["config","_private","keyFieldNamesByName","batchSize","queue","queueCurrentOffset","handleQueueTimeout","getKeyValue","name","record","result","keyFieldNames","i","length","value","handleDataEvent","dataEvent","dataEventType","onInitialEnd","array","arrayMapping","console","error","splice","keyValue","index","findIndex","x","_keyValue","handleQueue","clearTimeout","begin","end","Math","min","setTimeout","messageType","data","arrayKey","push","dataEvents","onChannelMessage","arrayName","state","callback","store","getters","start","deleteCount","item","commit","options","_options","url","indexOf","_url","window","location","protocol","host","_state","_stateTimeout","_auth","_subscriptionByChannelKey","debug","onStateChange","_clearStateTimeout","auth","_setState","_connecting","connectingStartMillis","Date","getTime","_webSocket","close","e","hasReconnected","reconnect","elapsedMillis","reconnectEveryMillis","wait","bind","WebSocket","onmessage","_onMessage","onopen","_authenticating","onerror","onclose","text","success","_sendText","authenticateEveryMillis","key","subscription","sent","channelKey","vars","JSON","stringify","_markSubscriptionsSent","_connected","_lastSendTextMillis","heartbeatEveryMillis","max","handlers","send","event","message","parse","_subscribing","disconnect","channel","Array","isArray","handler","_removeSubscription","_addSubscription","onSubscriptionsUpdated","_unsubscribing"],"mappings":"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","file":"butterfly-client.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"butterfly-client\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"butterfly-client\"] = factory();\n\telse\n\t\troot[\"butterfly-client\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = \"./src/index.js\");\n","export default function (config) {\r\n let _private = this;\r\n\r\n let keyFieldNamesByName = {};\r\n let batchSize = config.batchSize || 250;\n\n let queue = [];\n let queueCurrentOffset = 0;\n let handleQueueTimeout = null;\n\r\n _private.getKeyValue = function (name, record) {\r\n let result = '';\r\n let keyFieldNames = keyFieldNamesByName[name];\r\n for (let i = 0; i < keyFieldNames.length; i++) {\r\n let value = record[keyFieldNames[i]];\r\n if (!result && result.length > 0) result += ';';\r\n result += '' + value;\r\n }\r\n return result;\r\n }\r\n\n _private.handleDataEvent = function (dataEvent) {\n //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue);\r\n if (dataEvent.dataEventType === 'InitialEnd') {\r\n if (config.onInitialEnd) config.onInitialEnd();\r\n }\r\n else {\r\n let array = config.arrayMapping[dataEvent.name];\r\n if (!array) {\r\n console.error('No mapping for data event \\'' + dataEvent.name + '\\'');\r\n }\r\n else if (dataEvent.dataEventType === 'InitialBegin') {\r\n array.splice(0, array.length);\r\n keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames;\r\n }\r\n else if (dataEvent.dataEventType === 'Insert' || dataEvent.dataEventType === 'Initial') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n if (index >= 0) {\r\n console.error('Duplicate key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n }\r\n else {\r\n dataEvent.record['_keyValue'] = keyValue;\r\n array.splice(array.length, 0, dataEvent.record);\r\n }\r\n }\r\n else if (dataEvent.dataEventType === 'Update') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n if (index == -1) {\r\n console.error('Could not find key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n }\r\n else {\r\n dataEvent.record['_keyValue'] = keyValue;\r\n array.splice(index, 1, dataEvent.record);\r\n }\r\n }\r\n else if (dataEvent.dataEventType === 'Delete') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n array.splice(index, 1);\r\n }\r\n }\r\n };\n\n _private.handleQueue = function () {\n if (handleQueueTimeout) clearTimeout(handleQueueTimeout);\n\n if (queue.length > 0) {\n let begin = queueCurrentOffset;\n let end = Math.min(begin + batchSize, queue[0].length);\n for (let i = begin; i < end; i++) {\n _private.handleDataEvent(queue[0][i]);\r\n }\n if (end === queue[0].length) {\n queue.splice(0, 1);\n queueCurrentOffset = 0;\r\n }\n else {\n queueCurrentOffset += batchSize;\n handleQueueTimeout = setTimeout(_private.handleQueue, 0);\r\n }\n }\r\n }\n\r\n return function (messageType, data) {\r\n if (messageType === 'RESET') {\r\n for (let arrayKey in config.arrayMapping) {\r\n let array = config.arrayMapping[arrayKey];\r\n if (array) array.splice(0, array.length);\r\n }\r\n }\r\n else if (messageType === 'DATA-EVENT-TRANSACTION') {\r\n queue.push(data.dataEvents);\n _private.handleQueue();\r\n }\r\n else if (config.onChannelMessage) {\r\n config.onChannelMessage(messageType, data);\r\n }\r\n }\r\n}\r\n","import ArrayDataEventHandler from './array-data-event-handler.js';\nimport VuexArrayGetters from './vuex-array-getters.js';\nimport VuexArrayHandler from './vuex-array-handler.js';\nimport VuexArrayMutations from './vuex-array-mutations.js';\nimport WebSocketChannelClient from './web-socket-channel-client.js';\n\nexport {\n ArrayDataEventHandler,\n VuexArrayGetters,\n VuexArrayHandler,\n VuexArrayMutations,\n WebSocketChannelClient\r\n};\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Length`] = state => state[arrayName].length;\r\n\tresult[`${arrayName}FindIndex`] = state => callback => state[arrayName].findIndex(callback);\r\n\treturn result;\r\n}\r\n","export default function(store, arrayName) {\r\n\treturn {\r\n\t\tget length() { return store.getters[`${arrayName}Length`] },\r\n\t\tfindIndex(callback) { return store.getters[`${arrayName}FindIndex`](callback) },\r\n\t\tsplice(start, deleteCount, item) {\r\n\t\t\treturn store.commit(`${arrayName}Splice`, { start, deleteCount, item });\r\n\t\t},\r\n\t};\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Splice`] = (state, options) => {\r\n\t\tif (options.item) state[arrayName].splice(options.start, options.deleteCount, options.item);\r\n\t\telse state[arrayName].splice(options.start, options.deleteCount);\r\n\t};\r\n\treturn result;\r\n}\r\n","/*\n * States...\n * Disconnected - No WebSocket, no loop running\n * Connecting - Create WebSocket and wait for WebSocket.onopen()\n * Authenticating - Send Authentication and wait for server to send AUTHENTICATED or UNAUTHENTICATED\n * Subscribing - Send subscriptions and transition to Connected\n * Connected - Send heartbeats to server\n */\n\nexport default class {\r\n constructor(options) {\r\n this._options = options;\r\n\r\n let url = this._options.url;\n\r\n if (url.indexOf('://') === -1) {\r\n this._url = (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + window.location.host + url;\r\n }\r\n else {\r\n this._url = url;\r\n }\r\n\r\n this._state = 'Disconnected';\n this._stateTimeout = null;\r\n this._auth = null;\r\n this._subscriptionByChannelKey = {};\r\n }\r\n\r\n _setState(value) {\r\n if (this._state !== value) {\n console.debug(`_setState():value=${value}`);\r\n this._state = value;\r\n if (this._options.onStateChange) this._options.onStateChange(value);\r\n this._clearStateTimeout();\n }\r\n }\r\n\n connect(auth) {\r\n console.debug('WebSocketChannelClient.connect()');\r\n this._auth = auth;\n\r\n this._setState('Connecting');\n this._connecting();\r\n }\r\n\r\n _connecting() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Connecting');\n let connectingStartMillis = new Date().getTime();\n\n if (this._webSocket) {\n try {\n this._webSocket.close();\n }\n catch (e) { }\n this._webSocket = null;\r\n }\n\n let hasReconnected = false;\n let reconnect = error => {\n if (hasReconnected) return;\n hasReconnected = true;\n\n console.debug(`_connecting():reconnect():error=${error}`);\n let elapsedMillis = new Date().getTime() - connectingStartMillis;\n let reconnectEveryMillis = this._options.reconnectEveryMillis || 3000;\n\n if (elapsedMillis > reconnectEveryMillis) {\n this._connecting();\n }\n else {\n let wait = reconnectEveryMillis - elapsedMillis;\n\n this._stateTimeout = setTimeout(this._connecting.bind(this), wait);\r\n }\n };\n\r\n try {\r\n console.debug(`_connecting():new WebSocket(${this._url})`);\r\n this._webSocket = new WebSocket(this._url);\r\n this._webSocket.onmessage = this._onMessage.bind(this);\r\n this._webSocket.onopen = this._authenticating.bind(this);\n this._webSocket.onerror = reconnect.bind(this);\r\n this._webSocket.onclose = reconnect.bind(this);\r\n }\r\n catch (e) {\r\n reconnect(e);\r\n }\r\n }\n\n _authenticating() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Authenticating');\n let text = 'Authorization:' + (this._auth || '');\n let success = this._sendText(text);\n\n if (success) {\n let authenticateEveryMillis = this._options.authenticateEveryMillis || 3000;\n\n this._stateTimeout = setTimeout(this._authenticating.bind(this), authenticateEveryMillis);\n }\r\n }\n\n _subscribing() {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Subscribing');\n\n // Build data\n let data = [];\n\r\n for (let key in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[key];\n\r\n if (!subscription.sent) {\r\n data.push({\r\n channelKey: key,\r\n vars: subscription.vars,\r\n });\r\n }\r\n }\n\n // Subscribe\n let success = true;\n\r\n if (data.length > 0) {\r\n success = this._sendText('Subscribe:' + JSON.stringify(data));\r\n }\n\n if (success) {\n this._markSubscriptionsSent(true);\r\n this._connected();\n }\r\n }\r\n\n _unsubscribing(channelKey) {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Unsubscribing');\n let success = this._sendText('Unsubscribe:' + JSON.stringify(channelKey));\n\n if (success) {\n this._connected();\r\n }\r\n }\n\r\n _connected() {\n this._setState('Connected');\n\n let elapsedMillis = new Date().getTime() - this._lastSendTextMillis;\n let heartbeatEveryMillis = this._options.heartbeatEveryMillis || 3000;\n\n if (elapsedMillis >= heartbeatEveryMillis) {\n this._sendText('!');\n this._connected();\n }\n else {\n let wait = Math.max(0, heartbeatEveryMillis - elapsedMillis);\n\n this._stateTimeout = setTimeout(this._connected.bind(this), wait);\n }\r\n }\n\n disconnect() {\r\n console.debug('WebSocketChannelClient.disconnect()')\r\n this._setState('Disconnected');\r\n if (this._webSocket != null) {\n try {\r\n this._webSocket.close();\n }\n catch (e) { }\r\n this._webSocket = null;\r\n }\n this._clearStateTimeout();\n for (let channelKey in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i]('RESET');\r\n }\r\n }\r\n }\r\n }\r\n\n _clearStateTimeout() {\n if (this._stateTimeout) {\n clearTimeout(this._stateTimeout);\n this._stateTimeout = null;\n }\r\n }\r\n\n _sendText(text) {\n console.debug(`_sendText():text=${text}`);\n try {\n this._webSocket.send(text);\n this._lastSendTextMillis = new Date().getTime();\n return true;\n }\n catch (e) {\n console.error(e);\n this._connecting();\n return false;\r\n }\r\n }\n\n _onMessage(event) {\r\n let message = JSON.parse(event.data);\n\r\n console.debug(`_onMessage():message.messageType=${message.messageType}`);\r\n if (message.channelKey) {\r\n let subscription = this._subscriptionByChannelKey[message.channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i](message.messageType, message.data);\r\n }\r\n }\r\n }\r\n else if (message.messageType === 'AUTHENTICATED') {\n this._markSubscriptionsSent(false);\r\n this._subscribing();\r\n }\r\n else if (message.messageType === 'UNAUTHENTICATED') {\r\n this.disconnect();\r\n }\r\n }\r\n\n _markSubscriptionsSent(value) {\r\n for (let key in this._subscriptionByChannelKey) {\r\n this._subscriptionByChannelKey[key].sent = value;\r\n }\r\n }\r\n\n subscribe(options) {\r\n let channelKey = options.channel || 'default';\n let handlers = Array.isArray(options.handler) ? options.handler : [options.handler];\n let vars = options.vars;\n\r\n // console.debug(`WebSocketChannelClient.subscribe():channelKey=${channelKey}`);\r\n this._removeSubscription(channelKey);\r\n this._addSubscription(channelKey, {\r\n vars,\r\n handlers,\r\n sent: false\r\n });\n if (this._state === 'Connected') {\n this._subscribing();\n }\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n unsubscribe(channelKey) {\r\n // console.debug(`WebSocketChannelClient.unsubscribe():channelKey=${channelKey}`);\r\n if (!channelKey) channelKey = 'default';\r\n this._removeSubscription(channelKey);\r\n this._unsubscribing(channelKey);\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n _addSubscription(channelKey, subscription) {\r\n this._subscriptionByChannelKey[channelKey] = subscription;\r\n }\r\n\r\n _removeSubscription(channelKey) {\r\n delete this._subscriptionByChannelKey[channelKey];\r\n }\r\n\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/Butterfly.Client.Web/lib/butterfly-client.min.js b/Butterfly.Client.Web/lib/butterfly-client.min.js index 018ee66c..482c26d9 100644 --- a/Butterfly.Client.Web/lib/butterfly-client.min.js +++ b/Butterfly.Client.Web/lib/butterfly-client.min.js @@ -1,2 +1,2 @@ -!function(e,t){"object"==typeof exports&&"object"==typeof module?module.exports=t():"function"==typeof define&&define.amd?define("butterfly-client",[],t):"object"==typeof exports?exports["butterfly-client"]=t():e["butterfly-client"]=t()}(window,function(){return function(e){var t={};function n(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}return n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)n.d(i,s,function(t){return e[t]}.bind(null,s));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),Object.defineProperty(t,"ArrayDataEventHandler",{enumerable:!0,get:function(){return i.default}}),Object.defineProperty(t,"VuexArrayGetters",{enumerable:!0,get:function(){return s.default}}),Object.defineProperty(t,"VuexArrayHandler",{enumerable:!0,get:function(){return o.default}}),Object.defineProperty(t,"VuexArrayMutations",{enumerable:!0,get:function(){return r.default}}),Object.defineProperty(t,"WebSocketChannelClient",{enumerable:!0,get:function(){return a.default}});var i=c(n(1)),s=c(n(2)),o=c(n(3)),r=c(n(4)),a=c(n(5));function c(e){return e&&e.__esModule?e:{default:e}}},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t=this,n={};return t.getKeyValue=function(e,t){for(var i="",s=n[e],o=0;o0&&(i+=";"),i+=""+r}return i},function(i,s){if("RESET"==i)for(var o in e.arrayMapping){var r=e.arrayMapping[o];r&&r.splice(0,r.length)}else if("DATA-EVENT-TRANSACTION"==i)for(var a=s,c=0;c=0?console.error("Duplicate key '"+e+"' in table '"+u.name+"'"):(u.record._keyValue=e,l.splice(l.length,0,u.record))}():"Update"==u.dataEventType?function(){var e=t.getKeyValue(u.name,u.record),n=l.findIndex(function(t){return t._keyValue==e});-1==n?console.error("Could not find key '"+e+"' in table '"+u.name+"'"):(u.record._keyValue=e,l.splice(n,1,u.record))}():"Delete"==u.dataEventType&&function(){var e=t.getKeyValue(u.name,u.record),n=l.findIndex(function(t){return t._keyValue==e});l.splice(n,1)}():console.error("No mapping for data event '"+u.name+"'")}}else e.onChannelMessage&&e.onChannelMessage(i,s)}},e.exports=t.default},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t={};return t["".concat(e,"Length")]=function(t){return t[e].length},t["".concat(e,"FindIndex")]=function(t){return function(n){return t[e].findIndex(n)}},t},e.exports=t.default},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e,t){return{get length(){return e.getters["".concat(t,"Length")]},findIndex:function(n){return e.getters["".concat(t,"FindIndex")](n)},splice:function(n,i,s){return e.commit("".concat(t,"Splice"),{start:n,deleteCount:i,item:s})}}},e.exports=t.default},function(e,t,n){"use strict";Object.defineProperty(t,"__esModule",{value:!0}),t.default=function(e){var t={};return t["".concat(e,"Splice")]=function(t,n){n.item?t[e].splice(n.start,n.deleteCount,n.item):t[e].splice(n.start,n.deleteCount)},t},e.exports=t.default},function(e,t,n){"use strict";function i(e,t){for(var n=0;no)e._connecting();else{var r=o-s;e._stateTimeout=setTimeout(e._connecting.bind(e),r)}}};try{console.debug("_connecting():new WebSocket(".concat(this._url,")")),this._webSocket=new WebSocket(this._url),this._webSocket.onmessage=this._onMessage.bind(this),this._webSocket.onopen=this._authenticating.bind(this),this._webSocket.onerror=i.bind(this),this._webSocket.onclose=i.bind(this)}catch(e){i(e)}}}},{key:"_authenticating",value:function(){if("Disconnected"!==this._state){this._setState("Authenticating");var e="Authorization:"+(this._auth||"");if(this._sendText(e)){var t=this._options.authenticateEveryMillis||3e3;this._stateTimeout=setTimeout(this._authenticating.bind(this),t)}}}},{key:"_subscribing",value:function(){if("Disconnected"!==this._state){this._setState("Subscribing");var e=[];for(var t in this._subscriptionByChannelKey){var n=this._subscriptionByChannelKey[t];n.sent||e.push({channelKey:t,vars:n.vars})}var i=!0;e.length>0&&(i=this._sendText("Subscribe:"+JSON.stringify(e))),i&&(this._markSubscriptionsSent(!0),this._connected())}}},{key:"_unsubscribing",value:function(e){"Disconnected"!==this._state&&(this._setState("Unsubscribing"),this._sendText("Unsubscribe:"+JSON.stringify(e))&&this._connected())}},{key:"_connected",value:function(){this._setState("Connected");var e=(new Date).getTime()-this._lastSendTextMillis,t=this._options.heartbeatEveryMillis||3e3;if(e>=t)this._sendText("!"),this._connected();else{var n=Math.max(0,t-e);this._stateTimeout=setTimeout(this._connected.bind(this),n)}}},{key:"disconnect",value:function(){if(console.debug("WebSocketChannelClient.disconnect()"),this._setState("Disconnected"),null!=this._webSocket){try{this._webSocket.close()}catch(e){}this._webSocket=null}for(var e in this._clearStateTimeout(),this._subscriptionByChannelKey){var t=this._subscriptionByChannelKey[e];if(t.handlers)for(var n=0;n0&&(i+=";"),i+=""+r}return i},t.handleDataEvent=function(i){if("InitialEnd"===i.dataEventType)e.onInitialEnd&&e.onInitialEnd();else{var s=e.arrayMapping[i.name];if(s){if("InitialBegin"===i.dataEventType)s.splice(0,s.length),n[i.name]=i.keyFieldNames;else if("Insert"===i.dataEventType||"Initial"===i.dataEventType){var o=t.getKeyValue(i.name,i.record);s.findIndex(function(e){return e._keyValue==o})>=0?console.error("Duplicate key '"+o+"' in table '"+i.name+"'"):(i.record._keyValue=o,s.splice(s.length,0,i.record))}else if("Update"===i.dataEventType){var r=t.getKeyValue(i.name,i.record),a=s.findIndex(function(e){return e._keyValue==r});-1==a?console.error("Could not find key '"+r+"' in table '"+i.name+"'"):(i.record._keyValue=r,s.splice(a,1,i.record))}else if("Delete"===i.dataEventType){var c=t.getKeyValue(i.name,i.record),u=s.findIndex(function(e){return e._keyValue==c});s.splice(u,1)}}else console.error("No mapping for data event '"+i.name+"'")}},t.handleQueue=function(){if(r&&clearTimeout(r),s.length>0){for(var e=o,n=Math.min(e+i,s[0].length),a=e;ao)e._connecting();else{var r=o-s;e._stateTimeout=setTimeout(e._connecting.bind(e),r)}}};try{console.debug("_connecting():new WebSocket(".concat(this._url,")")),this._webSocket=new WebSocket(this._url),this._webSocket.onmessage=this._onMessage.bind(this),this._webSocket.onopen=this._authenticating.bind(this),this._webSocket.onerror=i.bind(this),this._webSocket.onclose=i.bind(this)}catch(e){i(e)}}}},{key:"_authenticating",value:function(){if("Disconnected"!==this._state){this._setState("Authenticating");var e="Authorization:"+(this._auth||"");if(this._sendText(e)){var t=this._options.authenticateEveryMillis||3e3;this._stateTimeout=setTimeout(this._authenticating.bind(this),t)}}}},{key:"_subscribing",value:function(){if("Disconnected"!==this._state){this._setState("Subscribing");var e=[];for(var t in this._subscriptionByChannelKey){var n=this._subscriptionByChannelKey[t];n.sent||e.push({channelKey:t,vars:n.vars})}var i=!0;e.length>0&&(i=this._sendText("Subscribe:"+JSON.stringify(e))),i&&(this._markSubscriptionsSent(!0),this._connected())}}},{key:"_unsubscribing",value:function(e){"Disconnected"!==this._state&&(this._setState("Unsubscribing"),this._sendText("Unsubscribe:"+JSON.stringify(e))&&this._connected())}},{key:"_connected",value:function(){this._setState("Connected");var e=(new Date).getTime()-this._lastSendTextMillis,t=this._options.heartbeatEveryMillis||3e3;if(e>=t)this._sendText("!"),this._connected();else{var n=Math.max(0,t-e);this._stateTimeout=setTimeout(this._connected.bind(this),n)}}},{key:"disconnect",value:function(){if(console.debug("WebSocketChannelClient.disconnect()"),this._setState("Disconnected"),null!=this._webSocket){try{this._webSocket.close()}catch(e){}this._webSocket=null}for(var e in this._clearStateTimeout(),this._subscriptionByChannelKey){var t=this._subscriptionByChannelKey[e];if(t.handlers)for(var n=0;n 0) result += ';';\r\n\t\t\tresult += '' + value;\r\n\t\t}\r\n\t\treturn result;\r\n\t}\r\n\r\n\treturn function (messageType, data) {\r\n\t\tif (messageType == 'RESET') {\r\n\t\t\tfor (let arrayKey in config.arrayMapping) {\r\n\t\t\t\tlet array = config.arrayMapping[arrayKey];\r\n\t\t\t\tif (array) array.splice(0, array.length);\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (messageType == 'DATA-EVENT-TRANSACTION') {\r\n\t\t\tlet dataEventTransaction = data;\r\n\t\t\tfor (let i = 0; i < dataEventTransaction.dataEvents.length; i++) {\r\n\t\t\t\tlet dataEvent = dataEventTransaction.dataEvents[i];\r\n\t\t\t\t//console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue);\r\n\t\t\t\tif (dataEvent.dataEventType == 'InitialEnd') {\r\n\t\t\t\t\tif (config.onInitialEnd) config.onInitialEnd();\r\n\t\t\t\t}\r\n\t\t\t\telse {\r\n\t\t\t\t\tlet array = config.arrayMapping[dataEvent.name];\r\n\t\t\t\t\tif (!array) {\r\n\t\t\t\t\t\tconsole.error('No mapping for data event \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'InitialBegin') {\r\n\t\t\t\t\t\tarray.splice(0, array.length);\r\n\t\t\t\t\t\tkeyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames;\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Insert' || dataEvent.dataEventType == 'Initial') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tif (index >= 0) {\r\n\t\t\t\t\t\t\tconsole.error('Duplicate key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tdataEvent.record['_keyValue'] = keyValue;\r\n\t\t\t\t\t\t\tarray.splice(array.length, 0, dataEvent.record);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Update') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tif (index == -1) {\r\n\t\t\t\t\t\t\tconsole.error('Could not find key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t\telse {\r\n\t\t\t\t\t\t\tdataEvent.record['_keyValue'] = keyValue;\r\n\t\t\t\t\t\t\tarray.splice(index, 1, dataEvent.record);\r\n\t\t\t\t\t\t}\r\n\t\t\t\t\t}\r\n\t\t\t\t\telse if (dataEvent.dataEventType == 'Delete') {\r\n\t\t\t\t\t\tlet keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n\t\t\t\t\t\tlet index = array.findIndex(x => x._keyValue == keyValue);\r\n\t\t\t\t\t\tarray.splice(index, 1);\r\n\t\t\t\t\t}\r\n\t\t\t\t}\r\n\t\t\t}\r\n\t\t}\r\n\t\telse if (config.onChannelMessage) {\r\n\t\t\tconfig.onChannelMessage(messageType, data);\r\n\t\t}\r\n\t}\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Length`] = state => state[arrayName].length;\r\n\tresult[`${arrayName}FindIndex`] = state => callback => state[arrayName].findIndex(callback);\r\n\treturn result;\r\n}\r\n","export default function(store, arrayName) {\r\n\treturn {\r\n\t\tget length() { return store.getters[`${arrayName}Length`] },\r\n\t\tfindIndex(callback) { return store.getters[`${arrayName}FindIndex`](callback) },\r\n\t\tsplice(start, deleteCount, item) {\r\n\t\t\treturn store.commit(`${arrayName}Splice`, { start, deleteCount, item });\r\n\t\t},\r\n\t};\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Splice`] = (state, options) => {\r\n\t\tif (options.item) state[arrayName].splice(options.start, options.deleteCount, options.item);\r\n\t\telse state[arrayName].splice(options.start, options.deleteCount);\r\n\t};\r\n\treturn result;\r\n}\r\n","/*\n * States...\n * Disconnected - No WebSocket, no loop running\n * Connecting - Create WebSocket and wait for WebSocket.onopen()\n * Authenticating - Send Authentication and wait for server to send AUTHENTICATED or UNAUTHENTICATED\n * Subscribing - Send subscriptions and transition to Connected\n * Connected - Send heartbeats to server\n */\n\nexport default class {\r\n constructor(options) {\r\n this._options = options;\r\n\r\n let url = this._options.url;\n\r\n if (url.indexOf('://') === -1) {\r\n this._url = (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + window.location.host + url;\r\n }\r\n else {\r\n this._url = url;\r\n }\r\n\r\n this._state = 'Disconnected';\n this._stateTimeout = null;\r\n this._auth = null;\r\n this._subscriptionByChannelKey = {};\r\n }\r\n\r\n _setState(value) {\r\n if (this._state !== value) {\n console.debug(`_setState():value=${value}`);\r\n this._state = value;\r\n if (this._options.onStateChange) this._options.onStateChange(value);\r\n this._clearStateTimeout();\n }\r\n }\r\n\n connect(auth) {\r\n console.debug('WebSocketChannelClient.connect()');\r\n this._auth = auth;\n\r\n this._setState('Connecting');\n this._connecting();\r\n }\r\n\r\n _connecting() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Connecting');\n let connectingStartMillis = new Date().getTime();\n\n if (this._webSocket) {\n try {\n this._webSocket.close();\n }\n catch (e) { }\n this._webSocket = null;\r\n }\n\n let hasReconnected = false;\n let reconnect = error => {\n if (hasReconnected) return;\n hasReconnected = true;\n\n console.debug(`_connecting():reconnect():error=${error}`);\n let elapsedMillis = new Date().getTime() - connectingStartMillis;\n let reconnectEveryMillis = this._options.reconnectEveryMillis || 3000;\n\n if (elapsedMillis > reconnectEveryMillis) {\n this._connecting();\n }\n else {\n let wait = reconnectEveryMillis - elapsedMillis;\n\n this._stateTimeout = setTimeout(this._connecting.bind(this), wait);\r\n }\n };\n\r\n try {\r\n console.debug(`_connecting():new WebSocket(${this._url})`);\r\n this._webSocket = new WebSocket(this._url);\r\n this._webSocket.onmessage = this._onMessage.bind(this);\r\n this._webSocket.onopen = this._authenticating.bind(this);\n this._webSocket.onerror = reconnect.bind(this);\r\n this._webSocket.onclose = reconnect.bind(this);\r\n }\r\n catch (e) {\r\n reconnect(e);\r\n }\r\n }\n\n _authenticating() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Authenticating');\n let text = 'Authorization:' + (this._auth || '');\n let success = this._sendText(text);\n\n if (success) {\n let authenticateEveryMillis = this._options.authenticateEveryMillis || 3000;\n\n this._stateTimeout = setTimeout(this._authenticating.bind(this), authenticateEveryMillis);\n }\r\n }\n\n _subscribing() {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Subscribing');\n\n // Build data\n let data = [];\n\r\n for (let key in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[key];\n\r\n if (!subscription.sent) {\r\n data.push({\r\n channelKey: key,\r\n vars: subscription.vars,\r\n });\r\n }\r\n }\n\n // Subscribe\n let success = true;\n\r\n if (data.length > 0) {\r\n success = this._sendText('Subscribe:' + JSON.stringify(data));\r\n }\n\n if (success) {\n this._markSubscriptionsSent(true);\r\n this._connected();\n }\r\n }\r\n\n _unsubscribing(channelKey) {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Unsubscribing');\n let success = this._sendText('Unsubscribe:' + JSON.stringify(channelKey));\n\n if (success) {\n this._connected();\r\n }\r\n }\n\r\n _connected() {\n this._setState('Connected');\n\n let elapsedMillis = new Date().getTime() - this._lastSendTextMillis;\n let heartbeatEveryMillis = this._options.heartbeatEveryMillis || 3000;\n\n if (elapsedMillis >= heartbeatEveryMillis) {\n this._sendText('!');\n this._connected();\n }\n else {\n let wait = Math.max(0, heartbeatEveryMillis - elapsedMillis);\n\n this._stateTimeout = setTimeout(this._connected.bind(this), wait);\n }\r\n }\n\n disconnect() {\r\n console.debug('WebSocketChannelClient.disconnect()')\r\n this._setState('Disconnected');\r\n if (this._webSocket != null) {\n try {\r\n this._webSocket.close();\n }\n catch (e) { }\r\n this._webSocket = null;\r\n }\n this._clearStateTimeout();\n for (let channelKey in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i]('RESET');\r\n }\r\n }\r\n }\r\n }\r\n\n _clearStateTimeout() {\n if (this._stateTimeout) {\n clearTimeout(this._stateTimeout);\n this._stateTimeout = null;\n }\r\n }\r\n\n _sendText(text) {\n console.debug(`_sendText():text=${text}`);\n try {\n this._webSocket.send(text);\n this._lastSendTextMillis = new Date().getTime();\n return true;\n }\n catch (e) {\n console.error(e);\n this._connecting();\n return false;\r\n }\r\n }\n\n _onMessage(event) {\r\n let message = JSON.parse(event.data);\n\r\n console.debug(`_onMessage():message.messageType=${message.messageType}`);\r\n if (message.channelKey) {\r\n let subscription = this._subscriptionByChannelKey[message.channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i](message.messageType, message.data);\r\n }\r\n }\r\n }\r\n else if (message.messageType === 'AUTHENTICATED') {\n this._markSubscriptionsSent(false);\r\n this._subscribing();\r\n }\r\n else if (message.messageType === 'UNAUTHENTICATED') {\r\n this.disconnect();\r\n }\r\n }\r\n\n _markSubscriptionsSent(value) {\r\n for (let key in this._subscriptionByChannelKey) {\r\n this._subscriptionByChannelKey[key].sent = value;\r\n }\r\n }\r\n\n subscribe(options) {\r\n let channelKey = options.channel || 'default';\n let handlers = Array.isArray(options.handler) ? options.handler : [options.handler];\n let vars = options.vars;\n\r\n // console.debug(`WebSocketChannelClient.subscribe():channelKey=${channelKey}`);\r\n this._removeSubscription(channelKey);\r\n this._addSubscription(channelKey, {\r\n vars,\r\n handlers,\r\n sent: false\r\n });\n if (this._state === 'Connected') {\n this._subscribing();\n }\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n unsubscribe(channelKey) {\r\n // console.debug(`WebSocketChannelClient.unsubscribe():channelKey=${channelKey}`);\r\n if (!channelKey) channelKey = 'default';\r\n this._removeSubscription(channelKey);\r\n this._unsubscribing(channelKey);\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n _addSubscription(channelKey, subscription) {\r\n this._subscriptionByChannelKey[channelKey] = subscription;\r\n }\r\n\r\n _removeSubscription(channelKey) {\r\n delete this._subscriptionByChannelKey[channelKey];\r\n }\r\n\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file +{"version":3,"sources":["webpack://butterfly-client/webpack/universalModuleDefinition","webpack://butterfly-client/webpack/bootstrap","webpack://butterfly-client/./src/index.js","webpack://butterfly-client/./src/array-data-event-handler.js","webpack://butterfly-client/./src/vuex-array-getters.js","webpack://butterfly-client/./src/vuex-array-handler.js","webpack://butterfly-client/./src/vuex-array-mutations.js","webpack://butterfly-client/./src/web-socket-channel-client.js"],"names":["root","factory","exports","module","define","amd","window","installedModules","__webpack_require__","moduleId","i","l","modules","call","m","c","d","name","getter","o","Object","defineProperty","enumerable","get","r","Symbol","toStringTag","value","t","mode","__esModule","ns","create","key","bind","n","object","property","prototype","hasOwnProperty","p","s","_arrayDataEventHandler","_interopRequireDefault","_vuexArrayGetters","_vuexArrayHandler","_vuexArrayMutations","_webSocketChannelClient","config","_private","this","keyFieldNamesByName","batchSize","queue","queueCurrentOffset","handleQueueTimeout","getKeyValue","record","result","keyFieldNames","length","handleDataEvent","dataEvent","dataEventType","onInitialEnd","array","arrayMapping","splice","keyValue","findIndex","x","_keyValue","console","error","index","handleQueue","clearTimeout","begin","end","Math","min","setTimeout","messageType","data","arrayKey","push","dataEvents","onChannelMessage","arrayName","concat","state","callback","store","getters","start","deleteCount","item","commit","options","_class","_classCallCheck","_options","url","indexOf","_url","location","protocol","host","_state","_stateTimeout","_auth","_subscriptionByChannelKey","debug","onStateChange","_clearStateTimeout","auth","_setState","_connecting","_this","connectingStartMillis","Date","getTime","_webSocket","close","e","hasReconnected","reconnect","elapsedMillis","reconnectEveryMillis","wait","WebSocket","onmessage","_onMessage","onopen","_authenticating","onerror","onclose","text","_sendText","authenticateEveryMillis","subscription","sent","channelKey","vars","success","JSON","stringify","_markSubscriptionsSent","_connected","_lastSendTextMillis","heartbeatEveryMillis","max","handlers","send","event","message","parse","_subscribing","disconnect","channel","Array","isArray","handler","_removeSubscription","_addSubscription","onSubscriptionsUpdated","_unsubscribing"],"mappings":"CAAA,SAAAA,EAAAC,GACA,iBAAAC,SAAA,iBAAAC,OACAA,OAAAD,QAAAD,IACA,mBAAAG,eAAAC,IACAD,OAAA,sBAAAH,GACA,iBAAAC,QACAA,QAAA,oBAAAD,IAEAD,EAAA,oBAAAC,IARA,CASCK,OAAA,WACD,mBCTA,IAAAC,KAGA,SAAAC,EAAAC,GAGA,GAAAF,EAAAE,GACA,OAAAF,EAAAE,GAAAP,QAGA,IAAAC,EAAAI,EAAAE,IACAC,EAAAD,EACAE,GAAA,EACAT,YAUA,OANAU,EAAAH,GAAAI,KAAAV,EAAAD,QAAAC,IAAAD,QAAAM,GAGAL,EAAAQ,GAAA,EAGAR,EAAAD,QA0DA,OArDAM,EAAAM,EAAAF,EAGAJ,EAAAO,EAAAR,EAGAC,EAAAQ,EAAA,SAAAd,EAAAe,EAAAC,GACAV,EAAAW,EAAAjB,EAAAe,IACAG,OAAAC,eAAAnB,EAAAe,GAA0CK,YAAA,EAAAC,IAAAL,KAK1CV,EAAAgB,EAAA,SAAAtB,GACA,oBAAAuB,eAAAC,aACAN,OAAAC,eAAAnB,EAAAuB,OAAAC,aAAwDC,MAAA,WAExDP,OAAAC,eAAAnB,EAAA,cAAiDyB,OAAA,KAQjDnB,EAAAoB,EAAA,SAAAD,EAAAE,GAEA,GADA,EAAAA,IAAAF,EAAAnB,EAAAmB,IACA,EAAAE,EAAA,OAAAF,EACA,KAAAE,GAAA,iBAAAF,QAAAG,WAAA,OAAAH,EACA,IAAAI,EAAAX,OAAAY,OAAA,MAGA,GAFAxB,EAAAgB,EAAAO,GACAX,OAAAC,eAAAU,EAAA,WAAyCT,YAAA,EAAAK,UACzC,EAAAE,GAAA,iBAAAF,EAAA,QAAAM,KAAAN,EAAAnB,EAAAQ,EAAAe,EAAAE,EAAA,SAAAA,GAAgH,OAAAN,EAAAM,IAAqBC,KAAA,KAAAD,IACrI,OAAAF,GAIAvB,EAAA2B,EAAA,SAAAhC,GACA,IAAAe,EAAAf,KAAA2B,WACA,WAA2B,OAAA3B,EAAA,SAC3B,WAAiC,OAAAA,GAEjC,OADAK,EAAAQ,EAAAE,EAAA,IAAAA,GACAA,GAIAV,EAAAW,EAAA,SAAAiB,EAAAC,GAAsD,OAAAjB,OAAAkB,UAAAC,eAAA1B,KAAAuB,EAAAC,IAGtD7B,EAAAgC,EAAA,GAIAhC,IAAAiC,EAAA,ijBClFA,IAAAC,EAAAC,EAAAnC,EAAA,IACAoC,EAAAD,EAAAnC,EAAA,IACAqC,EAAAF,EAAAnC,EAAA,IACAsC,EAAAH,EAAAnC,EAAA,IACAuC,EAAAJ,EAAAnC,EAAA,iJCJe,SAAUwC,GACvB,IAAIC,EAAWC,KAEXC,KACAC,EAAYJ,EAAOI,WAAa,IAEhCC,KACAC,EAAqB,EACrBC,EAAqB,KA6EzB,OA3EAN,EAASO,YAAc,SAAUvC,EAAMwC,GAGrC,IAFA,IAAIC,EAAS,GACTC,EAAgBR,EAAoBlC,GAC/BP,EAAI,EAAGA,EAAIiD,EAAcC,OAAQlD,IAAK,CAC7C,IAAIiB,EAAQ8B,EAAOE,EAAcjD,KAC5BgD,GAAUA,EAAOE,OAAS,IAAGF,GAAU,KAC5CA,GAAU,GAAK/B,EAEjB,OAAO+B,GAGTT,EAASY,gBAAkB,SAAUC,GAEnC,GAAgC,eAA5BA,EAAUC,cACRf,EAAOgB,cAAchB,EAAOgB,mBAE7B,CACH,IAAIC,EAAQjB,EAAOkB,aAAaJ,EAAU7C,MAC1C,GAAKgD,GAGA,GAAgC,iBAA5BH,EAAUC,cACjBE,EAAME,OAAO,EAAGF,EAAML,QACtBT,EAAoBW,EAAU7C,MAAQ6C,EAAUH,mBAE7C,GAAgC,WAA5BG,EAAUC,eAA0D,YAA5BD,EAAUC,cAA6B,CACtF,IAAIK,EAAWnB,EAASO,YAAYM,EAAU7C,KAAM6C,EAAUL,QAClDQ,EAAMI,UAAU,SAAAC,GAAC,OAAIA,EAAEC,WAAaH,KACnC,EACXI,QAAQC,MAAM,kBAAqBL,EAAW,eAAmBN,EAAU7C,KAAO,MAGlF6C,EAAUL,OAAV,UAAgCW,EAChCH,EAAME,OAAOF,EAAML,OAAQ,EAAGE,EAAUL,cAGvC,GAAgC,WAA5BK,EAAUC,cAA4B,CAC7C,IAAIK,EAAWnB,EAASO,YAAYM,EAAU7C,KAAM6C,EAAUL,QAC1DiB,EAAQT,EAAMI,UAAU,SAAAC,GAAC,OAAIA,EAAEC,WAAaH,KAClC,GAAVM,EACFF,QAAQC,MAAM,uBAA0BL,EAAW,eAAmBN,EAAU7C,KAAO,MAGvF6C,EAAUL,OAAV,UAAgCW,EAChCH,EAAME,OAAOO,EAAO,EAAGZ,EAAUL,cAGhC,GAAgC,WAA5BK,EAAUC,cAA4B,CAC7C,IAAIK,EAAWnB,EAASO,YAAYM,EAAU7C,KAAM6C,EAAUL,QAC1DiB,EAAQT,EAAMI,UAAU,SAAAC,GAAC,OAAIA,EAAEC,WAAaH,IAChDH,EAAME,OAAOO,EAAO,SA/BpBF,QAAQC,MAAM,8BAAiCX,EAAU7C,KAAO,OAoCtEgC,EAAS0B,YAAc,WAGrB,GAFIpB,GAAoBqB,aAAarB,GAEjCF,EAAMO,OAAS,EAAG,CAGpB,IAFA,IAAIiB,EAAQvB,EACRwB,EAAMC,KAAKC,IAAIH,EAAQzB,EAAWC,EAAM,GAAGO,QACtClD,EAAImE,EAAOnE,EAAIoE,EAAKpE,IAC3BuC,EAASY,gBAAgBR,EAAM,GAAG3C,IAEhCoE,IAAQzB,EAAM,GAAGO,QACnBP,EAAMc,OAAO,EAAG,GAChBb,EAAqB,IAGrBA,GAAsBF,EACtBG,EAAqB0B,WAAWhC,EAAS0B,YAAa,MAKrD,SAAUO,EAAaC,GAC5B,GAAoB,UAAhBD,EACF,IAAK,IAAIE,KAAYpC,EAAOkB,aAAc,CACxC,IAAID,EAAQjB,EAAOkB,aAAakB,GAC5BnB,GAAOA,EAAME,OAAO,EAAGF,EAAML,YAGZ,2BAAhBsB,GACP7B,EAAMgC,KAAKF,EAAKG,YAChBrC,EAAS0B,eAEF3B,EAAOuC,kBACdvC,EAAOuC,iBAAiBL,EAAaC,kHCjG5B,SAASK,GACvB,IAAI9B,KAGJ,OAFAA,EAAM,GAAA+B,OAAID,EAAJ,WAAyB,SAAAE,GAAK,OAAIA,EAAMF,GAAW5B,QACzDF,EAAM,GAAA+B,OAAID,EAAJ,cAA4B,SAAAE,GAAK,OAAI,SAAAC,GAAQ,OAAID,EAAMF,GAAWnB,UAAUsB,KAC3EjC,gHCJO,SAASkC,EAAOJ,GAC9B,OACC5B,aAAe,OAAOgC,EAAMC,QAAN,GAAAJ,OAAiBD,EAAjB,YACtBnB,UAFM,SAEIsB,GAAY,OAAOC,EAAMC,QAAN,GAAAJ,OAAiBD,EAAjB,cAAuCG,IACpExB,OAHM,SAGC2B,EAAOC,EAAaC,GAC1B,OAAOJ,EAAMK,OAAN,GAAAR,OAAgBD,EAAhB,WAAqCM,QAAOC,cAAaC,yHCLpD,SAASR,GACvB,IAAI9B,KAKJ,OAJAA,EAAM,GAAA+B,OAAID,EAAJ,WAAyB,SAACE,EAAOQ,GAClCA,EAAQF,KAAMN,EAAMF,GAAWrB,OAAO+B,EAAQJ,MAAOI,EAAQH,YAAaG,EAAQF,MACjFN,EAAMF,GAAWrB,OAAO+B,EAAQJ,MAAOI,EAAQH,cAE9CrC,8SCIN,SAAAyC,EAAYD,gGAASE,CAAAlD,KAAAiD,GACnBjD,KAAKmD,SAAWH,EAEhB,IAAII,EAAMpD,KAAKmD,SAASC,KAEI,IAAxBA,EAAIC,QAAQ,OACdrD,KAAKsD,MAAqC,WAA7BlG,OAAOmG,SAASC,SAAwB,OAAS,OAAS,KAAOpG,OAAOmG,SAASE,KAAOL,EAGrGpD,KAAKsD,KAAOF,EAGdpD,KAAK0D,OAAS,eACd1D,KAAK2D,cAAgB,KACrB3D,KAAK4D,MAAQ,KACb5D,KAAK6D,sHAGGpF,GACJuB,KAAK0D,SAAWjF,IAClB6C,QAAQwC,MAAR,qBAAAvB,OAAmC9D,IACnCuB,KAAK0D,OAASjF,EACVuB,KAAKmD,SAASY,eAAe/D,KAAKmD,SAASY,cAActF,GAC7DuB,KAAKgE,sDAIDC,GACN3C,QAAQwC,MAAM,oCACd9D,KAAK4D,MAAQK,EAEbjE,KAAKkE,UAAU,cACflE,KAAKmE,oDAGO,IAAAC,EAAApE,KACZ,GAAoB,iBAAhBA,KAAK0D,OAAT,CAEA1D,KAAKkE,UAAU,cACf,IAAIG,GAAwB,IAAIC,MAAOC,UAEvC,GAAIvE,KAAKwE,WAAY,CACnB,IACExE,KAAKwE,WAAWC,QAElB,MAAOC,IACP1E,KAAKwE,WAAa,KAGpB,IAAIG,GAAiB,EACjBC,EAAY,SAAArD,GACd,IAAIoD,EAAJ,CACAA,GAAiB,EAEjBrD,QAAQwC,MAAR,mCAAAvB,OAAiDhB,IACjD,IAAIsD,GAAgB,IAAIP,MAAOC,UAAYF,EACvCS,EAAuBV,EAAKjB,SAAS2B,sBAAwB,IAEjE,GAAID,EAAgBC,EAClBV,EAAKD,kBAEF,CACH,IAAIY,EAAOD,EAAuBD,EAElCT,EAAKT,cAAgB5B,WAAWqC,EAAKD,YAAYnF,KAAKoF,GAAOW,MAIjE,IACEzD,QAAQwC,MAAR,+BAAAvB,OAA6CvC,KAAKsD,KAAlD,MACAtD,KAAKwE,WAAa,IAAIQ,UAAUhF,KAAKsD,MACrCtD,KAAKwE,WAAWS,UAAYjF,KAAKkF,WAAWlG,KAAKgB,MACjDA,KAAKwE,WAAWW,OAASnF,KAAKoF,gBAAgBpG,KAAKgB,MACnDA,KAAKwE,WAAWa,QAAUT,EAAU5F,KAAKgB,MACzCA,KAAKwE,WAAWc,QAAUV,EAAU5F,KAAKgB,MAE3C,MAAO0E,GACLE,EAAUF,+CAKZ,GAAoB,iBAAhB1E,KAAK0D,OAAT,CAEA1D,KAAKkE,UAAU,kBACf,IAAIqB,EAAO,kBAAoBvF,KAAK4D,OAAS,IAG7C,GAFc5D,KAAKwF,UAAUD,GAEhB,CACX,IAAIE,EAA0BzF,KAAKmD,SAASsC,yBAA2B,IAEvEzF,KAAK2D,cAAgB5B,WAAW/B,KAAKoF,gBAAgBpG,KAAKgB,MAAOyF,4CAKnE,GAAoB,iBAAhBzF,KAAK0D,OAAT,CAEA1D,KAAKkE,UAAU,eAGf,IAAIjC,KAEJ,IAAK,IAAIlD,KAAOiB,KAAK6D,0BAA2B,CAC9C,IAAI6B,EAAe1F,KAAK6D,0BAA0B9E,GAE7C2G,EAAaC,MAChB1D,EAAKE,MACHyD,WAAY7G,EACZ8G,KAAMH,EAAaG,OAMzB,IAAIC,GAAU,EAEV7D,EAAKvB,OAAS,IAChBoF,EAAU9F,KAAKwF,UAAU,aAAeO,KAAKC,UAAU/D,KAGrD6D,IACF9F,KAAKiG,wBAAuB,GAC5BjG,KAAKkG,sDAIMN,GACO,iBAAhB5F,KAAK0D,SAET1D,KAAKkE,UAAU,iBACDlE,KAAKwF,UAAU,eAAiBO,KAAKC,UAAUJ,KAG3D5F,KAAKkG,mDAKPlG,KAAKkE,UAAU,aAEf,IAAIW,GAAgB,IAAIP,MAAOC,UAAYvE,KAAKmG,oBAC5CC,EAAuBpG,KAAKmD,SAASiD,sBAAwB,IAEjE,GAAIvB,GAAiBuB,EACnBpG,KAAKwF,UAAU,KACfxF,KAAKkG,iBAEF,CACH,IAAInB,EAAOlD,KAAKwE,IAAI,EAAGD,EAAuBvB,GAE9C7E,KAAK2D,cAAgB5B,WAAW/B,KAAKkG,WAAWlH,KAAKgB,MAAO+E,yCAO9D,GAFAzD,QAAQwC,MAAM,uCACd9D,KAAKkE,UAAU,gBACQ,MAAnBlE,KAAKwE,WAAoB,CAC3B,IACExE,KAAKwE,WAAWC,QAElB,MAAOC,IACP1E,KAAKwE,WAAa,KAGpB,IAAK,IAAIoB,KADT5F,KAAKgE,qBACkBhE,KAAK6D,0BAA2B,CACrD,IAAI6B,EAAe1F,KAAK6D,0BAA0B+B,GAElD,GAAIF,EAAaY,SACf,IAAK,IAAI9I,EAAI,EAAGA,EAAIkI,EAAaY,SAAS5F,OAAQlD,IAChDkI,EAAaY,SAAS9I,GAAG,uDAO3BwC,KAAK2D,gBACPjC,aAAa1B,KAAK2D,eAClB3D,KAAK2D,cAAgB,wCAIf4B,GACRjE,QAAQwC,MAAR,oBAAAvB,OAAkCgD,IAClC,IAGE,OAFAvF,KAAKwE,WAAW+B,KAAKhB,GACrBvF,KAAKmG,qBAAsB,IAAI7B,MAAOC,WAC/B,EAET,MAAOG,GAGL,OAFApD,QAAQC,MAAMmD,GACd1E,KAAKmE,eACE,sCAIAqC,GACT,IAAIC,EAAUV,KAAKW,MAAMF,EAAMvE,MAG/B,GADAX,QAAQwC,MAAR,oCAAAvB,OAAkDkE,EAAQzE,cACtDyE,EAAQb,WAAY,CACtB,IAAIF,EAAe1F,KAAK6D,0BAA0B4C,EAAQb,YAE1D,GAAIF,EAAaY,SACf,IAAK,IAAI9I,EAAI,EAAGA,EAAIkI,EAAaY,SAAS5F,OAAQlD,IAChDkI,EAAaY,SAAS9I,GAAGiJ,EAAQzE,YAAayE,EAAQxE,UAI3B,kBAAxBwE,EAAQzE,aACfhC,KAAKiG,wBAAuB,GAC5BjG,KAAK2G,gBAE0B,oBAAxBF,EAAQzE,aACfhC,KAAK4G,4DAIcnI,GACrB,IAAK,IAAIM,KAAOiB,KAAK6D,0BACnB7D,KAAK6D,0BAA0B9E,GAAK4G,KAAOlH,oCAIrCuE,GACR,IAAI4C,EAAa5C,EAAQ6D,SAAW,UAChCP,EAAWQ,MAAMC,QAAQ/D,EAAQgE,SAAWhE,EAAQgE,SAAWhE,EAAQgE,SACvEnB,EAAO7C,EAAQ6C,KAGnB7F,KAAKiH,oBAAoBrB,GACzB5F,KAAKkH,iBAAiBtB,GACpBC,OACAS,WACAX,MAAM,IAEY,cAAhB3F,KAAK0D,QACP1D,KAAK2G,eAEH3G,KAAKmD,SAASgE,wBAAwBnH,KAAKmD,SAASgE,6DAG9CvB,GAELA,IAAYA,EAAa,WAC9B5F,KAAKiH,oBAAoBrB,GACzB5F,KAAKoH,eAAexB,GAChB5F,KAAKmD,SAASgE,wBAAwBnH,KAAKmD,SAASgE,kEAGzCvB,EAAYF,GAC3B1F,KAAK6D,0BAA0B+B,GAAcF,8CAG3BE,UACX5F,KAAK6D,0BAA0B+B","file":"butterfly-client.min.js","sourcesContent":["(function webpackUniversalModuleDefinition(root, factory) {\n\tif(typeof exports === 'object' && typeof module === 'object')\n\t\tmodule.exports = factory();\n\telse if(typeof define === 'function' && define.amd)\n\t\tdefine(\"butterfly-client\", [], factory);\n\telse if(typeof exports === 'object')\n\t\texports[\"butterfly-client\"] = factory();\n\telse\n\t\troot[\"butterfly-client\"] = factory();\n})(window, function() {\nreturn "," \t// The module cache\n \tvar installedModules = {};\n\n \t// The require function\n \tfunction __webpack_require__(moduleId) {\n\n \t\t// Check if module is in cache\n \t\tif(installedModules[moduleId]) {\n \t\t\treturn installedModules[moduleId].exports;\n \t\t}\n \t\t// Create a new module (and put it into the cache)\n \t\tvar module = installedModules[moduleId] = {\n \t\t\ti: moduleId,\n \t\t\tl: false,\n \t\t\texports: {}\n \t\t};\n\n \t\t// Execute the module function\n \t\tmodules[moduleId].call(module.exports, module, module.exports, __webpack_require__);\n\n \t\t// Flag the module as loaded\n \t\tmodule.l = true;\n\n \t\t// Return the exports of the module\n \t\treturn module.exports;\n \t}\n\n\n \t// expose the modules object (__webpack_modules__)\n \t__webpack_require__.m = modules;\n\n \t// expose the module cache\n \t__webpack_require__.c = installedModules;\n\n \t// define getter function for harmony exports\n \t__webpack_require__.d = function(exports, name, getter) {\n \t\tif(!__webpack_require__.o(exports, name)) {\n \t\t\tObject.defineProperty(exports, name, { enumerable: true, get: getter });\n \t\t}\n \t};\n\n \t// define __esModule on exports\n \t__webpack_require__.r = function(exports) {\n \t\tif(typeof Symbol !== 'undefined' && Symbol.toStringTag) {\n \t\t\tObject.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });\n \t\t}\n \t\tObject.defineProperty(exports, '__esModule', { value: true });\n \t};\n\n \t// create a fake namespace object\n \t// mode & 1: value is a module id, require it\n \t// mode & 2: merge all properties of value into the ns\n \t// mode & 4: return value when already ns object\n \t// mode & 8|1: behave like require\n \t__webpack_require__.t = function(value, mode) {\n \t\tif(mode & 1) value = __webpack_require__(value);\n \t\tif(mode & 8) return value;\n \t\tif((mode & 4) && typeof value === 'object' && value && value.__esModule) return value;\n \t\tvar ns = Object.create(null);\n \t\t__webpack_require__.r(ns);\n \t\tObject.defineProperty(ns, 'default', { enumerable: true, value: value });\n \t\tif(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key));\n \t\treturn ns;\n \t};\n\n \t// getDefaultExport function for compatibility with non-harmony modules\n \t__webpack_require__.n = function(module) {\n \t\tvar getter = module && module.__esModule ?\n \t\t\tfunction getDefault() { return module['default']; } :\n \t\t\tfunction getModuleExports() { return module; };\n \t\t__webpack_require__.d(getter, 'a', getter);\n \t\treturn getter;\n \t};\n\n \t// Object.prototype.hasOwnProperty.call\n \t__webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); };\n\n \t// __webpack_public_path__\n \t__webpack_require__.p = \"\";\n\n\n \t// Load entry module and return exports\n \treturn __webpack_require__(__webpack_require__.s = 0);\n","import ArrayDataEventHandler from './array-data-event-handler.js';\nimport VuexArrayGetters from './vuex-array-getters.js';\nimport VuexArrayHandler from './vuex-array-handler.js';\nimport VuexArrayMutations from './vuex-array-mutations.js';\nimport WebSocketChannelClient from './web-socket-channel-client.js';\n\nexport {\n ArrayDataEventHandler,\n VuexArrayGetters,\n VuexArrayHandler,\n VuexArrayMutations,\n WebSocketChannelClient\r\n};\n","export default function (config) {\r\n let _private = this;\r\n\r\n let keyFieldNamesByName = {};\r\n let batchSize = config.batchSize || 250;\n\n let queue = [];\n let queueCurrentOffset = 0;\n let handleQueueTimeout = null;\n\r\n _private.getKeyValue = function (name, record) {\r\n let result = '';\r\n let keyFieldNames = keyFieldNamesByName[name];\r\n for (let i = 0; i < keyFieldNames.length; i++) {\r\n let value = record[keyFieldNames[i]];\r\n if (!result && result.length > 0) result += ';';\r\n result += '' + value;\r\n }\r\n return result;\r\n }\r\n\n _private.handleDataEvent = function (dataEvent) {\n //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue);\r\n if (dataEvent.dataEventType === 'InitialEnd') {\r\n if (config.onInitialEnd) config.onInitialEnd();\r\n }\r\n else {\r\n let array = config.arrayMapping[dataEvent.name];\r\n if (!array) {\r\n console.error('No mapping for data event \\'' + dataEvent.name + '\\'');\r\n }\r\n else if (dataEvent.dataEventType === 'InitialBegin') {\r\n array.splice(0, array.length);\r\n keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames;\r\n }\r\n else if (dataEvent.dataEventType === 'Insert' || dataEvent.dataEventType === 'Initial') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n if (index >= 0) {\r\n console.error('Duplicate key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n }\r\n else {\r\n dataEvent.record['_keyValue'] = keyValue;\r\n array.splice(array.length, 0, dataEvent.record);\r\n }\r\n }\r\n else if (dataEvent.dataEventType === 'Update') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n if (index == -1) {\r\n console.error('Could not find key \\'' + keyValue + '\\' in table \\'' + dataEvent.name + '\\'');\r\n }\r\n else {\r\n dataEvent.record['_keyValue'] = keyValue;\r\n array.splice(index, 1, dataEvent.record);\r\n }\r\n }\r\n else if (dataEvent.dataEventType === 'Delete') {\r\n let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record);\r\n let index = array.findIndex(x => x._keyValue == keyValue);\r\n array.splice(index, 1);\r\n }\r\n }\r\n };\n\n _private.handleQueue = function () {\n if (handleQueueTimeout) clearTimeout(handleQueueTimeout);\n\n if (queue.length > 0) {\n let begin = queueCurrentOffset;\n let end = Math.min(begin + batchSize, queue[0].length);\n for (let i = begin; i < end; i++) {\n _private.handleDataEvent(queue[0][i]);\r\n }\n if (end === queue[0].length) {\n queue.splice(0, 1);\n queueCurrentOffset = 0;\r\n }\n else {\n queueCurrentOffset += batchSize;\n handleQueueTimeout = setTimeout(_private.handleQueue, 0);\r\n }\n }\r\n }\n\r\n return function (messageType, data) {\r\n if (messageType === 'RESET') {\r\n for (let arrayKey in config.arrayMapping) {\r\n let array = config.arrayMapping[arrayKey];\r\n if (array) array.splice(0, array.length);\r\n }\r\n }\r\n else if (messageType === 'DATA-EVENT-TRANSACTION') {\r\n queue.push(data.dataEvents);\n _private.handleQueue();\r\n }\r\n else if (config.onChannelMessage) {\r\n config.onChannelMessage(messageType, data);\r\n }\r\n }\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Length`] = state => state[arrayName].length;\r\n\tresult[`${arrayName}FindIndex`] = state => callback => state[arrayName].findIndex(callback);\r\n\treturn result;\r\n}\r\n","export default function(store, arrayName) {\r\n\treturn {\r\n\t\tget length() { return store.getters[`${arrayName}Length`] },\r\n\t\tfindIndex(callback) { return store.getters[`${arrayName}FindIndex`](callback) },\r\n\t\tsplice(start, deleteCount, item) {\r\n\t\t\treturn store.commit(`${arrayName}Splice`, { start, deleteCount, item });\r\n\t\t},\r\n\t};\r\n}\r\n","export default function(arrayName) {\r\n\tlet result = {};\r\n\tresult[`${arrayName}Splice`] = (state, options) => {\r\n\t\tif (options.item) state[arrayName].splice(options.start, options.deleteCount, options.item);\r\n\t\telse state[arrayName].splice(options.start, options.deleteCount);\r\n\t};\r\n\treturn result;\r\n}\r\n","/*\n * States...\n * Disconnected - No WebSocket, no loop running\n * Connecting - Create WebSocket and wait for WebSocket.onopen()\n * Authenticating - Send Authentication and wait for server to send AUTHENTICATED or UNAUTHENTICATED\n * Subscribing - Send subscriptions and transition to Connected\n * Connected - Send heartbeats to server\n */\n\nexport default class {\r\n constructor(options) {\r\n this._options = options;\r\n\r\n let url = this._options.url;\n\r\n if (url.indexOf('://') === -1) {\r\n this._url = (window.location.protocol === 'https:' ? 'wss:' : 'ws:') + '//' + window.location.host + url;\r\n }\r\n else {\r\n this._url = url;\r\n }\r\n\r\n this._state = 'Disconnected';\n this._stateTimeout = null;\r\n this._auth = null;\r\n this._subscriptionByChannelKey = {};\r\n }\r\n\r\n _setState(value) {\r\n if (this._state !== value) {\n console.debug(`_setState():value=${value}`);\r\n this._state = value;\r\n if (this._options.onStateChange) this._options.onStateChange(value);\r\n this._clearStateTimeout();\n }\r\n }\r\n\n connect(auth) {\r\n console.debug('WebSocketChannelClient.connect()');\r\n this._auth = auth;\n\r\n this._setState('Connecting');\n this._connecting();\r\n }\r\n\r\n _connecting() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Connecting');\n let connectingStartMillis = new Date().getTime();\n\n if (this._webSocket) {\n try {\n this._webSocket.close();\n }\n catch (e) { }\n this._webSocket = null;\r\n }\n\n let hasReconnected = false;\n let reconnect = error => {\n if (hasReconnected) return;\n hasReconnected = true;\n\n console.debug(`_connecting():reconnect():error=${error}`);\n let elapsedMillis = new Date().getTime() - connectingStartMillis;\n let reconnectEveryMillis = this._options.reconnectEveryMillis || 3000;\n\n if (elapsedMillis > reconnectEveryMillis) {\n this._connecting();\n }\n else {\n let wait = reconnectEveryMillis - elapsedMillis;\n\n this._stateTimeout = setTimeout(this._connecting.bind(this), wait);\r\n }\n };\n\r\n try {\r\n console.debug(`_connecting():new WebSocket(${this._url})`);\r\n this._webSocket = new WebSocket(this._url);\r\n this._webSocket.onmessage = this._onMessage.bind(this);\r\n this._webSocket.onopen = this._authenticating.bind(this);\n this._webSocket.onerror = reconnect.bind(this);\r\n this._webSocket.onclose = reconnect.bind(this);\r\n }\r\n catch (e) {\r\n reconnect(e);\r\n }\r\n }\n\n _authenticating() {\n if (this._state === 'Disconnected') return;\n\n this._setState('Authenticating');\n let text = 'Authorization:' + (this._auth || '');\n let success = this._sendText(text);\n\n if (success) {\n let authenticateEveryMillis = this._options.authenticateEveryMillis || 3000;\n\n this._stateTimeout = setTimeout(this._authenticating.bind(this), authenticateEveryMillis);\n }\r\n }\n\n _subscribing() {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Subscribing');\n\n // Build data\n let data = [];\n\r\n for (let key in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[key];\n\r\n if (!subscription.sent) {\r\n data.push({\r\n channelKey: key,\r\n vars: subscription.vars,\r\n });\r\n }\r\n }\n\n // Subscribe\n let success = true;\n\r\n if (data.length > 0) {\r\n success = this._sendText('Subscribe:' + JSON.stringify(data));\r\n }\n\n if (success) {\n this._markSubscriptionsSent(true);\r\n this._connected();\n }\r\n }\r\n\n _unsubscribing(channelKey) {\r\n if (this._state === 'Disconnected') return;\n\n this._setState('Unsubscribing');\n let success = this._sendText('Unsubscribe:' + JSON.stringify(channelKey));\n\n if (success) {\n this._connected();\r\n }\r\n }\n\r\n _connected() {\n this._setState('Connected');\n\n let elapsedMillis = new Date().getTime() - this._lastSendTextMillis;\n let heartbeatEveryMillis = this._options.heartbeatEveryMillis || 3000;\n\n if (elapsedMillis >= heartbeatEveryMillis) {\n this._sendText('!');\n this._connected();\n }\n else {\n let wait = Math.max(0, heartbeatEveryMillis - elapsedMillis);\n\n this._stateTimeout = setTimeout(this._connected.bind(this), wait);\n }\r\n }\n\n disconnect() {\r\n console.debug('WebSocketChannelClient.disconnect()')\r\n this._setState('Disconnected');\r\n if (this._webSocket != null) {\n try {\r\n this._webSocket.close();\n }\n catch (e) { }\r\n this._webSocket = null;\r\n }\n this._clearStateTimeout();\n for (let channelKey in this._subscriptionByChannelKey) {\r\n let subscription = this._subscriptionByChannelKey[channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i]('RESET');\r\n }\r\n }\r\n }\r\n }\r\n\n _clearStateTimeout() {\n if (this._stateTimeout) {\n clearTimeout(this._stateTimeout);\n this._stateTimeout = null;\n }\r\n }\r\n\n _sendText(text) {\n console.debug(`_sendText():text=${text}`);\n try {\n this._webSocket.send(text);\n this._lastSendTextMillis = new Date().getTime();\n return true;\n }\n catch (e) {\n console.error(e);\n this._connecting();\n return false;\r\n }\r\n }\n\n _onMessage(event) {\r\n let message = JSON.parse(event.data);\n\r\n console.debug(`_onMessage():message.messageType=${message.messageType}`);\r\n if (message.channelKey) {\r\n let subscription = this._subscriptionByChannelKey[message.channelKey];\n\r\n if (subscription.handlers) {\r\n for (let i = 0; i < subscription.handlers.length; i++) {\r\n subscription.handlers[i](message.messageType, message.data);\r\n }\r\n }\r\n }\r\n else if (message.messageType === 'AUTHENTICATED') {\n this._markSubscriptionsSent(false);\r\n this._subscribing();\r\n }\r\n else if (message.messageType === 'UNAUTHENTICATED') {\r\n this.disconnect();\r\n }\r\n }\r\n\n _markSubscriptionsSent(value) {\r\n for (let key in this._subscriptionByChannelKey) {\r\n this._subscriptionByChannelKey[key].sent = value;\r\n }\r\n }\r\n\n subscribe(options) {\r\n let channelKey = options.channel || 'default';\n let handlers = Array.isArray(options.handler) ? options.handler : [options.handler];\n let vars = options.vars;\n\r\n // console.debug(`WebSocketChannelClient.subscribe():channelKey=${channelKey}`);\r\n this._removeSubscription(channelKey);\r\n this._addSubscription(channelKey, {\r\n vars,\r\n handlers,\r\n sent: false\r\n });\n if (this._state === 'Connected') {\n this._subscribing();\n }\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n unsubscribe(channelKey) {\r\n // console.debug(`WebSocketChannelClient.unsubscribe():channelKey=${channelKey}`);\r\n if (!channelKey) channelKey = 'default';\r\n this._removeSubscription(channelKey);\r\n this._unsubscribing(channelKey);\r\n if (this._options.onSubscriptionsUpdated) this._options.onSubscriptionsUpdated();\r\n }\r\n\r\n _addSubscription(channelKey, subscription) {\r\n this._subscriptionByChannelKey[channelKey] = subscription;\r\n }\r\n\r\n _removeSubscription(channelKey) {\r\n delete this._subscriptionByChannelKey[channelKey];\r\n }\r\n\r\n}\r\n"],"sourceRoot":""} \ No newline at end of file diff --git a/Butterfly.Client.Web/package-lock.json b/Butterfly.Client.Web/package-lock.json index c89a663c..028d3e18 100644 --- a/Butterfly.Client.Web/package-lock.json +++ b/Butterfly.Client.Web/package-lock.json @@ -1,6 +1,6 @@ { "name": "butterfly-client", - "version": "2.0.2", + "version": "2.0.3", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -4001,14 +4001,12 @@ "balanced-match": { "version": "1.0.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "brace-expansion": { "version": "1.1.11", "bundled": true, "dev": true, - "optional": true, "requires": { "balanced-match": "^1.0.0", "concat-map": "0.0.1" @@ -4023,20 +4021,17 @@ "code-point-at": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "concat-map": { "version": "0.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "console-control-strings": { "version": "1.1.0", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "core-util-is": { "version": "1.0.2", @@ -4153,8 +4148,7 @@ "inherits": { "version": "2.0.3", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "ini": { "version": "1.3.5", @@ -4166,7 +4160,6 @@ "version": "1.0.0", "bundled": true, "dev": true, - "optional": true, "requires": { "number-is-nan": "^1.0.0" } @@ -4181,7 +4174,6 @@ "version": "3.0.4", "bundled": true, "dev": true, - "optional": true, "requires": { "brace-expansion": "^1.1.7" } @@ -4189,14 +4181,12 @@ "minimist": { "version": "0.0.8", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "minipass": { "version": "2.2.4", "bundled": true, "dev": true, - "optional": true, "requires": { "safe-buffer": "^5.1.1", "yallist": "^3.0.0" @@ -4215,7 +4205,6 @@ "version": "0.5.1", "bundled": true, "dev": true, - "optional": true, "requires": { "minimist": "0.0.8" } @@ -4296,8 +4285,7 @@ "number-is-nan": { "version": "1.0.1", "bundled": true, - "dev": true, - "optional": true + "dev": true }, "object-assign": { "version": "4.1.1", @@ -4309,7 +4297,6 @@ "version": "1.4.0", "bundled": true, "dev": true, - "optional": true, "requires": { "wrappy": "1" } @@ -4431,7 +4418,6 @@ "version": "1.0.2", "bundled": true, "dev": true, - "optional": true, "requires": { "code-point-at": "^1.0.0", "is-fullwidth-code-point": "^1.0.0", diff --git a/Butterfly.Client.Web/package.json b/Butterfly.Client.Web/package.json index 937002c4..8899e98e 100644 --- a/Butterfly.Client.Web/package.json +++ b/Butterfly.Client.Web/package.json @@ -1,6 +1,6 @@ { "name": "butterfly-client", - "version": "2.0.2", + "version": "2.0.4", "description": "Client library for Butterfly Realtime Web App Server", "main": "lib/butterfly-client.js", "scripts": { diff --git a/Butterfly.Client.Web/src/array-data-event-handler.js b/Butterfly.Client.Web/src/array-data-event-handler.js index 62abd30b..bfa08f45 100644 --- a/Butterfly.Client.Web/src/array-data-event-handler.js +++ b/Butterfly.Client.Web/src/array-data-event-handler.js @@ -1,75 +1,101 @@ -export default function(config) { - let _private = this; +export default function (config) { + let _private = this; - let keyFieldNamesByName = {}; + let keyFieldNamesByName = {}; + let batchSize = config.batchSize || 250; - _private.getKeyValue = function (name, record) { - let result = ''; - let keyFieldNames = keyFieldNamesByName[name]; - for (let i = 0; i < keyFieldNames.length; i++) { - let value = record[keyFieldNames[i]]; - if (!result && result.length > 0) result += ';'; - result += '' + value; - } - return result; - } + let queue = []; + let queueCurrentOffset = 0; + let handleQueueTimeout = null; - return function (messageType, data) { - if (messageType == 'RESET') { - for (let arrayKey in config.arrayMapping) { - let array = config.arrayMapping[arrayKey]; - if (array) array.splice(0, array.length); - } - } - else if (messageType == 'DATA-EVENT-TRANSACTION') { - let dataEventTransaction = data; - for (let i = 0; i < dataEventTransaction.dataEvents.length; i++) { - let dataEvent = dataEventTransaction.dataEvents[i]; - //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue); - if (dataEvent.dataEventType == 'InitialEnd') { - if (config.onInitialEnd) config.onInitialEnd(); - } - else { - let array = config.arrayMapping[dataEvent.name]; - if (!array) { - console.error('No mapping for data event \'' + dataEvent.name + '\''); - } - else if (dataEvent.dataEventType == 'InitialBegin') { - array.splice(0, array.length); - keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames; - } - else if (dataEvent.dataEventType == 'Insert' || dataEvent.dataEventType == 'Initial') { - let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - let index = array.findIndex(x => x._keyValue == keyValue); - if (index >= 0) { - console.error('Duplicate key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); - } - else { - dataEvent.record['_keyValue'] = keyValue; - array.splice(array.length, 0, dataEvent.record); - } - } - else if (dataEvent.dataEventType == 'Update') { - let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - let index = array.findIndex(x => x._keyValue == keyValue); - if (index == -1) { - console.error('Could not find key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); - } - else { - dataEvent.record['_keyValue'] = keyValue; - array.splice(index, 1, dataEvent.record); - } - } - else if (dataEvent.dataEventType == 'Delete') { - let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); - let index = array.findIndex(x => x._keyValue == keyValue); - array.splice(index, 1); - } - } - } - } - else if (config.onChannelMessage) { - config.onChannelMessage(messageType, data); - } - } + _private.getKeyValue = function (name, record) { + let result = ''; + let keyFieldNames = keyFieldNamesByName[name]; + for (let i = 0; i < keyFieldNames.length; i++) { + let value = record[keyFieldNames[i]]; + if (!result && result.length > 0) result += ';'; + result += '' + value; + } + return result; + } + + _private.handleDataEvent = function (dataEvent) { + //console.debug('ArrayDataEventHandler.handle():dataEvent.type=' + dataEvent.dataEventType + ',name=', dataEvent.name + ',keyValue=' + dataEvent.keyValue); + if (dataEvent.dataEventType === 'InitialEnd') { + if (config.onInitialEnd) config.onInitialEnd(); + } + else { + let array = config.arrayMapping[dataEvent.name]; + if (!array) { + console.error('No mapping for data event \'' + dataEvent.name + '\''); + } + else if (dataEvent.dataEventType === 'InitialBegin') { + array.splice(0, array.length); + keyFieldNamesByName[dataEvent.name] = dataEvent.keyFieldNames; + } + else if (dataEvent.dataEventType === 'Insert' || dataEvent.dataEventType === 'Initial') { + let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); + let index = array.findIndex(x => x._keyValue == keyValue); + if (index >= 0) { + console.error('Duplicate key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); + } + else { + dataEvent.record['_keyValue'] = keyValue; + array.splice(array.length, 0, dataEvent.record); + } + } + else if (dataEvent.dataEventType === 'Update') { + let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); + let index = array.findIndex(x => x._keyValue == keyValue); + if (index == -1) { + console.error('Could not find key \'' + keyValue + '\' in table \'' + dataEvent.name + '\''); + } + else { + dataEvent.record['_keyValue'] = keyValue; + array.splice(index, 1, dataEvent.record); + } + } + else if (dataEvent.dataEventType === 'Delete') { + let keyValue = _private.getKeyValue(dataEvent.name, dataEvent.record); + let index = array.findIndex(x => x._keyValue == keyValue); + array.splice(index, 1); + } + } + }; + + _private.handleQueue = function () { + if (handleQueueTimeout) clearTimeout(handleQueueTimeout); + + if (queue.length > 0) { + let begin = queueCurrentOffset; + let end = Math.min(begin + batchSize, queue[0].length); + for (let i = begin; i < end; i++) { + _private.handleDataEvent(queue[0][i]); + } + if (end === queue[0].length) { + queue.splice(0, 1); + queueCurrentOffset = 0; + } + else { + queueCurrentOffset += batchSize; + handleQueueTimeout = setTimeout(_private.handleQueue, 0); + } + } + } + + return function (messageType, data) { + if (messageType === 'RESET') { + for (let arrayKey in config.arrayMapping) { + let array = config.arrayMapping[arrayKey]; + if (array) array.splice(0, array.length); + } + } + else if (messageType === 'DATA-EVENT-TRANSACTION') { + queue.push(data.dataEvents); + _private.handleQueue(); + } + else if (config.onChannelMessage) { + config.onChannelMessage(messageType, data); + } + } } diff --git a/Butterfly.Core/Database/BaseDatabase.cs b/Butterfly.Core/Database/BaseDatabase.cs index 62914288..37baead8 100644 --- a/Butterfly.Core/Database/BaseDatabase.cs +++ b/Butterfly.Core/Database/BaseDatabase.cs @@ -183,7 +183,7 @@ public async Task SelectValuesAsync(string sql, dynamic vars = null) { public async Task SelectRowAsync(string statementSql, dynamic vars = null) { SelectStatement statement = new SelectStatement(this, statementSql, limit: 1); - Dict[] rows = await this.SelectRowsAsync(statementSql, vars: vars); + Dict[] rows = await this.SelectRowsAsync(statement, vars: vars); if (rows.Length == 0) return null; else if (rows.Length > 1) throw new Exception("SelectRow returned more than one row"); return rows.First(); diff --git a/Butterfly.Core/Util/WebClientWithTimeout.cs b/Butterfly.Core/Util/WebClientWithTimeout.cs new file mode 100644 index 00000000..6fcf811b --- /dev/null +++ b/Butterfly.Core/Util/WebClientWithTimeout.cs @@ -0,0 +1,20 @@ +using System; +using System.Net; + +namespace Butterfly.Core.Util { + public class WebClientWithTimeout : WebClient { + + protected readonly int timeoutMillis; + + public WebClientWithTimeout(int timeoutMillis) { + this.timeoutMillis = timeoutMillis; + } + + protected override WebRequest GetWebRequest(Uri uri) { + WebRequest w = base.GetWebRequest(uri); + w.Timeout = this.timeoutMillis; + return w; + } + + } +} diff --git a/Butterfly.Twilio/TwilioPhoneTextNotifyMessageSender.cs b/Butterfly.Twilio/TwilioPhoneTextNotifyMessageSender.cs index 1b4e7682..95d3182b 100644 --- a/Butterfly.Twilio/TwilioPhoneTextNotifyMessageSender.cs +++ b/Butterfly.Twilio/TwilioPhoneTextNotifyMessageSender.cs @@ -2,7 +2,9 @@ * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ +using System; using System.Threading.Tasks; +using System.Collections.Generic; using NLog; @@ -29,16 +31,14 @@ public TwilioPhoneTextNotifyMessageSender(string twilioAccountSid, string twilio protected override async Task DoSendAsync(string from, string to, string subject, string bodyText, string bodyHtml) { TwilioClient.Init(this.twilioAccountSid, this.twilioAuthToken); - //try { - MessageResource messageResource = await MessageResource.CreateAsync( - to: new PhoneNumber(to), - from: new PhoneNumber(from), - body: bodyText); - return messageResource.Sid; - //} - //catch (Exception e) { - // logger.Error(e); - //} + var mediaUris = string.IsNullOrEmpty(bodyHtml) ? new List { new Uri(bodyHtml) } : null; + MessageResource messageResource = await MessageResource.CreateAsync( + to: new PhoneNumber(to), + from: new PhoneNumber(from), + body: bodyText, + mediaUrl: mediaUris + ); + return messageResource.Sid; } /*