UNPKG

7.49 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const utils_1 = require("../lib/utils");
4const log_1 = require("../common/log");
5const log = log_1.create('middleware-manager');
6const config_1 = require("./config");
7const accounts_1 = require("./accounts");
8const core_1 = require("./core");
9const stats_1 = require("./stats");
10const middleware_pipeline_1 = require("../lib/middleware-pipeline");
11const ilp_packet_1 = require("ilp-packet");
12const { codes, UnreachableError } = ilp_packet_1.Errors;
13const BUILTIN_MIDDLEWARES = {
14 errorHandler: {
15 type: 'error-handler'
16 },
17 rateLimit: {
18 type: 'rate-limit'
19 },
20 maxPacketAmount: {
21 type: 'max-packet-amount'
22 },
23 throughput: {
24 type: 'throughput'
25 },
26 balance: {
27 type: 'balance'
28 },
29 deduplicate: {
30 type: 'deduplicate'
31 },
32 expire: {
33 type: 'expire'
34 },
35 validateFulfillment: {
36 type: 'validate-fulfillment'
37 },
38 stats: {
39 type: 'stats'
40 },
41 alert: {
42 type: 'alert'
43 }
44};
45class MiddlewareManager {
46 constructor(deps) {
47 this.startupHandlers = new Map();
48 this.teardownHandlers = new Map();
49 this.outgoingDataHandlers = new Map();
50 this.outgoingMoneyHandlers = new Map();
51 this.started = false;
52 this.config = deps(config_1.default);
53 this.accounts = deps(accounts_1.default);
54 this.core = deps(core_1.default);
55 this.stats = deps(stats_1.default);
56 const disabledMiddlewareConfig = this.config.disableMiddleware || [];
57 const customMiddlewareConfig = this.config.middlewares || {};
58 this.middlewares = {};
59 for (const name of Object.keys(BUILTIN_MIDDLEWARES)) {
60 if (disabledMiddlewareConfig.includes(name)) {
61 continue;
62 }
63 this.middlewares[name] = this.construct(name, BUILTIN_MIDDLEWARES[name]);
64 }
65 for (const name of Object.keys(customMiddlewareConfig)) {
66 if (this.middlewares[name]) {
67 throw new Error('custom middleware has same name as built-in middleware. name=' + name);
68 }
69 this.middlewares[name] = this.construct(name, customMiddlewareConfig[name]);
70 }
71 }
72 construct(name, definition) {
73 const Middleware = utils_1.loadModuleOfType('middleware', definition.type);
74 return new Middleware(definition.options || {}, {
75 getInfo: accountId => this.accounts.getInfo(accountId),
76 getOwnAddress: () => this.accounts.getOwnAddress(),
77 sendData: this.sendData.bind(this),
78 sendMoney: this.sendMoney.bind(this),
79 stats: this.stats
80 });
81 }
82 async setup() {
83 for (const accountId of this.accounts.getAccountIds()) {
84 const plugin = this.accounts.getPlugin(accountId);
85 await this.addPlugin(accountId, plugin);
86 }
87 }
88 async startup() {
89 this.started = true;
90 for (const handler of this.startupHandlers.values()) {
91 await handler(undefined);
92 }
93 }
94 async addPlugin(accountId, plugin) {
95 const pipelines = {
96 startup: new middleware_pipeline_1.default(),
97 teardown: new middleware_pipeline_1.default(),
98 incomingData: new middleware_pipeline_1.default(),
99 incomingMoney: new middleware_pipeline_1.default(),
100 outgoingData: new middleware_pipeline_1.default(),
101 outgoingMoney: new middleware_pipeline_1.default()
102 };
103 for (const middlewareName of Object.keys(this.middlewares)) {
104 const middleware = this.middlewares[middlewareName];
105 try {
106 await middleware.applyToPipelines(pipelines, accountId);
107 }
108 catch (err) {
109 const errInfo = (err && typeof err === 'object' && err.stack) ? err.stack : String(err);
110 log.error('failed to apply middleware to account. middlewareName=%s accountId=%s error=%s', middlewareName, accountId, errInfo);
111 throw new Error('failed to apply middleware. middlewareName=' + middlewareName);
112 }
113 }
114 const submitData = async (data) => {
115 try {
116 return await plugin.sendData(data);
117 }
118 catch (e) {
119 let err = e;
120 if (!err || typeof err !== 'object') {
121 err = new Error('non-object thrown. value=' + e);
122 }
123 if (!err.ilpErrorCode) {
124 err.ilpErrorCode = codes.F02_UNREACHABLE;
125 }
126 err.message = 'failed to send packet: ' + err.message;
127 throw err;
128 }
129 };
130 const submitMoney = plugin.sendMoney.bind(plugin);
131 const startupHandler = this.createHandler(pipelines.startup, accountId, async () => { return; });
132 const teardownHandler = this.createHandler(pipelines.teardown, accountId, async () => { return; });
133 const outgoingDataHandler = this.createHandler(pipelines.outgoingData, accountId, submitData);
134 const outgoingMoneyHandler = this.createHandler(pipelines.outgoingMoney, accountId, submitMoney);
135 this.startupHandlers.set(accountId, startupHandler);
136 this.teardownHandlers.set(accountId, teardownHandler);
137 this.outgoingDataHandlers.set(accountId, outgoingDataHandler);
138 this.outgoingMoneyHandlers.set(accountId, outgoingMoneyHandler);
139 const handleData = (data) => this.core.processData(data, accountId, this.sendData.bind(this));
140 const handleMoney = async () => void 0;
141 const incomingDataHandler = this.createHandler(pipelines.incomingData, accountId, handleData);
142 const incomingMoneyHandler = this.createHandler(pipelines.incomingMoney, accountId, handleMoney);
143 plugin.registerDataHandler(incomingDataHandler);
144 plugin.registerMoneyHandler(incomingMoneyHandler);
145 if (this.started) {
146 await startupHandler(undefined);
147 }
148 }
149 async removePlugin(accountId, plugin) {
150 plugin.deregisterDataHandler();
151 plugin.deregisterMoneyHandler();
152 this.startupHandlers.delete(accountId);
153 const teardownHandler = this.teardownHandlers.get(accountId);
154 if (teardownHandler)
155 await teardownHandler(undefined);
156 this.teardownHandlers.delete(accountId);
157 this.outgoingDataHandlers.delete(accountId);
158 this.outgoingMoneyHandlers.delete(accountId);
159 }
160 async sendData(data, accountId) {
161 const handler = this.outgoingDataHandlers.get(accountId);
162 if (!handler) {
163 throw new UnreachableError('tried to send data to non-existent account. accountId=' + accountId);
164 }
165 return handler(data);
166 }
167 async sendMoney(amount, accountId) {
168 const handler = this.outgoingMoneyHandlers.get(accountId);
169 if (!handler) {
170 throw new UnreachableError('tried to send money to non-existent account. accountId=' + accountId);
171 }
172 return handler(amount);
173 }
174 getMiddleware(name) {
175 return this.middlewares[name];
176 }
177 createHandler(pipeline, accountId, next) {
178 const middleware = utils_1.composeMiddleware(pipeline.getMethods());
179 return (param) => middleware(param, next);
180 }
181}
182exports.default = MiddlewareManager;
183//# sourceMappingURL=middleware-manager.js.map
\No newline at end of file