forked from nftstorage/nft.storage-tools
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcluster-status.js
104 lines (93 loc) · 3.03 KB
/
cluster-status.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
101
102
103
104
/**
* Pretty print the pin status of all the CIDs in the passed pinlist file.
*
* Usage:
* node cluster-status.js pinlist.txt
*/
import fs from 'fs'
import ora from 'ora'
import { pipeline } from 'stream/promises'
import dotenv from 'dotenv'
import * as d3 from 'd3-format'
import { Cluster } from '@nftstorage/ipfs-cluster'
import batch from 'it-batch'
import fetch from 'node-fetch'
import split from './lib/split.js'
import { toPSAStatus } from './lib/cluster.js'
global.fetch = fetch
dotenv.config()
const format = d3.format(',')
const CONCURRENCY = 1000
async function main () {
if (!process.env.CLUSTER_URL) {
throw new Error('missing IPFS Cluster URL')
}
const filePath = process.argv[2]
if (!filePath) {
throw new Error('missing path to newline delimited CID list')
}
console.log(`🔌 Using IPFS Cluster URL: ${process.env.CLUSTER_URL}`)
const headers = process.env.CLUSTER_HEADERS ? JSON.parse(process.env.CLUSTER_HEADERS) : {}
const cluster = new Cluster(process.env.CLUSTER_URL, { headers })
const spinner = ora()
const start = Date.now()
const totals = { total: 0, queued: 0, pinning: 0, pinned: 0, failed: 0, unknown: 0, requests: 0, reqsPerSec: 0 }
spinner.start()
try {
await pipeline(
fs.createReadStream(filePath),
split,
cids => batch(cids, CONCURRENCY),
async batchedCids => {
for await (const cids of batchedCids) {
totals.total += cids.length
await Promise.all(cids.map(async cid => {
try {
const status = toPSAStatus(await cluster.status(cid))
totals[status]++
} catch (err) {
if (err.message === 'not found') {
totals.unknown++
} else {
throw err
}
} finally {
totals.total++
totals.requests++
totals.reqsPerSec = totals.requests / ((Date.now() - start) / 1000)
}
spinner.text = toText('Loading...', totals)
}))
}
}
)
} catch (err) {
spinner.stopAndPersist({ text: toText('Errored', totals) })
spinner.fail(`Error: ${err.message}`)
throw err
}
spinner.succeed(toText('Complete!', totals))
}
const percent = (value, total) => ((value / total) * 100).toFixed()
function toText (prefix, totals) {
const items = [`💖 Total: ${format(totals.total)}`]
if (totals.queued) {
items.push(line('👫 Queued', totals.queued, totals.total))
}
if (totals.pinning) {
items.push(line('⏳ Pinning', totals.pinning, totals.total))
}
if (totals.pinned) {
items.push(line('📌 Pinned', totals.pinned, totals.total))
}
if (totals.failed) {
items.push(line('💀 Failed', totals.failed, totals.total))
}
if (totals.unknown) {
items.push(line('❓ Unknown', totals.unknown, totals.total))
}
items.push(`🔁 Requests/sec: ${totals.reqsPerSec.toFixed(1)}`)
return `${prefix}\n${items.join('\n')}`
}
const line = (prefix, value, total) => `${prefix}: ${value} (${percent(value, total)}%)`
main()