uniswap-v2-loader 5.0.18 → 5.0.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.
@@ -35,7 +35,7 @@ jobs:
35
35
 
36
36
  run: npm i -g .
37
37
 
38
- - name: CLI Load first 4 pairs from Uniswap V2 using 2 workers
38
+ - name: Test CLI load first 4 pairs from Uniswap V2 using 2 workers
39
39
  run: uniswap-v2-loader --to=4 --multicall_size=2 --workers=2
40
40
 
41
41
  - name: Run ESM tests
package/README.md CHANGED
@@ -41,6 +41,7 @@ High-performance parallel fetcher for liquidity pairs. Efficiently synchronizes
41
41
  | `multicall_size` | `number` | RPC batch size per multicall request. | `50` |
42
42
  | `workers` | `number` | Number of parallel worker threads. | `CPU - 1` |
43
43
  | `progress` | `function` | Progress callback: `(current, total) => {}`. | `undefined` |
44
+ | `abort_signal` | `AbortSignal` | Signal to cancel loading and release workers. | `undefined` |
44
45
 
45
46
  **Returns**: `Promise<Pair[]>`
46
47
 
package/index.d.ts CHANGED
@@ -36,6 +36,8 @@ export interface load_params {
36
36
  pairs?: pair[]
37
37
  /** Timeout between updates in milliseconds. */
38
38
  update_timeout?: number
39
+ /** Signal to abort the loading process. */
40
+ abort_signal?: AbortSignal
39
41
  }
40
42
 
41
43
  /**
package/index.js CHANGED
@@ -16,9 +16,11 @@ const load = (params = {}) => {
16
16
  from = 0,
17
17
  to,
18
18
  progress,
19
+ abort_signal,
19
20
  workers = max_workers,
20
21
  pairs,
21
22
  } = params
23
+
22
24
  filename ??= default_cache_filename(factory)
23
25
  workers = Math.min(workers, max_workers)
24
26
 
@@ -44,10 +46,11 @@ const load = (params = {}) => {
44
46
 
45
47
  return Promise.resolve(pairs.slice(0, to))
46
48
  }
47
-
49
+
48
50
  return (to
49
51
  ? Promise.resolve(to)
50
52
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
53
+ signal: abort_signal,
51
54
  method: 'POST',
52
55
  headers: { 'Content-Type': 'application/json' },
53
56
  body: JSON.stringify({
@@ -92,18 +95,14 @@ const load = (params = {}) => {
92
95
  const ids = []
93
96
  for (var i = start_loading_from; i < all_pairs_length; i++)
94
97
  ids.push(i)
95
- return require('./loader')({ ids, factory, key, multicall_size }, onpair)
98
+ return require('./loader')({ ids, factory, key, multicall_size, abort_signal }, onpair)
96
99
  .then(() => pairs)
97
100
  }
98
101
 
99
- const missed = []
100
- for (var i = start_loading_from, ids; i < all_pairs_length; i++) {
101
- if (!ids || ids.length % multicall_size == 0) {
102
- ids = []
103
- missed.push(ids)
104
- }
105
- ids.push(i)
106
- }
102
+ const missed = Array(workers).fill(null).map(() => [])
103
+
104
+ for (var i = start_loading_from, iw = 0; i < all_pairs_length; i++)
105
+ missed[iw++ % workers].push(i)
107
106
 
108
107
  cluster.setupPrimary({ exec: path.join(__dirname, 'loader.js') })
109
108
 
@@ -111,14 +110,20 @@ const load = (params = {}) => {
111
110
  missed
112
111
  .filter(_ => _.length)
113
112
  .map((ids, i) => new Promise(y => {
113
+ if (abort_signal?.aborted) return y()
114
114
  const w = cluster.fork()
115
+ const onabort = () => w.send('abort')
116
+ abort_signal?.addEventListener('abort', onabort, { once: true })
115
117
  w.send({ ids, factory, key, multicall_size })
116
118
  w.on('message', onpair)
117
- w.on('exit', y)
119
+ w.on('exit', () => {
120
+ abort_signal?.removeEventListener('abort', onabort)
121
+ y()
122
+ })
118
123
  }))
119
124
  ).then(() => pairs)
120
125
  })
121
- .catch(() => new Promise(resolve => setTimeout(() => resolve(load(params)), 1000)))
126
+ .catch(() => abort_signal?.aborted ? pairs : new Promise(resolve => setTimeout(() => resolve(load(params)), 1000)))
122
127
  }
123
128
 
124
129
  module.exports.load = (params = {}) =>
package/loader.js CHANGED
@@ -1,6 +1,7 @@
1
- const get_pairs_addresses = (key, factory, ids) => ids.length == 0
1
+ const get_pairs_addresses = (key, factory, ids, abort_signal) => ids.length == 0
2
2
  ? Promise.resolve([])
3
3
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
4
+ signal: abort_signal,
4
5
  method: 'POST',
5
6
  headers: { 'Content-Type': 'application/json' },
6
7
  body: JSON.stringify(ids.map((id, i) => ({
@@ -30,14 +31,15 @@ const get_pairs_addresses = (key, factory, ids) => ids.length == 0
30
31
  return failed_ids.length == 0
31
32
  ? addresses
32
33
  : new Promise(resolve => setTimeout(() => resolve(
33
- get_pairs_addresses(key, factory, failed_ids).then(retried => [...addresses, ...retried])
34
+ get_pairs_addresses(key, factory, failed_ids, abort_signal).then(retried => [...addresses, ...retried])
34
35
  ), 10000))
35
36
  })
36
- .catch(() => new Promise(resolve => setTimeout(() => resolve(get_pairs_addresses(key, factory, ids)), 10000)))
37
+ .catch(() => abort_signal?.aborted ? [] : new Promise(resolve => setTimeout(() => resolve(get_pairs_addresses(key, factory, ids, abort_signal)), 10000)))
37
38
 
38
- const get_tokens = (key, addresses) => addresses.length == 0
39
+ const get_tokens = (key, addresses, abort_signal) => addresses.length == 0
39
40
  ? Promise.resolve({})
40
41
  : fetch('https://eth-mainnet.g.alchemy.com/v2/' + key, {
42
+ signal: abort_signal,
41
43
  method: 'POST',
42
44
  headers: { 'Content-Type': 'application/json' },
43
45
  body: JSON.stringify(addresses.flatMap((address, i) => [
@@ -83,20 +85,20 @@ const get_tokens = (key, addresses) => addresses.length == 0
83
85
  return failed_addresses.length == 0
84
86
  ? tokens
85
87
  : new Promise(resolve => setTimeout(() => resolve(
86
- get_tokens(key, failed_addresses).then(retried => ({ ...tokens, ...retried }))
88
+ get_tokens(key, failed_addresses, abort_signal).then(retried => ({ ...tokens, ...retried }))
87
89
  ), 10000))
88
90
  })
89
- .catch(() => new Promise(resolve => setTimeout(() => resolve(get_tokens(key, addresses)), 10000)))
91
+ .catch(() => abort_signal?.aborted ? {} : new Promise(resolve => setTimeout(() => resolve(get_tokens(key, addresses, abort_signal)), 10000)))
90
92
 
91
- const main = ({ids, factory, key, multicall_size}, onpair) => {
93
+ const main = ({ids, factory, key, multicall_size, abort_signal}, onpair) => {
92
94
  const chunks = []
93
95
  for (let i = 0; i < ids.length; i += multicall_size)
94
96
  chunks.push(ids.slice(i, i + multicall_size))
95
97
 
96
98
  return chunks.reduce((p, ids, ic) =>
97
99
  p.then(() =>
98
- get_pairs_addresses(key, factory, ids).then(pairs_addresses =>
99
- get_tokens(key, pairs_addresses).then(tokens =>
100
+ get_pairs_addresses(key, factory, ids, abort_signal).then(pairs_addresses =>
101
+ get_tokens(key, pairs_addresses, abort_signal).then(tokens =>
100
102
  ids.forEach((id, i) =>
101
103
  onpair({
102
104
  id,
@@ -113,12 +115,20 @@ const main = ({ids, factory, key, multicall_size}, onpair) => {
113
115
  }
114
116
 
115
117
 
116
- if (require.main != module)
118
+ if (require.main != module) {
117
119
  module.exports = main
118
- else
120
+ } else {
121
+ const abort_controller = new AbortController()
122
+ const abort_signal = abort_controller.signal
123
+
119
124
  process.on(
120
125
  'message',
121
- message =>
122
- main(message, pair => process.send(pair))
123
- .then(() => process.exit())
126
+ message => {
127
+ if (message == 'abort')
128
+ abort_controller.abort()
129
+ else
130
+ main({...message, abort_signal}, pair => process.send(pair))
131
+ .finally(() => process.exit())
132
+ }
124
133
  )
134
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "uniswap-v2-loader",
3
- "version": "5.0.18",
3
+ "version": "5.0.20",
4
4
  "description": "Uniswap v2 protocol loader",
5
5
  "keywords": [
6
6
  "uniswap-v2",
package/test-esm.mjs DELETED
@@ -1,18 +0,0 @@
1
- import { load, subscribe } from './index.mjs'
2
- import assert from 'node:assert/strict'
3
- import { describe, it } from 'node:test'
4
-
5
- describe('ESM Support', () => {
6
- it('should import load and subscribe', () => {
7
- assert.equal(typeof load, 'function')
8
- assert.equal(typeof subscribe, 'function')
9
- })
10
-
11
- it('should load first pair', () =>
12
- load({ to: 1 })
13
- .then(pairs => {
14
- assert.equal(pairs.length, 1)
15
- assert.equal(pairs[0].id, 0)
16
- })
17
- )
18
- })