diff --git a/generated/schema.graphql b/generated/schema.graphql index 70864b3..6991db6 100644 --- a/generated/schema.graphql +++ b/generated/schema.graphql @@ -432,10 +432,10 @@ enum DistributionBucketOperatorMetadataOrderByInput { nodeOperationalStatus_from_DESC nodeOperationalStatus_from_ASC_NULLS_FIRST nodeOperationalStatus_from_DESC_NULLS_LAST - nodeOperationalStatus_to_ASC - nodeOperationalStatus_to_DESC - nodeOperationalStatus_to_ASC_NULLS_FIRST - nodeOperationalStatus_to_DESC_NULLS_LAST + nodeOperationalStatus_until_ASC + nodeOperationalStatus_until_DESC + nodeOperationalStatus_until_ASC_NULLS_FIRST + nodeOperationalStatus_until_DESC_NULLS_LAST nodeOperationalStatus_isTypeOf_ASC nodeOperationalStatus_isTypeOf_DESC nodeOperationalStatus_isTypeOf_ASC_NULLS_FIRST @@ -1014,7 +1014,7 @@ input NodeLocationMetadataWhereInput { coordinates: GeoCoordinatesWhereInput } -union NodeOperationalStatus = NodeOperationalStatusNormal | NodeOperationalStatusNoService | NodeOperationalStatusNoServiceFrom | NodeOperationalStatusNoServiceDuring +union NodeOperationalStatus = NodeOperationalStatusNormal | NodeOperationalStatusNoService | NodeOperationalStatusNoServiceFrom | NodeOperationalStatusNoServiceUntil type NodeOperationalStatusNormal { """Reason why node was set to this state""" @@ -1032,7 +1032,7 @@ type NodeOperationalStatusNoService { rationale: String } -type NodeOperationalStatusNoServiceDuring { +type NodeOperationalStatusNoServiceFrom { """ Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing. @@ -1042,14 +1042,11 @@ type NodeOperationalStatusNoServiceDuring { """The time from which the bucket would have to no service""" from: DateTime! - """The time until which the bucket would have to no service""" - to: DateTime! - """Reason why node was set to this state""" rationale: String } -type NodeOperationalStatusNoServiceFrom { +type NodeOperationalStatusNoServiceUntil { """ Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing. @@ -1059,6 +1056,9 @@ type NodeOperationalStatusNoServiceFrom { """The time from which the bucket would have to no service""" from: DateTime! + """The time until which the bucket would have to no service""" + until: DateTime! + """Reason why node was set to this state""" rationale: String } @@ -1093,15 +1093,15 @@ input NodeOperationalStatusWhereInput { from_lte: DateTime from_in: [DateTime!] from_not_in: [DateTime!] - to_isNull: Boolean - to_eq: DateTime - to_not_eq: DateTime - to_gt: DateTime - to_gte: DateTime - to_lt: DateTime - to_lte: DateTime - to_in: [DateTime!] - to_not_in: [DateTime!] + until_isNull: Boolean + until_eq: DateTime + until_not_eq: DateTime + until_gt: DateTime + until_gte: DateTime + until_lt: DateTime + until_lte: DateTime + until_in: [DateTime!] + until_not_in: [DateTime!] isTypeOf_isNull: Boolean isTypeOf_eq: String isTypeOf_not_eq: String @@ -1593,10 +1593,10 @@ enum StorageBucketOperatorMetadataOrderByInput { nodeOperationalStatus_from_DESC nodeOperationalStatus_from_ASC_NULLS_FIRST nodeOperationalStatus_from_DESC_NULLS_LAST - nodeOperationalStatus_to_ASC - nodeOperationalStatus_to_DESC - nodeOperationalStatus_to_ASC_NULLS_FIRST - nodeOperationalStatus_to_DESC_NULLS_LAST + nodeOperationalStatus_until_ASC + nodeOperationalStatus_until_DESC + nodeOperationalStatus_until_ASC_NULLS_FIRST + nodeOperationalStatus_until_DESC_NULLS_LAST nodeOperationalStatus_isTypeOf_ASC nodeOperationalStatus_isTypeOf_DESC nodeOperationalStatus_isTypeOf_ASC_NULLS_FIRST diff --git a/schema/storage.graphql b/schema/storage.graphql index 4bcf152..64dad14 100644 --- a/schema/storage.graphql +++ b/schema/storage.graphql @@ -86,7 +86,7 @@ type NodeOperationalStatusNoServiceFrom { rationale: String } -type NodeOperationalStatusNoServiceDuring { +type NodeOperationalStatusNoServiceUntil { "Whether the state was set by lead (true) or by the operator (false), it is meant to prevent worker from unilaterally reversing." forced: Boolean! @@ -94,7 +94,7 @@ type NodeOperationalStatusNoServiceDuring { from: DateTime! "The time until which the bucket would have to no service" - to: DateTime! + until: DateTime! "Reason why node was set to this state" rationale: String @@ -104,7 +104,7 @@ union NodeOperationalStatus = NodeOperationalStatusNormal | NodeOperationalStatusNoService | NodeOperationalStatusNoServiceFrom - | NodeOperationalStatusNoServiceDuring + | NodeOperationalStatusNoServiceUntil type StorageBucketOperatorMetadata @entity { id: ID! diff --git a/src/mappings/storage/metadata.ts b/src/mappings/storage/metadata.ts index cd81116..ddeba17 100644 --- a/src/mappings/storage/metadata.ts +++ b/src/mappings/storage/metadata.ts @@ -4,9 +4,10 @@ import { IDistributionBucketOperatorMetadata, IGeographicalArea, INodeLocationMetadata, - INodeOperationalStatusMetadata, + INodeOperationalStatus, IStorageBucketOperatorMetadata, - NodeOperationalStatusMetadata, + NodeOperationalStatusNoServiceFrom as NodeOperationalStatusNoServiceFromMetadata, + NodeOperationalStatusNoServiceUntil as NodeOperationalStatusNoServiceUntilMetadata, } from '@joystream/metadata-protobuf' import { DecodedMetadataObject } from '@joystream/metadata-protobuf/types' import { @@ -29,13 +30,13 @@ import { NodeLocationMetadata, NodeOperationalStatus, NodeOperationalStatusNoService, - NodeOperationalStatusNoServiceDuring, NodeOperationalStatusNoServiceFrom, + NodeOperationalStatusNoServiceUntil, NodeOperationalStatusNormal, StorageBucketOperatorMetadata, } from '../../model' import { EntityManagerOverlay, Flat } from '../../utils/overlay' -import { invalidMetadata } from '../utils' +import { invalidMetadata, parseDateStr } from '../utils' export const protobufContinentToGraphlContinent: { [key in GeographicalAreaProto.Continent]: Continent @@ -68,7 +69,7 @@ export async function processStorageOperatorMetadata( processNodeLocationMetadata(operatorMetadata, metadataUpdate.location) } if (isSet(metadataUpdate.operationalStatus)) { - processNodeOperationalStatusMetadata( + operatorMetadata.nodeOperationalStatus = processNodeOperationalStatusMetadata( 'worker', operatorMetadata.nodeOperationalStatus, metadataUpdate.operationalStatus @@ -120,13 +121,13 @@ function processNodeLocationMetadata( export function processNodeOperationalStatusMetadata( actorContext: 'lead' | 'worker', currentStatus: NodeOperationalStatus | null | undefined, - meta: INodeOperationalStatusMetadata -): NodeOperationalStatus { + meta: INodeOperationalStatus +): NodeOperationalStatus | null | undefined { const isCurrentStatusForced = currentStatus && (currentStatus instanceof NodeOperationalStatusNoService || currentStatus instanceof NodeOperationalStatusNoServiceFrom || - currentStatus instanceof NodeOperationalStatusNoServiceDuring) && + currentStatus instanceof NodeOperationalStatusNoServiceUntil) && currentStatus.forced // if current state is forced by lead, then prevent worker from unilaterally reversing. @@ -134,59 +135,56 @@ export function processNodeOperationalStatusMetadata( return currentStatus } - // Validate date formats - let validatedNoServiceFrom: Date | undefined - let validatedNoServiceTo: Date | undefined - - try { - if (meta.noServiceFrom) { - new Date(meta.noServiceFrom).toISOString() - validatedNoServiceFrom = new Date(meta.noServiceFrom) - } - } catch (error) { - invalidMetadata(NodeOperationalStatusMetadata, `Invalid date format for "noServiceFrom"`, { - decodedMessage: meta, - }) + // For status type Normal + if (meta.normal) { + const status = new NodeOperationalStatusNormal() + status.rationale = meta.normal.rationale + return status } - - try { - if (meta.noServiceTo) { - new Date(meta.noServiceTo).toISOString() - validatedNoServiceTo = new Date(meta.noServiceTo) - } - } catch (error) { - invalidMetadata(NodeOperationalStatusMetadata, `Invalid date format for "noServiceTo"`, { - decodedMessage: meta, - }) + // For status type NoService + else if (meta.noService) { + const status = new NodeOperationalStatusNoService() + status.rationale = meta.noService.rationale + status.forced = actorContext === 'lead' + return status } + // For status type NoServiceFrom + else if (meta.noServiceFrom) { + const from = parseDateStr(meta.noServiceFrom.from) + if (!from) { + invalidMetadata( + NodeOperationalStatusNoServiceFromMetadata, + `Invalid date format for "noServiceFrom"`, + { decodedMessage: meta.noServiceFrom } + ) + return currentStatus + } - // set node state to NoService - if (meta.status === NodeOperationalStatusMetadata.OperationalStatus.NO_SERVICE) { - if (validatedNoServiceFrom && validatedNoServiceTo) { - const status = new NodeOperationalStatusNoServiceDuring() - status.rationale = meta.rationale - status.forced = actorContext === 'lead' - status.from = validatedNoServiceFrom - status.to = validatedNoServiceTo - return status - } else if (validatedNoServiceFrom && !validatedNoServiceTo) { - const status = new NodeOperationalStatusNoServiceFrom() - status.rationale = meta.rationale - status.forced = actorContext === 'lead' - status.from = validatedNoServiceFrom - return status - } else if (!validatedNoServiceFrom && !validatedNoServiceTo) { - const status = new NodeOperationalStatusNoService() - status.rationale = meta.rationale - status.forced = actorContext === 'lead' - return status + const status = new NodeOperationalStatusNoServiceFrom() + status.rationale = meta.noServiceFrom.rationale + status.forced = actorContext === 'lead' + status.from = from + return status + } + // For status type NoServiceUntil + else if (meta.noServiceUntil) { + const from = meta.noServiceUntil.from ? parseDateStr(meta.noServiceUntil.from) : new Date() + const until = parseDateStr(meta.noServiceUntil.until) + if (!from || !until) { + invalidMetadata( + NodeOperationalStatusNoServiceUntilMetadata, + `Invalid date format for "noServiceUntil"`, + { decodedMessage: meta.noServiceUntil } + ) + return currentStatus } + const status = new NodeOperationalStatusNoServiceUntil() + status.rationale = meta.noServiceUntil.rationale + status.forced = actorContext === 'lead' + status.from = from + status.until = until + return status } - - // Default operational status of the node - const status = new NodeOperationalStatusNormal() - status.rationale = meta.rationale - return status } export async function processDistributionOperatorMetadata( @@ -208,7 +206,7 @@ export async function processDistributionOperatorMetadata( processNodeLocationMetadata(operatorMetadata, metadataUpdate.location) } if (isSet(metadataUpdate.operationalStatus)) { - processNodeOperationalStatusMetadata( + operatorMetadata.nodeOperationalStatus = processNodeOperationalStatusMetadata( 'worker', operatorMetadata.nodeOperationalStatus, metadataUpdate.operationalStatus diff --git a/src/mappings/utils.ts b/src/mappings/utils.ts index 5e12382..3435df3 100644 --- a/src/mappings/utils.ts +++ b/src/mappings/utils.ts @@ -109,3 +109,15 @@ export function toLowerFirstLetter(str: string) { if (!str) return '' // Return an empty string if str is falsy return str.charAt(0).toLowerCase() + str.slice(1) } + +export function parseDateStr(date: string): Date | undefined { + try { + if (date) { + const dateObj = new Date(date) + dateObj.toISOString() // Throws an error if the date is invalid + return dateObj + } + } catch (error) { + console.error(`Invalid date format:`, date) + } +}