This repository was archived by the owner on Feb 12, 2024. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 1.2k
/
Copy pathpreload.js
100 lines (83 loc) · 2.52 KB
/
preload.js
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
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
import { multiaddrToUri } from '@multiformats/multiaddr-to-uri'
import { logger } from '@libp2p/logger'
import shuffle from 'array-shuffle'
import { preload } from 'ipfs-core-config/preload'
import hashlru from 'hashlru'
const log = logger('ipfs:preload')
/**
* @param {import('./types').PreloadOptions} [options]
*/
export function createPreloader (options = {}) {
options.enabled = Boolean(options.enabled)
options.addresses = options.addresses || []
options.cache = options.cache || 1000
if (!options.enabled || !options.addresses.length) {
log('preload disabled')
const api = () => {}
return Object.assign(api, {
start: () => {},
stop: () => {}
})
}
let stopped = true
/** @type {AbortController[]} */
let requests = []
const apiUris = options.addresses.map((str) => multiaddrToUri(str))
// Avoid preloading the same CID over and over again
const cache = hashlru(options.cache)
/**
* @type {import('./types').Preload}
*/
const api = async cid => {
try {
if (stopped) {
throw new Error(`preload ${cid} but preloader is not started`)
}
const path = cid.toString()
if (cache.has(path)) {
// we've preloaded this recently, don't preload it again
return
}
// make sure we don't preload this again any time soon
cache.set(path, true)
const fallbackApiUris = shuffle(apiUris)
let success = false
const now = Date.now()
for (const uri of fallbackApiUris) {
if (stopped) throw new Error(`preload aborted for ${path}`)
/** @type {AbortController} */
let controller
try {
controller = new AbortController()
requests = requests.concat(controller)
await preload(`${uri}/api/v0/refs?r=true&arg=${encodeURIComponent(path)}`, { signal: controller.signal })
success = true
} catch (/** @type {any} */ err) {
if (err.type !== 'aborted') log.error(err)
} finally {
requests = requests.filter(r => r !== controller)
}
if (success) break
}
log(`${success ? '' : 'un'}successfully preloaded ${path} in ${Date.now() - now}ms`)
} catch (/** @type {any} */ err) {
log.error(err)
}
}
/**
* @returns {void}
*/
api.start = () => {
stopped = false
}
/**
* @returns {void}
*/
api.stop = () => {
stopped = true
log(`aborting ${requests.length} pending preload request(s)`)
requests.forEach(r => r.abort())
requests = []
}
return api
}