index.ts 25 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666
  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 } from '../common'
  31. import { BTreeSet } from '@polkadot/types'
  32. import { In } from 'typeorm'
  33. import _ from 'lodash'
  34. import { DataObjectId, BagId, DynamicBagId, StaticBagId } from '@joystream/types/augment/all'
  35. import {
  36. processDistributionBucketFamilyMetadata,
  37. processDistributionOperatorMetadata,
  38. processStorageOperatorMetadata,
  39. } from './metadata'
  40. import { createDataObjects, getStorageSystem, removeDataObject } from './utils'
  41. async function getDataObjectsInBag(
  42. store: DatabaseManager,
  43. bagId: BagId,
  44. dataObjectIds: BTreeSet<DataObjectId>
  45. ): Promise<StorageDataObject[]> {
  46. const dataObjects = await store.getMany(StorageDataObject, {
  47. where: {
  48. id: In(Array.from(dataObjectIds).map((id) => id.toString())),
  49. storageBag: { id: getBagId(bagId) },
  50. },
  51. })
  52. if (dataObjects.length !== Array.from(dataObjectIds).length) {
  53. throw new Error(
  54. `Missing data objects: ${_.difference(
  55. Array.from(dataObjectIds).map((id) => id.toString()),
  56. dataObjects.map((o) => o.id)
  57. )} in bag ${getBagId(bagId)}`
  58. )
  59. }
  60. return dataObjects
  61. }
  62. function getStaticBagOwner(bagId: StaticBagId): typeof StorageBagOwner {
  63. if (bagId.isCouncil) {
  64. return new StorageBagOwnerCouncil()
  65. } else if (bagId.isWorkingGroup) {
  66. const owner = new StorageBagOwnerWorkingGroup()
  67. owner.workingGroupId = bagId.asWorkingGroup.toString().toLowerCase()
  68. return owner
  69. } else {
  70. throw new Error(`Unexpected static bag type: ${bagId.type}`)
  71. }
  72. }
  73. function getDynamicBagOwner(bagId: DynamicBagId) {
  74. if (bagId.isChannel) {
  75. const owner = new StorageBagOwnerChannel()
  76. owner.channelId = bagId.asChannel.toNumber()
  77. return owner
  78. } else if (bagId.isMember) {
  79. const owner = new StorageBagOwnerMember()
  80. owner.memberId = bagId.asMember.toNumber()
  81. return owner
  82. } else {
  83. throw new Error(`Unexpected dynamic bag type: ${bagId.type}`)
  84. }
  85. }
  86. function getStaticBagId(bagId: StaticBagId): string {
  87. if (bagId.isCouncil) {
  88. return `static:council`
  89. } else if (bagId.isWorkingGroup) {
  90. return `static:wg:${bagId.asWorkingGroup.type.toLowerCase()}`
  91. } else {
  92. throw new Error(`Unexpected static bag type: ${bagId.type}`)
  93. }
  94. }
  95. function getDynamicBagId(bagId: DynamicBagId): string {
  96. if (bagId.isChannel) {
  97. return `dynamic:channel:${bagId.asChannel.toString()}`
  98. } else if (bagId.isMember) {
  99. return `dynamic:member:${bagId.asMember.toString()}`
  100. } else {
  101. throw new Error(`Unexpected dynamic bag type: ${bagId.type}`)
  102. }
  103. }
  104. function getBagId(bagId: BagId) {
  105. return bagId.isStatic ? getStaticBagId(bagId.asStatic) : getDynamicBagId(bagId.asDynamic)
  106. }
  107. async function getDynamicBag(
  108. store: DatabaseManager,
  109. bagId: DynamicBagId,
  110. relations?: 'objects'[]
  111. ): Promise<StorageBag> {
  112. return getById(store, StorageBag, getDynamicBagId(bagId), relations)
  113. }
  114. async function getStaticBag(store: DatabaseManager, bagId: StaticBagId, relations?: 'objects'[]): Promise<StorageBag> {
  115. const id = getStaticBagId(bagId)
  116. const bag = await store.get(StorageBag, { where: { id }, relations })
  117. if (!bag) {
  118. console.log(`Creating new static bag: ${id}`)
  119. const newBag = new StorageBag({
  120. id,
  121. owner: getStaticBagOwner(bagId),
  122. })
  123. await store.save<StorageBag>(newBag)
  124. return newBag
  125. }
  126. return bag
  127. }
  128. async function getBag(store: DatabaseManager, bagId: BagId, relations?: 'objects'[]): Promise<StorageBag> {
  129. return bagId.isStatic
  130. ? getStaticBag(store, bagId.asStatic, relations)
  131. : getDynamicBag(store, bagId.asDynamic, relations)
  132. }
  133. async function getDistributionBucketOperatorWithMetadata(
  134. store: DatabaseManager,
  135. id: string
  136. ): Promise<DistributionBucketOperator> {
  137. const operator = await store.get(DistributionBucketOperator, {
  138. where: { id },
  139. relations: ['metadata', 'metadata.nodeLocation', 'metadata.nodeLocation.coordinates'],
  140. })
  141. if (!operator) {
  142. throw new Error(`DistributionBucketOperator not found by id: ${id}`)
  143. }
  144. return operator
  145. }
  146. async function getStorageBucketWithOperatorMetadata(store: DatabaseManager, id: string): Promise<StorageBucket> {
  147. const bucket = await store.get(StorageBucket, {
  148. where: { id },
  149. relations: ['operatorMetadata', 'operatorMetadata.nodeLocation', 'operatorMetadata.nodeLocation.coordinates'],
  150. })
  151. if (!bucket) {
  152. throw new Error(`StorageBucket not found by id: ${id}`)
  153. }
  154. return bucket
  155. }
  156. async function getDistributionBucketFamilyWithMetadata(
  157. store: DatabaseManager,
  158. id: string
  159. ): Promise<DistributionBucketFamily> {
  160. const family = await store.get(DistributionBucketFamily, {
  161. where: { id },
  162. relations: ['metadata', 'metadata.areas'],
  163. })
  164. if (!family) {
  165. throw new Error(`DistributionBucketFamily not found by id: ${id}`)
  166. }
  167. return family
  168. }
  169. // STORAGE BUCKETS
  170. export async function storage_StorageBucketCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  171. const [
  172. bucketId,
  173. invitedWorkerId,
  174. acceptingNewBags,
  175. dataObjectSizeLimit,
  176. dataObjectCountLimit,
  177. ] = new Storage.StorageBucketCreatedEvent(event).params
  178. const storageBucket = new StorageBucket({
  179. id: bucketId.toString(),
  180. acceptingNewBags: acceptingNewBags.isTrue,
  181. dataObjectCountLimit: new BN(dataObjectCountLimit.toString()),
  182. dataObjectsSizeLimit: new BN(dataObjectSizeLimit.toString()),
  183. dataObjectsCount: new BN(0),
  184. dataObjectsSize: new BN(0),
  185. })
  186. if (invitedWorkerId.isSome) {
  187. const operatorStatus = new StorageBucketOperatorStatusInvited()
  188. operatorStatus.workerId = invitedWorkerId.unwrap().toNumber()
  189. storageBucket.operatorStatus = operatorStatus
  190. } else {
  191. storageBucket.operatorStatus = new StorageBucketOperatorStatusMissing()
  192. }
  193. await store.save<StorageBucket>(storageBucket)
  194. }
  195. export async function storage_StorageOperatorMetadataSet({ event, store }: EventContext & StoreContext): Promise<void> {
  196. const [bucketId, , metadataBytes] = new Storage.StorageOperatorMetadataSetEvent(event).params
  197. const storageBucket = await getStorageBucketWithOperatorMetadata(store, bucketId.toString())
  198. storageBucket.operatorMetadata = await processStorageOperatorMetadata(
  199. store,
  200. storageBucket.operatorMetadata,
  201. metadataBytes
  202. )
  203. await store.save<StorageBucket>(storageBucket)
  204. }
  205. export async function storage_StorageBucketStatusUpdated({ event, store }: EventContext & StoreContext): Promise<void> {
  206. const [bucketId, acceptingNewBags] = new Storage.StorageBucketStatusUpdatedEvent(event).params
  207. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  208. storageBucket.acceptingNewBags = acceptingNewBags.isTrue
  209. await store.save<StorageBucket>(storageBucket)
  210. }
  211. export async function storage_StorageBucketInvitationAccepted({
  212. event,
  213. store,
  214. }: EventContext & StoreContext): Promise<void> {
  215. const [bucketId, workerId] = new Storage.StorageBucketInvitationAcceptedEvent(event).params
  216. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  217. const operatorStatus = new StorageBucketOperatorStatusActive()
  218. operatorStatus.workerId = workerId.toNumber()
  219. storageBucket.operatorStatus = operatorStatus
  220. await store.save<StorageBucket>(storageBucket)
  221. }
  222. export async function storage_StorageBucketInvitationCancelled({
  223. event,
  224. store,
  225. }: EventContext & StoreContext): Promise<void> {
  226. const [bucketId] = new Storage.StorageBucketInvitationCancelledEvent(event).params
  227. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  228. const operatorStatus = new StorageBucketOperatorStatusMissing()
  229. storageBucket.operatorStatus = operatorStatus
  230. await store.save<StorageBucket>(storageBucket)
  231. }
  232. export async function storage_StorageBucketOperatorInvited({
  233. event,
  234. store,
  235. }: EventContext & StoreContext): Promise<void> {
  236. const [bucketId, workerId] = new Storage.StorageBucketOperatorInvitedEvent(event).params
  237. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  238. const operatorStatus = new StorageBucketOperatorStatusInvited()
  239. operatorStatus.workerId = workerId.toNumber()
  240. storageBucket.operatorStatus = operatorStatus
  241. await store.save<StorageBucket>(storageBucket)
  242. }
  243. export async function storage_StorageBucketOperatorRemoved({
  244. event,
  245. store,
  246. }: EventContext & StoreContext): Promise<void> {
  247. const [bucketId] = new Storage.StorageBucketInvitationCancelledEvent(event).params
  248. const storageBucket = await getById(store, StorageBucket, bucketId.toString())
  249. const operatorStatus = new StorageBucketOperatorStatusMissing()
  250. storageBucket.operatorStatus = operatorStatus
  251. await store.save<StorageBucket>(storageBucket)
  252. }
  253. export async function storage_StorageBucketsUpdatedForBag({
  254. event,
  255. store,
  256. }: EventContext & StoreContext): Promise<void> {
  257. const [bagId, addedBucketsIds, removedBucketsIds] = new Storage.StorageBucketsUpdatedForBagEvent(event).params
  258. // Get or create bag
  259. const storageBag = await getBag(store, bagId)
  260. const assignmentsToRemove = await store.getMany(StorageBagStorageAssignment, {
  261. where: {
  262. storageBag,
  263. storageBucket: { id: In(Array.from(removedBucketsIds).map((bucketId) => bucketId.toString())) },
  264. },
  265. })
  266. const assignmentsToAdd = Array.from(addedBucketsIds).map(
  267. (bucketId) =>
  268. new StorageBagStorageAssignment({
  269. id: `${storageBag.id}-${bucketId.toString()}`,
  270. storageBag,
  271. storageBucket: new StorageBucket({ id: bucketId.toString() }),
  272. })
  273. )
  274. await Promise.all(assignmentsToRemove.map((a) => store.remove<StorageBagStorageAssignment>(a)))
  275. await Promise.all(assignmentsToAdd.map((a) => store.save<StorageBagStorageAssignment>(a)))
  276. }
  277. export async function storage_VoucherChanged({ event, store }: EventContext & StoreContext): Promise<void> {
  278. const [bucketId, voucher] = new Storage.VoucherChangedEvent(event).params
  279. const bucket = await getById(store, StorageBucket, bucketId.toString())
  280. bucket.dataObjectCountLimit = voucher.objectsLimit
  281. bucket.dataObjectsSizeLimit = voucher.sizeLimit
  282. bucket.dataObjectsCount = voucher.objectsUsed
  283. bucket.dataObjectsSize = voucher.sizeUsed
  284. await store.save<StorageBucket>(bucket)
  285. }
  286. export async function storage_StorageBucketVoucherLimitsSet({
  287. event,
  288. store,
  289. }: EventContext & StoreContext): Promise<void> {
  290. const [bucketId, sizeLimit, countLimit] = new Storage.StorageBucketVoucherLimitsSetEvent(event).params
  291. const bucket = await getById(store, StorageBucket, bucketId.toString())
  292. bucket.dataObjectsSizeLimit = sizeLimit
  293. bucket.dataObjectCountLimit = countLimit
  294. await store.save<StorageBucket>(bucket)
  295. }
  296. export async function storage_StorageBucketDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  297. const [bucketId] = new Storage.StorageBucketDeletedEvent(event).params
  298. // TODO: Cascade remove on db level (would require changes in Hydra / comitting autogenerated files)
  299. const assignments = await store.getMany(StorageBagStorageAssignment, {
  300. where: { storageBucket: { id: bucketId.toString() } },
  301. })
  302. await Promise.all(assignments.map((a) => store.remove<StorageBagStorageAssignment>(a)))
  303. await store.remove<StorageBucket>(new StorageBucket({ id: bucketId.toString() }))
  304. }
  305. // DYNAMIC BAGS
  306. export async function storage_DynamicBagCreated({ event, store }: EventContext & StoreContext): Promise<void> {
  307. const [bagId, , storageBucketIdsSet, distributionBucketIdsSet] = new Storage.DynamicBagCreatedEvent(event).params
  308. const storageBag = new StorageBag({
  309. id: getDynamicBagId(bagId),
  310. owner: getDynamicBagOwner(bagId),
  311. })
  312. const storageAssignments = Array.from(storageBucketIdsSet).map(
  313. (bucketId) =>
  314. new StorageBagStorageAssignment({
  315. id: `${storageBag.id}-${bucketId.toString()}`,
  316. storageBag,
  317. storageBucket: new StorageBucket({ id: bucketId.toString() }),
  318. })
  319. )
  320. const distributionAssignments = Array.from(distributionBucketIdsSet).map(
  321. (bucketId) =>
  322. new StorageBagDistributionAssignment({
  323. id: `${storageBag.id}-${bucketId.toString()}`,
  324. storageBag,
  325. distributionBucket: new DistributionBucket({ id: bucketId.toString() }),
  326. })
  327. )
  328. await store.save<StorageBag>(storageBag)
  329. await Promise.all(storageAssignments.map((a) => store.save<StorageBagStorageAssignment>(a)))
  330. await Promise.all(distributionAssignments.map((a) => store.save<StorageBagDistributionAssignment>(a)))
  331. }
  332. export async function storage_DynamicBagDeleted({ event, store }: EventContext & StoreContext): Promise<void> {
  333. const [, bagId] = new Storage.DynamicBagDeletedEvent(event).params
  334. const storageBag = await getDynamicBag(store, bagId, ['objects'])
  335. // The bag should already be empty, so no cascade-remove required
  336. await store.remove<StorageBag>(storageBag)
  337. }
  338. // DATA OBJECTS
  339. // Note: "Uploaded" here actually means "created" (the real upload happens later)
  340. export async function storage_DataObjectsUploaded({ event, store }: EventContext & StoreContext): Promise<void> {
  341. const [dataObjectIds, uploadParams] = new Storage.DataObjectsUploadedEvent(event).params
  342. const { bagId, objectCreationList } = uploadParams
  343. const storageBag = await getBag(store, bagId)
  344. await createDataObjects(store, objectCreationList, storageBag, dataObjectIds)
  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) => removeDataObject(store, 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. }