cli.js 4.7 KB

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