cli.js 4.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  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. async function assetRelationshipState(api, contentId, providers) {
  11. const dataObject = await api.query.dataDirectory.dataByContentId(contentId)
  12. const relationshipIds = await api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId)
  13. // how many relationships associated with active providers and in ready state
  14. const activeRelationships = await Promise.all(
  15. relationshipIds.map(async (id) => {
  16. let relationship = await api.query.dataObjectStorageRegistry.relationships(id)
  17. relationship = relationship.unwrap()
  18. // only interested in ready relationships
  19. if (!relationship.ready) {
  20. return undefined
  21. }
  22. // Does the relationship belong to an active provider ?
  23. return providers.find((provider) => relationship.storage_provider.eq(provider))
  24. })
  25. )
  26. return [activeRelationships.filter((active) => active).length, dataObject.liaison_judgement]
  27. }
  28. // HTTP HEAD with axios all known content ids on each provider
  29. async function countContentAvailability(contentIds, source) {
  30. const content = {}
  31. let found = 0
  32. let missing = 0
  33. for (let i = 0; i < contentIds.length; i++) {
  34. const assetUrl = makeAssetUrl(contentIds[i], source)
  35. try {
  36. const info = await axios.head(assetUrl)
  37. content[encodeAddress(contentIds[i])] = {
  38. type: info.headers['content-type'],
  39. bytes: info.headers['content-length'],
  40. }
  41. // TODO: cross check against dataobject size
  42. found++
  43. } catch (err) {
  44. missing++
  45. }
  46. }
  47. return { found, missing, content }
  48. }
  49. async function main() {
  50. const runtime = await RuntimeApi.create()
  51. const { api } = runtime
  52. // get all providers
  53. const { ids: storageProviders } = await runtime.workers.getAllProviders()
  54. console.log(`Found ${storageProviders.length} staked providers`)
  55. // Resolve Endpoints of providers
  56. console.log('\nResolving live provider API Endpoints...')
  57. const endpoints = await Promise.all(
  58. storageProviders.map(async (providerId) => {
  59. try {
  60. const endpoint = (await runtime.workers.getWorkerStorageValue(providerId)).toString()
  61. return { providerId, endpoint }
  62. } catch (err) {
  63. console.log('resolve failed for id', providerId, err.message)
  64. return { providerId, endpoint: null }
  65. }
  66. })
  67. )
  68. console.log('\nChecking API Endpoints are online')
  69. await Promise.all(
  70. endpoints.map(async (provider) => {
  71. if (!provider.endpoint) {
  72. console.log(provider.providerId, 'No url set, skipping')
  73. return
  74. }
  75. const swaggerUrl = `${stripEndingSlash(provider.endpoint)}/swagger.json`
  76. let error
  77. try {
  78. await axios.get(swaggerUrl)
  79. // maybe print out api version information to detect which version of colossus is running?
  80. // or add anothe api endpoint for diagnostics information
  81. } catch (err) {
  82. error = err
  83. }
  84. console.log(`${provider.providerId}`, `${provider.endpoint} - ${error ? error.message : 'OK'}`)
  85. })
  86. )
  87. const knownContentIds = await runtime.assets.getKnownContentIds()
  88. const assetStatuses = {}
  89. await Promise.all(
  90. knownContentIds.map(async (contentId) => {
  91. const [, judgement] = await assetRelationshipState(api, contentId, storageProviders)
  92. const j = judgement.toString()
  93. assetStatuses[j] = assetStatuses[j] ? assetStatuses[j] + 1 : 1
  94. })
  95. )
  96. console.log(`\nData Directory has ${knownContentIds.length} assets:`, assetStatuses)
  97. // interesting disconnect doesn't work unless an explicit provider was created
  98. // for underlying api instance
  99. // We no longer need a connection to the chain
  100. api.disconnect()
  101. console.log(`\nChecking available assets on providers (this can take some time)...`)
  102. endpoints.forEach(async ({ providerId, endpoint }) => {
  103. if (!endpoint) {
  104. return
  105. }
  106. const total = knownContentIds.length
  107. const { found } = await countContentAvailability(knownContentIds, endpoint)
  108. console.log(`provider ${providerId}: has ${found} out of ${total}`)
  109. })
  110. }
  111. main()