metadata.ts 7.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. import { DatabaseManager, SubstrateEvent } from '@joystream/hydra-common'
  2. import {
  3. DistributionBucketFamilyMetadata,
  4. DistributionBucketOperatorMetadata,
  5. StorageBucketOperatorMetadata,
  6. GeoCoordinates,
  7. NodeLocationMetadata,
  8. Continent,
  9. GeographicalAreaContinent,
  10. GeographicalAreaCountry,
  11. GeographicalAreaSubdivistion,
  12. DistributionBucketFamilyGeographicArea,
  13. } from 'query-node/dist/model'
  14. import { deserializeMetadata, deterministicEntityId, invalidMetadata } from '../common'
  15. import { Bytes } from '@polkadot/types'
  16. import {
  17. DistributionBucketOperatorMetadata as DistributionBucketOperatorMetadataProto,
  18. StorageBucketOperatorMetadata as StorageBucketOperatorMetadataProto,
  19. DistributionBucketFamilyMetadata as DistributionBucketFamilyMetadataProto,
  20. INodeLocationMetadata,
  21. GeographicalArea as GeographicalAreaProto,
  22. } from '@joystream/metadata-protobuf'
  23. import { isSet, isEmptyObject, isValidCountryCode, isValidSubdivisionCode } from '@joystream/metadata-protobuf/utils'
  24. const protobufContinentToGraphlContinent: { [key in GeographicalAreaProto.Continent]: Continent } = {
  25. [GeographicalAreaProto.Continent.AF]: Continent.AF,
  26. [GeographicalAreaProto.Continent.AN]: Continent.AN,
  27. [GeographicalAreaProto.Continent.AS]: Continent.AS,
  28. [GeographicalAreaProto.Continent.EU]: Continent.EU,
  29. [GeographicalAreaProto.Continent.NA]: Continent.NA,
  30. [GeographicalAreaProto.Continent.OC]: Continent.OC,
  31. [GeographicalAreaProto.Continent.SA]: Continent.SA,
  32. }
  33. async function processNodeLocationMetadata(
  34. event: SubstrateEvent,
  35. store: DatabaseManager,
  36. current: NodeLocationMetadata | undefined,
  37. meta: INodeLocationMetadata
  38. ): Promise<NodeLocationMetadata> {
  39. const nodeLocation = current || new NodeLocationMetadata({ id: deterministicEntityId(event) })
  40. if (isSet(meta.city)) {
  41. nodeLocation.city = meta.city
  42. }
  43. if (isSet(meta.coordinates)) {
  44. if (isEmptyObject(meta.coordinates)) {
  45. nodeLocation.coordinates = null as any
  46. } else {
  47. const coordinates = current?.coordinates || new GeoCoordinates({ id: deterministicEntityId(event) })
  48. coordinates.latitude = meta.coordinates.latitude || coordinates.latitude || 0
  49. coordinates.longitude = meta.coordinates.longitude || coordinates.longitude || 0
  50. await store.save<GeoCoordinates>(coordinates)
  51. nodeLocation.coordinates = coordinates
  52. }
  53. }
  54. if (isSet(meta.countryCode)) {
  55. if (isValidCountryCode(meta.countryCode)) {
  56. nodeLocation.countryCode = meta.countryCode
  57. } else {
  58. console.warn(`Invalid country code: ${meta.countryCode}`)
  59. nodeLocation.countryCode = null as any
  60. }
  61. }
  62. await store.save<NodeLocationMetadata>(nodeLocation)
  63. return nodeLocation
  64. }
  65. export async function processDistributionOperatorMetadata(
  66. event: SubstrateEvent,
  67. store: DatabaseManager,
  68. current: DistributionBucketOperatorMetadata | undefined,
  69. metadataBytes: Bytes
  70. ): Promise<DistributionBucketOperatorMetadata | undefined> {
  71. const meta = deserializeMetadata(DistributionBucketOperatorMetadataProto, metadataBytes)
  72. if (!meta) {
  73. return current
  74. }
  75. const metadataEntity = current || new DistributionBucketOperatorMetadata({ id: deterministicEntityId(event) })
  76. if (isSet(meta.endpoint)) {
  77. metadataEntity.nodeEndpoint = meta.endpoint
  78. }
  79. if (isSet(meta.location)) {
  80. metadataEntity.nodeLocation = isEmptyObject(meta.location)
  81. ? (null as any)
  82. : await processNodeLocationMetadata(event, store, metadataEntity.nodeLocation, meta.location)
  83. }
  84. if (isSet(meta.extra)) {
  85. metadataEntity.extra = meta.extra
  86. }
  87. await store.save<DistributionBucketOperatorMetadata>(metadataEntity)
  88. return metadataEntity
  89. }
  90. export async function processStorageOperatorMetadata(
  91. event: SubstrateEvent,
  92. store: DatabaseManager,
  93. current: StorageBucketOperatorMetadata | undefined,
  94. metadataBytes: Bytes
  95. ): Promise<StorageBucketOperatorMetadata | undefined> {
  96. const meta = deserializeMetadata(StorageBucketOperatorMetadataProto, metadataBytes)
  97. if (!meta) {
  98. return current
  99. }
  100. const metadataEntity = current || new StorageBucketOperatorMetadata({ id: deterministicEntityId(event) })
  101. if (isSet(meta.endpoint)) {
  102. metadataEntity.nodeEndpoint = meta.endpoint || (null as any)
  103. }
  104. if (isSet(meta.location)) {
  105. metadataEntity.nodeLocation = isEmptyObject(meta.location)
  106. ? (null as any)
  107. : await processNodeLocationMetadata(event, store, metadataEntity.nodeLocation, meta.location)
  108. }
  109. if (isSet(meta.extra)) {
  110. metadataEntity.extra = meta.extra || (null as any)
  111. }
  112. await store.save<StorageBucketOperatorMetadata>(metadataEntity)
  113. return metadataEntity
  114. }
  115. export async function processDistributionBucketFamilyMetadata(
  116. event: SubstrateEvent,
  117. store: DatabaseManager,
  118. current: DistributionBucketFamilyMetadata | undefined,
  119. metadataBytes: Bytes
  120. ): Promise<DistributionBucketFamilyMetadata | undefined> {
  121. const meta = deserializeMetadata(DistributionBucketFamilyMetadataProto, metadataBytes)
  122. if (!meta) {
  123. return current
  124. }
  125. const metadataEntity = current || new DistributionBucketFamilyMetadata({ id: deterministicEntityId(event) })
  126. if (isSet(meta.region)) {
  127. metadataEntity.region = meta.region || (null as any)
  128. }
  129. if (isSet(meta.description)) {
  130. metadataEntity.description = meta.description || (null as any)
  131. }
  132. if (isSet(meta.latencyTestTargets)) {
  133. metadataEntity.latencyTestTargets = meta.latencyTestTargets.filter((t) => t)
  134. }
  135. await store.save<DistributionBucketFamilyMetadata>(metadataEntity)
  136. // Update areas after metadata is saved (since we need an id to reference)
  137. if (isSet(meta.areas)) {
  138. // Drop current areas
  139. await Promise.all(metadataEntity.areas?.map((a) => store.remove<DistributionBucketFamilyGeographicArea>(a)) || [])
  140. // Save new areas
  141. await Promise.all(
  142. meta.areas
  143. .filter((a) => !isEmptyObject(a))
  144. .map(async (a) => {
  145. const area = new DistributionBucketFamilyGeographicArea({
  146. distributionBucketFamilyMetadata: metadataEntity,
  147. })
  148. if (a.continent) {
  149. const continent = new GeographicalAreaContinent()
  150. continent.code = protobufContinentToGraphlContinent[a.continent]
  151. if (!continent.code) {
  152. return invalidMetadata(`Unrecognized continent enum variant: ${a.continent}`)
  153. }
  154. area.id = `${metadataEntity.id}-C-${continent.code}`
  155. area.area = continent
  156. } else if (a.countryCode) {
  157. if (!isValidCountryCode(a.countryCode)) {
  158. return invalidMetadata(`Invalid country code: ${a.countryCode}`)
  159. }
  160. const country = new GeographicalAreaCountry()
  161. country.code = a.countryCode
  162. area.id = `${metadataEntity.id}-c-${country.code}`
  163. area.area = country
  164. } else if (a.subdivisionCode) {
  165. if (!isValidSubdivisionCode(a.subdivisionCode)) {
  166. return invalidMetadata(`Invalid subdivision code: ${a.subdivisionCode}`)
  167. }
  168. const subdivision = new GeographicalAreaSubdivistion()
  169. subdivision.code = a.subdivisionCode
  170. area.id = `${metadataEntity.id}-s-${subdivision.code}`
  171. area.area = subdivision
  172. } else {
  173. return
  174. }
  175. await store.save<DistributionBucketFamilyGeographicArea>(area)
  176. })
  177. )
  178. }
  179. return metadataEntity
  180. }