UNPKG

3.5 kBJavaScriptView Raw
1"use strict";
2Object.defineProperty(exports, "__esModule", { value: true });
3const log_1 = require("../common/log");
4const crypto_1 = require("crypto");
5const IlpPacket = require("ilp-packet");
6const bignumber_js_1 = require("bignumber.js");
7const STATIC_DATA_OFFSET = 25;
8const DEFAULT_CLEANUP_INTERVAL = 30000;
9const DEFAULT_PACKET_LIFETIME = 30000;
10class DeduplicateMiddleware {
11 constructor(opts, { getInfo }) {
12 this.packetCache = new Map();
13 this.getInfo = getInfo;
14 }
15 async applyToPipelines(pipelines, accountId) {
16 const log = log_1.create(`deduplicate-middleware[${accountId}]`);
17 const accountInfo = this.getInfo(accountId);
18 if (!accountInfo) {
19 throw new Error('account info unavailable. accountId=' + accountId);
20 }
21 const { cleanupInterval, packetLifetime } = accountInfo.deduplicate || {
22 cleanupInterval: DEFAULT_CLEANUP_INTERVAL,
23 packetLifetime: DEFAULT_PACKET_LIFETIME
24 };
25 let interval;
26 pipelines.startup.insertLast({
27 name: 'deduplicate',
28 method: async (dummy, next) => {
29 interval = setInterval(() => this.cleanupCache(packetLifetime), cleanupInterval);
30 return next(dummy);
31 }
32 });
33 pipelines.teardown.insertLast({
34 name: 'deduplicate',
35 method: async (dummy, next) => {
36 clearInterval(interval);
37 return next(dummy);
38 }
39 });
40 pipelines.outgoingData.insertLast({
41 name: 'deduplicate',
42 method: async (data, next) => {
43 if (data[0] === IlpPacket.Type.TYPE_ILP_PREPARE) {
44 const { contents } = IlpPacket.deserializeEnvelope(data);
45 const index = crypto_1.createHash('sha256')
46 .update(contents.slice(STATIC_DATA_OFFSET))
47 .digest()
48 .slice(0, 16)
49 .toString('base64');
50 const { amount, expiresAt } = IlpPacket.deserializeIlpPrepare(data);
51 const cachedPacket = this.packetCache.get(index);
52 if (cachedPacket) {
53 if (new bignumber_js_1.default(cachedPacket.amount).gte(amount) && cachedPacket.expiresAt >= expiresAt) {
54 log.warn('deduplicate packet cache hit. accountId=%s elapsed=%s amount=%s', accountId, cachedPacket.expiresAt.getTime() - Date.now(), amount);
55 return cachedPacket.promise;
56 }
57 }
58 const promise = next(data);
59 this.packetCache.set(index, {
60 amount,
61 expiresAt,
62 promise
63 });
64 return promise;
65 }
66 return next(data);
67 }
68 });
69 }
70 cleanupCache(packetLifetime) {
71 const now = Date.now();
72 for (const index of this.packetCache.keys()) {
73 const cachedPacket = this.packetCache.get(index);
74 if (!cachedPacket)
75 continue;
76 const packetExpiry = cachedPacket.expiresAt.getTime() + packetLifetime;
77 if (packetExpiry < now) {
78 this.packetCache.delete(index);
79 }
80 }
81 }
82}
83exports.default = DeduplicateMiddleware;
84//# sourceMappingURL=deduplicate.js.map
\No newline at end of file