metadata.ts 6.9 KB

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