@polkadot-api/ws-provider 0.3.4 → 0.3.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.
@@ -0,0 +1,66 @@
1
+ const methods = {};
2
+ ["v1", "unstable"].forEach((version) => {
3
+ methods[`chainHead_${version}_follow`] = "follow";
4
+ methods[`chainHead_${version}_unfollow`] = "unfollow";
5
+ });
6
+ const followEnhancer = (base, forceDisconnect) => {
7
+ const prematureStops = /* @__PURE__ */ new Set();
8
+ const preOpId = /* @__PURE__ */ new Set();
9
+ const onGoing = /* @__PURE__ */ new Set();
10
+ const result = (onMsg) => {
11
+ const { send, disconnect } = base((fromProvider) => {
12
+ const parsed = JSON.parse(fromProvider);
13
+ if ("id" in parsed) {
14
+ const { id, result: result2 } = parsed;
15
+ if (preOpId.has(id)) {
16
+ preOpId.delete(id);
17
+ if (prematureStops.has(result2)) {
18
+ prematureStops.delete(result2);
19
+ return;
20
+ }
21
+ onGoing.add(result2);
22
+ const currentSize = onGoing.size + preOpId.size;
23
+ if (currentSize > 2)
24
+ console.warn(
25
+ `Too many chainHead follow subscriptions (${currentSize})`
26
+ );
27
+ else if (parsed.error) {
28
+ console.warn(`chainHead follow failed on the ${currentSize} sub`);
29
+ Promise.resolve().then(forceDisconnect);
30
+ return;
31
+ }
32
+ }
33
+ } else {
34
+ const { subscription, result: result2 } = parsed.params;
35
+ if (result2?.event === "stop") {
36
+ if (onGoing.has(subscription)) onGoing.delete(subscription);
37
+ else prematureStops.add(subscription);
38
+ }
39
+ }
40
+ onMsg(fromProvider);
41
+ });
42
+ return {
43
+ send(toProvider) {
44
+ const parsed = JSON.parse(toProvider);
45
+ const method = methods[parsed.method];
46
+ if (method === "follow") {
47
+ preOpId.add(parsed.id);
48
+ } else if (method === "unfollow") {
49
+ onGoing.delete(parsed.params[0]);
50
+ }
51
+ send(toProvider);
52
+ },
53
+ disconnect
54
+ };
55
+ };
56
+ return Object.assign(result, {
57
+ cleanup: () => {
58
+ prematureStops.clear();
59
+ preOpId.clear();
60
+ onGoing.clear();
61
+ }
62
+ });
63
+ };
64
+
65
+ export { followEnhancer };
66
+ //# sourceMappingURL=follow-enhancer.mjs.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"follow-enhancer.mjs","sources":["../../../src/follow-enhancer.ts"],"sourcesContent":["import { JsonRpcProvider } from \"@polkadot-api/json-rpc-provider\"\n\nconst methods: Record<string, \"follow\" | \"unfollow\"> = {}\n;[\"v1\", \"unstable\"].forEach((version) => {\n methods[`chainHead_${version}_follow`] = \"follow\"\n methods[`chainHead_${version}_unfollow`] = \"unfollow\"\n})\n\nexport const followEnhancer: (\n input: JsonRpcProvider,\n forceDisconnect: () => void,\n) => JsonRpcProvider & {\n cleanup: () => void\n} = (base, forceDisconnect) => {\n const prematureStops = new Set<string>()\n const preOpId = new Set<string>()\n const onGoing = new Set<string>()\n\n const result: JsonRpcProvider = (onMsg) => {\n const { send, disconnect } = base((fromProvider) => {\n const parsed = JSON.parse(fromProvider)\n // it's a response\n if (\"id\" in parsed) {\n const { id, result } = parsed\n if (preOpId.has(id)) {\n preOpId.delete(id)\n if (prematureStops.has(result)) {\n prematureStops.delete(result)\n return\n }\n\n onGoing.add(result)\n const currentSize = onGoing.size + preOpId.size\n if (currentSize > 2)\n console.warn(\n `Too many chainHead follow subscriptions (${currentSize})`,\n )\n else if (parsed.error) {\n console.warn(`chainHead follow failed on the ${currentSize} sub`)\n Promise.resolve().then(forceDisconnect)\n return\n }\n }\n } else {\n // it's a notifiaction\n const { subscription, result } = (parsed as any).params\n if (result?.event === \"stop\") {\n if (onGoing.has(subscription)) onGoing.delete(subscription)\n else prematureStops.add(subscription)\n }\n }\n onMsg(fromProvider)\n })\n\n return {\n send(toProvider) {\n const parsed = JSON.parse(toProvider)\n const method = methods[parsed.method]\n if (method === \"follow\") {\n preOpId.add(parsed.id)\n } else if (method === \"unfollow\") {\n onGoing.delete(parsed.params[0])\n }\n send(toProvider)\n },\n disconnect,\n }\n }\n\n return Object.assign(result, {\n cleanup: () => {\n prematureStops.clear()\n preOpId.clear()\n onGoing.clear()\n },\n })\n}\n"],"names":["result"],"mappings":"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"}
@@ -1,5 +1,6 @@
1
1
  import { getSyncProvider } from '@polkadot-api/json-rpc-provider-proxy';
2
2
  import { WsEvent } from './types.mjs';
3
+ import { followEnhancer } from './follow-enhancer.mjs';
3
4
 
4
5
  const timeoutError = {
5
6
  type: WsEvent.ERROR,
@@ -33,109 +34,117 @@ const getInternalWsProvider = (WebsocketClass) => {
33
34
  let status;
34
35
  let switchTo = null;
35
36
  let disconnect = noop;
36
- const result = getSyncProvider(async () => {
37
- const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
38
- switchTo = null;
39
- const socket = new WebsocketClass(uri, protocols);
40
- const forceSocketClose = () => {
41
- try {
42
- socket.addEventListener("error", noop, { once: true });
43
- socket.close();
44
- } catch {
45
- }
46
- };
47
- onStatusChanged(
48
- status = {
49
- type: WsEvent.CONNECTING,
50
- uri,
51
- protocols
52
- }
53
- );
54
- await new Promise((resolve, reject) => {
55
- const onOpen = () => {
56
- initialCleanup();
57
- resolve();
37
+ let outerCleanup = noop;
38
+ const result = followEnhancer(
39
+ getSyncProvider(async () => {
40
+ const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
41
+ switchTo = null;
42
+ const socket = new WebsocketClass(uri, protocols);
43
+ const forceSocketClose = () => {
44
+ try {
45
+ socket.addEventListener("error", noop, { once: true });
46
+ socket.close();
47
+ } catch {
48
+ }
58
49
  };
59
- const onError = (e) => {
60
- initialCleanup();
61
- if (e == null) forceSocketClose();
62
- console.error(
63
- `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
64
- );
65
- onStatusChanged(
66
- status = {
67
- type: e ? WsEvent.ERROR : WsEvent.CLOSE,
68
- event: e
69
- }
70
- );
71
- setTimeout(reject, e ? 300 : 0, e);
50
+ onStatusChanged(
51
+ status = {
52
+ type: WsEvent.CONNECTING,
53
+ uri,
54
+ protocols
55
+ }
56
+ );
57
+ await new Promise((resolve, reject) => {
58
+ const onOpen = () => {
59
+ initialCleanup();
60
+ resolve();
61
+ };
62
+ const onError = (e) => {
63
+ initialCleanup();
64
+ if (e == null) forceSocketClose();
65
+ console.error(
66
+ `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
67
+ );
68
+ onStatusChanged(
69
+ status = {
70
+ type: e ? WsEvent.ERROR : WsEvent.CLOSE,
71
+ event: e
72
+ }
73
+ );
74
+ setTimeout(reject, e ? 300 : 0, e);
75
+ };
76
+ const timeoutToken = timeout !== Infinity ? setTimeout(() => {
77
+ initialCleanup();
78
+ forceSocketClose();
79
+ onStatusChanged(status = timeoutError);
80
+ reject(timeoutError.event);
81
+ }, timeout) : void 0;
82
+ const initialCleanup = () => {
83
+ clearTimeout(timeoutToken);
84
+ socket.removeEventListener("error", onError);
85
+ socket.removeEventListener("open", onOpen);
86
+ };
87
+ socket.addEventListener("open", onOpen);
88
+ socket.addEventListener("error", onError);
89
+ disconnect = () => {
90
+ onError(null);
91
+ };
92
+ });
93
+ onStatusChanged(
94
+ status = {
95
+ type: WsEvent.CONNECTED,
96
+ uri,
97
+ protocols
98
+ }
99
+ );
100
+ return (onMessage, onHalt) => {
101
+ const _onMessage = (e) => {
102
+ if (typeof e.data === "string") onMessage(e.data);
103
+ };
104
+ const innerHalt = (reason) => (e) => {
105
+ console.warn(`WS halt (${reason})`);
106
+ onStatusChanged(
107
+ status = {
108
+ type: reason,
109
+ event: e
110
+ }
111
+ );
112
+ onHalt();
113
+ };
114
+ const onError = innerHalt(WsEvent.ERROR);
115
+ const onClose = innerHalt(WsEvent.CLOSE);
116
+ socket.addEventListener("message", _onMessage);
117
+ socket.addEventListener("error", onError);
118
+ socket.addEventListener("close", onClose);
119
+ disconnect = (withHalt) => {
120
+ outerCleanup();
121
+ disconnect = noop;
122
+ socket.removeEventListener("message", _onMessage);
123
+ socket.removeEventListener("error", onError);
124
+ socket.removeEventListener("close", onClose);
125
+ forceSocketClose();
126
+ if (withHalt) onClose({});
127
+ };
128
+ return {
129
+ send: (msg) => {
130
+ socket.send(msg);
131
+ },
132
+ disconnect
133
+ };
72
134
  };
73
- const timeoutToken = timeout !== Infinity ? setTimeout(() => {
74
- initialCleanup();
75
- forceSocketClose();
76
- onStatusChanged(status = timeoutError);
77
- reject(timeoutError.event);
78
- }, timeout) : void 0;
79
- const initialCleanup = () => {
80
- clearTimeout(timeoutToken);
81
- socket.removeEventListener("error", onError);
82
- socket.removeEventListener("open", onOpen);
83
- };
84
- socket.addEventListener("open", onOpen);
85
- socket.addEventListener("error", onError);
86
- disconnect = () => {
87
- onError(null);
88
- };
89
- });
90
- onStatusChanged(
91
- status = {
92
- type: WsEvent.CONNECTED,
93
- uri,
94
- protocols
95
- }
96
- );
97
- return (onMessage, onHalt) => {
98
- const _onMessage = (e) => {
99
- if (typeof e.data === "string") onMessage(e.data);
100
- };
101
- const innerHalt = (reason) => (e) => {
102
- console.warn(`WS halt (${reason})`);
103
- onStatusChanged(
104
- status = {
105
- type: reason,
106
- event: e
107
- }
108
- );
109
- onHalt();
110
- };
111
- const onError = innerHalt(WsEvent.ERROR);
112
- const onClose = innerHalt(WsEvent.CLOSE);
113
- socket.addEventListener("message", _onMessage);
114
- socket.addEventListener("error", onError);
115
- socket.addEventListener("close", onClose);
116
- disconnect = (withHalt) => {
117
- disconnect = noop;
118
- socket.removeEventListener("message", _onMessage);
119
- socket.removeEventListener("error", onError);
120
- socket.removeEventListener("close", onClose);
121
- forceSocketClose();
122
- if (withHalt) onClose({});
123
- };
124
- return {
125
- send: (msg) => {
126
- socket.send(msg);
127
- },
128
- disconnect
129
- };
130
- };
131
- });
132
- result.getStatus = () => status;
133
- result.switch = (...args2) => {
135
+ }),
136
+ () => {
137
+ switchFn();
138
+ }
139
+ );
140
+ outerCleanup = result.cleanup;
141
+ delete result.cleanup;
142
+ const switchFn = (...args2) => {
134
143
  if (status.type === WsEvent.CLOSE) return;
135
144
  if (args2.length) switchTo = args2;
136
145
  if (status.type !== WsEvent.ERROR) disconnect(true);
137
146
  };
138
- return result;
147
+ return Object.assign(result, { switch: switchFn, getStatus: () => status });
139
148
  };
140
149
  };
141
150
 
@@ -1 +1 @@
1
- {"version":3,"file":"ws-provider.mjs","sources":["../../../src/ws-provider.ts"],"sourcesContent":["import { getSyncProvider } from \"@polkadot-api/json-rpc-provider-proxy\"\nimport {\n GetWsProviderInput,\n StatusChange,\n WsJsonRpcProvider,\n WsEvent,\n WsProviderConfig,\n} from \"./types\"\n\nconst timeoutError: StatusChange = {\n type: WsEvent.ERROR,\n event: { type: \"timeout\" },\n}\n\nconst noop = () => {}\n\nconst mapEndpoints = (\n endpoints: WsProviderConfig[\"endpoints\"],\n): Array<[string, string | string[]] | [string]> =>\n endpoints.map((x) => (typeof x === \"string\" ? [x] : [x.uri, x.protocol]))\n\nexport const getInternalWsProvider = (\n WebsocketClass: typeof WebSocket,\n): GetWsProviderInput => {\n return (...args): WsJsonRpcProvider => {\n let endpoints: Array<[string, string | string[]] | [string]> = []\n let onStatusChanged: (status: StatusChange) => void = noop\n let timeout = 3_500\n\n const [firstArg] = args\n if (\n args.length === 1 &&\n typeof firstArg === \"object\" &&\n !Array.isArray(firstArg)\n ) {\n endpoints = mapEndpoints(firstArg.endpoints)\n onStatusChanged = firstArg.onStatusChanged ?? noop\n timeout = firstArg.timeout ?? timeout\n } else {\n if (typeof args[1] === \"function\")\n onStatusChanged = args[1] as (status: StatusChange) => void\n if (Array.isArray(firstArg)) endpoints = mapEndpoints(firstArg)\n else {\n endpoints = [[firstArg as string]]\n if (args[1] && args[1] !== onStatusChanged)\n endpoints[0][1] = args[1] as any\n if (args[2]) onStatusChanged = args[2] as any\n }\n }\n\n let idx = 0\n let status: StatusChange\n let switchTo: [string] | [string, string | string[]] | null = null\n let disconnect: (withHalt?: boolean) => void = noop\n\n const result = getSyncProvider(async () => {\n const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length]\n switchTo = null\n const socket = new WebsocketClass(uri, protocols)\n const forceSocketClose = () => {\n try {\n socket.addEventListener(\"error\", noop, { once: true })\n socket.close()\n } catch {}\n }\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTING,\n uri,\n protocols,\n }),\n )\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n initialCleanup()\n resolve()\n }\n\n const onError = (e: Event | null) => {\n initialCleanup()\n if (e == null) forceSocketClose()\n console.error(\n `Unable to connect to ${uri}${\n protocols ? \", protocols: \" + protocols : \"\"\n }`,\n )\n onStatusChanged(\n (status = {\n type: e ? WsEvent.ERROR : WsEvent.CLOSE,\n event: e,\n }),\n )\n setTimeout(reject, e ? 300 : 0, e)\n }\n\n const timeoutToken =\n timeout !== Infinity\n ? setTimeout(() => {\n initialCleanup()\n forceSocketClose()\n onStatusChanged((status = timeoutError))\n reject(timeoutError.event)\n }, timeout)\n : undefined\n\n const initialCleanup = () => {\n clearTimeout(timeoutToken)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"open\", onOpen)\n }\n socket.addEventListener(\"open\", onOpen)\n socket.addEventListener(\"error\", onError)\n disconnect = () => {\n onError(null)\n }\n })\n\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTED,\n uri,\n protocols,\n }),\n )\n\n return (onMessage, onHalt) => {\n const _onMessage = (e: MessageEvent) => {\n if (typeof e.data === \"string\") onMessage(e.data)\n }\n const innerHalt =\n (reason: WsEvent.CLOSE | WsEvent.ERROR) => (e: any) => {\n console.warn(`WS halt (${reason})`)\n onStatusChanged(\n (status = {\n type: reason,\n event: e,\n }),\n )\n onHalt()\n }\n const onError = innerHalt(WsEvent.ERROR)\n const onClose = innerHalt(WsEvent.CLOSE)\n\n socket.addEventListener(\"message\", _onMessage)\n socket.addEventListener(\"error\", onError)\n socket.addEventListener(\"close\", onClose)\n disconnect = (withHalt) => {\n disconnect = noop\n socket.removeEventListener(\"message\", _onMessage)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"close\", onClose)\n forceSocketClose()\n if (withHalt) onClose({})\n }\n\n return {\n send: (msg) => {\n socket.send(msg)\n },\n disconnect,\n }\n }\n }) as WsJsonRpcProvider\n\n result.getStatus = () => status\n result.switch = (...args) => {\n if (status.type === WsEvent.CLOSE) return\n if (args.length) switchTo = args as any\n if (status.type !== WsEvent.ERROR) disconnect(true)\n }\n return result\n }\n}\n"],"names":["args"],"mappings":"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"}
1
+ {"version":3,"file":"ws-provider.mjs","sources":["../../../src/ws-provider.ts"],"sourcesContent":["import { getSyncProvider } from \"@polkadot-api/json-rpc-provider-proxy\"\nimport {\n GetWsProviderInput,\n StatusChange,\n WsJsonRpcProvider,\n WsEvent,\n WsProviderConfig,\n} from \"./types\"\nimport { followEnhancer } from \"./follow-enhancer\"\n\nconst timeoutError: StatusChange = {\n type: WsEvent.ERROR,\n event: { type: \"timeout\" },\n}\n\nconst noop = () => {}\n\nconst mapEndpoints = (\n endpoints: WsProviderConfig[\"endpoints\"],\n): Array<[string, string | string[]] | [string]> =>\n endpoints.map((x) => (typeof x === \"string\" ? [x] : [x.uri, x.protocol]))\n\nexport const getInternalWsProvider = (\n WebsocketClass: typeof WebSocket,\n): GetWsProviderInput => {\n return (...args): WsJsonRpcProvider => {\n let endpoints: Array<[string, string | string[]] | [string]> = []\n let onStatusChanged: (status: StatusChange) => void = noop\n let timeout = 3_500\n\n const [firstArg] = args\n if (\n args.length === 1 &&\n typeof firstArg === \"object\" &&\n !Array.isArray(firstArg)\n ) {\n endpoints = mapEndpoints(firstArg.endpoints)\n onStatusChanged = firstArg.onStatusChanged ?? noop\n timeout = firstArg.timeout ?? timeout\n } else {\n if (typeof args[1] === \"function\")\n onStatusChanged = args[1] as (status: StatusChange) => void\n if (Array.isArray(firstArg)) endpoints = mapEndpoints(firstArg)\n else {\n endpoints = [[firstArg as string]]\n if (args[1] && args[1] !== onStatusChanged)\n endpoints[0][1] = args[1] as any\n if (args[2]) onStatusChanged = args[2] as any\n }\n }\n\n let idx = 0\n let status: StatusChange\n let switchTo: [string] | [string, string | string[]] | null = null\n let disconnect: (withHalt?: boolean) => void = noop\n\n let outerCleanup: () => void = noop\n const result = followEnhancer(\n getSyncProvider(async () => {\n const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length]\n switchTo = null\n const socket = new WebsocketClass(uri, protocols)\n const forceSocketClose = () => {\n try {\n socket.addEventListener(\"error\", noop, { once: true })\n socket.close()\n } catch {}\n }\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTING,\n uri,\n protocols,\n }),\n )\n\n await new Promise<void>((resolve, reject) => {\n const onOpen = () => {\n initialCleanup()\n resolve()\n }\n\n const onError = (e: Event | null) => {\n initialCleanup()\n if (e == null) forceSocketClose()\n console.error(\n `Unable to connect to ${uri}${\n protocols ? \", protocols: \" + protocols : \"\"\n }`,\n )\n onStatusChanged(\n (status = {\n type: e ? WsEvent.ERROR : WsEvent.CLOSE,\n event: e,\n }),\n )\n setTimeout(reject, e ? 300 : 0, e)\n }\n\n const timeoutToken =\n timeout !== Infinity\n ? setTimeout(() => {\n initialCleanup()\n forceSocketClose()\n onStatusChanged((status = timeoutError))\n reject(timeoutError.event)\n }, timeout)\n : undefined\n\n const initialCleanup = () => {\n clearTimeout(timeoutToken)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"open\", onOpen)\n }\n socket.addEventListener(\"open\", onOpen)\n socket.addEventListener(\"error\", onError)\n disconnect = () => {\n onError(null)\n }\n })\n\n onStatusChanged(\n (status = {\n type: WsEvent.CONNECTED,\n uri,\n protocols,\n }),\n )\n\n return (onMessage, onHalt) => {\n const _onMessage = (e: MessageEvent) => {\n if (typeof e.data === \"string\") onMessage(e.data)\n }\n const innerHalt =\n (reason: WsEvent.CLOSE | WsEvent.ERROR) => (e: any) => {\n console.warn(`WS halt (${reason})`)\n onStatusChanged(\n (status = {\n type: reason,\n event: e,\n }),\n )\n onHalt()\n }\n const onError = innerHalt(WsEvent.ERROR)\n const onClose = innerHalt(WsEvent.CLOSE)\n\n socket.addEventListener(\"message\", _onMessage)\n socket.addEventListener(\"error\", onError)\n socket.addEventListener(\"close\", onClose)\n disconnect = (withHalt) => {\n outerCleanup()\n disconnect = noop\n socket.removeEventListener(\"message\", _onMessage)\n socket.removeEventListener(\"error\", onError)\n socket.removeEventListener(\"close\", onClose)\n forceSocketClose()\n if (withHalt) onClose({})\n }\n\n return {\n send: (msg) => {\n socket.send(msg)\n },\n disconnect,\n }\n }\n }),\n () => {\n switchFn()\n },\n )\n outerCleanup = result.cleanup\n delete (result as any).cleanup\n\n const switchFn: WsJsonRpcProvider[\"switch\"] = (...args) => {\n if (status.type === WsEvent.CLOSE) return\n if (args.length) switchTo = args as any\n if (status.type !== WsEvent.ERROR) disconnect(true)\n }\n\n return Object.assign(result, { switch: switchFn, getStatus: () => status })\n }\n}\n"],"names":["args"],"mappings":"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"}
package/dist/node/node.js CHANGED
@@ -11,6 +11,70 @@ var WsEvent = /* @__PURE__ */ ((WsEvent2) => {
11
11
  return WsEvent2;
12
12
  })(WsEvent || {});
13
13
 
14
+ const methods = {};
15
+ ["v1", "unstable"].forEach((version) => {
16
+ methods[`chainHead_${version}_follow`] = "follow";
17
+ methods[`chainHead_${version}_unfollow`] = "unfollow";
18
+ });
19
+ const followEnhancer = (base, forceDisconnect) => {
20
+ const prematureStops = /* @__PURE__ */ new Set();
21
+ const preOpId = /* @__PURE__ */ new Set();
22
+ const onGoing = /* @__PURE__ */ new Set();
23
+ const result = (onMsg) => {
24
+ const { send, disconnect } = base((fromProvider) => {
25
+ const parsed = JSON.parse(fromProvider);
26
+ if ("id" in parsed) {
27
+ const { id, result: result2 } = parsed;
28
+ if (preOpId.has(id)) {
29
+ preOpId.delete(id);
30
+ if (prematureStops.has(result2)) {
31
+ prematureStops.delete(result2);
32
+ return;
33
+ }
34
+ onGoing.add(result2);
35
+ const currentSize = onGoing.size + preOpId.size;
36
+ if (currentSize > 2)
37
+ console.warn(
38
+ `Too many chainHead follow subscriptions (${currentSize})`
39
+ );
40
+ else if (parsed.error) {
41
+ console.warn(`chainHead follow failed on the ${currentSize} sub`);
42
+ Promise.resolve().then(forceDisconnect);
43
+ return;
44
+ }
45
+ }
46
+ } else {
47
+ const { subscription, result: result2 } = parsed.params;
48
+ if (result2?.event === "stop") {
49
+ if (onGoing.has(subscription)) onGoing.delete(subscription);
50
+ else prematureStops.add(subscription);
51
+ }
52
+ }
53
+ onMsg(fromProvider);
54
+ });
55
+ return {
56
+ send(toProvider) {
57
+ const parsed = JSON.parse(toProvider);
58
+ const method = methods[parsed.method];
59
+ if (method === "follow") {
60
+ preOpId.add(parsed.id);
61
+ } else if (method === "unfollow") {
62
+ onGoing.delete(parsed.params[0]);
63
+ }
64
+ send(toProvider);
65
+ },
66
+ disconnect
67
+ };
68
+ };
69
+ return Object.assign(result, {
70
+ cleanup: () => {
71
+ prematureStops.clear();
72
+ preOpId.clear();
73
+ onGoing.clear();
74
+ }
75
+ });
76
+ };
77
+
14
78
  const timeoutError = {
15
79
  type: WsEvent.ERROR,
16
80
  event: { type: "timeout" }
@@ -43,109 +107,117 @@ const getInternalWsProvider = (WebsocketClass) => {
43
107
  let status;
44
108
  let switchTo = null;
45
109
  let disconnect = noop;
46
- const result = jsonRpcProviderProxy.getSyncProvider(async () => {
47
- const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
48
- switchTo = null;
49
- const socket = new WebsocketClass(uri, protocols);
50
- const forceSocketClose = () => {
51
- try {
52
- socket.addEventListener("error", noop, { once: true });
53
- socket.close();
54
- } catch {
55
- }
56
- };
57
- onStatusChanged(
58
- status = {
59
- type: WsEvent.CONNECTING,
60
- uri,
61
- protocols
62
- }
63
- );
64
- await new Promise((resolve, reject) => {
65
- const onOpen = () => {
66
- initialCleanup();
67
- resolve();
68
- };
69
- const onError = (e) => {
70
- initialCleanup();
71
- if (e == null) forceSocketClose();
72
- console.error(
73
- `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
74
- );
75
- onStatusChanged(
76
- status = {
77
- type: e ? WsEvent.ERROR : WsEvent.CLOSE,
78
- event: e
79
- }
80
- );
81
- setTimeout(reject, e ? 300 : 0, e);
82
- };
83
- const timeoutToken = timeout !== Infinity ? setTimeout(() => {
84
- initialCleanup();
85
- forceSocketClose();
86
- onStatusChanged(status = timeoutError);
87
- reject(timeoutError.event);
88
- }, timeout) : void 0;
89
- const initialCleanup = () => {
90
- clearTimeout(timeoutToken);
91
- socket.removeEventListener("error", onError);
92
- socket.removeEventListener("open", onOpen);
93
- };
94
- socket.addEventListener("open", onOpen);
95
- socket.addEventListener("error", onError);
96
- disconnect = () => {
97
- onError(null);
98
- };
99
- });
100
- onStatusChanged(
101
- status = {
102
- type: WsEvent.CONNECTED,
103
- uri,
104
- protocols
105
- }
106
- );
107
- return (onMessage, onHalt) => {
108
- const _onMessage = (e) => {
109
- if (typeof e.data === "string") onMessage(e.data);
110
- };
111
- const innerHalt = (reason) => (e) => {
112
- console.warn(`WS halt (${reason})`);
113
- onStatusChanged(
114
- status = {
115
- type: reason,
116
- event: e
117
- }
118
- );
119
- onHalt();
120
- };
121
- const onError = innerHalt(WsEvent.ERROR);
122
- const onClose = innerHalt(WsEvent.CLOSE);
123
- socket.addEventListener("message", _onMessage);
124
- socket.addEventListener("error", onError);
125
- socket.addEventListener("close", onClose);
126
- disconnect = (withHalt) => {
127
- disconnect = noop;
128
- socket.removeEventListener("message", _onMessage);
129
- socket.removeEventListener("error", onError);
130
- socket.removeEventListener("close", onClose);
131
- forceSocketClose();
132
- if (withHalt) onClose({});
110
+ let outerCleanup = noop;
111
+ const result = followEnhancer(
112
+ jsonRpcProviderProxy.getSyncProvider(async () => {
113
+ const [uri, protocols] = switchTo || endpoints[idx++ % endpoints.length];
114
+ switchTo = null;
115
+ const socket = new WebsocketClass(uri, protocols);
116
+ const forceSocketClose = () => {
117
+ try {
118
+ socket.addEventListener("error", noop, { once: true });
119
+ socket.close();
120
+ } catch {
121
+ }
133
122
  };
134
- return {
135
- send: (msg) => {
136
- socket.send(msg);
137
- },
138
- disconnect
123
+ onStatusChanged(
124
+ status = {
125
+ type: WsEvent.CONNECTING,
126
+ uri,
127
+ protocols
128
+ }
129
+ );
130
+ await new Promise((resolve, reject) => {
131
+ const onOpen = () => {
132
+ initialCleanup();
133
+ resolve();
134
+ };
135
+ const onError = (e) => {
136
+ initialCleanup();
137
+ if (e == null) forceSocketClose();
138
+ console.error(
139
+ `Unable to connect to ${uri}${protocols ? ", protocols: " + protocols : ""}`
140
+ );
141
+ onStatusChanged(
142
+ status = {
143
+ type: e ? WsEvent.ERROR : WsEvent.CLOSE,
144
+ event: e
145
+ }
146
+ );
147
+ setTimeout(reject, e ? 300 : 0, e);
148
+ };
149
+ const timeoutToken = timeout !== Infinity ? setTimeout(() => {
150
+ initialCleanup();
151
+ forceSocketClose();
152
+ onStatusChanged(status = timeoutError);
153
+ reject(timeoutError.event);
154
+ }, timeout) : void 0;
155
+ const initialCleanup = () => {
156
+ clearTimeout(timeoutToken);
157
+ socket.removeEventListener("error", onError);
158
+ socket.removeEventListener("open", onOpen);
159
+ };
160
+ socket.addEventListener("open", onOpen);
161
+ socket.addEventListener("error", onError);
162
+ disconnect = () => {
163
+ onError(null);
164
+ };
165
+ });
166
+ onStatusChanged(
167
+ status = {
168
+ type: WsEvent.CONNECTED,
169
+ uri,
170
+ protocols
171
+ }
172
+ );
173
+ return (onMessage, onHalt) => {
174
+ const _onMessage = (e) => {
175
+ if (typeof e.data === "string") onMessage(e.data);
176
+ };
177
+ const innerHalt = (reason) => (e) => {
178
+ console.warn(`WS halt (${reason})`);
179
+ onStatusChanged(
180
+ status = {
181
+ type: reason,
182
+ event: e
183
+ }
184
+ );
185
+ onHalt();
186
+ };
187
+ const onError = innerHalt(WsEvent.ERROR);
188
+ const onClose = innerHalt(WsEvent.CLOSE);
189
+ socket.addEventListener("message", _onMessage);
190
+ socket.addEventListener("error", onError);
191
+ socket.addEventListener("close", onClose);
192
+ disconnect = (withHalt) => {
193
+ outerCleanup();
194
+ disconnect = noop;
195
+ socket.removeEventListener("message", _onMessage);
196
+ socket.removeEventListener("error", onError);
197
+ socket.removeEventListener("close", onClose);
198
+ forceSocketClose();
199
+ if (withHalt) onClose({});
200
+ };
201
+ return {
202
+ send: (msg) => {
203
+ socket.send(msg);
204
+ },
205
+ disconnect
206
+ };
139
207
  };
140
- };
141
- });
142
- result.getStatus = () => status;
143
- result.switch = (...args2) => {
208
+ }),
209
+ () => {
210
+ switchFn();
211
+ }
212
+ );
213
+ outerCleanup = result.cleanup;
214
+ delete result.cleanup;
215
+ const switchFn = (...args2) => {
144
216
  if (status.type === WsEvent.CLOSE) return;
145
217
  if (args2.length) switchTo = args2;
146
218
  if (status.type !== WsEvent.ERROR) disconnect(true);
147
219
  };
148
- return result;
220
+ return Object.assign(result, { switch: switchFn, getStatus: () => status });
149
221
  };
150
222
  };
151
223