assets.js 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168
  1. 'use strict'
  2. const debug = require('debug')('joystream:runtime:assets')
  3. const { decodeAddress } = require('@polkadot/keyring')
  4. function parseContentId(contentId) {
  5. try {
  6. return decodeAddress(contentId)
  7. } catch (err) {
  8. return contentId
  9. }
  10. }
  11. /*
  12. * Add asset related functionality to the substrate API.
  13. */
  14. class AssetsApi {
  15. static async create(base) {
  16. const ret = new AssetsApi()
  17. ret.base = base
  18. await AssetsApi.init()
  19. return ret
  20. }
  21. static async init() {
  22. debug('Init')
  23. }
  24. /*
  25. * Create and return a data object.
  26. */
  27. async createDataObject(accountId, memberId, contentId, doTypeId, size, ipfsCid) {
  28. contentId = parseContentId(contentId)
  29. const tx = this.base.api.tx.dataDirectory.addContent(memberId, contentId, doTypeId, size, ipfsCid)
  30. await this.base.signAndSend(accountId, tx)
  31. // If the data object constructed properly, we should now be able to return
  32. // the data object from the state.
  33. return this.getDataObject(contentId)
  34. }
  35. /*
  36. * Return the Data Object for a contendId
  37. */
  38. async getDataObject(contentId) {
  39. contentId = parseContentId(contentId)
  40. return this.base.api.query.dataDirectory.dataObjectByContentId(contentId)
  41. }
  42. /*
  43. * Verify the liaison state for a DataObject:
  44. * - Check the content ID has a DataObject
  45. * - Check the storageProviderId is the liaison
  46. * - Check the liaison state is Pending
  47. *
  48. * Each failure errors out, success returns the data object.
  49. */
  50. async checkLiaisonForDataObject(storageProviderId, contentId) {
  51. contentId = parseContentId(contentId)
  52. let obj = await this.getDataObject(contentId)
  53. if (obj.isNone) {
  54. throw new Error(`No DataObject created for content ID: ${contentId}`)
  55. }
  56. obj = obj.unwrap()
  57. if (!obj.liaison.eq(storageProviderId)) {
  58. throw new Error(`This storage node is not liaison for the content ID: ${contentId}`)
  59. }
  60. if (obj.liaison_judgement.type !== 'Pending') {
  61. throw new Error(`Expected Pending judgement, but found: ${obj.liaison_judgement.type}`)
  62. }
  63. return obj
  64. }
  65. /*
  66. * Sets the data object liaison judgement to Accepted
  67. */
  68. async acceptContent(providerAccoundId, storageProviderId, contentId) {
  69. contentId = parseContentId(contentId)
  70. const tx = this.base.api.tx.dataDirectory.acceptContent(storageProviderId, contentId)
  71. return this.base.signAndSend(providerAccoundId, tx)
  72. }
  73. /*
  74. * Sets the data object liaison judgement to Rejected
  75. */
  76. async rejectContent(providerAccountId, storageProviderId, contentId) {
  77. contentId = parseContentId(contentId)
  78. const tx = this.base.api.tx.dataDirectory.rejectContent(storageProviderId, contentId)
  79. return this.base.signAndSend(providerAccountId, tx)
  80. }
  81. /*
  82. * Creates storage relationship for a data object and provider
  83. */
  84. async createStorageRelationship(providerAccountId, storageProviderId, contentId, callback) {
  85. contentId = parseContentId(contentId)
  86. const tx = this.base.api.tx.dataObjectStorageRegistry.addRelationship(storageProviderId, contentId)
  87. const subscribed = [['dataObjectStorageRegistry', 'DataObjectStorageRelationshipAdded']]
  88. return this.base.signAndSend(providerAccountId, tx, 3, subscribed, callback)
  89. }
  90. /*
  91. * Gets storage relationship for contentId for the given provider
  92. */
  93. async getStorageRelationshipAndId(storageProviderId, contentId) {
  94. contentId = parseContentId(contentId)
  95. const rids = await this.base.api.query.dataObjectStorageRegistry.relationshipsByContentId(contentId)
  96. while (rids.length) {
  97. const relationshipId = rids.shift()
  98. let relationship = await this.base.api.query.dataObjectStorageRegistry.relationships(relationshipId)
  99. relationship = relationship.unwrap()
  100. if (relationship.storage_provider.eq(storageProviderId)) {
  101. return { relationship, relationshipId }
  102. }
  103. }
  104. return {}
  105. }
  106. /*
  107. * Creates storage relationship for a data object and provider and returns the relationship id
  108. */
  109. async createAndReturnStorageRelationship(providerAccountId, storageProviderId, contentId) {
  110. contentId = parseContentId(contentId)
  111. // TODO: rewrite this method to async-await style
  112. // eslint-disable-next-line no-async-promise-executor
  113. return new Promise(async (resolve, reject) => {
  114. try {
  115. await this.createStorageRelationship(providerAccountId, storageProviderId, contentId, (events) => {
  116. events.forEach((event) => {
  117. resolve(event[1].DataObjectStorageRelationshipId)
  118. })
  119. })
  120. } catch (err) {
  121. reject(err)
  122. }
  123. })
  124. }
  125. /*
  126. * Set the ready state for a data object storage relationship to the new value
  127. */
  128. async toggleStorageRelationshipReady(providerAccountId, storageProviderId, dosrId, ready) {
  129. const tx = ready
  130. ? this.base.api.tx.dataObjectStorageRegistry.setRelationshipReady(storageProviderId, dosrId)
  131. : this.base.api.tx.dataObjectStorageRegistry.unsetRelationshipReady(storageProviderId, dosrId)
  132. return this.base.signAndSend(providerAccountId, tx)
  133. }
  134. /*
  135. * Returns array of know content ids
  136. */
  137. async getKnownContentIds() {
  138. return this.base.api.query.dataDirectory.knownContentIds()
  139. }
  140. }
  141. module.exports = {
  142. AssetsApi,
  143. }