envio 3.0.0-alpha.2 → 3.0.0-alpha.20
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 +164 -30
- package/bin.mjs +49 -0
- package/evm.schema.json +79 -169
- package/fuel.schema.json +50 -21
- package/index.d.ts +497 -1
- package/index.js +4 -0
- package/package.json +42 -31
- package/rescript.json +4 -1
- package/src/Batch.res +11 -8
- package/src/Batch.res.mjs +11 -9
- package/src/ChainFetcher.res +531 -0
- package/src/ChainFetcher.res.mjs +339 -0
- package/src/ChainManager.res +190 -0
- package/src/ChainManager.res.mjs +166 -0
- package/src/Change.res +3 -3
- package/src/Config.gen.ts +19 -0
- package/src/Config.res +737 -22
- package/src/Config.res.mjs +703 -26
- package/src/{Indexer.res → Ctx.res} +1 -1
- package/src/Ecosystem.res +9 -124
- package/src/Ecosystem.res.mjs +19 -160
- package/src/Env.res +30 -74
- package/src/Env.res.mjs +25 -87
- package/src/Envio.gen.ts +3 -1
- package/src/Envio.res +20 -9
- package/src/EventProcessing.res +469 -0
- package/src/EventProcessing.res.mjs +337 -0
- package/src/EvmTypes.gen.ts +6 -0
- package/src/EvmTypes.res +1 -0
- package/src/FetchState.res +1256 -639
- package/src/FetchState.res.mjs +1135 -612
- package/src/GlobalState.res +1190 -0
- package/src/GlobalState.res.mjs +1183 -0
- package/src/GlobalStateManager.res +68 -0
- package/src/GlobalStateManager.res.mjs +75 -0
- package/src/GlobalStateManager.resi +7 -0
- package/src/HandlerLoader.res +89 -0
- package/src/HandlerLoader.res.mjs +79 -0
- package/src/HandlerRegister.res +357 -0
- package/src/HandlerRegister.res.mjs +299 -0
- package/src/{EventRegister.resi → HandlerRegister.resi} +13 -13
- package/src/Hasura.res +111 -175
- package/src/Hasura.res.mjs +88 -150
- package/src/InMemoryStore.res +1 -1
- package/src/InMemoryStore.res.mjs +3 -3
- package/src/InMemoryTable.res +1 -1
- package/src/InMemoryTable.res.mjs +1 -1
- package/src/Internal.gen.ts +4 -0
- package/src/Internal.res +230 -12
- package/src/Internal.res.mjs +115 -1
- package/src/LoadLayer.res +444 -0
- package/src/LoadLayer.res.mjs +296 -0
- package/src/LoadLayer.resi +32 -0
- package/src/LogSelection.res +33 -27
- package/src/LogSelection.res.mjs +6 -0
- package/src/Logging.res +21 -7
- package/src/Logging.res.mjs +16 -8
- package/src/Main.res +377 -0
- package/src/Main.res.mjs +339 -0
- package/src/Persistence.res +7 -21
- package/src/Persistence.res.mjs +3 -3
- package/src/PgStorage.gen.ts +10 -0
- package/src/PgStorage.res +116 -69
- package/src/PgStorage.res.d.mts +5 -0
- package/src/PgStorage.res.mjs +93 -50
- package/src/Prometheus.res +294 -224
- package/src/Prometheus.res.mjs +353 -340
- package/src/ReorgDetection.res +6 -10
- package/src/ReorgDetection.res.mjs +6 -6
- package/src/SafeCheckpointTracking.res +4 -4
- package/src/SafeCheckpointTracking.res.mjs +2 -2
- package/src/Sink.res +4 -2
- package/src/Sink.res.mjs +2 -1
- package/src/TableIndices.res +0 -1
- package/src/TestIndexer.res +692 -0
- package/src/TestIndexer.res.mjs +527 -0
- package/src/TestIndexerProxyStorage.res +205 -0
- package/src/TestIndexerProxyStorage.res.mjs +151 -0
- package/src/TopicFilter.res +1 -1
- package/src/Types.ts +1 -1
- package/src/UserContext.res +424 -0
- package/src/UserContext.res.mjs +279 -0
- package/src/Utils.res +97 -26
- package/src/Utils.res.mjs +91 -44
- package/src/bindings/BigInt.res +10 -0
- package/src/bindings/BigInt.res.mjs +15 -0
- package/src/bindings/ClickHouse.res +120 -23
- package/src/bindings/ClickHouse.res.mjs +118 -28
- package/src/bindings/DateFns.res +74 -0
- package/src/bindings/DateFns.res.mjs +22 -0
- package/src/bindings/EventSource.res +8 -1
- package/src/bindings/EventSource.res.mjs +8 -1
- package/src/bindings/Express.res +1 -0
- package/src/bindings/Hrtime.res +14 -1
- package/src/bindings/Hrtime.res.mjs +22 -2
- package/src/bindings/Hrtime.resi +4 -0
- package/src/bindings/Lodash.res +0 -1
- package/src/bindings/NodeJs.res +49 -3
- package/src/bindings/NodeJs.res.mjs +11 -3
- package/src/bindings/Pino.res +24 -10
- package/src/bindings/Pino.res.mjs +14 -8
- package/src/bindings/Postgres.gen.ts +8 -0
- package/src/bindings/Postgres.res +5 -1
- package/src/bindings/Postgres.res.d.mts +5 -0
- package/src/bindings/PromClient.res +0 -10
- package/src/bindings/PromClient.res.mjs +0 -3
- package/src/bindings/Vitest.res +142 -0
- package/src/bindings/Vitest.res.mjs +9 -0
- package/src/bindings/WebSocket.res +27 -0
- package/src/bindings/WebSocket.res.mjs +2 -0
- package/src/bindings/Yargs.res +8 -0
- package/src/bindings/Yargs.res.mjs +2 -0
- package/src/db/EntityHistory.res +7 -7
- package/src/db/EntityHistory.res.mjs +9 -9
- package/src/db/InternalTable.res +59 -111
- package/src/db/InternalTable.res.mjs +73 -104
- package/src/db/Table.res +27 -8
- package/src/db/Table.res.mjs +25 -14
- package/src/sources/Evm.res +84 -0
- package/src/sources/Evm.res.mjs +105 -0
- package/src/sources/EvmChain.res +94 -0
- package/src/sources/EvmChain.res.mjs +60 -0
- package/src/sources/Fuel.res +19 -34
- package/src/sources/Fuel.res.mjs +34 -16
- package/src/sources/FuelSDK.res +38 -0
- package/src/sources/FuelSDK.res.mjs +29 -0
- package/src/sources/HyperFuel.res +2 -2
- package/src/sources/HyperFuel.resi +1 -1
- package/src/sources/HyperFuelClient.res +2 -2
- package/src/sources/HyperFuelSource.res +33 -13
- package/src/sources/HyperFuelSource.res.mjs +24 -16
- package/src/sources/HyperSync.res +36 -6
- package/src/sources/HyperSync.res.mjs +9 -7
- package/src/sources/HyperSync.resi +4 -0
- package/src/sources/HyperSyncClient.res +1 -1
- package/src/sources/HyperSyncHeightStream.res +47 -116
- package/src/sources/HyperSyncHeightStream.res.mjs +46 -73
- package/src/sources/HyperSyncSource.res +118 -139
- package/src/sources/HyperSyncSource.res.mjs +104 -121
- package/src/sources/Rpc.res +86 -14
- package/src/sources/Rpc.res.mjs +101 -9
- package/src/sources/RpcSource.res +621 -364
- package/src/sources/RpcSource.res.mjs +843 -410
- package/src/sources/RpcWebSocketHeightStream.res +181 -0
- package/src/sources/RpcWebSocketHeightStream.res.mjs +196 -0
- package/src/sources/Source.res +7 -5
- package/src/sources/SourceManager.res +325 -225
- package/src/sources/SourceManager.res.mjs +314 -171
- package/src/sources/SourceManager.resi +17 -6
- package/src/sources/Svm.res +81 -0
- package/src/sources/Svm.res.mjs +90 -0
- package/src/tui/Tui.res +247 -0
- package/src/tui/Tui.res.mjs +337 -0
- package/src/tui/bindings/Ink.res +371 -0
- package/src/tui/bindings/Ink.res.mjs +72 -0
- package/src/tui/bindings/Style.res +123 -0
- package/src/tui/bindings/Style.res.mjs +2 -0
- package/src/tui/components/BufferedProgressBar.res +40 -0
- package/src/tui/components/BufferedProgressBar.res.mjs +57 -0
- package/src/tui/components/CustomHooks.res +122 -0
- package/src/tui/components/CustomHooks.res.mjs +179 -0
- package/src/tui/components/Messages.res +41 -0
- package/src/tui/components/Messages.res.mjs +75 -0
- package/src/tui/components/SyncETA.res +174 -0
- package/src/tui/components/SyncETA.res.mjs +263 -0
- package/src/tui/components/TuiData.res +47 -0
- package/src/tui/components/TuiData.res.mjs +34 -0
- package/svm.schema.json +112 -0
- package/bin.js +0 -48
- package/src/EventRegister.res +0 -241
- package/src/EventRegister.res.mjs +0 -240
- package/src/bindings/Ethers.gen.ts +0 -14
- package/src/bindings/Ethers.res +0 -204
- package/src/bindings/Ethers.res.mjs +0 -130
- /package/src/{Indexer.res.mjs → Ctx.res.mjs} +0 -0
|
@@ -0,0 +1,181 @@
|
|
|
1
|
+
/*
|
|
2
|
+
WebSocket-based implementation for real-time block height tracking.
|
|
3
|
+
Uses eth_subscribe("newHeads") for low-latency block detection.
|
|
4
|
+
Falls back behavior is handled by SourceManager when subscription fails.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
let retryCount = 9
|
|
8
|
+
let baseDuration = 125
|
|
9
|
+
// Close and reconnect if no new block head arrives within this period.
|
|
10
|
+
// Detects silently dropped server-side subscriptions.
|
|
11
|
+
let staleTimeMillis = 60_000
|
|
12
|
+
|
|
13
|
+
type wsMessage =
|
|
14
|
+
| NewHead(int)
|
|
15
|
+
| SubscriptionConfirmed(string)
|
|
16
|
+
| ErrorResponse
|
|
17
|
+
|
|
18
|
+
let subscribeRequestJson =
|
|
19
|
+
{"jsonrpc": "2.0", "id": 1, "method": "eth_subscribe", "params": ["newHeads"]}
|
|
20
|
+
->(Utils.magic: {
|
|
21
|
+
"jsonrpc": string,
|
|
22
|
+
"id": int,
|
|
23
|
+
"method": string,
|
|
24
|
+
"params": array<string>,
|
|
25
|
+
} => Js.Json.t)
|
|
26
|
+
->Js.Json.serializeExn
|
|
27
|
+
|
|
28
|
+
let wsMessageSchema = S.union([
|
|
29
|
+
S.object(s => {
|
|
30
|
+
let _ = s.field("method", S.literal("eth_subscription"))
|
|
31
|
+
NewHead(
|
|
32
|
+
s.field(
|
|
33
|
+
"params",
|
|
34
|
+
S.object(s => {
|
|
35
|
+
s.field(
|
|
36
|
+
"result",
|
|
37
|
+
S.object(
|
|
38
|
+
s => {
|
|
39
|
+
s.field("number", Rpc.hexIntSchema)
|
|
40
|
+
},
|
|
41
|
+
),
|
|
42
|
+
)
|
|
43
|
+
}),
|
|
44
|
+
),
|
|
45
|
+
)
|
|
46
|
+
}),
|
|
47
|
+
S.object(s => {
|
|
48
|
+
SubscriptionConfirmed(s.field("result", S.string))
|
|
49
|
+
}),
|
|
50
|
+
S.object(s => {
|
|
51
|
+
let _ = s.field("error", S.unknown)
|
|
52
|
+
ErrorResponse
|
|
53
|
+
}),
|
|
54
|
+
])
|
|
55
|
+
|
|
56
|
+
let subscribe = (~wsUrl, ~chainId, ~onHeight: int => unit): (unit => unit) => {
|
|
57
|
+
let wsRef: ref<option<WebSocket.t>> = ref(None)
|
|
58
|
+
let isUnsubscribed = ref(false)
|
|
59
|
+
let errorCount = ref(0)
|
|
60
|
+
let staleTimeoutId: ref<option<Js.Global.timeoutId>> = ref(None)
|
|
61
|
+
|
|
62
|
+
let clearStaleTimeout = () => {
|
|
63
|
+
switch staleTimeoutId.contents {
|
|
64
|
+
| Some(id) =>
|
|
65
|
+
Js.Global.clearTimeout(id)
|
|
66
|
+
staleTimeoutId := None
|
|
67
|
+
| None => ()
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
let resetStaleTimeout = () => {
|
|
72
|
+
clearStaleTimeout()
|
|
73
|
+
staleTimeoutId := Some(Js.Global.setTimeout(() => {
|
|
74
|
+
// Connection went stale - close to trigger reconnect
|
|
75
|
+
switch wsRef.contents {
|
|
76
|
+
| Some(ws) => ws->WebSocket.close
|
|
77
|
+
| None => ()
|
|
78
|
+
}
|
|
79
|
+
}, staleTimeMillis))
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
let rec scheduleReconnect = () => {
|
|
83
|
+
if !isUnsubscribed.contents && errorCount.contents < retryCount {
|
|
84
|
+
let duration =
|
|
85
|
+
baseDuration *
|
|
86
|
+
Js.Math.pow_float(~base=2.0, ~exp=errorCount.contents->Belt.Int.toFloat)->Belt.Float.toInt
|
|
87
|
+
let _ = Js.Global.setTimeout(() => {
|
|
88
|
+
if !isUnsubscribed.contents {
|
|
89
|
+
startConnection()
|
|
90
|
+
}
|
|
91
|
+
}, duration)
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
and startConnection = () => {
|
|
95
|
+
if isUnsubscribed.contents || errorCount.contents >= retryCount {
|
|
96
|
+
()
|
|
97
|
+
} else {
|
|
98
|
+
let ws = WebSocket.create(wsUrl)
|
|
99
|
+
wsRef := Some(ws)
|
|
100
|
+
|
|
101
|
+
ws->WebSocket.onopen(() => {
|
|
102
|
+
ws->WebSocket.send(subscribeRequestJson)
|
|
103
|
+
resetStaleTimeout()
|
|
104
|
+
})
|
|
105
|
+
|
|
106
|
+
ws->WebSocket.onmessage(event => {
|
|
107
|
+
try {
|
|
108
|
+
switch event.data->Js.Json.parseExn->S.parseOrThrow(wsMessageSchema) {
|
|
109
|
+
| NewHead(blockNumber) =>
|
|
110
|
+
errorCount := 0
|
|
111
|
+
resetStaleTimeout()
|
|
112
|
+
Prometheus.SourceRequestCount.increment(
|
|
113
|
+
~sourceName="WebSocket",
|
|
114
|
+
~chainId,
|
|
115
|
+
~method="eth_subscribe",
|
|
116
|
+
)
|
|
117
|
+
onHeight(blockNumber)
|
|
118
|
+
| SubscriptionConfirmed(_) => resetStaleTimeout()
|
|
119
|
+
| ErrorResponse =>
|
|
120
|
+
if errorCount.contents < retryCount {
|
|
121
|
+
errorCount := errorCount.contents + 1
|
|
122
|
+
}
|
|
123
|
+
switch wsRef.contents {
|
|
124
|
+
| Some(ws) => ws->WebSocket.close
|
|
125
|
+
| None => ()
|
|
126
|
+
}
|
|
127
|
+
}
|
|
128
|
+
} catch {
|
|
129
|
+
| S.Raised(_) =>
|
|
130
|
+
Logging.warn({
|
|
131
|
+
"msg": "WebSocket height stream received unrecognized message",
|
|
132
|
+
"chainId": chainId,
|
|
133
|
+
"data": event.data,
|
|
134
|
+
})
|
|
135
|
+
| Js.Exn.Error(_) as e =>
|
|
136
|
+
Logging.warn({
|
|
137
|
+
"msg": "WebSocket height stream failed to parse message",
|
|
138
|
+
"chainId": chainId,
|
|
139
|
+
"err": e->Utils.prettifyExn,
|
|
140
|
+
"data": event.data,
|
|
141
|
+
})
|
|
142
|
+
| e =>
|
|
143
|
+
Logging.error({
|
|
144
|
+
"msg": "Unexpected error in WebSocket height stream message handler",
|
|
145
|
+
"chainId": chainId,
|
|
146
|
+
"err": e->Utils.prettifyExn,
|
|
147
|
+
"data": event.data,
|
|
148
|
+
})
|
|
149
|
+
raise(e)
|
|
150
|
+
}
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
ws->WebSocket.onerror(_error => {
|
|
154
|
+
if errorCount.contents < retryCount {
|
|
155
|
+
errorCount := errorCount.contents + 1
|
|
156
|
+
}
|
|
157
|
+
switch wsRef.contents {
|
|
158
|
+
| Some(ws) if ws->WebSocket.readyState === Open => ws->WebSocket.close
|
|
159
|
+
| _ => ()
|
|
160
|
+
}
|
|
161
|
+
})
|
|
162
|
+
|
|
163
|
+
ws->WebSocket.onclose(() => {
|
|
164
|
+
wsRef := None
|
|
165
|
+
clearStaleTimeout()
|
|
166
|
+
scheduleReconnect()
|
|
167
|
+
})
|
|
168
|
+
}
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
startConnection()
|
|
172
|
+
|
|
173
|
+
() => {
|
|
174
|
+
isUnsubscribed := true
|
|
175
|
+
clearStaleTimeout()
|
|
176
|
+
switch wsRef.contents {
|
|
177
|
+
| Some(ws) => ws->WebSocket.close
|
|
178
|
+
| None => ()
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
}
|
|
@@ -0,0 +1,196 @@
|
|
|
1
|
+
// Generated by ReScript, PLEASE EDIT WITH CARE
|
|
2
|
+
|
|
3
|
+
import * as Rpc from "./Rpc.res.mjs";
|
|
4
|
+
import * as Utils from "../Utils.res.mjs";
|
|
5
|
+
import * as Js_exn from "rescript/lib/es6/js_exn.js";
|
|
6
|
+
import * as Js_json from "rescript/lib/es6/js_json.js";
|
|
7
|
+
import * as Logging from "../Logging.res.mjs";
|
|
8
|
+
import * as Prometheus from "../Prometheus.res.mjs";
|
|
9
|
+
import * as Caml_option from "rescript/lib/es6/caml_option.js";
|
|
10
|
+
import * as S$RescriptSchema from "rescript-schema/src/S.res.mjs";
|
|
11
|
+
import * as Caml_js_exceptions from "rescript/lib/es6/caml_js_exceptions.js";
|
|
12
|
+
|
|
13
|
+
var subscribeRequestJson = Js_json.serializeExn({
|
|
14
|
+
jsonrpc: "2.0",
|
|
15
|
+
id: 1,
|
|
16
|
+
method: "eth_subscribe",
|
|
17
|
+
params: ["newHeads"]
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
var wsMessageSchema = S$RescriptSchema.union([
|
|
21
|
+
S$RescriptSchema.object(function (s) {
|
|
22
|
+
s.f("method", S$RescriptSchema.literal("eth_subscription"));
|
|
23
|
+
return {
|
|
24
|
+
TAG: "NewHead",
|
|
25
|
+
_0: s.f("params", S$RescriptSchema.object(function (s) {
|
|
26
|
+
return s.f("result", S$RescriptSchema.object(function (s) {
|
|
27
|
+
return s.f("number", Rpc.hexIntSchema);
|
|
28
|
+
}));
|
|
29
|
+
}))
|
|
30
|
+
};
|
|
31
|
+
}),
|
|
32
|
+
S$RescriptSchema.object(function (s) {
|
|
33
|
+
return {
|
|
34
|
+
TAG: "SubscriptionConfirmed",
|
|
35
|
+
_0: s.f("result", S$RescriptSchema.string)
|
|
36
|
+
};
|
|
37
|
+
}),
|
|
38
|
+
S$RescriptSchema.object(function (s) {
|
|
39
|
+
s.f("error", S$RescriptSchema.unknown);
|
|
40
|
+
return "ErrorResponse";
|
|
41
|
+
})
|
|
42
|
+
]);
|
|
43
|
+
|
|
44
|
+
function subscribe(wsUrl, chainId, onHeight) {
|
|
45
|
+
var wsRef = {
|
|
46
|
+
contents: undefined
|
|
47
|
+
};
|
|
48
|
+
var isUnsubscribed = {
|
|
49
|
+
contents: false
|
|
50
|
+
};
|
|
51
|
+
var errorCount = {
|
|
52
|
+
contents: 0
|
|
53
|
+
};
|
|
54
|
+
var staleTimeoutId = {
|
|
55
|
+
contents: undefined
|
|
56
|
+
};
|
|
57
|
+
var clearStaleTimeout = function () {
|
|
58
|
+
var id = staleTimeoutId.contents;
|
|
59
|
+
if (id !== undefined) {
|
|
60
|
+
clearTimeout(Caml_option.valFromOption(id));
|
|
61
|
+
staleTimeoutId.contents = undefined;
|
|
62
|
+
return ;
|
|
63
|
+
}
|
|
64
|
+
|
|
65
|
+
};
|
|
66
|
+
var resetStaleTimeout = function () {
|
|
67
|
+
clearStaleTimeout();
|
|
68
|
+
staleTimeoutId.contents = Caml_option.some(setTimeout((function () {
|
|
69
|
+
var ws = wsRef.contents;
|
|
70
|
+
if (ws !== undefined) {
|
|
71
|
+
Caml_option.valFromOption(ws).close();
|
|
72
|
+
return ;
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
}), 60000));
|
|
76
|
+
};
|
|
77
|
+
var scheduleReconnect = function () {
|
|
78
|
+
if (!(!isUnsubscribed.contents && errorCount.contents < 9)) {
|
|
79
|
+
return ;
|
|
80
|
+
}
|
|
81
|
+
var duration = Math.imul(125, Math.pow(2.0, errorCount.contents) | 0);
|
|
82
|
+
setTimeout((function () {
|
|
83
|
+
if (!isUnsubscribed.contents) {
|
|
84
|
+
return startConnection();
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
}), duration);
|
|
88
|
+
};
|
|
89
|
+
var startConnection = function () {
|
|
90
|
+
if (isUnsubscribed.contents || errorCount.contents >= 9) {
|
|
91
|
+
return ;
|
|
92
|
+
}
|
|
93
|
+
var ws = new WebSocket(wsUrl);
|
|
94
|
+
wsRef.contents = Caml_option.some(ws);
|
|
95
|
+
ws.onopen = (function () {
|
|
96
|
+
ws.send(subscribeRequestJson);
|
|
97
|
+
resetStaleTimeout();
|
|
98
|
+
});
|
|
99
|
+
ws.onmessage = (function ($$event) {
|
|
100
|
+
try {
|
|
101
|
+
var blockNumber = S$RescriptSchema.parseOrThrow(JSON.parse($$event.data), wsMessageSchema);
|
|
102
|
+
if (typeof blockNumber !== "object") {
|
|
103
|
+
if (errorCount.contents < 9) {
|
|
104
|
+
errorCount.contents = errorCount.contents + 1 | 0;
|
|
105
|
+
}
|
|
106
|
+
var ws = wsRef.contents;
|
|
107
|
+
if (ws !== undefined) {
|
|
108
|
+
Caml_option.valFromOption(ws).close();
|
|
109
|
+
return ;
|
|
110
|
+
} else {
|
|
111
|
+
return ;
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
if (blockNumber.TAG !== "NewHead") {
|
|
115
|
+
return resetStaleTimeout();
|
|
116
|
+
}
|
|
117
|
+
errorCount.contents = 0;
|
|
118
|
+
resetStaleTimeout();
|
|
119
|
+
Prometheus.SourceRequestCount.increment("WebSocket", chainId, "eth_subscribe");
|
|
120
|
+
return onHeight(blockNumber._0);
|
|
121
|
+
}
|
|
122
|
+
catch (raw_e){
|
|
123
|
+
var e = Caml_js_exceptions.internalToOCamlException(raw_e);
|
|
124
|
+
if (e.RE_EXN_ID === S$RescriptSchema.Raised) {
|
|
125
|
+
return Logging.warn({
|
|
126
|
+
msg: "WebSocket height stream received unrecognized message",
|
|
127
|
+
chainId: chainId,
|
|
128
|
+
data: $$event.data
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
if (e.RE_EXN_ID === Js_exn.$$Error) {
|
|
132
|
+
return Logging.warn({
|
|
133
|
+
msg: "WebSocket height stream failed to parse message",
|
|
134
|
+
chainId: chainId,
|
|
135
|
+
err: Utils.prettifyExn(e),
|
|
136
|
+
data: $$event.data
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
Logging.error({
|
|
140
|
+
msg: "Unexpected error in WebSocket height stream message handler",
|
|
141
|
+
chainId: chainId,
|
|
142
|
+
err: Utils.prettifyExn(e),
|
|
143
|
+
data: $$event.data
|
|
144
|
+
});
|
|
145
|
+
throw e;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
ws.onerror = (function (_error) {
|
|
149
|
+
if (errorCount.contents < 9) {
|
|
150
|
+
errorCount.contents = errorCount.contents + 1 | 0;
|
|
151
|
+
}
|
|
152
|
+
var ws = wsRef.contents;
|
|
153
|
+
if (ws === undefined) {
|
|
154
|
+
return ;
|
|
155
|
+
}
|
|
156
|
+
var ws$1 = Caml_option.valFromOption(ws);
|
|
157
|
+
if (ws$1.readyState === 1) {
|
|
158
|
+
ws$1.close();
|
|
159
|
+
return ;
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
});
|
|
163
|
+
ws.onclose = (function () {
|
|
164
|
+
wsRef.contents = undefined;
|
|
165
|
+
clearStaleTimeout();
|
|
166
|
+
scheduleReconnect();
|
|
167
|
+
});
|
|
168
|
+
};
|
|
169
|
+
startConnection();
|
|
170
|
+
return function () {
|
|
171
|
+
isUnsubscribed.contents = true;
|
|
172
|
+
clearStaleTimeout();
|
|
173
|
+
var ws = wsRef.contents;
|
|
174
|
+
if (ws !== undefined) {
|
|
175
|
+
Caml_option.valFromOption(ws).close();
|
|
176
|
+
return ;
|
|
177
|
+
}
|
|
178
|
+
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
|
|
182
|
+
var retryCount = 9;
|
|
183
|
+
|
|
184
|
+
var baseDuration = 125;
|
|
185
|
+
|
|
186
|
+
var staleTimeMillis = 60000;
|
|
187
|
+
|
|
188
|
+
export {
|
|
189
|
+
retryCount ,
|
|
190
|
+
baseDuration ,
|
|
191
|
+
staleTimeMillis ,
|
|
192
|
+
subscribeRequestJson ,
|
|
193
|
+
wsMessageSchema ,
|
|
194
|
+
subscribe ,
|
|
195
|
+
}
|
|
196
|
+
/* subscribeRequestJson Not a pure module */
|
package/src/sources/Source.res
CHANGED
|
@@ -2,16 +2,16 @@
|
|
|
2
2
|
A set of stats for logging about the block range fetch
|
|
3
3
|
*/
|
|
4
4
|
type blockRangeFetchStats = {
|
|
5
|
-
@as("total time elapsed (
|
|
6
|
-
@as("parsing time (
|
|
7
|
-
@as("page fetch time (
|
|
5
|
+
@as("total time elapsed (s)") totalTimeElapsed: float,
|
|
6
|
+
@as("parsing time (s)") parsingTimeElapsed?: float,
|
|
7
|
+
@as("page fetch time (s)") pageFetchTime?: float,
|
|
8
8
|
}
|
|
9
9
|
|
|
10
10
|
/**
|
|
11
11
|
Thes response returned from a block range fetch
|
|
12
12
|
*/
|
|
13
13
|
type blockRangeFetchResponse = {
|
|
14
|
-
|
|
14
|
+
knownHeight: int,
|
|
15
15
|
reorgGuard: ReorgDetection.reorgGuard,
|
|
16
16
|
parsedQueueItems: array<Internal.item>,
|
|
17
17
|
fromBlockQueried: int,
|
|
@@ -33,6 +33,7 @@ type getItemsError =
|
|
|
33
33
|
exception GetItemsError(getItemsError)
|
|
34
34
|
|
|
35
35
|
type sourceFor = Sync | Fallback | Live
|
|
36
|
+
|
|
36
37
|
type t = {
|
|
37
38
|
name: string,
|
|
38
39
|
sourceFor: sourceFor,
|
|
@@ -50,10 +51,11 @@ type t = {
|
|
|
50
51
|
~toBlock: option<int>,
|
|
51
52
|
~addressesByContractName: dict<array<Address.t>>,
|
|
52
53
|
~indexingContracts: dict<Internal.indexingContract>,
|
|
53
|
-
~
|
|
54
|
+
~knownHeight: int,
|
|
54
55
|
~partitionId: string,
|
|
55
56
|
~selection: FetchState.selection,
|
|
56
57
|
~retry: int,
|
|
57
58
|
~logger: Pino.t,
|
|
58
59
|
) => promise<blockRangeFetchResponse>,
|
|
60
|
+
createHeightSubscription?: (~onHeight: int => unit) => unit => unit,
|
|
59
61
|
}
|