index.ts 24 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668
  1. /*
  2. eslint-disable @typescript-eslint/naming-convention
  3. */
  4. import { DatabaseManager, EventContext, StoreContext } from '@joystream/hydra-common'
  5. import { Storage } from '../generated/types/storage'
  6. import {
  7. DistributionBucket,
  8. DistributionBucketFamily,
  9. DistributionBucketOperator,
  10. DistributionBucketOperatorMetadata,
  11. DistributionBucketOperatorStatus,
  12. NodeLocationMetadata,
  13. StorageBag,
  14. StorageBagOwner,
  15. StorageBagOwnerChannel,
  16. StorageBagOwnerCouncil,
  17. StorageBagOwnerMember,
  18. StorageBagOwnerWorkingGroup,
  19. StorageBucket,
  20. StorageBucketOperatorStatusActive,
  21. StorageBucketOperatorStatusInvited,
  22. StorageBucketOperatorStatusMissing,
  23. StorageDataObject,
  24. StorageSystemParameters,
  25. GeoCoordinates,
  26. StorageBagDistributionAssignment,
  27. StorageBagStorageAssignment,
  28. } from 'query-node/dist/model'
  29. import BN from 'bn.js'
  30. import { getById, bytesToString } from '../common'
  31. import { BTreeSet } from '@polkadot/types'
  32. import { DataObjectCreationParameters } from '@joystream/types/storage'
  33. import { registry } from '@joystream/types'
  34. import { In } from 'typeorm'
  35. import _ from 'lodash'
  36. import { DataObjectId, BagId, DynamicBagId, StaticBagId } from '@joystream/types/augment/all'
  37. import {
  38. processDistributionBucketFamilyMetadata,
  39. processDistributionOperatorMetadata,
  40. processStorageOperatorMetadata,
  41. } from './metadata'
  42. async function getDataObjectsInBag(
  43. store: DatabaseManager,
  44. bagId: BagId,
  45. dataObjectIds: BTreeSet<DataObjectId>
  46. ): Promise<StorageDataObject[]> {
  47. const dataObjects = await store.getMany(StorageDataObject, {
  48. where: {
  49. id: In(Array.from(dataObjectIds).map((id) => id.toString())),
  50. storageBag: { id: getBagId(bagId) },
  51. },
  52. })
  53. if (dataObjects.length !== Array.from(dataObjectIds).length) {
  54. throw new Error(
  55. `Missing data objects: ${_.difference(
  56. Array.from(dataObjectIds).map((id) => id.toString()),
  57. dataObjects.map((o) => o.id)
  58. )} in bag ${getBagId(bagId)}`
  59. )
  60. }
  61. return dataObjects
  62. }
  63. function getStaticBagOwner(bagId: StaticBagId): typeof StorageBagOwner {
  64. if (bagId.isCouncil) {
  65. return new StorageBagOwnerCouncil()
  66. } else if (bagId.isWorkingGroup) {
  67. const owner = new StorageBagOwnerWorkingGroup()
  68. owner.workingGroupId = bagId.asWorkingGroup.toString().toLowerCase()
  69. return owner
  70. } else {
  71. throw new Error(`Unexpected static bag type: ${bagId.type}`)
  72. }
  73. }
  74. function getDynamicBagOwner(bagId: DynamicBagId) {
  75. if (bagId.isChannel) {
  76. const owner = new StorageBagOwnerChannel()
  77. owner.channelId = bagId.asChannel.toNumber()
  78. return owner
  79. } else if (bagId.isMember) {
  80. const owner = new StorageBagOwnerMember()
  81. owner.memberId = bagId.asMember.toNumber()
  82. return owner
  83. } else {
  84. throw new Error(`Unexpected dynamic bag type: ${bagId.type}`)
  85. }
  86. }
  87. function getStaticBagId(bagId: StaticBagId): string {
  88. if (bagId.isCouncil) {
  89. return `static:council`
  90. } else if (bagId.isWorkingGroup) {
  91. return `static:wg:${bagId.asWorkingGroup.type.toLowerCase()}`
  92. } else {
  93. throw new Error(`Unexpected static bag type: ${bagId.type}`)
  94. }
  95. }
  96. function getDynamicBagId(bagId: DynamicBagId): string {
  97. if (bagId.isChannel) {
  98. return `dynamic:channel:${bagId.asChannel.toString()}`
  99. } else if (bagId.isMember) {
  100. return `dynamic:member:${bagId.asMember.toString()}`
  101. } else {
  102. throw new Error(`Unexpected dynamic bag type: ${bagId.type}`)
  103. }
  104. }
  105. function getBagId(bagId: BagId) {
  106. return bagId.isStatic ? getStaticBagId(bagId.asStatic) : getDynamicBagId(bagId.asDynamic)
  107. }
  108. async function getDynamicBag(
  109. store: DatabaseManager,
  110. bagId: DynamicBagId,
  111. relations?: 'objects'[]
  112. ): Promise<StorageBag> {
  113. return getById(store, StorageBag, getDynamicBagId(bagId), relations)
  114. }
  115. async function getStaticBag(store: DatabaseManager, bagId: StaticBagId, relations?: 'objects'[]): Promise<StorageBag> {
  116. const id = getStaticBagId(bagId)
  117. const bag = await store.get(StorageBag, { where: { id }, relations })
  118. if (!bag) {
  119. console.log(`Creating new static bag: ${id}`)
  120. const newBag = new StorageBag({
  121. id,
  122. owner: getStaticBagOwner(bagId),
  123. })
  124. await store.save<StorageBag>(newBag)
  125. return newBag
  126. }
  127. return bag
  128. }
  129. async function getBag(store: DatabaseManager, bagId: BagId, relations?: 'objects'[]): Promise<StorageBag> {
  130. return bagId.isStatic
  131. ? getStaticBag(store, bagId.asStatic, relations)
  132. : getDynamicBag(store, bagId.asDynamic, relations)
  133. }
  134. async function getDistributionBucketOperatorWithMetadata(
  135. store: DatabaseManager,
  136. id: string
  137. ): Promise<DistributionBucketOperator> {
  138. const operator = await store.get(DistributionBucketOperator, {
  139. where: { id },
  140. relations: ['metadata', 'metadata.nodeLocation', 'metadata.nodeLocation.coordinates'],
  141. })
  142. if (!operator) {
  143. throw new Error(`DistributionBucketOperator not found by id: ${id}`)
  144. }
  145. return operator
  146. }
  147. async function getStorageBucketWithOperatorMetadata(store: DatabaseManager, id: string): Promise<StorageBucket> {
  148. const bucket = await store.get(StorageBucket, {
  149. where: { id },
  150. relations: ['operatorMetadata', 'operatorMetadata.nodeLocation', 'operatorMetadata.nodeLocation.coordinates'],
  151. })
  152. if (!bucket) {
  153. throw new Error(`StorageBucket not found by id: ${id}`)
  154. }
  155. return bucket
  156. }
  157. async function getDistributionBucketFamilyWithMetadata(
  158. store: DatabaseManager,
  159. id: string
  160. ): Promise<DistributionBucketFamily> {
  161. const family = await store.get(DistributionBucketFamily, {
  162. where: { id },
  163. relations: ['metadata', 'metadata.boundary'],
  164. })
  165. if (!family) {
  166. throw new Error(`DistributionBucketFamily not found by id: ${id}`)
  167. }
  168. return family
  169. }
  170. async function getStorageSystem(store: DatabaseManager) {
  171. const storageSystem = await store.get(StorageSystemParameters, {})
  172. if (!storageSystem) {
  173. throw new Error('Storage system entity is missing!')
  174. }
  175. return storageSystem
  176. }
  177. // STORAGE BUCKETS
  178. export async function storage_StorageBucketCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  179. const [
  180. bucketId,
  181. invitedWorkerId,
  182. acceptingNewBags,
  183. dataObjectSizeLimit,
  184. dataObjectCountLimit,
  185. ] = new Storage.StorageBucketCreatedEvent(event).params
  186. const storageBucket = new StorageBucket({
  187. id: bucketId.toString(),
  188. acceptingNewBags: acceptingNewBags.isTrue,
  189. dataObjectCountLimit: new BN(dataObjectCountLimit.toString()),
  190. dataObjectsSizeLimit: new BN(dataObjectSizeLimit.toString()),
  191. dataObjectsCount: new BN(0),
  192. dataObjectsSize: new BN(0),
  193. })
  194. if (invitedWorkerId.isSome) {
  195. const operatorStatus = new StorageBucketOperatorStatusInvited()
  196. operatorStatus.workerId = invitedWorkerId.unwrap().toNumber()
  197. storageBucket.operatorStatus = operatorStatus
  198. } else {
  199. storageBucket.operatorStatus = new StorageBucketOperatorStatusMissing()
  200. }
  201. await store.save<StorageBucket>(storageBucket)
  202. }
  203. export async function storage_StorageOperatorMetadataSet({ event, store }: EventContext & StoreContext): Promise<void> {
  204. const [bucketId, , metadataBytes] = new Storage.StorageOperatorMetadataSetEvent(event).params
  205. const storageBucket = await getStorageBucketWithOperatorMetadata(store, bucketId.toString())
  206. storageBucket.operatorMetadata = await processStorageOperatorMetadata(
  207. store,
  208. storageBucket.operatorMetadata,
  209. metadataBytes
  210. )
  211. await store.save<StorageBucket>(storageBucket)
  212. }
  213. export async function storage_StorageBucketStatusUpdated({ event, store }: EventContext & StoreContext): Promise<void> {
  214. const [bucketId, acceptingNewBags] = new Storage.StorageBucketStatusUpdatedEvent(event).params
  215. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  216. storageBucket.acceptingNewBags = acceptingNewBags.isTrue
  217. await store.save<StorageBucket>(storageBucket)
  218. }
  219. export async function storage_StorageBucketInvitationAccepted({
  220. event,
  221. store,
  222. }: EventContext & StoreContext): Promise<void> {
  223. const [bucketId, workerId] = new Storage.StorageBucketInvitationAcceptedEvent(event).params
  224. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  225. const operatorStatus = new StorageBucketOperatorStatusActive()
  226. operatorStatus.workerId = workerId.toNumber()
  227. storageBucket.operatorStatus = operatorStatus
  228. await store.save<StorageBucket>(storageBucket)
  229. }
  230. export async function storage_StorageBucketInvitationCancelled({
  231. event,
  232. store,
  233. }: EventContext & StoreContext): Promise<void> {
  234. const [bucketId] = new Storage.StorageBucketInvitationCancelledEvent(event).params
  235. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  236. const operatorStatus = new StorageBucketOperatorStatusMissing()
  237. storageBucket.operatorStatus = operatorStatus
  238. await store.save<StorageBucket>(storageBucket)
  239. }
  240. export async function storage_StorageBucketOperatorInvited({
  241. event,
  242. store,
  243. }: EventContext & StoreContext): Promise<void> {
  244. const [bucketId, workerId] = new Storage.StorageBucketOperatorInvitedEvent(event).params
  245. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  246. const operatorStatus = new StorageBucketOperatorStatusInvited()
  247. operatorStatus.workerId = workerId.toNumber()
  248. storageBucket.operatorStatus = operatorStatus
  249. await store.save<StorageBucket>(storageBucket)
  250. }
  251. export async function storage_StorageBucketOperatorRemoved({
  252. event,
  253. store,
  254. }: EventContext & StoreContext): Promise<void> {
  255. const [bucketId] = new Storage.StorageBucketInvitationCancelledEvent(event).params
  256. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  257. const operatorStatus = new StorageBucketOperatorStatusMissing()
  258. storageBucket.operatorStatus = operatorStatus
  259. await store.save<StorageBucket>(storageBucket)
  260. }
  261. export async function storage_StorageBucketsUpdatedForBag({
  262. event,
  263. store,
  264. }: EventContext & StoreContext): Promise<void> {
  265. const [bagId, addedBucketsIds, removedBucketsIds] = new Storage.StorageBucketsUpdatedForBagEvent(event).params
  266. // Get or create bag
  267. const storageBag = await getBag(store, bagId)
  268. const assignmentsToRemove = await store.getMany(StorageBagStorageAssignment, {
  269. where: {
  270. storageBag,
  271. storageBucket: { id: In(Array.from(removedBucketsIds).map((bucketId) => bucketId.toString())) },
  272. },
  273. })
  274. const assignmentsToAdd = Array.from(addedBucketsIds).map(
  275. (bucketId) =>
  276. new StorageBagStorageAssignment({
  277. id: `${storageBag.id}-${bucketId.toString()}`,
  278. storageBag,
  279. storageBucket: new StorageBucket({ id: bucketId.toString() }),
  280. })
  281. )
  282. await Promise.all(assignmentsToRemove.map((a) => store.remove<StorageBagStorageAssignment>(a)))
  283. await Promise.all(assignmentsToAdd.map((a) => store.save<StorageBagStorageAssignment>(a)))
  284. }
  285. export async function storage_VoucherChanged({ event, store }: EventContext & StoreContext): Promise<void> {
  286. const [bucketId, voucher] = new Storage.VoucherChangedEvent(event).params
  287. const bucket = await getById(store, StorageBucket, bucketId.toString())
  288. bucket.dataObjectCountLimit = voucher.objectsLimit
  289. bucket.dataObjectsSizeLimit = voucher.sizeLimit
  290. bucket.dataObjectsCount = voucher.objectsUsed
  291. bucket.dataObjectsSize = voucher.sizeUsed
  292. await store.save<StorageBucket>(bucket)
  293. }
  294. export async function storage_StorageBucketVoucherLimitsSet({
  295. event,
  296. store,
  297. }: EventContext & StoreContext): Promise<void> {
  298. const [bucketId, sizeLimit, countLimit] = new Storage.StorageBucketVoucherLimitsSetEvent(event).params
  299. const bucket = await getById(store, StorageBucket, bucketId.toString())
  300. bucket.dataObjectsSizeLimit = sizeLimit
  301. bucket.dataObjectCountLimit = countLimit
  302. await store.save<StorageBucket>(bucket)
  303. }
  304. export async function storage_StorageBucketDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  305. const [bucketId] = new Storage.StorageBucketDeletedEvent(event).params
  306. // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
  307. const assignments = await store.getMany(StorageBagStorageAssignment, {
  308. where: { storageBucket: { id: bucketId.toString() } },
  309. })
  310. await Promise.all(assignments.map((a) => store.remove<StorageBagStorageAssignment>(a)))
  311. await store.remove<StorageBucket>(new StorageBucket({ id: bucketId.toString() }))
  312. }
  313. // DYNAMIC BAGS
  314. export async function storage_DynamicBagCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  315. const [bagId] = new Storage.DynamicBagCreatedEvent(event).params
  316. const storageBag = new StorageBag({
  317. id: getDynamicBagId(bagId),
  318. owner: getDynamicBagOwner(bagId),
  319. })
  320. await store.save<StorageBag>(storageBag)
  321. }
  322. export async function storage_DynamicBagDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  323. const [, bagId] = new Storage.DynamicBagDeletedEvent(event).params
  324. const storageBag = await getDynamicBag(store, bagId, ['objects'])
  325. // The bag should already be empty, so no cascade-remove required
  326. await store.remove<StorageBag>(storageBag)
  327. }
  328. // DATA OBJECTS
  329. // Note: "Uploaded" here actually means "created" (the real upload happens later)
  330. export async function storage_DataObjectsUploaded({ event, store }: EventContext & StoreContext): Promise<void> {
  331. const [dataObjectIds, uploadParams] = new Storage.DataObjectsUploadedEvent(event).params
  332. const { bagId, objectCreationList } = uploadParams
  333. const storageBag = await getBag(store, bagId)
  334. const dataObjects = dataObjectIds.map((objectId, i) => {
  335. const objectParams = new DataObjectCreationParameters(registry, objectCreationList[i].toJSON() as any)
  336. return new StorageDataObject({
  337. id: objectId.toString(),
  338. isAccepted: false,
  339. ipfsHash: bytesToString(objectParams.ipfsContentId),
  340. size: new BN(objectParams.getField('size').toString()),
  341. storageBag,
  342. })
  343. })
  344. await Promise.all(dataObjects.map((o) => store.save<StorageDataObject>(o)))
  345. }
  346. export async function storage_PendingDataObjectsAccepted({ event, store }: EventContext & StoreContext): Promise<void> {
  347. const [, , bagId, dataObjectIds] = new Storage.PendingDataObjectsAcceptedEvent(event).params
  348. const dataObjects = await getDataObjectsInBag(store, bagId, dataObjectIds)
  349. await Promise.all(
  350. dataObjects.map(async (dataObject) => {
  351. dataObject.isAccepted = true
  352. await store.save<StorageDataObject>(dataObject)
  353. })
  354. )
  355. }
  356. export async function storage_DataObjectsMoved({ event, store }: EventContext & StoreContext): Promise<void> {
  357. const [srcBagId, destBagId, dataObjectIds] = new Storage.DataObjectsMovedEvent(event).params
  358. const dataObjects = await getDataObjectsInBag(store, srcBagId, dataObjectIds)
  359. const destBag = await getBag(store, destBagId)
  360. await Promise.all(
  361. dataObjects.map(async (dataObject) => {
  362. dataObject.storageBag = destBag
  363. await store.save<StorageDataObject>(dataObject)
  364. })
  365. )
  366. }
  367. export async function storage_DataObjectsDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  368. const [, bagId, dataObjectIds] = new Storage.DataObjectsDeletedEvent(event).params
  369. const dataObjects = await getDataObjectsInBag(store, bagId, dataObjectIds)
  370. await Promise.all(dataObjects.map((o) => store.remove<StorageDataObject>(o)))
  371. }
  372. // DISTRIBUTION FAMILY
  373. export async function storage_DistributionBucketFamilyCreated({
  374. event,
  375. store,
  376. }: EventContext & StoreContext): Promise<void> {
  377. const [familyId] = new Storage.DistributionBucketFamilyCreatedEvent(event).params
  378. const family = new DistributionBucketFamily({
  379. id: familyId.toString(),
  380. })
  381. await store.save<DistributionBucketFamily>(family)
  382. }
  383. export async function storage_DistributionBucketFamilyMetadataSet({
  384. event,
  385. store,
  386. }: EventContext & StoreContext): Promise<void> {
  387. const [familyId, metadataBytes] = new Storage.DistributionBucketFamilyMetadataSetEvent(event).params
  388. const family = await getDistributionBucketFamilyWithMetadata(store, familyId.toString())
  389. family.metadata = await processDistributionBucketFamilyMetadata(store, family.metadata, metadataBytes)
  390. await store.save<DistributionBucketFamily>(family)
  391. }
  392. export async function storage_DistributionBucketFamilyDeleted({
  393. event,
  394. store,
  395. }: EventContext & StoreContext): Promise<void> {
  396. const [familyId] = new Storage.DistributionBucketFamilyDeletedEvent(event).params
  397. const family = await getById(store, DistributionBucketFamily, familyId.toString())
  398. await store.remove(family)
  399. }
  400. // DISTRIBUTION BUCKET
  401. export async function storage_DistributionBucketCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  402. const [familyId, acceptingNewBags, bucketId] = new Storage.DistributionBucketCreatedEvent(event).params
  403. const family = await getById(store, DistributionBucketFamily, familyId.toString())
  404. const bucket = new DistributionBucket({
  405. id: bucketId.toString(),
  406. acceptingNewBags: acceptingNewBags.valueOf(),
  407. distributing: true, // Runtime default
  408. family,
  409. })
  410. await store.save<DistributionBucket>(bucket)
  411. }
  412. export async function storage_DistributionBucketStatusUpdated({
  413. event,
  414. store,
  415. }: EventContext & StoreContext): Promise<void> {
  416. const [, bucketId, acceptingNewBags] = new Storage.DistributionBucketStatusUpdatedEvent(event).params
  417. const bucket = await getById(store, DistributionBucket, bucketId.toString())
  418. bucket.acceptingNewBags = acceptingNewBags.valueOf()
  419. await store.save<DistributionBucket>(bucket)
  420. }
  421. export async function storage_DistributionBucketDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  422. const [, bucketId] = new Storage.DistributionBucketDeletedEvent(event).params
  423. // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
  424. const assignments = await store.getMany(StorageBagDistributionAssignment, {
  425. where: { distributionBucket: { id: bucketId.toString() } },
  426. })
  427. await Promise.all(assignments.map((a) => store.remove<StorageBagDistributionAssignment>(a)))
  428. await store.remove<DistributionBucket>(new DistributionBucket({ id: bucketId.toString() }))
  429. }
  430. export async function storage_DistributionBucketsUpdatedForBag({
  431. event,
  432. store,
  433. }: EventContext & StoreContext): Promise<void> {
  434. const [bagId, , addedBucketsIds, removedBucketsIds] = new Storage.DistributionBucketsUpdatedForBagEvent(event).params
  435. // Get or create bag
  436. const storageBag = await getBag(store, bagId)
  437. const assignmentsToRemove = await store.getMany(StorageBagDistributionAssignment, {
  438. where: {
  439. storageBag,
  440. distributionBucket: { id: In(Array.from(removedBucketsIds).map((bucketId) => bucketId.toString())) },
  441. },
  442. })
  443. const assignmentsToAdd = Array.from(addedBucketsIds).map(
  444. (bucketId) =>
  445. new StorageBagDistributionAssignment({
  446. id: `${storageBag.id}-${bucketId.toString()}`,
  447. storageBag,
  448. distributionBucket: new DistributionBucket({ id: bucketId.toString() }),
  449. })
  450. )
  451. await Promise.all(assignmentsToRemove.map((a) => store.remove<StorageBagDistributionAssignment>(a)))
  452. await Promise.all(assignmentsToAdd.map((a) => store.save<StorageBagDistributionAssignment>(a)))
  453. }
  454. export async function storage_DistributionBucketModeUpdated({
  455. event,
  456. store,
  457. }: EventContext & StoreContext): Promise<void> {
  458. const [, bucketId, distributing] = new Storage.DistributionBucketModeUpdatedEvent(event).params
  459. const bucket = await getById(store, DistributionBucket, bucketId.toString())
  460. bucket.distributing = distributing.valueOf()
  461. await store.save<DistributionBucket>(bucket)
  462. }
  463. export async function storage_DistributionBucketOperatorInvited({
  464. event,
  465. store,
  466. }: EventContext & StoreContext): Promise<void> {
  467. const [, bucketId, workerId] = new Storage.DistributionBucketOperatorInvitedEvent(event).params
  468. const bucket = await getById(store, DistributionBucket, bucketId.toString())
  469. const invitedOperator = new DistributionBucketOperator({
  470. id: `${bucketId}-${workerId}`,
  471. distributionBucket: bucket,
  472. status: DistributionBucketOperatorStatus.INVITED,
  473. workerId: workerId.toNumber(),
  474. })
  475. await store.save<DistributionBucketOperator>(invitedOperator)
  476. }
  477. export async function storage_DistributionBucketInvitationCancelled({
  478. event,
  479. store,
  480. }: EventContext & StoreContext): Promise<void> {
  481. const [, bucketId, workerId] = new Storage.DistributionBucketOperatorInvitedEvent(event).params
  482. const invitedOperator = await getById(store, DistributionBucketOperator, `${bucketId}-${workerId}`)
  483. await store.remove<DistributionBucketOperator>(invitedOperator)
  484. }
  485. export async function storage_DistributionBucketInvitationAccepted({
  486. event,
  487. store,
  488. }: EventContext & StoreContext): Promise<void> {
  489. const [workerId, , bucketId] = new Storage.DistributionBucketInvitationAcceptedEvent(event).params
  490. const invitedOperator = await getById(store, DistributionBucketOperator, `${bucketId}-${workerId}`)
  491. invitedOperator.status = DistributionBucketOperatorStatus.ACTIVE
  492. await store.save<DistributionBucketOperator>(invitedOperator)
  493. }
  494. export async function storage_DistributionBucketMetadataSet({
  495. event,
  496. store,
  497. }: EventContext & StoreContext): Promise<void> {
  498. const [workerId, , bucketId, metadataBytes] = new Storage.DistributionBucketMetadataSetEvent(event).params
  499. const operator = await getDistributionBucketOperatorWithMetadata(store, `${bucketId}-${workerId}`)
  500. operator.metadata = await processDistributionOperatorMetadata(store, operator.metadata, metadataBytes)
  501. await store.save<DistributionBucketOperator>(operator)
  502. }
  503. export async function storage_DistributionBucketOperatorRemoved({
  504. event,
  505. store,
  506. }: EventContext & StoreContext): Promise<void> {
  507. const [, bucketId, workerId] = new Storage.DistributionBucketOperatorRemovedEvent(event).params
  508. // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
  509. const operator = await getDistributionBucketOperatorWithMetadata(store, `${bucketId}-${workerId}`)
  510. await store.remove<DistributionBucketOperator>(operator)
  511. if (operator.metadata) {
  512. await store.remove<DistributionBucketOperatorMetadata>(operator.metadata)
  513. if (operator.metadata.nodeLocation) {
  514. await store.remove<NodeLocationMetadata>(operator.metadata.nodeLocation)
  515. if (operator.metadata.nodeLocation.coordinates) {
  516. await store.remove<GeoCoordinates>(operator.metadata.nodeLocation.coordinates)
  517. }
  518. }
  519. }
  520. }
  521. // STORAGE SYSTEM GLOBAL PARAMS
  522. export async function storage_UpdateBlacklist({ event, store }: EventContext & StoreContext): Promise<void> {
  523. const [removedContentIds, addedContentIds] = new Storage.UpdateBlacklistEvent(event).params
  524. const storageSystem = await getStorageSystem(store)
  525. storageSystem.blacklist = storageSystem.blacklist
  526. .filter((cid) => !Array.from(removedContentIds).some((id) => id.eq(cid)))
  527. .concat(Array.from(addedContentIds).map((id) => id.toString()))
  528. await store.save<StorageSystemParameters>(storageSystem)
  529. }
  530. export async function storage_DistributionBucketsPerBagLimitUpdated({
  531. event,
  532. store,
  533. }: EventContext & StoreContext): Promise<void> {
  534. const [newLimit] = new Storage.DistributionBucketsPerBagLimitUpdatedEvent(event).params
  535. const storageSystem = await getStorageSystem(store)
  536. storageSystem.distributionBucketsPerBagLimit = newLimit.toNumber()
  537. await store.save<StorageSystemParameters>(storageSystem)
  538. }
  539. export async function storage_StorageBucketsPerBagLimitUpdated({
  540. event,
  541. store,
  542. }: EventContext & StoreContext): Promise<void> {
  543. const [newLimit] = new Storage.StorageBucketsPerBagLimitUpdatedEvent(event).params
  544. const storageSystem = await getStorageSystem(store)
  545. storageSystem.storageBucketsPerBagLimit = newLimit.toNumber()
  546. await store.save<StorageSystemParameters>(storageSystem)
  547. }
  548. export async function storage_StorageBucketsVoucherMaxLimitsUpdated({
  549. event,
  550. store,
  551. }: EventContext & StoreContext): Promise<void> {
  552. const [sizeLimit, countLimit] = new Storage.StorageBucketsVoucherMaxLimitsUpdatedEvent(event).params
  553. const storageSystem = await getStorageSystem(store)
  554. storageSystem.storageBucketMaxObjectsSizeLimit = sizeLimit
  555. storageSystem.storageBucketMaxObjectsCountLimit = countLimit
  556. await store.save<StorageSystemParameters>(storageSystem)
  557. }
  558. export async function storage_UploadingBlockStatusUpdated({
  559. event,
  560. store,
  561. }: EventContext & StoreContext): Promise<void> {
  562. const [isBlocked] = new Storage.UploadingBlockStatusUpdatedEvent(event).params
  563. const storageSystem = await getStorageSystem(store)
  564. storageSystem.uploadingBlocked = isBlocked.isTrue
  565. await store.save<StorageSystemParameters>(storageSystem)
  566. }
  567. export async function storage_DataObjectPerMegabyteFeeUpdated({
  568. event,
  569. store,
  570. }: EventContext & StoreContext): Promise<void> {
  571. const [newFee] = new Storage.DataObjectPerMegabyteFeeUpdatedEvent(event).params
  572. const storageSystem = await getStorageSystem(store)
  573. storageSystem.dataObjectFeePerMb = newFee
  574. await store.save<StorageSystemParameters>(storageSystem)
  575. }