cli.js 4.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128
  1. #!/usr/bin/env node
  2. const { RuntimeApi } = require('@joystream/storage-runtime-api')
  3. const { encodeAddress } = require('@polkadot/keyring')
  4. const axios = require('axios')
  5. const stripEndingSlash = require('@joystream/storage-utils/stripEndingSlash')
  6. function makeAssetUrl(contentId, source) {
  7. source = stripEndingSlash(source)
  8. return `${source}/asset/v0/${encodeAddress(contentId)}`
  9. }
  10. // HTTP HEAD with axios all known content ids on given endpoint
  11. async function countContentAvailability(providerId, endpoint, contentIds) {
  12. let found = 0
  13. let errored = 0
  14. let requestsSent = 0
  15. // Avoid opening too many connections, do it in chunks.. otherwise we get
  16. // "Client network socket disconnected before secure TLS connection was established" errors
  17. while (contentIds.length) {
  18. const chunk = contentIds.splice(0, 100)
  19. requestsSent += chunk.length
  20. const results = await Promise.allSettled(chunk.map((id) => axios.head(makeAssetUrl(id, endpoint))))
  21. results.forEach((result, _ix) => {
  22. if (result.status === 'rejected') {
  23. errored++
  24. } else {
  25. found++
  26. }
  27. })
  28. // show some progress
  29. console.error(`provider: ${providerId}:`, `total checks: ${requestsSent}`, `ok: ${found}`, `errors: ${errored}`)
  30. }
  31. return { found, errored }
  32. }
  33. async function testProviderHasAssets(providerId, endpoint, contentIds) {
  34. const total = contentIds.length
  35. const startedAt = Date.now()
  36. const { found, errored } = await countContentAvailability(providerId, endpoint, contentIds)
  37. const completedAt = Date.now()
  38. console.log(`
  39. ---------------------------------------
  40. Final Result for provider ${providerId}
  41. url: ${endpoint}
  42. fetched: ${found}/${total}
  43. failed: ${errored}
  44. check took: ${(completedAt - startedAt) / 1000}s
  45. ------------------------------------------
  46. `)
  47. }
  48. async function main() {
  49. const runtime = await RuntimeApi.create()
  50. const { api } = runtime
  51. // get all providers
  52. const { ids: storageProviders } = await runtime.workers.getAllProviders()
  53. console.log(`Found ${storageProviders.length} staked providers`)
  54. // Resolve Endpoints of providers
  55. console.log('\nResolving live provider API Endpoints...')
  56. const endpoints = await Promise.all(
  57. storageProviders.map(async (providerId) => {
  58. try {
  59. const endpoint = (await runtime.workers.getWorkerStorageValue(providerId)).toString()
  60. return { providerId, endpoint }
  61. } catch (err) {
  62. console.log('resolve failed for id', providerId, err.message)
  63. return { providerId, endpoint: null }
  64. }
  65. })
  66. )
  67. console.log('\nChecking API Endpoints are online')
  68. await Promise.all(
  69. endpoints.map(async (provider) => {
  70. if (!provider.endpoint) {
  71. console.log(provider.providerId, 'No url set, skipping')
  72. return
  73. }
  74. const swaggerUrl = `${stripEndingSlash(provider.endpoint)}/swagger.json`
  75. try {
  76. const { data } = await axios.get(swaggerUrl)
  77. console.log(
  78. `${provider.providerId}:`,
  79. `${provider.endpoint}`,
  80. '- OK -',
  81. `storage node version ${data.info.version}`
  82. )
  83. } catch (err) {
  84. console.log(`${provider.providerId}`, `${provider.endpoint} - ${err.message}`)
  85. }
  86. })
  87. )
  88. // Load data objects
  89. await runtime.assets.fetchDataObjects()
  90. const allContentIds = await runtime.assets.getKnownContentIds()
  91. const acceptedContentIds = runtime.assets.getAcceptedContentIds()
  92. const ipfsHashes = runtime.assets.getAcceptedIpfsHashes()
  93. console.log('\nData Directory objects:')
  94. console.log(allContentIds.length, 'created')
  95. console.log(acceptedContentIds.length, 'accepted')
  96. console.log(ipfsHashes.length, 'unique accepted hashes')
  97. // We no longer need a connection to the chain
  98. api.disconnect()
  99. console.log(`
  100. Checking available assets on providers (this can take some time)
  101. This is done by sending HEAD requests for all 'Accepted' assets.
  102. `)
  103. endpoints.forEach(async ({ providerId, endpoint }) => {
  104. if (!endpoint) {
  105. return
  106. }
  107. return testProviderHasAssets(providerId, endpoint, acceptedContentIds.slice())
  108. })
  109. }
  110. main()