UNPKG

@aeternity/aepp-sdk

Version:
437 lines (374 loc) 15.5 kB
import _toArray from "@babel/runtime-corejs3/helpers/toArray"; import _objectWithoutProperties from "@babel/runtime-corejs3/helpers/objectWithoutProperties"; import _slicedToArray from "@babel/runtime-corejs3/helpers/slicedToArray"; import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator"; import _toConsumableArray from "@babel/runtime-corejs3/helpers/toConsumableArray"; import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator"; import _WeakMap from "@babel/runtime-corejs3/core-js-stable/weak-map"; import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat"; import _setTimeout from "@babel/runtime-corejs3/core-js-stable/set-timeout"; import _Promise from "@babel/runtime-corejs3/core-js-stable/promise"; import _findIndexInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/find-index"; import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter"; import _sliceInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/slice"; import _Map from "@babel/runtime-corejs3/core-js-stable/map"; import _URL from "@babel/runtime-corejs3/core-js-stable/url"; import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each"; import _Object$entries from "@babel/runtime-corejs3/core-js-stable/object/entries"; import _includesInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/includes"; import _Object$assign from "@babel/runtime-corejs3/core-js-stable/object/assign"; /* * ISC License (ISC) * Copyright (c) 2018 aeternity developers * * Permission to use, copy, modify, and/or distribute this software for any * purpose with or without fee is hereby granted, provided that the above * copyright notice and this permission notice appear in all copies. * * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH * REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY * AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, * INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM * LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR * OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR * PERFORMANCE OF THIS SOFTWARE. */ import { w3cwebsocket as W3CWebSocket } from 'websocket'; import { EventEmitter } from 'events'; import JsonBig from '../utils/json-big'; import { pascalToSnake } from '../utils/string'; import { awaitingConnection, awaitingReconnection, channelOpen } from './handlers'; // Send ping message every 10 seconds var PING_TIMEOUT_MS = 10000; // Close connection if pong message is not received within 5 seconds var PONG_TIMEOUT_MS = 5000; export var options = new _WeakMap(); export var status = new _WeakMap(); export var state = new _WeakMap(); var fsm = new _WeakMap(); var websockets = new _WeakMap(); export var eventEmitters = new _WeakMap(); var messageQueue = new _WeakMap(); var messageQueueLocked = new _WeakMap(); var actionQueue = new _WeakMap(); var actionQueueLocked = new _WeakMap(); var sequence = new _WeakMap(); export var channelId = new _WeakMap(); var rpcCallbacks = new _WeakMap(); var pingTimeoutId = new _WeakMap(); var pongTimeoutId = new _WeakMap(); export var fsmId = new _WeakMap(); export function emit(channel) { var _eventEmitters$get; for (var _len = arguments.length, args = new Array(_len > 1 ? _len - 1 : 0), _key = 1; _key < _len; _key++) { args[_key - 1] = arguments[_key]; } (_eventEmitters$get = eventEmitters.get(channel)).emit.apply(_eventEmitters$get, args); } function enterState(channel, nextState) { if (!nextState) { throw new Error('State Channels FSM entered unknown state'); } fsm.set(channel, nextState); if (nextState.handler.enter) { nextState.handler.enter(channel); } dequeueAction(channel); } export function changeStatus(channel, newStatus) { var prevStatus = status.get(channel); if (newStatus !== prevStatus) { status.set(channel, newStatus); emit(channel, 'statusChanged', newStatus); } } export function changeState(channel, newState) { state.set(channel, newState); emit(channel, 'stateChanged', newState); } export function send(channel, message) { var _options$get = options.get(channel), _options$get$debug = _options$get.debug, debug = _options$get$debug === void 0 ? false : _options$get$debug; if (debug) console.log('Send message: ', message); websockets.get(channel).send(JsonBig.stringify(message)); } export function enqueueAction(channel, guard, action) { var _context; actionQueue.set(channel, _concatInstanceProperty(_context = []).call(_context, _toConsumableArray(actionQueue.get(channel) || []), [{ guard: guard, action: action }])); dequeueAction(channel); } function dequeueAction(_x) { return _dequeueAction.apply(this, arguments); } function _dequeueAction() { _dequeueAction = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(channel) { var locked, queue, state, index, nextState; return _regeneratorRuntime.wrap(function _callee$(_context4) { while (1) { switch (_context4.prev = _context4.next) { case 0: locked = actionQueueLocked.get(channel); queue = actionQueue.get(channel) || []; if (!(locked || !queue.length)) { _context4.next = 4; break; } return _context4.abrupt("return"); case 4: state = fsm.get(channel); index = _findIndexInstanceProperty(queue).call(queue, function (item) { return item.guard(channel, state); }); if (!(index === -1)) { _context4.next = 8; break; } return _context4.abrupt("return"); case 8: actionQueue.set(channel, _filterInstanceProperty(queue).call(queue, function (_, i) { return index !== i; })); actionQueueLocked.set(channel, true); _context4.next = 12; return _Promise.resolve(queue[index].action(channel, state)); case 12: nextState = _context4.sent; actionQueueLocked.set(channel, false); enterState(channel, nextState); case 15: case "end": return _context4.stop(); } } }, _callee); })); return _dequeueAction.apply(this, arguments); } function handleMessage(_x2, _x3) { return _handleMessage.apply(this, arguments); } function _handleMessage() { _handleMessage = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2(channel, message) { var _fsm$get, handler, state; return _regeneratorRuntime.wrap(function _callee2$(_context5) { while (1) { switch (_context5.prev = _context5.next) { case 0: _fsm$get = fsm.get(channel), handler = _fsm$get.handler, state = _fsm$get.state; _context5.t0 = enterState; _context5.t1 = channel; _context5.next = 5; return _Promise.resolve(handler(channel, message, state)); case 5: _context5.t2 = _context5.sent; (0, _context5.t0)(_context5.t1, _context5.t2); case 7: case "end": return _context5.stop(); } } }, _callee2); })); return _handleMessage.apply(this, arguments); } function dequeueMessage(_x4) { return _dequeueMessage.apply(this, arguments); } function _dequeueMessage() { _dequeueMessage = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3(channel) { var queue, _queue, message, remaining; return _regeneratorRuntime.wrap(function _callee3$(_context6) { while (1) { switch (_context6.prev = _context6.next) { case 0: queue = messageQueue.get(channel); if (!(messageQueueLocked.get(channel) || !queue.length)) { _context6.next = 3; break; } return _context6.abrupt("return"); case 3: _queue = _toArray(queue), message = _queue[0], remaining = _sliceInstanceProperty(_queue).call(_queue, 1); messageQueue.set(channel, remaining || []); messageQueueLocked.set(channel, true); _context6.next = 8; return handleMessage(channel, message); case 8: messageQueueLocked.set(channel, false); dequeueMessage(channel); case 10: case "end": return _context6.stop(); } } }, _callee3); })); return _dequeueMessage.apply(this, arguments); } function ping(channel) { clearTimeout(pingTimeoutId.get(channel)); clearTimeout(pongTimeoutId.get(channel)); pingTimeoutId.set(channel, _setTimeout(function () { send(channel, { jsonrpc: '2.0', method: 'channels.system', params: { action: 'ping' } }); pongTimeoutId.set(channel, _setTimeout(function () { disconnect(channel); emit(channel, 'error', new Error('Server pong timed out')); }, PONG_TIMEOUT_MS)); }, PING_TIMEOUT_MS)); } function onMessage(channel, data) { var message = JsonBig.parse(data); var _options$get2 = options.get(channel), _options$get2$debug = _options$get2.debug, debug = _options$get2$debug === void 0 ? false : _options$get2$debug; if (debug) console.log('Receive message: ', message); if (message.id) { var callback = rpcCallbacks.get(channel).get(message.id); try { callback(message); } finally { rpcCallbacks.get(channel)["delete"](message.id); } } else if (message.method === 'channels.message') { emit(channel, 'message', message.params.data.message); } else if (message.method === 'channels.system.pong') { if (message.params.channel_id === channelId.get(channel) || // Skip channelId check if channelId is not known yet channelId.get(channel) == null) { ping(channel); } } else { var _context2; messageQueue.set(channel, _concatInstanceProperty(_context2 = []).call(_context2, _toConsumableArray(messageQueue.get(channel) || []), [message])); dequeueMessage(channel); } } function wrapCallErrorMessage(message) { var _ref = message.error.data || [], _ref2 = _slicedToArray(_ref, 1), _ref2$ = _ref2[0]; _ref2$ = _ref2$ === void 0 ? {} : _ref2$; var details = _ref2$.message; if (details) { var _context3; return new Error(_concatInstanceProperty(_context3 = "".concat(message.error.message, ": ")).call(_context3, details)); } return new Error(message.error.message); } export function call(channel, method, params) { return new _Promise(function (resolve, reject) { var id = sequence.set(channel, sequence.get(channel) + 1).get(channel); rpcCallbacks.get(channel).set(id, function (message) { if (message.result) return resolve(message.result); if (message.error) return reject(wrapCallErrorMessage(message)); }); send(channel, { jsonrpc: '2.0', method: method, id: id, params: params }); }); } export function disconnect(channel) { websockets.get(channel).close(); clearTimeout(pingTimeoutId.get(channel)); clearTimeout(pongTimeoutId.get(channel)); } export function initialize(_x5, _x6) { return _initialize.apply(this, arguments); } function _initialize() { _initialize = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee5(channel, _ref3) { var _context7, _context8; var url, channelOptions, wsUrl, ws; return _regeneratorRuntime.wrap(function _callee5$(_context11) { while (1) { switch (_context11.prev = _context11.next) { case 0: url = _ref3.url, channelOptions = _objectWithoutProperties(_ref3, ["url"]); options.set(channel, channelOptions); fsm.set(channel, { handler: channelOptions.existingFsmId ? awaitingReconnection : awaitingConnection }); eventEmitters.set(channel, new EventEmitter()); sequence.set(channel, 0); rpcCallbacks.set(channel, new _Map()); wsUrl = new _URL(url); _forEachInstanceProperty(_context7 = _filterInstanceProperty(_context8 = _Object$entries(channelOptions)).call(_context8, function (_ref4) { var _context9; var _ref5 = _slicedToArray(_ref4, 1), key = _ref5[0]; return !_includesInstanceProperty(_context9 = ['sign', 'debug']).call(_context9, key); })).call(_context7, function (_ref6) { var _ref7 = _slicedToArray(_ref6, 2), key = _ref7[0], value = _ref7[1]; return wsUrl.searchParams.set(pascalToSnake(key), value); }); wsUrl.searchParams.set('protocol', 'json-rpc'); changeStatus(channel, 'connecting'); ws = new W3CWebSocket(wsUrl.toString()); _context11.next = 13; return new _Promise(function (resolve, reject) { return _Object$assign(ws, { onerror: reject, onopen: function onopen() { resolve(); changeStatus(channel, 'connected'); if (channelOptions.reconnectTx) { enterState(channel, { handler: channelOpen }); _setTimeout( /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4() { return _regeneratorRuntime.wrap(function _callee4$(_context10) { while (1) { switch (_context10.prev = _context10.next) { case 0: _context10.t0 = changeState; _context10.t1 = channel; _context10.next = 4; return call(channel, 'channels.get.offchain_state', {}); case 4: _context10.t2 = _context10.sent.signed_tx; return _context10.abrupt("return", (0, _context10.t0)(_context10.t1, _context10.t2)); case 6: case "end": return _context10.stop(); } } }, _callee4); }))); } ping(channel); }, onclose: function onclose() { changeStatus(channel, 'disconnected'); clearTimeout(pingTimeoutId.get(channel)); clearTimeout(pongTimeoutId.get(channel)); }, onmessage: function onmessage(_ref9) { var data = _ref9.data; return onMessage(channel, data); } }); }); case 13: websockets.set(channel, ws); case 14: case "end": return _context11.stop(); } } }, _callee5); })); return _initialize.apply(this, arguments); } //# sourceMappingURL=internal.js.map