]> git.giacomolli.uk - onehouse/blobdiff - protocol/message.go
Exchange bounded M31 Modbus TCP requests
[onehouse] / protocol / message.go
index cb575d2eca521743e840b6ff823e169d7b3d9c0f..50a2e1ce22ea34c893af7d0d550a04412c38378e 100644 (file)
@@ -42,41 +42,28 @@ func Parse(topic string, data []byte, retained bool) (Message[any], error) {
 
        switch address.Kind {
        case Descriptor:
 
        switch address.Kind {
        case Descriptor:
-               return eraseMessage(ParseDescriptor(topic, data, retained))
+               return eraseMessage(parsePayload[DescriptorPayload](address, data, retained))
        case Availability:
        case Availability:
-               return eraseMessage(ParseAvailability(topic, data, retained))
+               return eraseMessage(parsePayload[AvailabilityPayload](address, data, retained))
        case Reported:
        case Reported:
-               return eraseMessage(ParseReported(topic, data, retained))
+               return eraseMessage(parsePayload[ValuePayload](address, data, retained))
        case Telemetry:
        case Telemetry:
-               return eraseMessage(ParseTelemetry(topic, data, retained))
+               return eraseMessage(parsePayload[ValuePayload](address, data, retained))
        case Event:
        case Event:
-               return eraseMessage(ParseEvent(topic, data, retained))
+               return eraseMessage(parsePayload[EventPayload](address, data, retained))
        case Command:
        case Command:
-               return eraseMessage(ParseCommand(topic, data, retained))
+               return eraseMessage(parsePayload[ValuePayload](address, data, retained))
        case CommandBatch:
        case CommandBatch:
-               return eraseMessage(ParseCommandBatch(topic, data, retained))
+               return eraseMessage(parsePayload[BatchPayload](address, data, retained))
        case Result:
        case Result:
-               return eraseMessage(ParseResult(topic, data, retained))
+               return eraseMessage(parsePayload[ResultPayload](address, data, retained))
        case HubStatus:
        case HubStatus:
-               return eraseMessage(ParseHubStatus(topic, data, retained))
+               return eraseMessage(parsePayload[HubStatusPayload](address, data, retained))
        default:
                return Message[any]{}, fmt.Errorf("unsupported message kind")
        }
 }
 
        default:
                return Message[any]{}, fmt.Errorf("unsupported message kind")
        }
 }
 
-func eraseMessage[T any](message Message[T], err error) (Message[any], error) {
-       if err != nil {
-               return Message[any]{}, fmt.Errorf("parse message: %w", err)
-       }
-
-       return Message[any]{
-               Address:  message.Address,
-               Metadata: message.Metadata,
-               Payload:  message.Payload,
-               Retained: message.Retained,
-       }, nil
-}
-
 func buildMessage[T any](address Address, metadata Metadata, payload T) (Publication, error) {
        topic, err := address.topic()
        if err != nil {
 func buildMessage[T any](address Address, metadata Metadata, payload T) (Publication, error) {
        topic, err := address.topic()
        if err != nil {
@@ -156,6 +143,19 @@ func parseMessage[T any](kind Kind, topic string, data []byte, retained bool) (M
        return message, nil
 }
 
        return message, nil
 }
 
+func eraseMessage[T any](message Message[T], err error) (Message[any], error) {
+       if err != nil {
+               return Message[any]{}, fmt.Errorf("parse message: %w", err)
+       }
+
+       return Message[any]{
+               Address:  message.Address,
+               Metadata: message.Metadata,
+               Payload:  message.Payload,
+               Retained: message.Retained,
+       }, nil
+}
+
 func parsePayload[T any](address Address, data []byte, retained bool) (Message[T], error) {
        kind := address.Kind
 
 func parsePayload[T any](address Address, data []byte, retained bool) (Message[T], error) {
        kind := address.Kind
 
@@ -252,28 +252,6 @@ func validatePayload(address Address, metadata Metadata, payload any) error {
        return nil
 }
 
        return nil
 }
 
-func validateDescriptor(payload DescriptorPayload) error {
-       if payload.Manufacturer == "" || payload.Model == "" || payload.Firmware == "" || len(string([]rune(payload.Attribution))) > 2000 || len(payload.Capabilities) == 0 {
-               return fmt.Errorf("descriptor metadata or capabilities are invalid")
-       }
-
-       seen := make(map[string]bool, len(payload.Capabilities))
-
-       for _, capability := range payload.Capabilities {
-               if !ValidIdentifier(capability.ID) || !ValidIdentifier(capability.Type) || seen[capability.ID] {
-                       return fmt.Errorf("capability IDs and types must be valid and unique")
-               }
-
-               if !capability.ReportsState && !capability.AcceptsCommands {
-                       return fmt.Errorf("capability must have at least one access mode")
-               }
-
-               seen[capability.ID] = true
-       }
-
-       return nil
-}
-
 func validateDescriptorFlags(raw json.RawMessage) error {
        var fields struct {
                Capabilities []map[string]json.RawMessage `json:"capabilities"`
 func validateDescriptorFlags(raw json.RawMessage) error {
        var fields struct {
                Capabilities []map[string]json.RawMessage `json:"capabilities"`
@@ -296,6 +274,28 @@ func validateDescriptorFlags(raw json.RawMessage) error {
        return nil
 }
 
        return nil
 }
 
+func validateDescriptor(payload DescriptorPayload) error {
+       if payload.Manufacturer == "" || payload.Model == "" || payload.Firmware == "" || len(string([]rune(payload.Attribution))) > 2000 || len(payload.Capabilities) == 0 {
+               return fmt.Errorf("descriptor metadata or capabilities are invalid")
+       }
+
+       seen := make(map[string]bool, len(payload.Capabilities))
+
+       for _, capability := range payload.Capabilities {
+               if !ValidIdentifier(capability.ID) || !ValidIdentifier(capability.Type) || seen[capability.ID] {
+                       return fmt.Errorf("capability IDs and types must be valid and unique")
+               }
+
+               if !capability.ReportsState && !capability.AcceptsCommands {
+                       return fmt.Errorf("capability must have at least one access mode")
+               }
+
+               seen[capability.ID] = true
+       }
+
+       return nil
+}
+
 func validateAvailability(payload AvailabilityPayload) error {
        if payload.Status != "online" && payload.Status != "offline" {
                return fmt.Errorf("availability must be online or offline")
 func validateAvailability(payload AvailabilityPayload) error {
        if payload.Status != "online" && payload.Status != "offline" {
                return fmt.Errorf("availability must be online or offline")