/
watch-blocks-v1-endpoint.ts
83 lines (71 loc) · 3.1 KB
/
watch-blocks-v1-endpoint.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
import { Socket as SocketIoSocket } from "socket.io";
import Web3 from "web3";
import { Logger, Checks } from "@hyperledger/cactus-common";
import { LogLevelDesc, LoggerProvider } from "@hyperledger/cactus-common";
import { WatchBlocksV1Progress } from "../generated/openapi/typescript-axios";
import { WatchBlocksV1 } from "../generated/openapi/typescript-axios";
import { Web3BlockHeader } from "../generated/openapi/typescript-axios";
export interface IWatchBlocksV1EndpointOptions {
logLevel?: LogLevelDesc;
socket: SocketIoSocket;
web3: Web3;
}
export class WatchBlocksV1Endpoint {
public static readonly CLASS_NAME = "WatchBlocksV1Endpoint";
private readonly log: Logger;
private readonly socket: SocketIoSocket<
Record<WatchBlocksV1, (next: string) => void>,
Record<WatchBlocksV1, (next: WatchBlocksV1Progress | Error) => void>
>;
private readonly web3: Web3;
public get className(): string {
return WatchBlocksV1Endpoint.CLASS_NAME;
}
constructor(public readonly options: IWatchBlocksV1EndpointOptions) {
const fnTag = `${this.className}#constructor()`;
Checks.truthy(options, `${fnTag} arg options`);
Checks.truthy(options.web3, `${fnTag} arg options.web3`);
Checks.truthy(options.socket, `${fnTag} arg options.socket`);
this.web3 = options.web3;
this.socket = options.socket;
const level = this.options.logLevel || "INFO";
const label = this.className;
this.log = LoggerProvider.getOrCreate({ level, label });
}
public async subscribe(): Promise<void> {
const { socket, log, web3 } = this;
log.debug(`${WatchBlocksV1.Subscribe} => ${socket.id}`);
const sub = web3.eth.subscribe("newBlockHeaders", (ex, blockHeader) => {
log.debug("newBlockHeaders: Error=%o BlockHeader=%o", ex, blockHeader);
if (blockHeader) {
const next: WatchBlocksV1Progress = {
// Cast needed because somewhere between Web3 v1.5.2 and v1.6.1 they
// made the receiptRoot property of the BlockHeader type optional.
// This could be accompanied by a breaking change in their code or
// it could've been just a mistake in their typings that they corrected.
// Either way, with the next major release, we need to make it optional
// in our API specs as well so that they match up.
blockHeader: blockHeader as unknown as Web3BlockHeader,
};
socket.emit(WatchBlocksV1.Next, next);
}
if (ex) {
socket.emit(WatchBlocksV1.Error, ex);
sub.unsubscribe();
}
});
log.debug("Subscribing to Web3 new block headers event...");
socket.on("disconnect", async (reason: string) => {
log.debug("WebSocket:disconnect reason=%o", reason);
sub.unsubscribe((ex: Error, success: boolean) => {
log.debug("Web3 unsubscribe success=%o, ex=%", success, ex);
});
});
socket.on(WatchBlocksV1.Unsubscribe, () => {
log.debug(`${WatchBlocksV1.Unsubscribe}: unsubscribing Web3...`);
sub.unsubscribe((ex: Error, success: boolean) => {
log.debug("Web3 unsubscribe error=%o, success=%", ex, success);
});
});
}
}