12 type publicationValue struct {
13 publication protocol.Publication
14 address protocol.Address
15 metadata protocol.Metadata
22 func newPublicationValue[T any](address protocol.Address, metadata protocol.Metadata, payload T) (publicationValue, error) {
23 metadata, err := newMetadata(metadata)
25 return publicationValue{}, fmt.Errorf("create publication metadata: %w", err)
28 value := publicationValue{
33 value.publication, err = value.build()
35 return publicationValue{}, fmt.Errorf("build typed publication: %w", err)
38 data, err := json.Marshal(payload)
40 return publicationValue{}, fmt.Errorf("encode comparison payload: %w", err)
45 decoder := json.NewDecoder(bytes.NewReader(data))
48 err = decoder.Decode(&normalized)
50 return publicationValue{}, fmt.Errorf("decode comparison payload: %w", err)
53 comparison, err := json.Marshal(normalized)
55 return publicationValue{}, fmt.Errorf("normalize comparison payload: %w", err)
60 err = json.Unmarshal(comparison, &copied)
62 return publicationValue{}, fmt.Errorf("copy publication payload: %w", err)
65 value.payload = copied
66 value.comparison = comparison
68 switch typed := any(copied).(type) {
69 case protocol.ValuePayload:
70 value.measurement = address.Kind == protocol.Telemetry || string(typed.Value) != "true" && string(typed.Value) != "false"
71 case protocol.AvailabilityPayload:
72 value.online = typed.Status == "online"
78 func newMetadata(metadata protocol.Metadata) (protocol.Metadata, error) {
79 now := time.Now().UTC()
80 if metadata.MessageID == "" {
81 id, err := protocol.NewID(now)
83 return protocol.Metadata{}, fmt.Errorf("create message ID: %w", err)
86 metadata.MessageID = id
89 if metadata.SentAt == nil {
90 metadata.SentAt = &now
92 timestamp := *metadata.SentAt
93 metadata.SentAt = ×tamp
96 if metadata.ExpiresAt != nil {
97 timestamp := *metadata.ExpiresAt
98 metadata.ExpiresAt = ×tamp
104 func (v publicationValue) build() (protocol.Publication, error) {
106 publication protocol.Publication
110 switch payload := v.payload.(type) {
111 case protocol.DescriptorPayload:
112 publication, err = protocol.BuildDescriptor(v.address.ID, v.metadata, payload)
113 case protocol.AvailabilityPayload:
114 publication, err = protocol.BuildAvailability(v.address.ID, v.metadata, payload)
115 case protocol.ValuePayload:
116 if v.address.Kind == protocol.Telemetry {
117 publication, err = protocol.BuildTelemetry(v.address.ID, v.address.Target, v.metadata, payload)
119 publication, err = protocol.BuildReported(v.address.ID, v.address.Target, v.metadata, payload)
121 case protocol.EventPayload:
122 publication, err = protocol.BuildEvent(v.address.ID, v.address.Target, v.metadata, payload)
123 case protocol.ResultPayload:
124 publication, err = protocol.BuildResult(v.address.ID, v.address.Target, v.metadata, payload)
126 return protocol.Publication{}, fmt.Errorf("unsupported publication payload")
130 return protocol.Publication{}, fmt.Errorf("build %s: %w", v.address.Kind, err)
133 return publication, nil
136 func (v publicationValue) repeated() (publicationValue, error) {
137 metadata, err := newMetadata(protocol.Metadata{SentAt: v.metadata.SentAt})
139 return publicationValue{}, fmt.Errorf("create repeat metadata: %w", err)
142 v.metadata = metadata
143 if v.address.Kind == protocol.Telemetry {
144 v.address.Kind = protocol.Reported
147 v.publication, err = v.build()
149 return publicationValue{}, fmt.Errorf("build repeated publication: %w", err)