@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
437 lines (374 loc) • 15.5 kB
JavaScript
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