@mainnet-cash/postgresql-storage 2.1.0-alpha.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +3 -0
- package/dist/module/SqlProvider.d.ts +30 -0
- package/dist/module/SqlProvider.js +159 -0
- package/dist/module/SqlProvider.js.map +1 -0
- package/dist/module/index.d.ts +2 -0
- package/dist/module/index.js +3 -0
- package/dist/module/index.js.map +1 -0
- package/dist/module/util.d.ts +7 -0
- package/dist/module/util.js +24 -0
- package/dist/module/util.js.map +1 -0
- package/dist/module/webhook/Webhook.d.ts +35 -0
- package/dist/module/webhook/Webhook.js +77 -0
- package/dist/module/webhook/Webhook.js.map +1 -0
- package/dist/module/webhook/WebhookBch.d.ts +13 -0
- package/dist/module/webhook/WebhookBch.js +141 -0
- package/dist/module/webhook/WebhookBch.js.map +1 -0
- package/dist/module/webhook/WebhookWorker.d.ts +22 -0
- package/dist/module/webhook/WebhookWorker.js +94 -0
- package/dist/module/webhook/WebhookWorker.js.map +1 -0
- package/dist/module/webhook/index.d.ts +4 -0
- package/dist/module/webhook/index.js +5 -0
- package/dist/module/webhook/index.js.map +1 -0
- package/dist/module/webhook/interface.d.ts +7 -0
- package/dist/module/webhook/interface.js +2 -0
- package/dist/module/webhook/interface.js.map +1 -0
- package/dist/tsconfig.browser.tsbuildinfo +1 -0
- package/package.json +34 -0
- package/src/SqlProvider.test.ts +264 -0
- package/src/SqlProvider.ts +233 -0
- package/src/Wallet.test.ts +571 -0
- package/src/createWallet.test.ts +158 -0
- package/src/index.test.ts +67 -0
- package/src/index.ts +2 -0
- package/src/util.ts +30 -0
- package/src/webhook/Webhook.test.ts +9 -0
- package/src/webhook/Webhook.ts +99 -0
- package/src/webhook/WebhookBch.test.ts +323 -0
- package/src/webhook/WebhookBch.ts +198 -0
- package/src/webhook/WebhookWorker.test.ts +94 -0
- package/src/webhook/WebhookWorker.ts +119 -0
- package/src/webhook/index.ts +4 -0
- package/src/webhook/interface.ts +7 -0
- package/tsconfig.browser.json +6 -0
- package/tsconfig.json +28 -0
package/README.md
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { StorageProvider, WalletI, TxI } from "mainnet-js";
|
|
2
|
+
import { RegisterWebhookParams } from "./webhook/interface.js";
|
|
3
|
+
import { Webhook } from "./webhook/index.js";
|
|
4
|
+
export default class SqlProvider implements StorageProvider {
|
|
5
|
+
private db;
|
|
6
|
+
private config;
|
|
7
|
+
private info;
|
|
8
|
+
private formatter;
|
|
9
|
+
private walletTable;
|
|
10
|
+
private webhookTable;
|
|
11
|
+
private isInit;
|
|
12
|
+
constructor(walletTable?: string);
|
|
13
|
+
getConfig(): any;
|
|
14
|
+
init(): Promise<StorageProvider>;
|
|
15
|
+
close(): Promise<StorageProvider>;
|
|
16
|
+
getInfo(): string;
|
|
17
|
+
addWallet(name: string, walletId: string): Promise<boolean>;
|
|
18
|
+
getWallets(): Promise<Array<WalletI>>;
|
|
19
|
+
getWallet(name: string): Promise<WalletI | undefined>;
|
|
20
|
+
updateWallet(name: string, walletId: string): Promise<void>;
|
|
21
|
+
walletExists(name: string): Promise<boolean>;
|
|
22
|
+
webhookFromDb(hook: Webhook): Promise<import("./webhook/WebhookBch.js").WebhookBch>;
|
|
23
|
+
addWebhook(params: RegisterWebhookParams): Promise<Webhook>;
|
|
24
|
+
getWebhooks(): Promise<Array<Webhook>>;
|
|
25
|
+
getWebhook(id: number): Promise<Webhook | undefined>;
|
|
26
|
+
setWebhookStatus(id: number, status: string): Promise<void>;
|
|
27
|
+
setWebhookSeenTxLastHeight(id: number, tx_seen: Array<TxI>, last_height: number): Promise<void>;
|
|
28
|
+
deleteWebhook(id: number): Promise<void>;
|
|
29
|
+
clearWebhooks(): Promise<void>;
|
|
30
|
+
}
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { getSslConfig } from "./util.js";
|
|
2
|
+
import parseDbUrl from "parse-database-url";
|
|
3
|
+
import pg from "pg";
|
|
4
|
+
import format from "pg-format";
|
|
5
|
+
import { WebhookRecurrence, WebhookType } from "./webhook/index.js";
|
|
6
|
+
export default class SqlProvider {
|
|
7
|
+
constructor(walletTable) {
|
|
8
|
+
this.webhookTable = "webhook";
|
|
9
|
+
this.isInit = false;
|
|
10
|
+
this.walletTable = walletTable ? walletTable : "wallet";
|
|
11
|
+
if (!process.env.DATABASE_URL) {
|
|
12
|
+
throw new Error("Named wallets and webhooks require a postgres DATABASE_URL environment variable to be set");
|
|
13
|
+
}
|
|
14
|
+
let dbConfig = parseDbUrl(process.env.DATABASE_URL);
|
|
15
|
+
let ssl = getSslConfig();
|
|
16
|
+
if (ssl) {
|
|
17
|
+
dbConfig.ssl = ssl;
|
|
18
|
+
}
|
|
19
|
+
this.config = dbConfig;
|
|
20
|
+
const Pool = pg.Pool;
|
|
21
|
+
this.db = new Pool(dbConfig);
|
|
22
|
+
this.formatter = format;
|
|
23
|
+
}
|
|
24
|
+
getConfig() {
|
|
25
|
+
return this.config;
|
|
26
|
+
}
|
|
27
|
+
async init() {
|
|
28
|
+
if (!this.isInit) {
|
|
29
|
+
this.isInit = true;
|
|
30
|
+
await this.db;
|
|
31
|
+
await this.formatter;
|
|
32
|
+
let createWalletTable = this.formatter("CREATE TABLE IF NOT EXISTS %I (id SERIAL, name TEXT PRIMARY KEY, wallet TEXT );", this.walletTable);
|
|
33
|
+
const resWallet = await this.db.query(createWalletTable);
|
|
34
|
+
let createWebhookTable = this.formatter("CREATE TABLE IF NOT EXISTS %I (" +
|
|
35
|
+
"id SERIAL PRIMARY KEY," +
|
|
36
|
+
"cashaddr TEXT," +
|
|
37
|
+
"type TEXT," +
|
|
38
|
+
"recurrence TEXT," +
|
|
39
|
+
"url TEXT," +
|
|
40
|
+
"status TEXT," +
|
|
41
|
+
"tx_seen JSON," +
|
|
42
|
+
"last_height INTEGER," +
|
|
43
|
+
"expires_at TIMESTAMPTZ" +
|
|
44
|
+
");", this.webhookTable);
|
|
45
|
+
const resWebhook = await this.db.query(createWebhookTable);
|
|
46
|
+
if (!resWallet || !resWebhook)
|
|
47
|
+
throw new Error("Failed to init SqlProvider");
|
|
48
|
+
}
|
|
49
|
+
return this;
|
|
50
|
+
}
|
|
51
|
+
async close() {
|
|
52
|
+
await this.db.end();
|
|
53
|
+
return this;
|
|
54
|
+
}
|
|
55
|
+
getInfo() {
|
|
56
|
+
return this.info;
|
|
57
|
+
}
|
|
58
|
+
async addWallet(name, walletId) {
|
|
59
|
+
let text = this.formatter("INSERT into %I (name,wallet) VALUES ($1, $2);", this.walletTable);
|
|
60
|
+
return await this.db.query(text, [name, walletId]);
|
|
61
|
+
}
|
|
62
|
+
async getWallets() {
|
|
63
|
+
let text = this.formatter("SELECT * FROM %I;", this.walletTable);
|
|
64
|
+
let result = await this.db.query(text);
|
|
65
|
+
if (result) {
|
|
66
|
+
const WalletArray = await Promise.all(result.rows.map(async (obj) => {
|
|
67
|
+
return obj;
|
|
68
|
+
}));
|
|
69
|
+
return WalletArray;
|
|
70
|
+
}
|
|
71
|
+
else {
|
|
72
|
+
return [];
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
async getWallet(name) {
|
|
76
|
+
let text = this.formatter("SELECT * FROM %I WHERE name = $1;", this.walletTable);
|
|
77
|
+
let result = await this.db.query(text, [name]);
|
|
78
|
+
let w = result.rows[0];
|
|
79
|
+
return w;
|
|
80
|
+
}
|
|
81
|
+
async updateWallet(name, walletId) {
|
|
82
|
+
let text = this.formatter("UPDATE %I SET wallet = $1 WHERE name = $2;", this.walletTable);
|
|
83
|
+
await this.db.query(text, [walletId, name]);
|
|
84
|
+
}
|
|
85
|
+
async walletExists(name) {
|
|
86
|
+
return (await this.getWallet(name)) !== undefined;
|
|
87
|
+
}
|
|
88
|
+
async webhookFromDb(hook) {
|
|
89
|
+
const { WebhookBch } = await import("./webhook/WebhookBch.js");
|
|
90
|
+
return new WebhookBch(hook);
|
|
91
|
+
}
|
|
92
|
+
async addWebhook(params) {
|
|
93
|
+
// init db if it was not, useful for external api calls
|
|
94
|
+
await this.init();
|
|
95
|
+
params.type = params.type || WebhookType.transactionInOut;
|
|
96
|
+
params.recurrence = params.recurrence || WebhookRecurrence.once;
|
|
97
|
+
const expireTimeout = Number(process.env.WEBHOOK_EXPIRE_TIMEOUT_SECONDS) || 86400;
|
|
98
|
+
params.duration_sec = params.duration_sec || expireTimeout;
|
|
99
|
+
params.duration_sec =
|
|
100
|
+
params.duration_sec > expireTimeout ? expireTimeout : params.duration_sec;
|
|
101
|
+
const expires_at = new Date(new Date().getTime() + params.duration_sec * 1000);
|
|
102
|
+
let text = this.formatter("INSERT into %I (cashaddr,type,recurrence,url,status,tx_seen,last_height,expires_at) VALUES ($1, $2, $3, $4, $5, $6, $7, $8) RETURNING *;", this.webhookTable);
|
|
103
|
+
const result = await this.db.query(text, [
|
|
104
|
+
params.cashaddr,
|
|
105
|
+
params.type,
|
|
106
|
+
params.recurrence,
|
|
107
|
+
params.url,
|
|
108
|
+
"",
|
|
109
|
+
"[]",
|
|
110
|
+
0,
|
|
111
|
+
expires_at.toISOString(),
|
|
112
|
+
]);
|
|
113
|
+
const hook = await this.webhookFromDb(result.rows[0]);
|
|
114
|
+
hook.db = this;
|
|
115
|
+
return hook;
|
|
116
|
+
}
|
|
117
|
+
async getWebhooks() {
|
|
118
|
+
let text = this.formatter("SELECT * FROM %I;", this.webhookTable);
|
|
119
|
+
let result = await this.db.query(text);
|
|
120
|
+
if (result) {
|
|
121
|
+
const WebhookArray = await Promise.all(result.rows.map(async (obj) => {
|
|
122
|
+
obj = await this.webhookFromDb(obj);
|
|
123
|
+
obj.db = this;
|
|
124
|
+
return obj;
|
|
125
|
+
}));
|
|
126
|
+
return WebhookArray;
|
|
127
|
+
}
|
|
128
|
+
else {
|
|
129
|
+
return [];
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
async getWebhook(id) {
|
|
133
|
+
const text = this.formatter("SELECT * FROM %I WHERE id = $1;", this.webhookTable);
|
|
134
|
+
const result = await this.db.query(text, [id]);
|
|
135
|
+
let hook = result.rows[0];
|
|
136
|
+
if (hook) {
|
|
137
|
+
hook = this.webhookFromDb(hook);
|
|
138
|
+
hook.db = this;
|
|
139
|
+
}
|
|
140
|
+
return hook;
|
|
141
|
+
}
|
|
142
|
+
async setWebhookStatus(id, status) {
|
|
143
|
+
let text = this.formatter("UPDATE %I SET status = $1 WHERE id = $2;", this.webhookTable);
|
|
144
|
+
await this.db.query(text, [status, id]);
|
|
145
|
+
}
|
|
146
|
+
async setWebhookSeenTxLastHeight(id, tx_seen, last_height) {
|
|
147
|
+
let text = this.formatter("UPDATE %I SET tx_seen = $1, last_height = $2 WHERE id = $3;", this.webhookTable);
|
|
148
|
+
await this.db.query(text, [JSON.stringify(tx_seen), last_height, id]);
|
|
149
|
+
}
|
|
150
|
+
async deleteWebhook(id) {
|
|
151
|
+
let text = this.formatter("DELETE FROM %I WHERE id = $1;", this.webhookTable);
|
|
152
|
+
await this.db.query(text, [id]);
|
|
153
|
+
}
|
|
154
|
+
async clearWebhooks() {
|
|
155
|
+
let text = this.formatter("DELETE FROM %I;", this.webhookTable);
|
|
156
|
+
await this.db.query(text);
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
//# sourceMappingURL=SqlProvider.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SqlProvider.js","sourceRoot":"","sources":["../../src/SqlProvider.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,IAAI,WAAW,EAAE,MAAM,kBAAkB,CAAC;AAC1D,cAAc,oBAAoB,CAAC"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
export function getSslConfig() {
|
|
2
|
+
const ca = process.env.DATABASE_SSL_CA
|
|
3
|
+
? Buffer.from(process.env.DATABASE_SSL_CA, "base64").toString("ascii")
|
|
4
|
+
: undefined;
|
|
5
|
+
const key = process.env.DATABASE_SSL_KEY
|
|
6
|
+
? Buffer.from(process.env.DATABASE_SSL_KEY, "base64").toString("ascii")
|
|
7
|
+
: undefined;
|
|
8
|
+
const cert = process.env.DATABASE_SSL_CERT
|
|
9
|
+
? Buffer.from(process.env.DATABASE_SSL_CERT, "base64").toString("ascii")
|
|
10
|
+
: undefined;
|
|
11
|
+
let ssl = {
|
|
12
|
+
rejectUnauthorized: process.env.DATABASE_SSL_REJECT_UNAUTHORIZED == "false" ? false : true,
|
|
13
|
+
ca: ca,
|
|
14
|
+
key: key,
|
|
15
|
+
cert: cert,
|
|
16
|
+
};
|
|
17
|
+
if (ssl.ca || ssl.cert || ssl.key) {
|
|
18
|
+
return ssl;
|
|
19
|
+
}
|
|
20
|
+
else {
|
|
21
|
+
return;
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
//# sourceMappingURL=util.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"util.js","sourceRoot":"","sources":["../../src/util.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,YAAY;IAC1B,MAAM,EAAE,GAAG,OAAO,CAAC,GAAG,CAAC,eAAe;QACpC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,eAAe,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QACtE,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC,gBAAgB;QACtC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QACvE,CAAC,CAAC,SAAS,CAAC;IACd,MAAM,IAAI,GAAG,OAAO,CAAC,GAAG,CAAC,iBAAiB;QACxC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC;QACxE,CAAC,CAAC,SAAS,CAAC;IACd,IAAI,GAAG,GAAe;QACpB,kBAAkB,EAChB,OAAO,CAAC,GAAG,CAAC,gCAAgC,IAAI,OAAO,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI;QACxE,EAAE,EAAE,EAAE;QACN,GAAG,EAAE,GAAG;QACR,IAAI,EAAE,IAAI;KACX,CAAC;IACF,IAAI,GAAG,CAAC,EAAE,IAAI,GAAG,CAAC,IAAI,IAAI,GAAG,CAAC,GAAG,EAAE;QACjC,OAAO,GAAG,CAAC;KACZ;SAAM;QACL,OAAO;KACR;AACH,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
import SqlProvider from "../SqlProvider.js";
|
|
2
|
+
import { TxI } from "mainnet-js";
|
|
3
|
+
export declare enum WebhookType {
|
|
4
|
+
transactionIn = "transaction:in",
|
|
5
|
+
transactionOut = "transaction:out",
|
|
6
|
+
transactionInOut = "transaction:in,out",
|
|
7
|
+
balance = "balance"
|
|
8
|
+
}
|
|
9
|
+
export declare enum WebhookRecurrence {
|
|
10
|
+
once = "once",
|
|
11
|
+
recurrent = "recurrent"
|
|
12
|
+
}
|
|
13
|
+
export declare class Webhook {
|
|
14
|
+
id?: number;
|
|
15
|
+
cashaddr: string;
|
|
16
|
+
type: string;
|
|
17
|
+
recurrence: string;
|
|
18
|
+
url: string;
|
|
19
|
+
status: string;
|
|
20
|
+
last_height: number;
|
|
21
|
+
tx_seen: TxI[];
|
|
22
|
+
expires_at: Date;
|
|
23
|
+
db: SqlProvider;
|
|
24
|
+
constructor(hook: Webhook | Object);
|
|
25
|
+
start(): Promise<void>;
|
|
26
|
+
stop(): Promise<void>;
|
|
27
|
+
destroy(): Promise<void>;
|
|
28
|
+
post(data: any): Promise<boolean>;
|
|
29
|
+
static debug: {
|
|
30
|
+
new (): {};
|
|
31
|
+
setupAxiosMocks(): void;
|
|
32
|
+
reset(): void;
|
|
33
|
+
responses: any;
|
|
34
|
+
};
|
|
35
|
+
}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
var _a;
|
|
2
|
+
import axios from "axios";
|
|
3
|
+
export var WebhookType;
|
|
4
|
+
(function (WebhookType) {
|
|
5
|
+
WebhookType["transactionIn"] = "transaction:in";
|
|
6
|
+
WebhookType["transactionOut"] = "transaction:out";
|
|
7
|
+
WebhookType["transactionInOut"] = "transaction:in,out";
|
|
8
|
+
WebhookType["balance"] = "balance";
|
|
9
|
+
})(WebhookType || (WebhookType = {}));
|
|
10
|
+
export var WebhookRecurrence;
|
|
11
|
+
(function (WebhookRecurrence) {
|
|
12
|
+
WebhookRecurrence["once"] = "once";
|
|
13
|
+
WebhookRecurrence["recurrent"] = "recurrent";
|
|
14
|
+
})(WebhookRecurrence || (WebhookRecurrence = {}));
|
|
15
|
+
export class Webhook {
|
|
16
|
+
constructor(hook) {
|
|
17
|
+
Object.assign(this, hook);
|
|
18
|
+
}
|
|
19
|
+
// abstract, empty implementation
|
|
20
|
+
async start() { }
|
|
21
|
+
// abstract, empty implementation
|
|
22
|
+
async stop() { }
|
|
23
|
+
async destroy() {
|
|
24
|
+
if (this.id) {
|
|
25
|
+
await this.db.deleteWebhook(this.id);
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
async post(data) {
|
|
29
|
+
try {
|
|
30
|
+
await axios.post(this.url, data);
|
|
31
|
+
// console.debug("Posted webhook", this.url, data);
|
|
32
|
+
return true;
|
|
33
|
+
}
|
|
34
|
+
catch (e) {
|
|
35
|
+
if (e.message && e.message.status === 200) {
|
|
36
|
+
return true;
|
|
37
|
+
}
|
|
38
|
+
// console.debug("Failed to post webhook", this.url, e);
|
|
39
|
+
return false;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
//#region debug
|
|
44
|
+
Webhook.debug = (_a = class {
|
|
45
|
+
static setupAxiosMocks() {
|
|
46
|
+
axios.interceptors.request.use((config) => {
|
|
47
|
+
const url = config.url;
|
|
48
|
+
if (!url.startsWith("http://example.com")) {
|
|
49
|
+
return config;
|
|
50
|
+
}
|
|
51
|
+
let response;
|
|
52
|
+
if (url === "http://example.com/fail") {
|
|
53
|
+
response = { status: 503 };
|
|
54
|
+
}
|
|
55
|
+
else {
|
|
56
|
+
response = { status: 200 };
|
|
57
|
+
}
|
|
58
|
+
if (url in this.responses) {
|
|
59
|
+
this.responses[url].push(response);
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
this.responses[url] = [response];
|
|
63
|
+
}
|
|
64
|
+
// cancel actual http request
|
|
65
|
+
return {
|
|
66
|
+
...config,
|
|
67
|
+
cancelToken: new axios.CancelToken((cancel) => cancel(response)),
|
|
68
|
+
};
|
|
69
|
+
});
|
|
70
|
+
}
|
|
71
|
+
static reset() {
|
|
72
|
+
this.responses = {};
|
|
73
|
+
}
|
|
74
|
+
},
|
|
75
|
+
_a.responses = {},
|
|
76
|
+
_a);
|
|
77
|
+
//# sourceMappingURL=Webhook.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Webhook.js","sourceRoot":"","sources":["../../../src/webhook/Webhook.ts"],"names":[],"mappings":";AAGA,OAAO,KAAK,MAAM,OAAO,CAAC;AAE1B,MAAM,CAAN,IAAY,WAKX;AALD,WAAY,WAAW;IACrB,+CAAgC,CAAA;IAChC,iDAAkC,CAAA;IAClC,sDAAuC,CAAA;IACvC,kCAAmB,CAAA;AACrB,CAAC,EALW,WAAW,KAAX,WAAW,QAKtB;AAED,MAAM,CAAN,IAAY,iBAGX;AAHD,WAAY,iBAAiB;IAC3B,kCAAa,CAAA;IACb,4CAAuB,CAAA;AACzB,CAAC,EAHW,iBAAiB,KAAjB,iBAAiB,QAG5B;AAED,MAAM,OAAO,OAAO;IAalB,YAAY,IAAsB;QAChC,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,IAAI,CAAC,CAAC;IAC5B,CAAC;IAED,iCAAiC;IACjC,KAAK,CAAC,KAAK,KAAmB,CAAC;IAE/B,iCAAiC;IACjC,KAAK,CAAC,IAAI,KAAmB,CAAC;IAE9B,KAAK,CAAC,OAAO;QACX,IAAI,IAAI,CAAC,EAAE,EAAE;YACX,MAAM,IAAI,CAAC,EAAE,CAAC,aAAa,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;SACtC;IACH,CAAC;IAED,KAAK,CAAC,IAAI,CAAC,IAAS;QAClB,IAAI;YACF,MAAM,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,CAAC;YACjC,mDAAmD;YACnD,OAAO,IAAI,CAAC;SACb;QAAC,OAAO,CAAM,EAAE;YACf,IAAI,CAAC,CAAC,OAAO,IAAI,CAAC,CAAC,OAAO,CAAC,MAAM,KAAK,GAAG,EAAE;gBACzC,OAAO,IAAI,CAAC;aACb;YAED,wDAAwD;YACxD,OAAO,KAAK,CAAC;SACd;IACH,CAAC;;AAED,eAAe;AACD,aAAK,SAAG;QACpB,MAAM,CAAC,eAAe;YACpB,KAAK,CAAC,YAAY,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,EAAE,EAAE;gBACxC,MAAM,GAAG,GAAG,MAAM,CAAC,GAAI,CAAC;gBACxB,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,oBAAoB,CAAC,EAAE;oBACzC,OAAO,MAAM,CAAC;iBACf;gBAED,IAAI,QAAQ,CAAC;gBACb,IAAI,GAAG,KAAK,yBAAyB,EAAE;oBACrC,QAAQ,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;iBAC5B;qBAAM;oBACL,QAAQ,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE,CAAC;iBAC5B;gBAED,IAAI,GAAG,IAAI,IAAI,CAAC,SAAS,EAAE;oBACzB,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;iBACpC;qBAAM;oBACL,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;iBAClC;gBAED,6BAA6B;gBAC7B,OAAO;oBACL,GAAG,MAAM;oBACT,WAAW,EAAE,IAAI,KAAK,CAAC,WAAW,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;iBACjE,CAAC;YACJ,CAAC,CAAC,CAAC;QACL,CAAC;QAED,MAAM,CAAC,KAAK;YACV,IAAI,CAAC,SAAS,GAAG,EAAE,CAAC;QACtB,CAAC;KAGF;IADQ,YAAS,GAAQ,EAAG;QAC3B"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import SqlProvider from "../SqlProvider.js";
|
|
2
|
+
import { Wallet } from "mainnet-js";
|
|
3
|
+
import { Webhook } from "./Webhook.js";
|
|
4
|
+
export declare class WebhookBch extends Webhook {
|
|
5
|
+
callback: (data: any | string | Array<string>) => void;
|
|
6
|
+
wallet: Wallet;
|
|
7
|
+
db: SqlProvider;
|
|
8
|
+
seenStatuses: string[];
|
|
9
|
+
constructor(hook: Webhook | Object);
|
|
10
|
+
stop(): Promise<void>;
|
|
11
|
+
start(): Promise<void>;
|
|
12
|
+
handler(status: string): Promise<void>;
|
|
13
|
+
}
|
|
@@ -0,0 +1,141 @@
|
|
|
1
|
+
import { balanceResponseFromSatoshi } from "mainnet-js";
|
|
2
|
+
import { Wallet } from "mainnet-js";
|
|
3
|
+
import { Webhook, WebhookRecurrence, WebhookType } from "./Webhook.js";
|
|
4
|
+
import WebhookWorker from "./WebhookWorker.js";
|
|
5
|
+
export class WebhookBch extends Webhook {
|
|
6
|
+
constructor(hook) {
|
|
7
|
+
super(hook);
|
|
8
|
+
this.seenStatuses = [];
|
|
9
|
+
Object.assign(this, hook);
|
|
10
|
+
}
|
|
11
|
+
async stop() {
|
|
12
|
+
await this.wallet.provider.unsubscribeFromAddress(this.cashaddr, this.callback);
|
|
13
|
+
}
|
|
14
|
+
async start() {
|
|
15
|
+
const webhookCallback = async (data) => {
|
|
16
|
+
let status = "";
|
|
17
|
+
if (typeof data === "string") {
|
|
18
|
+
// subscription acknowledgement notification with current status
|
|
19
|
+
status = data;
|
|
20
|
+
// we should skip fetching transactions for freshly registered hooks upon acknowledements
|
|
21
|
+
if (this.status === "") {
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
else if (data instanceof Array) {
|
|
26
|
+
status = data[1];
|
|
27
|
+
if (data[0] !== this.cashaddr) {
|
|
28
|
+
// console.warn("Address missmatch, skipping", data[0], this.cashaddr);
|
|
29
|
+
return;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
else {
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
if (status != this.status && this.seenStatuses.indexOf(status) === -1) {
|
|
36
|
+
this.seenStatuses.push(status);
|
|
37
|
+
await this.handler(status);
|
|
38
|
+
}
|
|
39
|
+
};
|
|
40
|
+
this.callback = webhookCallback;
|
|
41
|
+
this.wallet = await Wallet.fromCashaddr(this.cashaddr);
|
|
42
|
+
await this.wallet.provider.subscribeToAddress(this.cashaddr, this.callback);
|
|
43
|
+
}
|
|
44
|
+
async handler(status) {
|
|
45
|
+
// console.debug("Dispatching action for a webhook", this);
|
|
46
|
+
// get transactions
|
|
47
|
+
const history = await this.wallet.provider.getHistory(this.cashaddr);
|
|
48
|
+
// figure out which transactions to send to the hook
|
|
49
|
+
let txs = [];
|
|
50
|
+
if (status === "") {
|
|
51
|
+
// send the last transaction only if no tracking was done
|
|
52
|
+
txs = history.slice(-1);
|
|
53
|
+
}
|
|
54
|
+
else {
|
|
55
|
+
// reverse history for faster search
|
|
56
|
+
const revHistory = history.reverse();
|
|
57
|
+
// update height of transactions, which are now confirmed
|
|
58
|
+
this.tx_seen = this.tx_seen.map((seenTx) => {
|
|
59
|
+
if (seenTx.height <= 0) {
|
|
60
|
+
const histTx = revHistory.find((val) => val.tx_hash === seenTx.tx_hash);
|
|
61
|
+
if (histTx) {
|
|
62
|
+
seenTx.height = histTx.height;
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return seenTx;
|
|
66
|
+
});
|
|
67
|
+
const seenHashes = this.tx_seen.map((val) => val.tx_hash);
|
|
68
|
+
txs = history.filter((val) => (val.height >= this.last_height || val.height <= 0) &&
|
|
69
|
+
!seenHashes.includes(val.tx_hash));
|
|
70
|
+
}
|
|
71
|
+
let shouldUpdateStatus = true;
|
|
72
|
+
for (const tx of txs) {
|
|
73
|
+
// watching transactions
|
|
74
|
+
let result = false;
|
|
75
|
+
if (this.type.indexOf("transaction:") >= 0) {
|
|
76
|
+
// console.debug("Getting raw tx", tx.tx_hash);
|
|
77
|
+
const rawTx = await this.wallet.provider.getRawTransactionObject(tx.tx_hash);
|
|
78
|
+
const parentTxs = await Promise.all(rawTx.vin.map((t) => this.wallet.provider.getRawTransactionObject(t.txid)));
|
|
79
|
+
// console.debug("Got raw tx", JSON.stringify(rawTx, null, 2));
|
|
80
|
+
const haveAddressInOutputs = rawTx.vout.some((val) => val.scriptPubKey.addresses.includes(this.cashaddr));
|
|
81
|
+
const haveAddressInParentOutputs = parentTxs.some((parent) => parent.vout.some((val) => val.scriptPubKey.addresses.includes(this.cashaddr)));
|
|
82
|
+
const wantsIn = this.type.indexOf("in") >= 0;
|
|
83
|
+
const wantsOut = this.type.indexOf("out") >= 0;
|
|
84
|
+
const txDirection = haveAddressInParentOutputs && haveAddressInOutputs
|
|
85
|
+
? WebhookType.transactionInOut
|
|
86
|
+
: haveAddressInParentOutputs
|
|
87
|
+
? WebhookType.transactionOut
|
|
88
|
+
: WebhookType.transactionIn;
|
|
89
|
+
if (wantsIn && haveAddressInOutputs) {
|
|
90
|
+
result = await this.post({
|
|
91
|
+
direction: txDirection,
|
|
92
|
+
data: rawTx,
|
|
93
|
+
});
|
|
94
|
+
}
|
|
95
|
+
else if (wantsOut && haveAddressInParentOutputs) {
|
|
96
|
+
result = await this.post({
|
|
97
|
+
direction: txDirection,
|
|
98
|
+
data: rawTx,
|
|
99
|
+
});
|
|
100
|
+
}
|
|
101
|
+
else {
|
|
102
|
+
// not interested in this transaction
|
|
103
|
+
continue;
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
else if (this.type === WebhookType.balance) {
|
|
107
|
+
// watching address balance
|
|
108
|
+
const balanceSat = await this.wallet.provider.getBalance(this.cashaddr);
|
|
109
|
+
const balanceObject = await balanceResponseFromSatoshi(balanceSat);
|
|
110
|
+
result = await this.post(balanceObject);
|
|
111
|
+
}
|
|
112
|
+
if (result) {
|
|
113
|
+
this.tx_seen.push(tx);
|
|
114
|
+
await this.db.setWebhookSeenTxLastHeight(this.id, this.tx_seen, this.last_height);
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
// console.debug("Failed to execute webhook", hook);
|
|
118
|
+
shouldUpdateStatus = false;
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
// successful run
|
|
122
|
+
if (shouldUpdateStatus) {
|
|
123
|
+
if (this.recurrence === WebhookRecurrence.once) {
|
|
124
|
+
// we have to notify the worker about end of life
|
|
125
|
+
await (await WebhookWorker.instance()).stopHook(this);
|
|
126
|
+
await this.destroy();
|
|
127
|
+
return;
|
|
128
|
+
}
|
|
129
|
+
this.status = status;
|
|
130
|
+
await this.db.setWebhookStatus(this.id, status);
|
|
131
|
+
// update last_height and truncate tx_seen
|
|
132
|
+
const maxHeight = Math.max(...this.tx_seen.map((val) => val.height));
|
|
133
|
+
if (maxHeight >= this.last_height) {
|
|
134
|
+
this.last_height = maxHeight;
|
|
135
|
+
this.tx_seen = this.tx_seen.filter((val) => val.height === maxHeight || val.height <= 0);
|
|
136
|
+
await this.db.setWebhookSeenTxLastHeight(this.id, this.tx_seen, this.last_height);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
//# sourceMappingURL=WebhookBch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"WebhookBch.js","sourceRoot":"","sources":["../../../src/webhook/WebhookBch.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import SqlProvider from "../SqlProvider.js";
|
|
2
|
+
import { RegisterWebhookParams } from "./interface.js";
|
|
3
|
+
import { Webhook } from "./Webhook";
|
|
4
|
+
export default class WebhookWorker {
|
|
5
|
+
activeHooks: Map<number, Webhook>;
|
|
6
|
+
callbacks: Map<number, (data: any | string | Array<string>) => void>;
|
|
7
|
+
db: SqlProvider;
|
|
8
|
+
checkInterval: any;
|
|
9
|
+
private static _instance;
|
|
10
|
+
static instance(): Promise<WebhookWorker>;
|
|
11
|
+
constructor();
|
|
12
|
+
init(): Promise<void>;
|
|
13
|
+
destroy(): Promise<void>;
|
|
14
|
+
pickupHooks(start?: boolean): Promise<void>;
|
|
15
|
+
evictOldHooks(): Promise<void>;
|
|
16
|
+
registerWebhook(params: RegisterWebhookParams, start?: boolean): Promise<number>;
|
|
17
|
+
getWebhook(id: number): Promise<Webhook | undefined>;
|
|
18
|
+
deleteWebhook(id: number): Promise<void>;
|
|
19
|
+
deleteAllWebhooks(): Promise<void>;
|
|
20
|
+
stopAll(): Promise<void>;
|
|
21
|
+
stopHook(hook: Webhook): Promise<void>;
|
|
22
|
+
}
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import SqlProvider from "../SqlProvider.js";
|
|
2
|
+
export default class WebhookWorker {
|
|
3
|
+
constructor() {
|
|
4
|
+
this.activeHooks = new Map();
|
|
5
|
+
this.callbacks = new Map();
|
|
6
|
+
this.checkInterval = undefined;
|
|
7
|
+
this.db = new SqlProvider();
|
|
8
|
+
}
|
|
9
|
+
static async instance() {
|
|
10
|
+
if (!WebhookWorker._instance) {
|
|
11
|
+
WebhookWorker._instance = new WebhookWorker();
|
|
12
|
+
await WebhookWorker._instance.init();
|
|
13
|
+
}
|
|
14
|
+
return WebhookWorker._instance;
|
|
15
|
+
}
|
|
16
|
+
async init() {
|
|
17
|
+
await this.db.init();
|
|
18
|
+
await this.evictOldHooks();
|
|
19
|
+
await this.pickupHooks(true);
|
|
20
|
+
if (!this.checkInterval) {
|
|
21
|
+
this.checkInterval = setInterval(async () => {
|
|
22
|
+
await this.evictOldHooks();
|
|
23
|
+
await this.pickupHooks(true);
|
|
24
|
+
}, 5 * 60 * 1000);
|
|
25
|
+
}
|
|
26
|
+
}
|
|
27
|
+
async destroy() {
|
|
28
|
+
await this.stopAll();
|
|
29
|
+
if (this.checkInterval) {
|
|
30
|
+
clearInterval(this.checkInterval);
|
|
31
|
+
this.checkInterval = undefined;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
async pickupHooks(start = false) {
|
|
35
|
+
const hooks = await this.db.getWebhooks();
|
|
36
|
+
for (const hook of hooks) {
|
|
37
|
+
if (!this.activeHooks.has(hook.id)) {
|
|
38
|
+
this.activeHooks.set(hook.id, hook);
|
|
39
|
+
if (start) {
|
|
40
|
+
await hook.start();
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
async evictOldHooks() {
|
|
46
|
+
const now = new Date();
|
|
47
|
+
const dbHooks = await this.db.getWebhooks();
|
|
48
|
+
for (const hook of dbHooks) {
|
|
49
|
+
if (now >= hook.expires_at) {
|
|
50
|
+
// console.debug("Evicting expired hook with id", hook.id, new Date(), hook.expires_at);
|
|
51
|
+
if (this.activeHooks.has(hook.id)) {
|
|
52
|
+
await this.stopHook(hook);
|
|
53
|
+
}
|
|
54
|
+
await this.db.deleteWebhook(hook.id);
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
async registerWebhook(params, start = true) {
|
|
59
|
+
const webhook = await this.db.addWebhook(params);
|
|
60
|
+
if (start) {
|
|
61
|
+
this.activeHooks.set(webhook.id, webhook);
|
|
62
|
+
await webhook.start();
|
|
63
|
+
}
|
|
64
|
+
return webhook.id;
|
|
65
|
+
}
|
|
66
|
+
async getWebhook(id) {
|
|
67
|
+
if (this.activeHooks.has(id)) {
|
|
68
|
+
return this.activeHooks.get(id);
|
|
69
|
+
}
|
|
70
|
+
return await this.db.getWebhook(id);
|
|
71
|
+
}
|
|
72
|
+
async deleteWebhook(id) {
|
|
73
|
+
if (this.activeHooks.has(id)) {
|
|
74
|
+
await this.stopHook(this.activeHooks.get(id));
|
|
75
|
+
}
|
|
76
|
+
await this.db.deleteWebhook(id);
|
|
77
|
+
}
|
|
78
|
+
async deleteAllWebhooks() {
|
|
79
|
+
await this.stopAll();
|
|
80
|
+
await this.db.clearWebhooks();
|
|
81
|
+
}
|
|
82
|
+
async stopAll() {
|
|
83
|
+
for (const [, hook] of this.activeHooks) {
|
|
84
|
+
await this.stopHook(hook);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
async stopHook(hook) {
|
|
88
|
+
if (this.activeHooks.has(hook.id)) {
|
|
89
|
+
await hook.stop();
|
|
90
|
+
this.activeHooks.delete(hook.id);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
//# sourceMappingURL=WebhookWorker.js.map
|