10 | About ◈ 11 | Prerequisites ◈ 12 | Installation ◈ 13 | Getting started ◈ 14 | API reference ◈ 15 | Supporting the project ◈ 16 | Joining the discussion 17 |
18 | 19 | --- 20 | 21 | ## About 22 | 23 | The Client Load Balancer is a utility package for sending commands to a list of nodes instead of just a single provider. 24 | 25 | This package is compatible with the [IOTA JavaScript client library](https://github.com/iotaledger/iota.js) and [mam.client.js](https://github.com/iotaledger/mam.client.js). 26 | 27 | There is a separate branch [https://github.com/iotaledger/client-load-balancer/tree/no-mam](https://github.com/iotaledger/client-load-balancer/tree/no-mam) which contains a version of this library for use with [mam.js](https://github.com/iotaledger/mam.js). This branch removes all the MAM specific methods and references as `mam.js` utilises the regular `composeAPI` for its communications. 28 | 29 | Features include: 30 | 31 | * Snapshot aware option which tries alternate nodes if getTrytes returns all 9s for result. 32 | 33 | * Node list walk strategies: 34 | 35 | * Linear - Walks the list of nodes sequentially 36 | 37 | * Random - Randomly picks a node from the list 38 | 39 | * Custom - Create your own walk strategy 40 | 41 | * Success mode for when an operation completes successfully: 42 | 43 | * Keep - Keep using the same node until it fails. 44 | 45 | * Next - Always step to the next node. 46 | 47 | * Fail mode for when a node does not respond or returns error: 48 | 49 | * Single - Fails the whole call after a single failure. 50 | 51 | * All - Tries all the nodes until one succeeds. 52 | 53 | * Timeout for non-responsive nodes. 54 | 55 | * Blacklist limit, nodes failing a number of times are longer used until all nodes exhausted. 56 | 57 | * Settings available on a per node or global level: 58 | 59 | * Minimum weight magnitude 60 | * Depth 61 | * AttachToTangle 62 | * TimeoutMs 63 | 64 | This is beta software, so there may be performance and stability issues. 65 | Please report any issues in our [issue tracker](https://github.com/iotaledger/client-load-balancer/issues/new). 66 | 67 | ## Prerequisites 68 | 69 | To use the Client Load Balancer in your own applications, you need [Node.js](https://nodejs.org/en/download/) installed on your device. 70 | 71 | To check if you have Node.js installed, run the following command: 72 | 73 | ```bash 74 | node -v 75 | ``` 76 | 77 | If Node.js is installed, you should see the version that's installed. 78 | 79 | ## Installation 80 | 81 | To install this package, use one of the following commands: 82 | 83 | 84 | - `npm install iotaledger/client-load-balancer` 85 | 86 | 87 | - `yarn add iotaledger/client-load-balancer` 88 | 89 | ## Getting started 90 | 91 | To jump in now, see the following code sample: 92 | 93 | ```js 94 | const { composeAPI, FailMode, RandomWalkStrategy, SuccessMode } = require('@iota/client-load-balancer'); 95 | 96 | (async function () { 97 | try { 98 | const api = composeAPI({ 99 | nodeWalkStrategy: new RandomWalkStrategy( 100 | [ 101 | { 102 | "provider": "https://altnodes.devnet.iota.org:443", 103 | "depth": 3, 104 | "mwm": 9 105 | }, 106 | { 107 | "provider": "https://nodes.devnet.iota.org:443", 108 | "depth": 3, 109 | "mwm": 9 110 | } 111 | ] 112 | ), 113 | successMode: SuccessMode.next, 114 | failMode: FailMode.all, 115 | timeoutMs: 5000, 116 | tryNodeCallback: (node) => { 117 | console.log(`Trying node ${node.provider}`); 118 | }, 119 | failNodeCallback: (node, err) => { 120 | console.log(`Failed node ${node.provider}, ${err.message}`); 121 | } 122 | }); 123 | 124 | const res = await api.getNodeInfo(); 125 | console.log("App Name:", res.appName); 126 | console.log("App Version:", res.appVersion); 127 | } catch (err) { 128 | console.error(`Error: ${err.message}`); 129 | } 130 | })(); 131 | ``` 132 | 133 | Will output: 134 | 135 | ```shell 136 | Trying node https://nodes.devnet.iota.org:443 137 | App Name: IRI Testnet 138 | App Version: 1.5.6-RELEASE 139 | ``` 140 | 141 | ## MWM and Depth 142 | 143 | The `mwm` and `depth` parameters can be set at multiple levels within the configuration. You can specify them at a node level, but they are optional. 144 | 145 | ```js 146 | { 147 | provider: "https://altnodes.devnet.iota.org:443", 148 | depth?: 3, 149 | mwm?: 9 150 | } 151 | ``` 152 | If you don't specify them for each node you can set them at the top level load balancer settings. 153 | 154 | ```js 155 | const api = composeAPI({ 156 | nodeWalkStrategy: ..., 157 | depth?: 3, 158 | mwm?: 9 159 | }); 160 | ``` 161 | 162 | Or you can just provide them when calling the regular methods that require them. 163 | 164 | ```js 165 | const iota = composeAPI(loadBalancerSettings); 166 | const trytes = await iota.prepareTransfers(seed, transfers, options); 167 | await iota.sendTrytes(trytes, 3, 9); 168 | ``` 169 | 170 | If you want methods like `sendTrytes` to use the values from the configuration just pass `undefined` instead, in `JavaScript` you can skip the parameters altogether but `TypeScript` will require some values, hence `undefined`. 171 | 172 | In this case of `undefined` parameters the code will first look at the configuration for the node that it is currently using, if that does not provide values it uses the load balancer settings. If they are not provided the defaults are `depth=3` and `mwm=9` 173 | 174 | ```js 175 | await iota.sendTrytes(trytes, undefined, undefined); 176 | ``` 177 | 178 | ## API Reference 179 | 180 | See the [JavaScript API reference](./docs/README.md). 181 | 182 | ## Supporting the project 183 | 184 | If you want to contribute, consider submitting a [bug report](https://github.com/iotaledger/client-load-balancer/issues/new), [feature request](https://github.com/iotaledger/client-load-balancer/issues/new) or a [pull request](https://github.com/iotaledger/client-load-balancer/pulls/). 185 | 186 | See our [contributing guidelines](.github/CONTRIBUTING.md) for more information. 187 | 188 | ## Joining the discussion 189 | 190 | If you want to get involved in the community, need help with getting set up, have any issues or just want to discuss IOTA, Distributed Registry Technology (DRT), and IoT with other people, feel free to join our [Discord](https://discord.iota.org/). 191 | -------------------------------------------------------------------------------- /dist/iota-client-load-balancer.js: -------------------------------------------------------------------------------- 1 | (function (global, factory) { 2 | typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports, require('@iota/core'), require('@iota/validators'), require('@iota/mam'), require('bluebird')) : 3 | typeof define === 'function' && define.amd ? define(['exports', '@iota/core', '@iota/validators', '@iota/mam', 'bluebird'], factory) : 4 | (global = typeof globalThis !== 'undefined' ? globalThis : global || self, factory(global.IotaClientLoadBalancer = {}, global.core, global.validators, global.MamCore, global.Bluebird)); 5 | }(this, (function (exports, core, validators, MamCore, Bluebird) { 'use strict'; 6 | 7 | function _interopNamespace(e) { 8 | if (e && e.__esModule) return e; 9 | var n = Object.create(null); 10 | if (e) { 11 | Object.keys(e).forEach(function (k) { 12 | if (k !== 'default') { 13 | var d = Object.getOwnPropertyDescriptor(e, k); 14 | Object.defineProperty(n, k, d.get ? d : { 15 | enumerable: true, 16 | get: function () { 17 | return e[k]; 18 | } 19 | }); 20 | } 21 | }); 22 | } 23 | n['default'] = e; 24 | return Object.freeze(n); 25 | } 26 | 27 | var Bluebird__namespace = /*#__PURE__*/_interopNamespace(Bluebird); 28 | 29 | /*! ***************************************************************************** 30 | Copyright (c) Microsoft Corporation. All rights reserved. 31 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 32 | this file except in compliance with the License. You may obtain a copy of the 33 | License at http://www.apache.org/licenses/LICENSE-2.0 34 | 35 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 36 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 37 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 38 | MERCHANTABLITY OR NON-INFRINGEMENT. 39 | 40 | See the Apache Version 2.0 License for specific language governing permissions 41 | and limitations under the License. 42 | ***************************************************************************** */ 43 | /* global Reflect, Promise */ 44 | 45 | var extendStatics = function(d, b) { 46 | extendStatics = Object.setPrototypeOf || 47 | ({ __proto__: [] } instanceof Array && function (d, b) { d.__proto__ = b; }) || 48 | function (d, b) { for (var p in b) if (b.hasOwnProperty(p)) d[p] = b[p]; }; 49 | return extendStatics(d, b); 50 | }; 51 | 52 | function __extends(d, b) { 53 | extendStatics(d, b); 54 | function __() { this.constructor = d; } 55 | d.prototype = b === null ? Object.create(b) : (__.prototype = b.prototype, new __()); 56 | } 57 | 58 | function __awaiter(thisArg, _arguments, P, generator) { 59 | return new (P || (P = Promise))(function (resolve, reject) { 60 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } } 61 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } } 62 | function step(result) { result.done ? resolve(result.value) : new P(function (resolve) { resolve(result.value); }).then(fulfilled, rejected); } 63 | step((generator = generator.apply(thisArg, _arguments || [])).next()); 64 | }); 65 | } 66 | 67 | function __generator(thisArg, body) { 68 | var _ = { label: 0, sent: function() { if (t[0] & 1) throw t[1]; return t[1]; }, trys: [], ops: [] }, f, y, t, g; 69 | return g = { next: verb(0), "throw": verb(1), "return": verb(2) }, typeof Symbol === "function" && (g[Symbol.iterator] = function() { return this; }), g; 70 | function verb(n) { return function (v) { return step([n, v]); }; } 71 | function step(op) { 72 | if (f) throw new TypeError("Generator is already executing."); 73 | while (_) try { 74 | if (f = 1, y && (t = op[0] & 2 ? y["return"] : op[0] ? y["throw"] || ((t = y["return"]) && t.call(y), 0) : y.next) && !(t = t.call(y, op[1])).done) return t; 75 | if (y = 0, t) op = [op[0] & 2, t.value]; 76 | switch (op[0]) { 77 | case 0: case 1: t = op; break; 78 | case 4: _.label++; return { value: op[1], done: false }; 79 | case 5: _.label++; y = op[1]; op = [0]; continue; 80 | case 7: op = _.ops.pop(); _.trys.pop(); continue; 81 | default: 82 | if (!(t = _.trys, t = t.length > 0 && t[t.length - 1]) && (op[0] === 6 || op[0] === 2)) { _ = 0; continue; } 83 | if (op[0] === 3 && (!t || (op[1] > t[0] && op[1] < t[3]))) { _.label = op[1]; break; } 84 | if (op[0] === 6 && _.label < t[1]) { _.label = t[1]; t = op; break; } 85 | if (t && _.label < t[2]) { _.label = t[2]; _.ops.push(op); break; } 86 | if (t[2]) _.ops.pop(); 87 | _.trys.pop(); continue; 88 | } 89 | op = body.call(thisArg, _); 90 | } catch (e) { op = [6, e]; y = 0; } finally { f = t = 0; } 91 | if (op[0] & 5) throw op[1]; return { value: op[0] ? op[1] : void 0, done: true }; 92 | } 93 | } 94 | 95 | /** 96 | * Fail modes for the load balancer. 97 | */ 98 | (function (FailMode) { 99 | /** 100 | * Try single node only, failure throws exception. 101 | */ 102 | FailMode["single"] = "single"; 103 | /** 104 | * Try all nodes until one succeeds, on all failing throws combined exception. 105 | */ 106 | FailMode["all"] = "all"; 107 | })(exports.FailMode || (exports.FailMode = {})); 108 | 109 | /** 110 | * Success modes for the load balancer. 111 | */ 112 | (function (SuccessMode) { 113 | /** 114 | * Keep the node if it was successful. 115 | */ 116 | SuccessMode["keep"] = "keep"; 117 | /** 118 | * Move to the next node even if it was successful. 119 | */ 120 | SuccessMode["next"] = "next"; 121 | })(exports.SuccessMode || (exports.SuccessMode = {})); 122 | 123 | /** 124 | * Create a new instance of the API. 125 | * @param settings The load balancer settings. 126 | * @param updateProvider Update the provider in the calling context. 127 | * @param methodPromise The method to call. 128 | * @param validateResult Let the caller validate the result. 129 | * @returns The api. 130 | * @private 131 | */ 132 | function loadBalancer(settings, updateProvider, methodPromise, validateResult) { 133 | return __awaiter(this, void 0, Promise, function () { 134 | var res, tryNextNode, totalNodes, triedCount, errorList, node, timeout, validMessage, err_1; 135 | return __generator(this, function (_a) { 136 | switch (_a.label) { 137 | case 0: 138 | tryNextNode = false; 139 | totalNodes = settings.nodeWalkStrategy.totalUsable(); 140 | triedCount = 0; 141 | errorList = []; 142 | _a.label = 1; 143 | case 1: 144 | node = settings.nodeWalkStrategy.current(); 145 | updateProvider(node); 146 | if (settings.tryNodeCallback) { 147 | settings.tryNodeCallback(node); 148 | } 149 | _a.label = 2; 150 | case 2: 151 | _a.trys.push([2, 7, , 8]); 152 | timeout = node.timeoutMs || settings.timeoutMs; 153 | if (!timeout) return [3 /*break*/, 4]; 154 | return [4 /*yield*/, methodPromise(node).timeout(timeout, node.provider + " the request timed out")]; 155 | case 3: 156 | res = _a.sent(); 157 | return [3 /*break*/, 6]; 158 | case 4: return [4 /*yield*/, methodPromise(node)]; 159 | case 5: 160 | res = _a.sent(); 161 | _a.label = 6; 162 | case 6: 163 | if (validateResult) { 164 | validMessage = validateResult(res); 165 | if (validMessage) { 166 | throw new Error(validMessage); 167 | } 168 | } 169 | tryNextNode = false; 170 | if (settings.successMode === exports.SuccessMode.next) { 171 | // Walk to the next node in the strategy 172 | settings.nodeWalkStrategy.next(false); 173 | } 174 | return [3 /*break*/, 8]; 175 | case 7: 176 | err_1 = _a.sent(); 177 | settings.nodeWalkStrategy.blacklist(); 178 | if (settings.failNodeCallback) { 179 | settings.failNodeCallback(node, err_1); 180 | } 181 | if (settings.failMode === exports.FailMode.single) { 182 | // Single fail mode so just throw the error 183 | throw err_1; 184 | } 185 | else if (settings.failMode === exports.FailMode.all) { 186 | // Fail mode is try all until one succeeds 187 | errorList.push(err_1.message ? err_1 : { message: err_1 }); 188 | // Try to use the next node if the current one errored 189 | triedCount++; 190 | // But only if we have not already tried all the nodes 191 | tryNextNode = triedCount < totalNodes; 192 | if (!tryNextNode) { 193 | // No more nodes to try so throw the combined exceptions 194 | throw new Error("All nodes failed\n " + errorList.map(function (e) { return e.message; }).join("\n ")); 195 | } 196 | // Walk to the next node in the strategy 197 | settings.nodeWalkStrategy.next(true); 198 | } 199 | return [3 /*break*/, 8]; 200 | case 8: 201 | if (tryNextNode) return [3 /*break*/, 1]; 202 | _a.label = 9; 203 | case 9: return [2 /*return*/, res]; 204 | } 205 | }); 206 | }); 207 | } 208 | /** 209 | * Wrap a method and handle either callback or async result. 210 | * @param settings The load balancer settings. 211 | * @param api The composed api. 212 | * @param method The method to wrap. 213 | * @param methodName The name of the method. 214 | * @returns The wrapped method. 215 | * @private 216 | */ 217 | function wrapMethodCallbackOrAsync(settings, api, method, methodName) { 218 | var _this = this; 219 | return function () { 220 | var p = []; 221 | for (var _i = 0; _i < arguments.length; _i++) { 222 | p[_i] = arguments[_i]; 223 | } 224 | return __awaiter(_this, void 0, void 0, function () { 225 | var originalCallbackParam; 226 | return __generator(this, function (_a) { 227 | originalCallbackParam = p[method.length - 1]; 228 | // If the caller is using the callback parameter remove it and use the promise 229 | // method then restore on method completion. 230 | if (originalCallbackParam) { 231 | p[method.length - 1] = undefined; 232 | } 233 | return [2 /*return*/, loadBalancer(settings, function (node) { return api.setSettings({ 234 | provider: node.provider, 235 | attachToTangle: node.attachToTangle || settings.attachToTangle, 236 | user: node.user || settings.user, 237 | password: node.password || settings.password 238 | }); }, function (node) { 239 | // Apply the default depth and mwm to methods that use them if they have not been supplied 240 | if (methodName === "promoteTransaction" || 241 | methodName === "replayBundle" || 242 | methodName === "sendTrytes") { 243 | p[1] = p[1] || node.depth || settings.depth; 244 | p[2] = p[2] || node.mwm || settings.mwm; 245 | } 246 | return method.apply(void 0, p); 247 | }, function (res) { 248 | if (settings.snapshotAware && methodName === "getTrytes") { 249 | var trytes = res; 250 | if (trytes) { 251 | for (var i = 0; i < trytes.length; i++) { 252 | if (validators.isEmpty(trytes[i])) { 253 | return "Data has been removed by snapshot"; 254 | } 255 | } 256 | } 257 | } 258 | return ""; 259 | }) 260 | .then(function (res) { 261 | if (originalCallbackParam) { 262 | originalCallbackParam(null, res); 263 | return undefined; 264 | } 265 | else { 266 | return res; 267 | } 268 | }).catch(function (err) { 269 | if (originalCallbackParam) { 270 | originalCallbackParam(err); 271 | } 272 | else { 273 | throw err; 274 | } 275 | })]; 276 | }); 277 | }); 278 | }; 279 | } 280 | 281 | /** 282 | * Create a new instance of the API wrapped with load balancing support. 283 | * @param settings The load balancer settings. 284 | * @returns The api. 285 | */ 286 | function composeAPI(settings) { 287 | if (!settings) { 288 | throw new Error("You must provider settings"); 289 | } 290 | if (!settings.nodeWalkStrategy) { 291 | throw new Error("The nodeWalkStrategy field must be provided"); 292 | } 293 | settings.mwm = settings.mwm || 9; 294 | settings.depth = settings.depth || 3; 295 | settings.successMode = settings.successMode || exports.SuccessMode.next; 296 | settings.failMode = settings.failMode || exports.FailMode.all; 297 | var api = core.composeAPI({ attachToTangle: settings.attachToTangle }); 298 | // Wrap all the web methods with additional handling 299 | api.addNeighbors = wrapMethodCallbackOrAsync(settings, api, api.addNeighbors, "addNeighbors"); 300 | api.broadcastTransactions = wrapMethodCallbackOrAsync(settings, api, api.broadcastTransactions, "broadcastTransactions"); 301 | api.checkConsistency = wrapMethodCallbackOrAsync(settings, api, api.checkConsistency, "checkConsistency"); 302 | api.findTransactions = wrapMethodCallbackOrAsync(settings, api, api.findTransactions, "findTransactions"); 303 | api.getBalances = wrapMethodCallbackOrAsync(settings, api, api.getBalances, "getBalances"); 304 | api.getInclusionStates = wrapMethodCallbackOrAsync(settings, api, api.getInclusionStates, "getInclusionStates"); 305 | api.getNeighbors = wrapMethodCallbackOrAsync(settings, api, api.getNeighbors, "getNeighbors"); 306 | api.getNodeInfo = wrapMethodCallbackOrAsync(settings, api, api.getNodeInfo, "getNodeInfo"); 307 | api.getTransactionsToApprove = wrapMethodCallbackOrAsync(settings, api, api.getTransactionsToApprove, "getTransactionsToApprove"); 308 | api.getTrytes = wrapMethodCallbackOrAsync(settings, api, api.getTrytes, "getTrytes"); 309 | api.interruptAttachingToTangle = wrapMethodCallbackOrAsync(settings, api, api.interruptAttachingToTangle, "interruptAttachingToTangle"); 310 | api.removeNeighbors = wrapMethodCallbackOrAsync(settings, api, api.removeNeighbors, "removeNeighbors"); 311 | api.storeTransactions = wrapMethodCallbackOrAsync(settings, api, api.storeTransactions, "storeTransactions"); 312 | api.broadcastBundle = wrapMethodCallbackOrAsync(settings, api, api.broadcastBundle, "broadcastBundle"); 313 | api.getAccountData = wrapMethodCallbackOrAsync(settings, api, api.getAccountData, "getAccountData"); 314 | api.getBundle = wrapMethodCallbackOrAsync(settings, api, api.getBundle, "getBundle"); 315 | api.getBundlesFromAddresses = wrapMethodCallbackOrAsync(settings, api, api.getBundlesFromAddresses, "getBundlesFromAddresses"); 316 | api.getNewAddress = wrapMethodCallbackOrAsync(settings, api, api.getNewAddress, "getNewAddress"); 317 | api.getTransactionObjects = wrapMethodCallbackOrAsync(settings, api, api.getTransactionObjects, "getTransactionObjects"); 318 | api.findTransactionObjects = wrapMethodCallbackOrAsync(settings, api, api.findTransactionObjects, "findTransactionObjects"); 319 | api.getInputs = wrapMethodCallbackOrAsync(settings, api, api.getInputs, "getInputs"); 320 | api.getTransfers = wrapMethodCallbackOrAsync(settings, api, api.getTransfers, "getTransfers"); 321 | api.isPromotable = wrapMethodCallbackOrAsync(settings, api, api.isPromotable, "isPromotable"); 322 | api.isReattachable = wrapMethodCallbackOrAsync(settings, api, api.isReattachable, "isReattachable"); 323 | api.prepareTransfers = wrapMethodCallbackOrAsync(settings, api, api.prepareTransfers, "prepareTransfers"); 324 | api.promoteTransaction = wrapMethodCallbackOrAsync(settings, api, api.promoteTransaction, "promoteTransaction"); 325 | api.replayBundle = wrapMethodCallbackOrAsync(settings, api, api.replayBundle, "replayBundle"); 326 | api.sendTrytes = wrapMethodCallbackOrAsync(settings, api, api.sendTrytes, "sendTrytes"); 327 | api.storeAndBroadcast = wrapMethodCallbackOrAsync(settings, api, api.storeAndBroadcast, "storeAndBroadcast"); 328 | api.traverseBundle = wrapMethodCallbackOrAsync(settings, api, api.traverseBundle, "traverseBundle"); 329 | return api; 330 | } 331 | 332 | /** 333 | * Wrapper for Mam with load balancing 334 | */ 335 | var Mam = /** @class */ (function () { 336 | function Mam() { 337 | } 338 | /** 339 | * Initialisation function which returns a state object 340 | * @param settings Settings for the load balancer. 341 | * @param seed The seed to initialise with. 342 | * @param security The security level, defaults to 2. 343 | * @returns The mam state. 344 | */ 345 | Mam.init = function (settings, seed, security) { 346 | if (security === void 0) { security = 2; } 347 | if (!settings) { 348 | throw new Error("You must provider settings"); 349 | } 350 | if (!settings.nodeWalkStrategy) { 351 | throw new Error("The nodeWalkStrategy field must be provided"); 352 | } 353 | settings.mwm = settings.mwm || 9; 354 | settings.depth = settings.depth || 3; 355 | settings.successMode = settings.successMode || exports.SuccessMode.next; 356 | settings.failMode = settings.failMode || exports.FailMode.all; 357 | Mam.loadBalancerSettings = settings; 358 | return MamCore.init({ provider: "" }, seed, security); 359 | }; 360 | /** 361 | * Change the mode for the mam state. 362 | * @param state The current mam state. 363 | * @param mode [public/private/restricted]. 364 | * @param sidekey, required for restricted mode. 365 | * @returns Updated state object to be used with future actions. 366 | */ 367 | Mam.changeMode = function (state, mode, sidekey) { 368 | return MamCore.changeMode(state, mode, sidekey); 369 | }; 370 | /** 371 | * Get the root from the mam state. 372 | * @param state The mam state. 373 | * @returns The root. 374 | */ 375 | Mam.getRoot = function (state) { 376 | return MamCore.getRoot(state); 377 | }; 378 | /** 379 | * Add a subscription to your state object 380 | * @param state The state object to add the subscription to. 381 | * @param channelRoot The root of the channel to subscribe to. 382 | * @param channelMode Can be `public`, `private` or `restricted`. 383 | * @param channelKey Optional, the key of the channel to subscribe to. 384 | * @returns Updated state object to be used with future actions. 385 | */ 386 | Mam.subscribe = function (state, channelRoot, channelMode, channelKey) { 387 | return MamCore.subscribe(state, channelRoot, channelMode, channelKey); 388 | }; 389 | /** 390 | * Listen for new message on the channel. 391 | * @param channel The channel to listen on. 392 | * @param callback The callback to receive any messages, 393 | */ 394 | Mam.listen = function (channel, callback) { 395 | return MamCore.listen(channel, callback); 396 | }; 397 | /** 398 | * Creates a MAM message payload from a state object. 399 | * @param state The current mam state. 400 | * @param message Tryte encoded string. 401 | * @returns An object containing the payload and updated state. 402 | */ 403 | Mam.create = function (state, message) { 404 | return MamCore.create(state, message); 405 | }; 406 | /** 407 | * Decode a message. 408 | * @param payload The payload of the message. 409 | * @param sideKey The sideKey used in the message. 410 | * @param root The root used for the message. 411 | * @returns The decoded payload. 412 | */ 413 | Mam.decode = function (payload, sideKey, root) { 414 | return MamCore.decode(payload, sideKey, root); 415 | }; 416 | /** 417 | * Fetch the messages asynchronously. 418 | * @param root The root key to use. 419 | * @param mode The mode of the channel. 420 | * @param sideKey The sideKey used in the messages, only required for restricted. 421 | * @param callback Optional callback to receive each payload. 422 | * @param limit Limit the number of messages that are fetched. 423 | * @returns The nextRoot and the messages if no callback was supplied, or an Error. 424 | */ 425 | Mam.fetch = function (root, mode, sideKey, callback, limit) { 426 | return __awaiter(this, void 0, Promise, function () { 427 | return __generator(this, function (_a) { 428 | return [2 /*return*/, loadBalancer(Mam.loadBalancerSettings, function (node) { 429 | MamCore.setIOTA(node.provider); 430 | MamCore.setAttachToTangle(node.attachToTangle || Mam.loadBalancerSettings.attachToTangle); 431 | }, function () { return new Bluebird__namespace(function (resolve, reject) { 432 | MamCore.fetch(root, mode, sideKey, callback, limit) 433 | .then(resolve) 434 | .catch(reject); 435 | }); })]; 436 | }); 437 | }); 438 | }; 439 | /** 440 | * Fetch a single message asynchronously. 441 | * @param root The root key to use. 442 | * @param mode The mode of the channel. 443 | * @param sideKey The sideKey used in the messages. 444 | * @returns The nextRoot and the payload, or an Error. 445 | */ 446 | Mam.fetchSingle = function (root, mode, sideKey) { 447 | return __awaiter(this, void 0, Promise, function () { 448 | var response; 449 | return __generator(this, function (_a) { 450 | switch (_a.label) { 451 | case 0: return [4 /*yield*/, Mam.fetch(root, mode, sideKey, undefined, 1)]; 452 | case 1: 453 | response = _a.sent(); 454 | return [2 /*return*/, response instanceof Error ? response : { 455 | payload: response.messages && response.messages.length === 1 ? response.messages[0] : undefined, 456 | nextRoot: response.nextRoot 457 | }]; 458 | } 459 | }); 460 | }); 461 | }; 462 | /** 463 | * Attach the mam trytes to the tangle. 464 | * @param trytes The trytes to attach. 465 | * @param root The root to attach them to. 466 | * @param depth The depth to attach them with, defaults to 3. 467 | * @param mwm The minimum weight magnitude to attach with, defaults to 9 for devnet, 14 required for mainnet. 468 | * @param tag Trytes to tag the message with. 469 | * @returns The transaction objects. 470 | */ 471 | Mam.attach = function (trytes, root, depth, mwm, tag) { 472 | return __awaiter(this, void 0, Promise, function () { 473 | var _a, prepareTransfers, sendTrytes, response; 474 | return __generator(this, function (_b) { 475 | switch (_b.label) { 476 | case 0: 477 | _a = composeAPI(Mam.loadBalancerSettings), prepareTransfers = _a.prepareTransfers, sendTrytes = _a.sendTrytes; 478 | return [4 /*yield*/, prepareTransfers("9".repeat(81), [ 479 | { 480 | address: root, 481 | value: 0, 482 | message: trytes, 483 | tag: tag 484 | } 485 | ])]; 486 | case 1: 487 | response = _b.sent(); 488 | return [2 /*return*/, sendTrytes(response, depth || 0, mwm || 0)]; 489 | } 490 | }); 491 | }); 492 | }; 493 | return Mam; 494 | }()); 495 | 496 | /** 497 | * Settings to use for the load balancer. 498 | */ 499 | var LoadBalancerSettings = /** @class */ (function () { 500 | function LoadBalancerSettings() { 501 | } 502 | return LoadBalancerSettings; 503 | }()); 504 | 505 | /** 506 | * The configuration for a single node. 507 | */ 508 | var NodeConfiguration = /** @class */ (function () { 509 | function NodeConfiguration() { 510 | } 511 | return NodeConfiguration; 512 | }()); 513 | 514 | /** 515 | * Common features for the node strategies. 516 | * @private 517 | */ 518 | var BaseWalkStrategy = /** @class */ (function () { 519 | /** 520 | * Create a new instance of BaseWalkStrategy. 521 | * @param nodes The nodes to iterate through. 522 | * @param blacklistLimit The number of failures before a node is blacklisted. 523 | */ 524 | function BaseWalkStrategy(nodes, blacklistLimit) { 525 | if (!nodes || nodes.length === 0) { 526 | throw new Error("You must supply at least one node to the strategy"); 527 | } 528 | this._allNodes = nodes; 529 | this._usableNodes = nodes.slice(); 530 | this._blacklistLimit = blacklistLimit; 531 | this._blacklistNodes = {}; 532 | } 533 | /** 534 | * The total number of nodes configured for the strategy. 535 | * @returns The total number of nodes. 536 | */ 537 | BaseWalkStrategy.prototype.totalUsable = function () { 538 | return this._usableNodes.length; 539 | }; 540 | /** 541 | * Blacklist the current node, so it doesn't get used again once limit is reached. 542 | */ 543 | BaseWalkStrategy.prototype.blacklist = function () { 544 | if (this._blacklistLimit) { 545 | var current = this.current(); 546 | if (current) { 547 | if (!this._blacklistNodes[current.provider]) { 548 | this._blacklistNodes[current.provider] = 1; 549 | } 550 | else { 551 | this._blacklistNodes[current.provider]++; 552 | } 553 | if (this._blacklistNodes[current.provider] >= this._blacklistLimit) { 554 | var idx = this._usableNodes.indexOf(current); 555 | if (idx >= 0) { 556 | this._usableNodes.splice(idx, 1); 557 | } 558 | } 559 | // If there are no usable nodes left then reset the blacklists 560 | if (this._usableNodes.length === 0) { 561 | this._blacklistNodes = {}; 562 | this._usableNodes = this._allNodes.slice(); 563 | } 564 | } 565 | } 566 | }; 567 | /** 568 | * Get the list of nodes that have not been blacklisted. 569 | * @returns The non blacklisted nodes. 570 | */ 571 | BaseWalkStrategy.prototype.getUsableNodes = function () { 572 | return this._usableNodes; 573 | }; 574 | return BaseWalkStrategy; 575 | }()); 576 | 577 | /** 578 | * Node choice strategy which just iterates through the list of nodes. 579 | */ 580 | var LinearWalkStrategy = /** @class */ (function (_super) { 581 | __extends(LinearWalkStrategy, _super); 582 | /** 583 | * Create a new instance of LinearWalkStrategy. 584 | * @param nodes The nodes to randomly pick from. 585 | * @param blacklistLimit The number of failures before a node is blacklisted. 586 | */ 587 | function LinearWalkStrategy(nodes, blacklistLimit) { 588 | var _this = _super.call(this, nodes, blacklistLimit) || this; 589 | _this._currentIndex = 0; 590 | return _this; 591 | } 592 | /** 593 | * Get the current node from the strategy. 594 | * @returns A node configuration from the strategy. 595 | */ 596 | LinearWalkStrategy.prototype.current = function () { 597 | return this.getUsableNodes()[this._currentIndex]; 598 | }; 599 | /** 600 | * Move to the next node in the strategy. 601 | * @param retainOrder Retain the ordering if resetting the list. 602 | */ 603 | LinearWalkStrategy.prototype.next = function (retainOrder) { 604 | this._currentIndex = (this._currentIndex + 1) % this.getUsableNodes().length; 605 | }; 606 | return LinearWalkStrategy; 607 | }(BaseWalkStrategy)); 608 | 609 | /** 610 | * Node choice strategy which randomly picks from the list of nodes. 611 | */ 612 | var RandomWalkStrategy = /** @class */ (function (_super) { 613 | __extends(RandomWalkStrategy, _super); 614 | /** 615 | * Create a new instance of RandomWalkStategy. 616 | * @param nodes The nodes to randomly pick from. 617 | * @param blacklistLimit The number of failures before a node is blacklisted. 618 | */ 619 | function RandomWalkStrategy(nodes, blacklistLimit) { 620 | var _this = _super.call(this, nodes, blacklistLimit) || this; 621 | _this._remainingNodes = []; 622 | _this._randomNodes = []; 623 | _this.populateRemaining(); 624 | return _this; 625 | } 626 | /** 627 | * Get the current node from the strategy. 628 | * @returns A node configuration from the strategy. 629 | */ 630 | RandomWalkStrategy.prototype.current = function () { 631 | return this._remainingNodes[0]; 632 | }; 633 | /** 634 | * Move to the next node in the strategy. 635 | * @param retainOrder Retain the ordering if resetting the list. 636 | */ 637 | RandomWalkStrategy.prototype.next = function (retainOrder) { 638 | this._remainingNodes.shift(); 639 | if (this._remainingNodes.length === 0) { 640 | if (retainOrder) { 641 | this._remainingNodes = this._randomNodes.slice(); 642 | } 643 | else { 644 | this.populateRemaining(); 645 | } 646 | } 647 | }; 648 | /** 649 | * Populate the remaining array by randomizing the nodes. 650 | * @internal 651 | * @private 652 | */ 653 | RandomWalkStrategy.prototype.populateRemaining = function () { 654 | var _a; 655 | this._remainingNodes = _super.prototype.getUsableNodes.call(this).slice(); 656 | for (var i = this._remainingNodes.length - 1; i > 0; i--) { 657 | // tslint:disable-next-line:insecure-random 658 | var j = Math.floor(Math.random() * (i + 1)); 659 | _a = [this._remainingNodes[j], this._remainingNodes[i]], this._remainingNodes[i] = _a[0], this._remainingNodes[j] = _a[1]; 660 | } 661 | this._randomNodes = this._remainingNodes.slice(); 662 | }; 663 | return RandomWalkStrategy; 664 | }(BaseWalkStrategy)); 665 | 666 | exports.LinearWalkStrategy = LinearWalkStrategy; 667 | exports.LoadBalancerSettings = LoadBalancerSettings; 668 | exports.Mam = Mam; 669 | exports.NodeConfiguration = NodeConfiguration; 670 | exports.RandomWalkStrategy = RandomWalkStrategy; 671 | exports.composeAPI = composeAPI; 672 | 673 | Object.defineProperty(exports, '__esModule', { value: true }); 674 | 675 | }))); 676 | -------------------------------------------------------------------------------- /dist/iota-client-load-balancer.min.js: -------------------------------------------------------------------------------- 1 | !function(e,t){"object"==typeof exports&&"undefined"!=typeof module?t(exports,require("@iota/core"),require("@iota/validators"),require("@iota/mam"),require("bluebird")):"function"==typeof define&&define.amd?define(["exports","@iota/core","@iota/validators","@iota/mam","bluebird"],t):t((e="undefined"!=typeof globalThis?globalThis:e||self).IotaClientLoadBalancer={},e.core,e.validators,e.MamCore,e.Bluebird)}(this,(function(e,t,n,r,o){"use strict";function s(e){if(e&&e.__esModule)return e;var t=Object.create(null);return e&&Object.keys(e).forEach((function(n){if("default"!==n){var r=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(t,n,r.get?r:{enumerable:!0,get:function(){return e[n]}})}})),t.default=e,Object.freeze(t)}var a,i,c=s(o),l=function(e,t){return(l=Object.setPrototypeOf||{__proto__:[]}instanceof Array&&function(e,t){e.__proto__=t}||function(e,t){for(var n in t)t.hasOwnProperty(n)&&(e[n]=t[n])})(e,t)}; 2 | /*! ***************************************************************************** 3 | Copyright (c) Microsoft Corporation. All rights reserved. 4 | Licensed under the Apache License, Version 2.0 (the "License"); you may not use 5 | this file except in compliance with the License. You may obtain a copy of the 6 | License at http://www.apache.org/licenses/LICENSE-2.0 7 | 8 | THIS CODE IS PROVIDED ON AN *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY 9 | KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED 10 | WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, 11 | MERCHANTABLITY OR NON-INFRINGEMENT. 12 | 13 | See the Apache Version 2.0 License for specific language governing permissions 14 | and limitations under the License. 15 | ***************************************************************************** */function u(e,t){function n(){this.constructor=e}l(e,t),e.prototype=null===t?Object.create(t):(n.prototype=t.prototype,new n)}function d(e,t,n,r){return new(n||(n=Promise))((function(o,s){function a(e){try{c(r.next(e))}catch(e){s(e)}}function i(e){try{c(r.throw(e))}catch(e){s(e)}}function c(e){e.done?o(e.value):new n((function(t){t(e.value)})).then(a,i)}c((r=r.apply(e,t||[])).next())}))}function f(e,t){var n,r,o,s,a={label:0,sent:function(){if(1&o[0])throw o[1];return o[1]},trys:[],ops:[]};return s={next:i(0),throw:i(1),return:i(2)},"function"==typeof Symbol&&(s[Symbol.iterator]=function(){return this}),s;function i(s){return function(i){return function(s){if(n)throw new TypeError("Generator is already executing.");for(;a;)try{if(n=1,r&&(o=2&s[0]?r.return:s[0]?r.throw||((o=r.return)&&o.call(r),0):r.next)&&!(o=o.call(r,s[1])).done)return o;switch(r=0,o&&(s=[2&s[0],o.value]),s[0]){case 0:case 1:o=s;break;case 4:return a.label++,{value:s[1],done:!1};case 5:a.label++,r=s[1],s=[0];continue;case 7:s=a.ops.pop(),a.trys.pop();continue;default:if(!(o=a.trys,(o=o.length>0&&o[o.length-1])||6!==s[0]&&2!==s[0])){a=0;continue}if(3===s[0]&&(!o||s[1]>o[0]&&s[1]Wrapper for Mam with load balancing
6 |Settings to use for the load balancer.
9 |The configuration for a single node.
12 |Node choice strategy which just iterates through the list of nodes.
15 |Node choice strategy which randomly picks from the list of nodes.
18 |Fail modes for the load balancer.
26 |Success modes for the load balancer.
29 |Create a new instance of the API wrapped with load balancing support.
37 |Mam
](#Mam)
65 | **Returns**: The mam state.
66 |
67 | | Param | Default | Description |
68 | | --- | --- | --- |
69 | | settings | | Settings for the load balancer. |
70 | | seed | | The seed to initialise with. |
71 | | security | 2
| The security level, defaults to 2. |
72 |
73 |
74 |
75 | ### Mam.changeMode(state, mode, sidekey,) ⇒
76 | Change the mode for the mam state.
77 |
78 | **Kind**: static method of [Mam
](#Mam)
79 | **Returns**: Updated state object to be used with future actions.
80 |
81 | | Param | Description |
82 | | --- | --- |
83 | | state | The current mam state. |
84 | | mode | [public/private/restricted]. |
85 | | sidekey, | required for restricted mode. |
86 |
87 |
88 |
89 | ### Mam.getRoot(state) ⇒
90 | Get the root from the mam state.
91 |
92 | **Kind**: static method of [Mam
](#Mam)
93 | **Returns**: The root.
94 |
95 | | Param | Description |
96 | | --- | --- |
97 | | state | The mam state. |
98 |
99 |
100 |
101 | ### Mam.subscribe(state, channelRoot, channelMode, channelKey) ⇒
102 | Add a subscription to your state object
103 |
104 | **Kind**: static method of [Mam
](#Mam)
105 | **Returns**: Updated state object to be used with future actions.
106 |
107 | | Param | Description |
108 | | --- | --- |
109 | | state | The state object to add the subscription to. |
110 | | channelRoot | The root of the channel to subscribe to. |
111 | | channelMode | Can be `public`, `private` or `restricted`. |
112 | | channelKey | Optional, the key of the channel to subscribe to. |
113 |
114 |
115 |
116 | ### Mam.listen(channel, callback)
117 | Listen for new message on the channel.
118 |
119 | **Kind**: static method of [Mam
](#Mam)
120 |
121 | | Param | Description |
122 | | --- | --- |
123 | | channel | The channel to listen on. |
124 | | callback | The callback to receive any messages, |
125 |
126 |
127 |
128 | ### Mam.create(state, message) ⇒
129 | Creates a MAM message payload from a state object.
130 |
131 | **Kind**: static method of [Mam
](#Mam)
132 | **Returns**: An object containing the payload and updated state.
133 |
134 | | Param | Description |
135 | | --- | --- |
136 | | state | The current mam state. |
137 | | message | Tryte encoded string. |
138 |
139 |
140 |
141 | ### Mam.decode(payload, sideKey, root) ⇒
142 | Decode a message.
143 |
144 | **Kind**: static method of [Mam
](#Mam)
145 | **Returns**: The decoded payload.
146 |
147 | | Param | Description |
148 | | --- | --- |
149 | | payload | The payload of the message. |
150 | | sideKey | The sideKey used in the message. |
151 | | root | The root used for the message. |
152 |
153 |
154 |
155 | ### Mam.fetch(root, mode, sideKey, callback, limit) ⇒
156 | Fetch the messages asynchronously.
157 |
158 | **Kind**: static method of [Mam
](#Mam)
159 | **Returns**: The nextRoot and the messages if no callback was supplied, or an Error.
160 |
161 | | Param | Description |
162 | | --- | --- |
163 | | root | The root key to use. |
164 | | mode | The mode of the channel. |
165 | | sideKey | The sideKey used in the messages, only required for restricted. |
166 | | callback | Optional callback to receive each payload. |
167 | | limit | Limit the number of messages that are fetched. |
168 |
169 |
170 |
171 | ### Mam.fetchSingle(root, mode, sideKey) ⇒
172 | Fetch a single message asynchronously.
173 |
174 | **Kind**: static method of [Mam
](#Mam)
175 | **Returns**: The nextRoot and the payload, or an Error.
176 |
177 | | Param | Description |
178 | | --- | --- |
179 | | root | The root key to use. |
180 | | mode | The mode of the channel. |
181 | | sideKey | The sideKey used in the messages. |
182 |
183 |
184 |
185 | ### Mam.attach(trytes, root, depth, mwm, tag) ⇒
186 | Attach the mam trytes to the tangle.
187 |
188 | **Kind**: static method of [Mam
](#Mam)
189 | **Returns**: The transaction objects.
190 |
191 | | Param | Description |
192 | | --- | --- |
193 | | trytes | The trytes to attach. |
194 | | root | The root to attach them to. |
195 | | depth | The depth to attach them with, defaults to 3. |
196 | | mwm | The minimum weight magnitude to attach with, defaults to 9 for devnet, 14 required for mainnet. |
197 | | tag | Trytes to tag the message with. |
198 |
199 |
200 |
201 | ## LoadBalancerSettings
202 | Settings to use for the load balancer.
203 |
204 | **Kind**: global class
205 |
206 |
207 | ## NodeConfiguration
208 | The configuration for a single node.
209 |
210 | **Kind**: global class
211 |
212 |
213 | ## LinearWalkStrategy
214 | Node choice strategy which just iterates through the list of nodes.
215 |
216 | **Kind**: global class
217 |
218 | * [LinearWalkStrategy](#LinearWalkStrategy)
219 | * [new LinearWalkStrategy(nodes, blacklistLimit)](#new_LinearWalkStrategy_new)
220 | * [.current()](#LinearWalkStrategy+current) ⇒
221 | * [.next(retainOrder)](#LinearWalkStrategy+next)
222 |
223 |
224 |
225 | ### new LinearWalkStrategy(nodes, blacklistLimit)
226 | Create a new instance of LinearWalkStrategy.
227 |
228 |
229 | | Param | Description |
230 | | --- | --- |
231 | | nodes | The nodes to randomly pick from. |
232 | | blacklistLimit | The number of failures before a node is blacklisted. |
233 |
234 |
235 |
236 | ### linearWalkStrategy.current() ⇒
237 | Get the current node from the strategy.
238 |
239 | **Kind**: instance method of [LinearWalkStrategy
](#LinearWalkStrategy)
240 | **Returns**: A node configuration from the strategy.
241 |
242 |
243 | ### linearWalkStrategy.next(retainOrder)
244 | Move to the next node in the strategy.
245 |
246 | **Kind**: instance method of [LinearWalkStrategy
](#LinearWalkStrategy)
247 |
248 | | Param | Description |
249 | | --- | --- |
250 | | retainOrder | Retain the ordering if resetting the list. |
251 |
252 |
253 |
254 | ## RandomWalkStrategy
255 | Node choice strategy which randomly picks from the list of nodes.
256 |
257 | **Kind**: global class
258 |
259 | * [RandomWalkStrategy](#RandomWalkStrategy)
260 | * [new RandomWalkStrategy(nodes, blacklistLimit)](#new_RandomWalkStrategy_new)
261 | * [.current()](#RandomWalkStrategy+current) ⇒
262 | * [.next(retainOrder)](#RandomWalkStrategy+next)
263 |
264 |
265 |
266 | ### new RandomWalkStrategy(nodes, blacklistLimit)
267 | Create a new instance of RandomWalkStategy.
268 |
269 |
270 | | Param | Description |
271 | | --- | --- |
272 | | nodes | The nodes to randomly pick from. |
273 | | blacklistLimit | The number of failures before a node is blacklisted. |
274 |
275 |
276 |
277 | ### randomWalkStrategy.current() ⇒
278 | Get the current node from the strategy.
279 |
280 | **Kind**: instance method of [RandomWalkStrategy
](#RandomWalkStrategy)
281 | **Returns**: A node configuration from the strategy.
282 |
283 |
284 | ### randomWalkStrategy.next(retainOrder)
285 | Move to the next node in the strategy.
286 |
287 | **Kind**: instance method of [RandomWalkStrategy
](#RandomWalkStrategy)
288 |
289 | | Param | Description |
290 | | --- | --- |
291 | | retainOrder | Retain the ordering if resetting the list. |
292 |
293 |
294 |
295 | ## FailMode
296 | Fail modes for the load balancer.
297 |
298 | **Kind**: global variable
299 |
300 | * [FailMode](#FailMode)
301 | * [.single](#FailMode.single)
302 | * [.all](#FailMode.all)
303 |
304 |
305 |
306 | ### FailMode.single
307 | Try single node only, failure throws exception.
308 |
309 | **Kind**: static property of [FailMode
](#FailMode)
310 |
311 |
312 | ### FailMode.all
313 | Try all nodes until one succeeds, on all failing throws combined exception.
314 |
315 | **Kind**: static property of [FailMode
](#FailMode)
316 |
317 |
318 | ## SuccessMode
319 | Success modes for the load balancer.
320 |
321 | **Kind**: global variable
322 |
323 | * [SuccessMode](#SuccessMode)
324 | * [.keep](#SuccessMode.keep)
325 | * [.next](#SuccessMode.next)
326 |
327 |
328 |
329 | ### SuccessMode.keep
330 | Keep the node if it was successful.
331 |
332 | **Kind**: static property of [SuccessMode
](#SuccessMode)
333 |
334 |
335 | ### SuccessMode.next
336 | Move to the next node even if it was successful.
337 |
338 | **Kind**: static property of [SuccessMode
](#SuccessMode)
339 |
340 |
341 | ## composeAPI(settings) ⇒
342 | Create a new instance of the API wrapped with load balancing support.
343 |
344 | **Kind**: global function
345 | **Returns**: The api.
346 |
347 | | Param | Description |
348 | | --- | --- |
349 | | settings | The load balancer settings. |
350 |
351 |
--------------------------------------------------------------------------------
/es/composeAPI.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.composeAPI = void 0;
4 | const core_1 = require("@iota/core");
5 | const internals_1 = require("./internals");
6 | const failMode_1 = require("./models/failMode");
7 | const successMode_1 = require("./models/successMode");
8 | /**
9 | * Create a new instance of the API wrapped with load balancing support.
10 | * @param settings The load balancer settings.
11 | * @returns The api.
12 | */
13 | function composeAPI(settings) {
14 | if (!settings) {
15 | throw new Error("You must provider settings");
16 | }
17 | if (!settings.nodeWalkStrategy) {
18 | throw new Error("The nodeWalkStrategy field must be provided");
19 | }
20 | settings.mwm = settings.mwm || 9;
21 | settings.depth = settings.depth || 3;
22 | settings.successMode = settings.successMode || successMode_1.SuccessMode.next;
23 | settings.failMode = settings.failMode || failMode_1.FailMode.all;
24 | const api = core_1.composeAPI({ attachToTangle: settings.attachToTangle });
25 | // Wrap all the web methods with additional handling
26 | api.addNeighbors = internals_1.wrapMethodCallbackOrAsync(settings, api, api.addNeighbors, "addNeighbors");
27 | api.broadcastTransactions = internals_1.wrapMethodCallbackOrAsync(settings, api, api.broadcastTransactions, "broadcastTransactions");
28 | api.checkConsistency = internals_1.wrapMethodCallbackOrAsync(settings, api, api.checkConsistency, "checkConsistency");
29 | api.findTransactions = internals_1.wrapMethodCallbackOrAsync(settings, api, api.findTransactions, "findTransactions");
30 | api.getBalances = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getBalances, "getBalances");
31 | api.getInclusionStates = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getInclusionStates, "getInclusionStates");
32 | api.getNeighbors = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getNeighbors, "getNeighbors");
33 | api.getNodeInfo = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getNodeInfo, "getNodeInfo");
34 | api.getTransactionsToApprove = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getTransactionsToApprove, "getTransactionsToApprove");
35 | api.getTrytes = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getTrytes, "getTrytes");
36 | api.interruptAttachingToTangle = internals_1.wrapMethodCallbackOrAsync(settings, api, api.interruptAttachingToTangle, "interruptAttachingToTangle");
37 | api.removeNeighbors = internals_1.wrapMethodCallbackOrAsync(settings, api, api.removeNeighbors, "removeNeighbors");
38 | api.storeTransactions = internals_1.wrapMethodCallbackOrAsync(settings, api, api.storeTransactions, "storeTransactions");
39 | api.broadcastBundle = internals_1.wrapMethodCallbackOrAsync(settings, api, api.broadcastBundle, "broadcastBundle");
40 | api.getAccountData = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getAccountData, "getAccountData");
41 | api.getBundle = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getBundle, "getBundle");
42 | api.getBundlesFromAddresses = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getBundlesFromAddresses, "getBundlesFromAddresses");
43 | api.getNewAddress = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getNewAddress, "getNewAddress");
44 | api.getTransactionObjects = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getTransactionObjects, "getTransactionObjects");
45 | api.findTransactionObjects = internals_1.wrapMethodCallbackOrAsync(settings, api, api.findTransactionObjects, "findTransactionObjects");
46 | api.getInputs = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getInputs, "getInputs");
47 | api.getTransfers = internals_1.wrapMethodCallbackOrAsync(settings, api, api.getTransfers, "getTransfers");
48 | api.isPromotable = internals_1.wrapMethodCallbackOrAsync(settings, api, api.isPromotable, "isPromotable");
49 | api.isReattachable = internals_1.wrapMethodCallbackOrAsync(settings, api, api.isReattachable, "isReattachable");
50 | api.prepareTransfers = internals_1.wrapMethodCallbackOrAsync(settings, api, api.prepareTransfers, "prepareTransfers");
51 | api.promoteTransaction = internals_1.wrapMethodCallbackOrAsync(settings, api, api.promoteTransaction, "promoteTransaction");
52 | api.replayBundle = internals_1.wrapMethodCallbackOrAsync(settings, api, api.replayBundle, "replayBundle");
53 | api.sendTrytes = internals_1.wrapMethodCallbackOrAsync(settings, api, api.sendTrytes, "sendTrytes");
54 | api.storeAndBroadcast = internals_1.wrapMethodCallbackOrAsync(settings, api, api.storeAndBroadcast, "storeAndBroadcast");
55 | api.traverseBundle = internals_1.wrapMethodCallbackOrAsync(settings, api, api.traverseBundle, "traverseBundle");
56 | return api;
57 | }
58 | exports.composeAPI = composeAPI;
59 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiY29tcG9zZUFQSS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uL3NyYy9jb21wb3NlQVBJLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBLHFDQUErRDtBQUMvRCwyQ0FBd0Q7QUFDeEQsZ0RBQTZDO0FBRTdDLHNEQUFtRDtBQUVuRDs7OztHQUlHO0FBQ0gsU0FBZ0IsVUFBVSxDQUFDLFFBQThCO0lBQ3JELElBQUksQ0FBQyxRQUFRLEVBQUU7UUFDWCxNQUFNLElBQUksS0FBSyxDQUFDLDRCQUE0QixDQUFDLENBQUM7S0FDakQ7SUFDRCxJQUFJLENBQUMsUUFBUSxDQUFDLGdCQUFnQixFQUFFO1FBQzVCLE1BQU0sSUFBSSxLQUFLLENBQUMsNkNBQTZDLENBQUMsQ0FBQztLQUNsRTtJQUNELFFBQVEsQ0FBQyxHQUFHLEdBQUcsUUFBUSxDQUFDLEdBQUcsSUFBSSxDQUFDLENBQUM7SUFDakMsUUFBUSxDQUFDLEtBQUssR0FBRyxRQUFRLENBQUMsS0FBSyxJQUFJLENBQUMsQ0FBQztJQUNyQyxRQUFRLENBQUMsV0FBVyxHQUFHLFFBQVEsQ0FBQyxXQUFXLElBQUkseUJBQVcsQ0FBQyxJQUFJLENBQUM7SUFDaEUsUUFBUSxDQUFDLFFBQVEsR0FBRyxRQUFRLENBQUMsUUFBUSxJQUFJLG1CQUFRLENBQUMsR0FBRyxDQUFDO0lBRXRELE1BQU0sR0FBRyxHQUFHLGlCQUFjLENBQUMsRUFBRSxjQUFjLEVBQUUsUUFBUSxDQUFDLGNBQWMsRUFBRSxDQUFDLENBQUM7SUFFeEUsb0RBQW9EO0lBQ3BELEdBQUcsQ0FBQyxZQUFZLEdBQUcscUNBQXlCLENBQUMsUUFBUSxFQUFFLEdBQUcsRUFBRSxHQUFHLENBQUMsWUFBWSxFQUFFLGNBQWMsQ0FBQyxDQUFDO0lBQzlGLEdBQUcsQ0FBQyxxQkFBcUIsR0FBRyxxQ0FBeUIsQ0FBQyxRQUFRLEVBQUUsR0FBRyxFQUFFLEdBQUcsQ0FBQyxxQkFBcUIsRUFBRSx1QkFBdUIsQ0FBQyxDQUFDO0lBQ3pILEdB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
--------------------------------------------------------------------------------
/es/index.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
3 | if (k2 === undefined) k2 = k;
4 | Object.defineProperty(o, k2, { enumerable: true, get: function() { return m[k]; } });
5 | }) : (function(o, m, k, k2) {
6 | if (k2 === undefined) k2 = k;
7 | o[k2] = m[k];
8 | }));
9 | var __exportStar = (this && this.__exportStar) || function(m, exports) {
10 | for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
11 | };
12 | Object.defineProperty(exports, "__esModule", { value: true });
13 | __exportStar(require("./composeAPI"), exports);
14 | __exportStar(require("./mam"), exports);
15 | __exportStar(require("./models/failMode"), exports);
16 | __exportStar(require("./models/loadBalancerSettings"), exports);
17 | __exportStar(require("./models/nodeConfiguration"), exports);
18 | __exportStar(require("./models/nodeWalkStrategy"), exports);
19 | __exportStar(require("./models/successMode"), exports);
20 | __exportStar(require("./walkStrategies/linearWalkStrategy"), exports);
21 | __exportStar(require("./walkStrategies/randomWalkStrategy"), exports);
22 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6Ijs7Ozs7Ozs7Ozs7O0FBQUEsK0NBQTZCO0FBQzdCLHdDQUFzQjtBQUN0QixvREFBa0M7QUFDbEMsZ0VBQThDO0FBQzlDLDZEQUEyQztBQUMzQyw0REFBMEM7QUFDMUMsdURBQXFDO0FBQ3JDLHNFQUFvRDtBQUNwRCxzRUFBb0QifQ==
--------------------------------------------------------------------------------
/es/internals.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.wrapMethodCallbackOrAsync = exports.loadBalancer = void 0;
13 | const validators_1 = require("@iota/validators");
14 | const failMode_1 = require("./models/failMode");
15 | const successMode_1 = require("./models/successMode");
16 | /**
17 | * Create a new instance of the API.
18 | * @param settings The load balancer settings.
19 | * @param updateProvider Update the provider in the calling context.
20 | * @param methodPromise The method to call.
21 | * @param validateResult Let the caller validate the result.
22 | * @returns The api.
23 | * @private
24 | */
25 | function loadBalancer(settings, updateProvider, methodPromise, validateResult) {
26 | return __awaiter(this, void 0, void 0, function* () {
27 | let res;
28 | let tryNextNode = false;
29 | const totalNodes = settings.nodeWalkStrategy.totalUsable();
30 | let triedCount = 0;
31 | const errorList = [];
32 | do {
33 | // Get the next node from the strategy
34 | const node = settings.nodeWalkStrategy.current();
35 | updateProvider(node);
36 | if (settings.tryNodeCallback) {
37 | settings.tryNodeCallback(node);
38 | }
39 | try {
40 | const timeout = node.timeoutMs || settings.timeoutMs;
41 | if (timeout) {
42 | res = yield methodPromise(node).timeout(timeout, `${node.provider} the request timed out`);
43 | }
44 | else {
45 | res = yield methodPromise(node);
46 | }
47 | if (validateResult) {
48 | const validMessage = validateResult(res);
49 | if (validMessage) {
50 | throw new Error(validMessage);
51 | }
52 | }
53 | tryNextNode = false;
54 | if (settings.successMode === successMode_1.SuccessMode.next) {
55 | // Walk to the next node in the strategy
56 | settings.nodeWalkStrategy.next(false);
57 | }
58 | }
59 | catch (err) {
60 | settings.nodeWalkStrategy.blacklist();
61 | if (settings.failNodeCallback) {
62 | settings.failNodeCallback(node, err);
63 | }
64 | if (settings.failMode === failMode_1.FailMode.single) {
65 | // Single fail mode so just throw the error
66 | throw err;
67 | }
68 | else if (settings.failMode === failMode_1.FailMode.all) {
69 | // Fail mode is try all until one succeeds
70 | errorList.push(err.message ? err : { message: err });
71 | // Try to use the next node if the current one errored
72 | triedCount++;
73 | // But only if we have not already tried all the nodes
74 | tryNextNode = triedCount < totalNodes;
75 | if (!tryNextNode) {
76 | // No more nodes to try so throw the combined exceptions
77 | throw new Error(`All nodes failed\n ${errorList.map(e => e.message).join("\n ")}`);
78 | }
79 | // Walk to the next node in the strategy
80 | settings.nodeWalkStrategy.next(true);
81 | }
82 | }
83 | } while (tryNextNode);
84 | return res;
85 | });
86 | }
87 | exports.loadBalancer = loadBalancer;
88 | /**
89 | * Wrap a method and handle either callback or async result.
90 | * @param settings The load balancer settings.
91 | * @param api The composed api.
92 | * @param method The method to wrap.
93 | * @param methodName The name of the method.
94 | * @returns The wrapped method.
95 | * @private
96 | */
97 | function wrapMethodCallbackOrAsync(settings, api, method, methodName) {
98 | return (...p) => __awaiter(this, void 0, void 0, function* () {
99 | const originalCallbackParam = p[method.length - 1];
100 | // If the caller is using the callback parameter remove it and use the promise
101 | // method then restore on method completion.
102 | if (originalCallbackParam) {
103 | p[method.length - 1] = undefined;
104 | }
105 | return loadBalancer(settings, (node) => api.setSettings({
106 | provider: node.provider,
107 | attachToTangle: node.attachToTangle || settings.attachToTangle,
108 | user: node.user || settings.user,
109 | password: node.password || settings.password
110 | }), (node) => {
111 | // Apply the default depth and mwm to methods that use them if they have not been supplied
112 | if (methodName === "promoteTransaction" ||
113 | methodName === "replayBundle" ||
114 | methodName === "sendTrytes") {
115 | p[1] = p[1] || node.depth || settings.depth;
116 | p[2] = p[2] || node.mwm || settings.mwm;
117 | }
118 | return method(...p);
119 | }, (res) => {
120 | if (settings.snapshotAware && methodName === "getTrytes") {
121 | const trytes = res;
122 | if (trytes) {
123 | for (let i = 0; i < trytes.length; i++) {
124 | if (validators_1.isEmpty(trytes[i])) {
125 | return "Data has been removed by snapshot";
126 | }
127 | }
128 | }
129 | }
130 | return "";
131 | })
132 | .then((res) => {
133 | if (originalCallbackParam) {
134 | originalCallbackParam(null, res);
135 | return undefined;
136 | }
137 | else {
138 | return res;
139 | }
140 | }).catch((err) => {
141 | if (originalCallbackParam) {
142 | originalCallbackParam(err);
143 | }
144 | else {
145 | throw err;
146 | }
147 | });
148 | });
149 | }
150 | exports.wrapMethodCallbackOrAsync = wrapMethodCallbackOrAsync;
151 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW50ZXJuYWxzLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL2ludGVybmFscy50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFDQSxpREFBMkM7QUFFM0MsZ0RBQTZDO0FBRzdDLHNEQUFtRDtBQUVuRDs7Ozs7Ozs7R0FRRztBQUNILFNBQXNCLFlBQVksQ0FDOUIsUUFBOEIsRUFDOUIsY0FBaUQsRUFDakQsYUFBeUQsRUFDekQsY0FBcUM7O1FBQ3JDLElBQUksR0FBRyxDQUFDO1FBQ1IsSUFBSSxXQUFXLEdBQUcsS0FBSyxDQUFDO1FBQ3hCLE1BQU0sVUFBVSxHQUFHLFFBQVEsQ0FBQyxnQkFBZ0IsQ0FBQyxXQUFXLEVBQUUsQ0FBQztRQUMzRCxJQUFJLFVBQVUsR0FBRyxDQUFDLENBQUM7UUFDbkIsTUFBTSxTQUFTLEdBQVksRUFBRSxDQUFDO1FBRTlCLEdBQUc7WUFDQyxzQ0FBc0M7WUFDdEMsTUFBTSxJQUFJLEdBQUcsUUFBUSxDQUFDLGdCQUFnQixDQUFDLE9BQU8sRUFBRSxDQUFDO1lBRWpELGNBQWMsQ0FBQyxJQUFJLENBQUMsQ0FBQztZQUVyQixJQUFJLFFBQVEsQ0FBQyxlQUFlLEVBQUU7Z0JBQzFCLFFBQVEsQ0FBQyxlQUFlLENBQUMsSUFBSSxDQUFDLENBQUM7YUFDbEM7WUFFRCxJQUFJO2dCQUNBLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxTQUFTLElBQUksUUFBUSxDQUFDLFNBQVMsQ0FBQztnQkFDckQsSUFBSSxPQUFPLEVBQUU7b0JBQ1QsR0FBRyxHQUFHLE1BQU0sYUFBYSxDQUFDLElBQUksQ0FBQyxDQUFDLE9BQU8sQ0FBQyxPQUFPLEVBQUUsR0FBRyxJQUFJLENBQUMsUUFBUSx3QkFBd0IsQ0FBQyxDQUFDO2lCQUM5RjtxQkFBTTtvQkFDSCxHQUFHLEdBQUcsTUFBTSxhQUFhLENBQUMsSUFBSSxDQUFDLENBQUM7aUJBQ25DO2dCQUVELElBQUksY0FBYyxFQUFFO29CQUNoQixNQUFNLFlB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
--------------------------------------------------------------------------------
/es/mam.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3 | function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4 | return new (P || (P = Promise))(function (resolve, reject) {
5 | function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6 | function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7 | function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8 | step((generator = generator.apply(thisArg, _arguments || [])).next());
9 | });
10 | };
11 | Object.defineProperty(exports, "__esModule", { value: true });
12 | exports.Mam = void 0;
13 | const MamCore = require("@iota/mam");
14 | const Bluebird = require("bluebird");
15 | const composeAPI_1 = require("./composeAPI");
16 | const internals_1 = require("./internals");
17 | const failMode_1 = require("./models/failMode");
18 | const successMode_1 = require("./models/successMode");
19 | /**
20 | * Wrapper for Mam with load balancing
21 | */
22 | class Mam {
23 | /**
24 | * Initialisation function which returns a state object
25 | * @param settings Settings for the load balancer.
26 | * @param seed The seed to initialise with.
27 | * @param security The security level, defaults to 2.
28 | * @returns The mam state.
29 | */
30 | static init(settings, seed, security = 2) {
31 | if (!settings) {
32 | throw new Error("You must provider settings");
33 | }
34 | if (!settings.nodeWalkStrategy) {
35 | throw new Error("The nodeWalkStrategy field must be provided");
36 | }
37 | settings.mwm = settings.mwm || 9;
38 | settings.depth = settings.depth || 3;
39 | settings.successMode = settings.successMode || successMode_1.SuccessMode.next;
40 | settings.failMode = settings.failMode || failMode_1.FailMode.all;
41 | Mam.loadBalancerSettings = settings;
42 | return MamCore.init({ provider: "" }, seed, security);
43 | }
44 | /**
45 | * Change the mode for the mam state.
46 | * @param state The current mam state.
47 | * @param mode [public/private/restricted].
48 | * @param sidekey, required for restricted mode.
49 | * @returns Updated state object to be used with future actions.
50 | */
51 | static changeMode(state, mode, sidekey) {
52 | return MamCore.changeMode(state, mode, sidekey);
53 | }
54 | /**
55 | * Get the root from the mam state.
56 | * @param state The mam state.
57 | * @returns The root.
58 | */
59 | static getRoot(state) {
60 | return MamCore.getRoot(state);
61 | }
62 | /**
63 | * Add a subscription to your state object
64 | * @param state The state object to add the subscription to.
65 | * @param channelRoot The root of the channel to subscribe to.
66 | * @param channelMode Can be `public`, `private` or `restricted`.
67 | * @param channelKey Optional, the key of the channel to subscribe to.
68 | * @returns Updated state object to be used with future actions.
69 | */
70 | static subscribe(state, channelRoot, channelMode, channelKey) {
71 | return MamCore.subscribe(state, channelRoot, channelMode, channelKey);
72 | }
73 | /**
74 | * Listen for new message on the channel.
75 | * @param channel The channel to listen on.
76 | * @param callback The callback to receive any messages,
77 | */
78 | static listen(channel, callback) {
79 | return MamCore.listen(channel, callback);
80 | }
81 | /**
82 | * Creates a MAM message payload from a state object.
83 | * @param state The current mam state.
84 | * @param message Tryte encoded string.
85 | * @returns An object containing the payload and updated state.
86 | */
87 | static create(state, message) {
88 | return MamCore.create(state, message);
89 | }
90 | /**
91 | * Decode a message.
92 | * @param payload The payload of the message.
93 | * @param sideKey The sideKey used in the message.
94 | * @param root The root used for the message.
95 | * @returns The decoded payload.
96 | */
97 | static decode(payload, sideKey, root) {
98 | return MamCore.decode(payload, sideKey, root);
99 | }
100 | /**
101 | * Fetch the messages asynchronously.
102 | * @param root The root key to use.
103 | * @param mode The mode of the channel.
104 | * @param sideKey The sideKey used in the messages, only required for restricted.
105 | * @param callback Optional callback to receive each payload.
106 | * @param limit Limit the number of messages that are fetched.
107 | * @returns The nextRoot and the messages if no callback was supplied, or an Error.
108 | */
109 | static fetch(root, mode, sideKey, callback, limit) {
110 | return __awaiter(this, void 0, void 0, function* () {
111 | return internals_1.loadBalancer(Mam.loadBalancerSettings, (node) => {
112 | MamCore.setIOTA(node.provider);
113 | MamCore.setAttachToTangle(node.attachToTangle || Mam.loadBalancerSettings.attachToTangle);
114 | }, () => new Bluebird((resolve, reject) => {
115 | MamCore.fetch(root, mode, sideKey, callback, limit)
116 | .then(resolve)
117 | .catch(reject);
118 | }));
119 | });
120 | }
121 | /**
122 | * Fetch a single message asynchronously.
123 | * @param root The root key to use.
124 | * @param mode The mode of the channel.
125 | * @param sideKey The sideKey used in the messages.
126 | * @returns The nextRoot and the payload, or an Error.
127 | */
128 | static fetchSingle(root, mode, sideKey) {
129 | return __awaiter(this, void 0, void 0, function* () {
130 | const response = yield Mam.fetch(root, mode, sideKey, undefined, 1);
131 | return response instanceof Error ? response : {
132 | payload: response.messages && response.messages.length === 1 ? response.messages[0] : undefined,
133 | nextRoot: response.nextRoot
134 | };
135 | });
136 | }
137 | /**
138 | * Attach the mam trytes to the tangle.
139 | * @param trytes The trytes to attach.
140 | * @param root The root to attach them to.
141 | * @param depth The depth to attach them with, defaults to 3.
142 | * @param mwm The minimum weight magnitude to attach with, defaults to 9 for devnet, 14 required for mainnet.
143 | * @param tag Trytes to tag the message with.
144 | * @returns The transaction objects.
145 | */
146 | static attach(trytes, root, depth, mwm, tag) {
147 | return __awaiter(this, void 0, void 0, function* () {
148 | const { prepareTransfers, sendTrytes } = composeAPI_1.composeAPI(Mam.loadBalancerSettings);
149 | const response = yield prepareTransfers("9".repeat(81), [
150 | {
151 | address: root,
152 | value: 0,
153 | message: trytes,
154 | tag: tag
155 | }
156 | ]);
157 | return sendTrytes(response, depth || 0, mwm || 0);
158 | });
159 | }
160 | }
161 | exports.Mam = Mam;
162 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWFtLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vc3JjL21hbS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7Ozs7Ozs7Ozs7QUFDQSxxQ0FBcUM7QUFDckMscUNBQXFDO0FBQ3JDLDZDQUEwQztBQUMxQywyQ0FBMkM7QUFDM0MsZ0RBQTZDO0FBRTdDLHNEQUFtRDtBQUVuRDs7R0FFRztBQUNILE1BQWEsR0FBRztJQU1aOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxJQUFJLENBQUMsUUFBOEIsRUFBRSxJQUFhLEVBQUUsV0FBbUIsQ0FBQztRQUNsRixJQUFJLENBQUMsUUFBUSxFQUFFO1lBQ1gsTUFBTSxJQUFJLEtBQUssQ0FBQyw0QkFBNEIsQ0FBQyxDQUFDO1NBQ2pEO1FBQ0QsSUFBSSxDQUFDLFFBQVEsQ0FBQyxnQkFBZ0IsRUFBRTtZQUM1QixNQUFNLElBQUksS0FBSyxDQUFDLDZDQUE2QyxDQUFDLENBQUM7U0FDbEU7UUFDRCxRQUFRLENBQUMsR0FBRyxHQUFHLFFBQVEsQ0FBQyxHQUFHLElBQUksQ0FBQyxDQUFDO1FBQ2pDLFFBQVEsQ0FBQyxLQUFLLEdBQUcsUUFBUSxDQUFDLEtBQUssSUFBSSxDQUFDLENBQUM7UUFDckMsUUFBUSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxJQUFJLHlCQUFXLENBQUMsSUFBSSxDQUFDO1FBQ2hFLFFBQVEsQ0FBQyxRQUFRLEdBQUcsUUFBUSxDQUFDLFFBQVEsSUFBSSxtQkFBUSxDQUFDLEdBQUcsQ0FBQztRQUN0RCxHQUFHLENBQUMsb0JBQW9CLEdBQUcsUUFBUSxDQUFDO1FBQ3BDLE9BQU8sT0FBTyxDQUFDLElBQUksQ0FBQyxFQUFFLFFBQVEsRUFBRSxFQUFFLEVBQUUsRUFBRSxJQUFJLEVBQUUsUUFBUSxDQUFDLENBQUM7SUFDMUQsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxVQUFVLENBQUMsS0FBdUIsRUFBRSxJQUFxQixFQUFFLE9BQWdCO1FBQ3JGLE9BQU8sT0FBTyxDQUFDLFVBQVUsQ0FBQyxLQUFLLEVBQUUsSUFBSSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ3BELENBQUM7SUFFRDs7OztPQUlHO0lBQ0ksTUFBTSxDQUFDLE9BQU8sQ0FBQyxLQUF1QjtRQUN6QyxPQUFPLE9BQU8sQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLENBQUM7SUFDbEMsQ0FBQztJQUVEOzs7Ozs7O09BT0c7SUFDSSxNQUFNLENBQUMsU0FBUyxDQUFDLEtBQXVCLEVBQUUsV0FBbUIsRUFBRSxXQUE0QixFQUFFLFVBQW1CO1FBQ25ILE9BQU8sT0FBTyxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsV0FBVyxFQUFFLFdBQVcsRUFBRSxVQUFVLENBQUMsQ0FBQztJQUMxRSxDQUFDO0lBRUQ7Ozs7T0FJRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBcUMsRUFBRSxRQUFzQztRQUM5RixPQUFPLE9BQU8sQ0FBQyxNQUFNLENBQUMsT0FBTyxFQUFFLFFBQVEsQ0FBQyxDQUFDO0lBQzdDLENBQUM7SUFFRDs7Ozs7T0FLRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsS0FBdUIsRUFBRSxPQUFlO1FBQ3pELE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxLQUFLLEVBQUUsT0FBTyxDQUFDLENBQUM7SUFDMUMsQ0FBQztJQUVEOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBQyxNQUFNLENBQUMsT0FBZSxFQUFFLE9BQWUsRUFBRSxJQUFZO1FBQy9ELE9BQU8sT0FBTyxDQUFDLE1BQU0sQ0FBQyxPQUFPLEVBQUUsT0FBTyxFQUFFLElBQUksQ0FBQyxDQUFDO0lBQ2xELENBQUM7SUFFRDs7Ozs7Ozs7T0FRRztJQUNJLE1BQU0sQ0FBTyxLQUFLLENBQUMsSUFBWSxFQUFFLElBQXFCLEVBQUUsT0FBZ0IsRUFBRSxRQUFvQyxFQUFFLEtBQWM7O1lBVWpJLE9BQU8sd0JBQVksQ0FDZixHQUFHLENBQUMsb0JBQW9CLEVBQ3hCLENBQUMsSUFBSSxFQUFFLEVBQUU7Z0JBQ0wsT0FBTyxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsUUFBUSxDQUFDLENBQUM7Z0JBQy9CLE9BQU8sQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLENBQUMsY0FBYyxJQUFJLEdBQUcsQ0FBQyxvQkFBb0IsQ0FBQyxjQUFjLENBQUMsQ0FBQztZQUM5RixDQUFDLEVBQ0QsR0FBRyxFQUFFLENBQUMsSUFBSSxRQUFRLENBQU0sQ0FBQyxPQUFPLEVBQUUsTUFBTSxFQUFFLEVBQUU7Z0JBQ3hDLE9BQU8sQ0FBQyxLQUFLLENBQUMsSUFBSSxFQUFFLElBQUksRUFBRSxPQUFPLEVBQUUsUUFBUSxFQUFFLEtBQUssQ0FBQztxQkFDOUMsSUFBSSxDQUFDLE9BQU8sQ0FBQztxQkFDYixLQUFLLENBQUMsTUFBTSxDQUFDLENBQUM7WUFDdkIsQ0FBQyxDQUFDLENBQUMsQ0FBQztRQUNaLENBQUM7S0FBQTtJQUVEOzs7Ozs7T0FNRztJQUNJLE1BQU0sQ0FBTyxXQUFXLENBQUMsSUFBWSxFQUFFLElBQXFCLEVBQUUsT0FBZ0I7O1lBVWpGLE1BQU0sUUFBUSxHQUFHLE1BQU0sR0FBRyxDQUFDLEtBQUssQ0FBQyxJQUFJLEVBQUUsSUFBSSxFQUFFLE9BQU8sRUFBRSxTQUFTLEVBQUUsQ0FBQyxDQUFDLENBQUM7WUFDcEUsT0FBTyxRQUFRLFlBQVksS0FBSyxDQUFDLENBQUMsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDO2dCQUMxQyxPQUFPLEVBQUUsUUFBUSxDQUFDLFFBQVEsSUFBSSxRQUFRLENBQUMsUUFBUSxDQUFDLE1BQU0sS0FBSyxDQUFDLENBQUMsQ0FBQyxDQUFDLFFBQVEsQ0FBQyxRQUFRLENBQUMsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDLFNBQVM7Z0JBQy9GLFFBQVEsRUFBRSxRQUFRLENBQUMsUUFBUTthQUM5QixDQUFDO1FBQ04sQ0FBQztLQUFBO0lBRUQ7Ozs7Ozs7O09BUUc7SUFDSSxNQUFNLENBQU8sTUFBTSxDQUFDLE1BQWMsRUFBRSxJQUFZLEVBQUUsS0FBYyxFQUFFLEdBQVksRUFBRSxHQUFZOztZQUMvRixNQUFNLEVBQUUsZ0JBQWdCLEVBQUUsVUFBVSxFQUFFLEdBQUcsdUJBQVUsQ0FBQyxHQUFHLENBQUMsb0JBQW9CLENBQUMsQ0FBQztZQUU5RSxNQUFNLFFBQVEsR0FBRyxNQUFNLGdCQUFnQixDQUNuQyxHQUFHLENBQUMsTUFBTSxDQUFDLEVBQUUsQ0FBQyxFQUFFO2dCQUNaO29CQUNJLE9BQU8sRUFBRSxJQUFJO29CQUNiLEtBQUssRUFBRSxDQUFDO29CQUNSLE9BQU8sRUFBRSxNQUFNO29CQUNmLEdBQUcsRUFBRSxHQUFHO2lCQUNYO2FBQ0osQ0FBQyxDQUFDO1lBRVAsT0FBTyxVQUFVLENBQUMsUUFBUSxFQUFFLEtBQUssSUFBSSxDQUFDLEVBQUUsR0FBRyxJQUFJLENBQUMsQ0FBQyxDQUFDO1FBQ3RELENBQUM7S0FBQTtDQUNKO0FBMUtELGtCQTBLQyJ9
--------------------------------------------------------------------------------
/es/models/failMode.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.FailMode = void 0;
4 | /**
5 | * Fail modes for the load balancer.
6 | */
7 | var FailMode;
8 | (function (FailMode) {
9 | /**
10 | * Try single node only, failure throws exception.
11 | */
12 | FailMode["single"] = "single";
13 | /**
14 | * Try all nodes until one succeeds, on all failing throws combined exception.
15 | */
16 | FailMode["all"] = "all";
17 | })(FailMode = exports.FailMode || (exports.FailMode = {}));
18 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmFpbE1vZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWxzL2ZhaWxNb2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOztHQUVHO0FBQ0gsSUFBWSxRQVNYO0FBVEQsV0FBWSxRQUFRO0lBQ2hCOztPQUVHO0lBQ0gsNkJBQWlCLENBQUE7SUFDakI7O09BRUc7SUFDSCx1QkFBVyxDQUFBO0FBQ2YsQ0FBQyxFQVRXLFFBQVEsR0FBUixnQkFBUSxLQUFSLGdCQUFRLFFBU25CIn0=
--------------------------------------------------------------------------------
/es/models/loadBalancerSettings.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.LoadBalancerSettings = void 0;
4 | /**
5 | * Settings to use for the load balancer.
6 | */
7 | class LoadBalancerSettings {
8 | }
9 | exports.LoadBalancerSettings = LoadBalancerSettings;
10 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibG9hZEJhbGFuY2VyU2V0dGluZ3MuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWxzL2xvYWRCYWxhbmNlclNldHRpbmdzLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQU1BOztHQUVHO0FBQ0gsTUFBYSxvQkFBb0I7Q0ErRGhDO0FBL0RELG9EQStEQyJ9
--------------------------------------------------------------------------------
/es/models/nodeConfiguration.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.NodeConfiguration = void 0;
4 | /**
5 | * The configuration for a single node.
6 | */
7 | class NodeConfiguration {
8 | }
9 | exports.NodeConfiguration = NodeConfiguration;
10 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZUNvbmZpZ3VyYXRpb24uanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWxzL25vZGVDb25maWd1cmF0aW9uLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUVBOztHQUVHO0FBQ0gsTUFBYSxpQkFBaUI7Q0FtQzdCO0FBbkNELDhDQW1DQyJ9
--------------------------------------------------------------------------------
/es/models/nodeWalkStrategy.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm9kZVdhbGtTdHJhdGVneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tb2RlbHMvbm9kZVdhbGtTdHJhdGVneS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiIn0=
--------------------------------------------------------------------------------
/es/models/successMode.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.SuccessMode = void 0;
4 | /**
5 | * Success modes for the load balancer.
6 | */
7 | var SuccessMode;
8 | (function (SuccessMode) {
9 | /**
10 | * Keep the node if it was successful.
11 | */
12 | SuccessMode["keep"] = "keep";
13 | /**
14 | * Move to the next node even if it was successful.
15 | */
16 | SuccessMode["next"] = "next";
17 | })(SuccessMode = exports.SuccessMode || (exports.SuccessMode = {}));
18 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoic3VjY2Vzc01vZGUuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbW9kZWxzL3N1Y2Nlc3NNb2RlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUFBOztHQUVHO0FBQ0gsSUFBWSxXQVNYO0FBVEQsV0FBWSxXQUFXO0lBQ25COztPQUVHO0lBQ0gsNEJBQWEsQ0FBQTtJQUNiOztPQUVHO0lBQ0gsNEJBQWEsQ0FBQTtBQUNqQixDQUFDLEVBVFcsV0FBVyxHQUFYLG1CQUFXLEtBQVgsbUJBQVcsUUFTdEIifQ==
--------------------------------------------------------------------------------
/es/walkStrategies/baseWalkStrategy.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.BaseWalkStrategy = void 0;
4 | /**
5 | * Common features for the node strategies.
6 | * @private
7 | */
8 | class BaseWalkStrategy {
9 | /**
10 | * Create a new instance of BaseWalkStrategy.
11 | * @param nodes The nodes to iterate through.
12 | * @param blacklistLimit The number of failures before a node is blacklisted.
13 | */
14 | constructor(nodes, blacklistLimit) {
15 | if (!nodes || nodes.length === 0) {
16 | throw new Error("You must supply at least one node to the strategy");
17 | }
18 | this._allNodes = nodes;
19 | this._usableNodes = nodes.slice();
20 | this._blacklistLimit = blacklistLimit;
21 | this._blacklistNodes = {};
22 | }
23 | /**
24 | * The total number of nodes configured for the strategy.
25 | * @returns The total number of nodes.
26 | */
27 | totalUsable() {
28 | return this._usableNodes.length;
29 | }
30 | /**
31 | * Blacklist the current node, so it doesn't get used again once limit is reached.
32 | */
33 | blacklist() {
34 | if (this._blacklistLimit) {
35 | const current = this.current();
36 | if (current) {
37 | if (!this._blacklistNodes[current.provider]) {
38 | this._blacklistNodes[current.provider] = 1;
39 | }
40 | else {
41 | this._blacklistNodes[current.provider]++;
42 | }
43 | if (this._blacklistNodes[current.provider] >= this._blacklistLimit) {
44 | const idx = this._usableNodes.indexOf(current);
45 | if (idx >= 0) {
46 | this._usableNodes.splice(idx, 1);
47 | }
48 | }
49 | // If there are no usable nodes left then reset the blacklists
50 | if (this._usableNodes.length === 0) {
51 | this._blacklistNodes = {};
52 | this._usableNodes = this._allNodes.slice();
53 | }
54 | }
55 | }
56 | }
57 | /**
58 | * Get the list of nodes that have not been blacklisted.
59 | * @returns The non blacklisted nodes.
60 | */
61 | getUsableNodes() {
62 | return this._usableNodes;
63 | }
64 | }
65 | exports.BaseWalkStrategy = BaseWalkStrategy;
66 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYmFzZVdhbGtTdHJhdGVneS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy93YWxrU3RyYXRlZ2llcy9iYXNlV2Fsa1N0cmF0ZWd5LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiI7OztBQUdBOzs7R0FHRztBQUNILE1BQXNCLGdCQUFnQjtJQXFCbEM7Ozs7T0FJRztJQUNILFlBQVksS0FBMEIsRUFBRSxjQUF1QjtRQUMzRCxJQUFJLENBQUMsS0FBSyxJQUFJLEtBQUssQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQzlCLE1BQU0sSUFBSSxLQUFLLENBQUMsbURBQW1ELENBQUMsQ0FBQztTQUN4RTtRQUNELElBQUksQ0FBQyxTQUFTLEdBQUcsS0FBSyxDQUFDO1FBQ3ZCLElBQUksQ0FBQyxZQUFZLEdBQUcsS0FBSyxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQ2xDLElBQUksQ0FBQyxlQUFlLEdBQUcsY0FBYyxDQUFDO1FBQ3RDLElBQUksQ0FBQyxlQUFlLEdBQUcsRUFBRSxDQUFDO0lBQzlCLENBQUM7SUFFRDs7O09BR0c7SUFDSSxXQUFXO1FBQ2QsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDLE1BQU0sQ0FBQztJQUNwQyxDQUFDO0lBY0Q7O09BRUc7SUFDSSxTQUFTO1FBQ1osSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFO1lBQ3RCLE1BQU0sT0FBTyxHQUFHLElBQUksQ0FBQyxPQUFPLEVBQUUsQ0FBQztZQUMvQixJQUFJLE9BQU8sRUFBRTtnQkFDVCxJQUFJLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUU7b0JBQ3pDLElBQUksQ0FBQyxlQUFlLENBQUMsT0FBTyxDQUFDLFFBQVEsQ0FBQyxHQUFHLENBQUMsQ0FBQztpQkFDOUM7cUJBQU07b0JBQ0gsSUFBSSxDQUFDLGVBQWUsQ0FBQyxPQUFPLENBQUMsUUFBUSxDQUFDLEVBQUUsQ0FBQztpQkFDNUM7Z0JBQ0QsSUFBSSxJQUFJLENBQUMsZUFBZSxDQUFDLE9BQU8sQ0FBQyxRQUFRLENBQUMsSUFBSSxJQUFJLENBQUMsZUFBZSxFQUFFO29CQUNoRSxNQUFNLEdBQUcsR0FBRyxJQUFJLENBQUMsWUFBWSxDQUFDLE9BQU8sQ0FBQyxPQUFPLENBQUMsQ0FBQztvQkFDL0MsSUFBSSxHQUFHLElBQUksQ0FBQyxFQUFFO3dCQUNWLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxDQUFDLEdBQUcsRUFBRSxDQUFDLENBQUMsQ0FBQztxQkFDcEM7aUJBQ0o7Z0JBRUQsOERBQThEO2dCQUM5RCxJQUFJLElBQUksQ0FBQyxZQUFZLENBQUMsTUFBTSxLQUFLLENBQUMsRUFBRTtvQkFDaEMsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7b0JBQzFCLElBQUksQ0FBQyxZQUFZLEdBQUcsSUFBSSxDQUFDLFNBQVMsQ0FBQyxLQUFLLEVBQUUsQ0FBQztpQkFDOUM7YUFDSjtTQUNKO0lBQ0wsQ0FBQztJQUVEOzs7T0FHRztJQUNPLGNBQWM7UUFDcEIsT0FBTyxJQUFJLENBQUMsWUFBWSxDQUFDO0lBQzdCLENBQUM7Q0FDSjtBQTNGRCw0Q0EyRkMifQ==
--------------------------------------------------------------------------------
/es/walkStrategies/linearWalkStrategy.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.LinearWalkStrategy = void 0;
4 | const baseWalkStrategy_1 = require("./baseWalkStrategy");
5 | /**
6 | * Node choice strategy which just iterates through the list of nodes.
7 | */
8 | class LinearWalkStrategy extends baseWalkStrategy_1.BaseWalkStrategy {
9 | /**
10 | * Create a new instance of LinearWalkStrategy.
11 | * @param nodes The nodes to randomly pick from.
12 | * @param blacklistLimit The number of failures before a node is blacklisted.
13 | */
14 | constructor(nodes, blacklistLimit) {
15 | super(nodes, blacklistLimit);
16 | this._currentIndex = 0;
17 | }
18 | /**
19 | * Get the current node from the strategy.
20 | * @returns A node configuration from the strategy.
21 | */
22 | current() {
23 | return this.getUsableNodes()[this._currentIndex];
24 | }
25 | /**
26 | * Move to the next node in the strategy.
27 | * @param retainOrder Retain the ordering if resetting the list.
28 | */
29 | next(retainOrder) {
30 | this._currentIndex = (this._currentIndex + 1) % this.getUsableNodes().length;
31 | }
32 | }
33 | exports.LinearWalkStrategy = LinearWalkStrategy;
34 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibGluZWFyV2Fsa1N0cmF0ZWd5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhbGtTdHJhdGVnaWVzL2xpbmVhcldhbGtTdHJhdGVneS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx5REFBc0Q7QUFFdEQ7O0dBRUc7QUFDSCxNQUFhLGtCQUFtQixTQUFRLG1DQUFnQjtJQU1wRDs7OztPQUlHO0lBQ0gsWUFBWSxLQUEwQixFQUFFLGNBQXVCO1FBQzNELEtBQUssQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLGFBQWEsR0FBRyxDQUFDLENBQUM7SUFDM0IsQ0FBQztJQUVEOzs7T0FHRztJQUNJLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxjQUFjLEVBQUUsQ0FBQyxJQUFJLENBQUMsYUFBYSxDQUFDLENBQUM7SUFDckQsQ0FBQztJQUVEOzs7T0FHRztJQUNJLElBQUksQ0FBQyxXQUFvQjtRQUM1QixJQUFJLENBQUMsYUFBYSxHQUFHLENBQUMsSUFBSSxDQUFDLGFBQWEsR0FBRyxDQUFDLENBQUMsR0FBRyxJQUFJLENBQUMsY0FBYyxFQUFFLENBQUMsTUFBTSxDQUFDO0lBQ2pGLENBQUM7Q0FDSjtBQS9CRCxnREErQkMifQ==
--------------------------------------------------------------------------------
/es/walkStrategies/randomWalkStrategy.js:
--------------------------------------------------------------------------------
1 | "use strict";
2 | Object.defineProperty(exports, "__esModule", { value: true });
3 | exports.RandomWalkStrategy = void 0;
4 | const baseWalkStrategy_1 = require("./baseWalkStrategy");
5 | /**
6 | * Node choice strategy which randomly picks from the list of nodes.
7 | */
8 | class RandomWalkStrategy extends baseWalkStrategy_1.BaseWalkStrategy {
9 | /**
10 | * Create a new instance of RandomWalkStategy.
11 | * @param nodes The nodes to randomly pick from.
12 | * @param blacklistLimit The number of failures before a node is blacklisted.
13 | */
14 | constructor(nodes, blacklistLimit) {
15 | super(nodes, blacklistLimit);
16 | this._remainingNodes = [];
17 | this._randomNodes = [];
18 | this.populateRemaining();
19 | }
20 | /**
21 | * Get the current node from the strategy.
22 | * @returns A node configuration from the strategy.
23 | */
24 | current() {
25 | return this._remainingNodes[0];
26 | }
27 | /**
28 | * Move to the next node in the strategy.
29 | * @param retainOrder Retain the ordering if resetting the list.
30 | */
31 | next(retainOrder) {
32 | this._remainingNodes.shift();
33 | if (this._remainingNodes.length === 0) {
34 | if (retainOrder) {
35 | this._remainingNodes = this._randomNodes.slice();
36 | }
37 | else {
38 | this.populateRemaining();
39 | }
40 | }
41 | }
42 | /**
43 | * Populate the remaining array by randomizing the nodes.
44 | * @internal
45 | * @private
46 | */
47 | populateRemaining() {
48 | this._remainingNodes = super.getUsableNodes().slice();
49 | for (let i = this._remainingNodes.length - 1; i > 0; i--) {
50 | // tslint:disable-next-line:insecure-random
51 | const j = Math.floor(Math.random() * (i + 1));
52 | [this._remainingNodes[i], this._remainingNodes[j]] = [this._remainingNodes[j], this._remainingNodes[i]];
53 | }
54 | this._randomNodes = this._remainingNodes.slice();
55 | }
56 | }
57 | exports.RandomWalkStrategy = RandomWalkStrategy;
58 | //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoicmFuZG9tV2Fsa1N0cmF0ZWd5LmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL3dhbGtTdHJhdGVnaWVzL3JhbmRvbVdhbGtTdHJhdGVneS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiOzs7QUFDQSx5REFBc0Q7QUFFdEQ7O0dBRUc7QUFDSCxNQUFhLGtCQUFtQixTQUFRLG1DQUFnQjtJQWFwRDs7OztPQUlHO0lBQ0gsWUFBWSxLQUEwQixFQUFFLGNBQXVCO1FBQzNELEtBQUssQ0FBQyxLQUFLLEVBQUUsY0FBYyxDQUFDLENBQUM7UUFDN0IsSUFBSSxDQUFDLGVBQWUsR0FBRyxFQUFFLENBQUM7UUFDMUIsSUFBSSxDQUFDLFlBQVksR0FBRyxFQUFFLENBQUM7UUFDdkIsSUFBSSxDQUFDLGlCQUFpQixFQUFFLENBQUM7SUFDN0IsQ0FBQztJQUVEOzs7T0FHRztJQUNJLE9BQU87UUFDVixPQUFPLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLENBQUM7SUFDbkMsQ0FBQztJQUVEOzs7T0FHRztJQUNJLElBQUksQ0FBQyxXQUFvQjtRQUM1QixJQUFJLENBQUMsZUFBZSxDQUFDLEtBQUssRUFBRSxDQUFDO1FBQzdCLElBQUksSUFBSSxDQUFDLGVBQWUsQ0FBQyxNQUFNLEtBQUssQ0FBQyxFQUFFO1lBQ25DLElBQUksV0FBVyxFQUFFO2dCQUNiLElBQUksQ0FBQyxlQUFlLEdBQUcsSUFBSSxDQUFDLFlBQVksQ0FBQyxLQUFLLEVBQUUsQ0FBQzthQUNwRDtpQkFBTTtnQkFDSCxJQUFJLENBQUMsaUJBQWlCLEVBQUUsQ0FBQzthQUM1QjtTQUNKO0lBQ0wsQ0FBQztJQUVEOzs7O09BSUc7SUFDSyxpQkFBaUI7UUFDckIsSUFBSSxDQUFDLGVBQWUsR0FBRyxLQUFLLENBQUMsY0FBYyxFQUFFLENBQUMsS0FBSyxFQUFFLENBQUM7UUFDdEQsS0FBSyxJQUFJLENBQUMsR0FBRyxJQUFJLENBQUMsZUFBZSxDQUFDLE1BQU0sR0FBRyxDQUFDLEVBQUUsQ0FBQyxHQUFHLENBQUMsRUFBRSxDQUFDLEVBQUUsRUFBRTtZQUN0RCwyQ0FBMkM7WUFDM0MsTUFBTSxDQUFDLEdBQUcsSUFBSSxDQUFDLEtBQUssQ0FBQyxJQUFJLENBQUMsTUFBTSxFQUFFLEdBQUcsQ0FBQyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQztZQUM5QyxDQUFDLElBQUksQ0FBQyxlQUFlLENBQUMsQ0FBQyxDQUFDLEVBQUUsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsQ0FBQyxHQUFHLENBQUMsSUFBSSxDQUFDLGVBQWUsQ0FBQyxDQUFDLENBQUMsRUFBRSxJQUFJLENBQUMsZUFBZSxDQUFDLENBQUMsQ0FBQyxDQUFDLENBQUM7U0FDM0c7UUFDRCxJQUFJLENBQUMsWUFBWSxHQUFHLElBQUksQ0FBQyxlQUFlLENBQUMsS0FBSyxFQUFFLENBQUM7SUFDckQsQ0FBQztDQUNKO0FBOURELGdEQThEQyJ9
--------------------------------------------------------------------------------
/examples/README.md:
--------------------------------------------------------------------------------
1 | # IOTA JavaScript Client Load Balancer Examples
2 |
3 | The examples contain the following items:
4 |
5 | ## Simple
6 |
7 | A simple usage of the load balancer with composeAPI.
8 |
9 | See [./simple](./simple) for more details.
10 |
11 | ## MAM
12 |
13 | Demonstrates publishing and fetching messages using MAM.
14 |
15 | See [./mam](./mam) for more details.
16 |
--------------------------------------------------------------------------------
/examples/mam/index.js:
--------------------------------------------------------------------------------
1 | const { FailMode, LinearWalkStrategy, Mam, SuccessMode } = require('@iota/client-load-balancer');
2 | const { asciiToTrytes, trytesToAscii } = require('@iota/converter');
3 |
4 | // Set the channel mode
5 | const channelMode = 'public' // 'private' 'restricted'
6 | const retrictedSideKeyTrytes = channelMode === 'restricted' ? 'THIS9IS9A9RESTRICTED9KEY' : undefined;
7 | const explorer = 'https://devnet.thetangle.org';
8 |
9 | // Publish a new message
10 | async function publishMessage(mamState, trytesMessage) {
11 | console.log(`Publishing Message: ${trytesMessage}`);
12 |
13 | // Create MAM Payload
14 | const message = Mam.create(mamState, trytesMessage);
15 |
16 | console.log(`Root: ${message.root}`);
17 | console.log(`Address: ${message.address}`);
18 |
19 | // Attach the payload
20 | console.log('Attaching payload, please wait...');
21 |
22 | try {
23 | await Mam.attach(message.payload, message.address);
24 | return message;
25 | } catch (err) {
26 | console.error('There was an error attaching the message', err.message);
27 | }
28 | }
29 |
30 | // Fetch message beginning at the specific root.
31 | async function fetchMessages(messageRoot) {
32 | console.log(`Fetching Messages from Root: ${messageRoot}`);
33 |
34 | try {
35 | const response = await Mam.fetch(messageRoot, channelMode, retrictedSideKeyTrytes);
36 |
37 | if (response) {
38 | if (!response.messages || response.messages.length === 0) {
39 | console.log('There are no messages.')
40 | } else {
41 | response.messages.forEach(messageTrytes => {
42 | console.log(`Fetched Message: ${trytesToAscii(messageTrytes)}`);
43 | });
44 | }
45 | console.log(`Next Root: ${response.nextRoot}`);
46 | }
47 | return response;
48 | } catch (err) {
49 | console.error('There was an error fetching messages', err);
50 | }
51 | }
52 |
53 | (async function () {
54 | try {
55 | const nodeWalkStrategy = new LinearWalkStrategy(
56 | [
57 | {
58 | 'provider': 'https://thiswillfailbigly.eu',
59 | 'depth': 3,
60 | 'mwm': 9
61 | },
62 | {
63 | 'provider': 'https://nodes.devnet.iota.org:443',
64 | 'depth': 3,
65 | 'mwm': 9
66 | }
67 | ],
68 | 1 // Blacklist count, will stop using the initial node once it has failed
69 | );
70 |
71 | let mamState = Mam.init({
72 | nodeWalkStrategy,
73 | successMode: SuccessMode.next,
74 | failMode: FailMode.all,
75 | timeoutMs: 5000,
76 | tryNodeCallback: (node) => {
77 | console.log(`Trying node ${node.provider}`);
78 | },
79 | failNodeCallback: (node, err) => {
80 | console.log(`Failed node ${node.provider}, ${err.message}`);
81 | }
82 | });
83 |
84 | const initialRoot = Mam.getRoot(mamState);
85 | console.log('Root', initialRoot);
86 |
87 | console.log(`Channel Mode: ${channelMode}`);
88 | mamState = Mam.changeMode(mamState, channelMode, retrictedSideKeyTrytes);
89 |
90 | const messageResponse = await fetchMessages(initialRoot);
91 |
92 | if (messageResponse) {
93 | mamState.channel.start = messageResponse.messages.length;
94 |
95 | const message = await publishMessage(mamState, asciiToTrytes(`This is my message ${messageResponse.messages.length + 1}`));
96 |
97 | if (message) {
98 | console.log('Message Published');
99 | if (channelMode === 'public') {
100 | console.log(`You can view the message chain on the tangle:`);
101 | console.log(`${explorer}/mam/${initialRoot}`);
102 | console.log(`or just for this message at:`);
103 | console.log(`${explorer}/mam/${message.address}`);
104 | } else {
105 | console.log(`You can view the transactions for this this message at:`);
106 | console.log(`${explorer}/address/${message.address}`);
107 | }
108 | await fetchMessages(message.root);
109 | }
110 | }
111 |
112 | } catch (err) {
113 | console.error(`Error: ${err.message}`);
114 | }
115 | })();
--------------------------------------------------------------------------------
/examples/mam/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "mam",
3 | "description": "Mam example for IOTA Client Load Balancer",
4 | "version": "1.0.0",
5 | "author": "Martyn Janes