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