/* Package transport contains the network transport definitions for rs2322tcp. This file defines the control protocol messages. It deliberately does not contain any network I/O. The actual TCP implementation will be added later. Project: rs2322tcp Module: git.lang-dieter.de/rs2322tcp */ package transport import ( "encoding/json" "fmt" "git.lang-dieter.de/rs2322tcp/internal/config" ) /////////////////////////////////////////////////////////////////////////////// // Protocol /////////////////////////////////////////////////////////////////////////////// // ProtocolVersion is the current control protocol version. const ProtocolVersion = 1 // MessageType identifies a control protocol message. type MessageType string const ( MessageHello MessageType = "hello" MessageHelloResponse MessageType = "hello_response" MessageGetDevices MessageType = "get_devices" MessageDeviceList MessageType = "device_list" MessageError MessageType = "error" ) /////////////////////////////////////////////////////////////////////////////// // Generic message /////////////////////////////////////////////////////////////////////////////// // Message is the common envelope for all control protocol messages. type Message struct { Version int `json:"version"` Type MessageType `json:"type"` } /////////////////////////////////////////////////////////////////////////////// // Hello /////////////////////////////////////////////////////////////////////////////// // HelloMessage starts a control session. type HelloMessage struct { Message } // HelloResponseMessage confirms that the server accepts the protocol // version used by the client. type HelloResponseMessage struct { Message } /////////////////////////////////////////////////////////////////////////////// // Get devices /////////////////////////////////////////////////////////////////////////////// // GetDevicesMessage requests the devices currently available from the // server. type GetDevicesMessage struct { Message } /////////////////////////////////////////////////////////////////////////////// // Device list /////////////////////////////////////////////////////////////////////////////// // RemoteDeviceInfo describes a device returned by the server. // // DataPort is runtime information belonging to the current server session. // It is therefore deliberately not part of config.RemoteDevice. type RemoteDeviceInfo struct { ID string `json:"id"` Name string `json:"name"` BaudRate int `json:"baud_rate"` DataBits int `json:"data_bits"` Parity string `json:"parity"` StopBits int `json:"stop_bits"` DataPort int `json:"data_port"` } // DeviceListMessage contains the devices currently available from the // server and their session-specific data ports. type DeviceListMessage struct { Message Devices []RemoteDeviceInfo `json:"devices"` } /////////////////////////////////////////////////////////////////////////////// // Error /////////////////////////////////////////////////////////////////////////////// // ErrorCode identifies a protocol error. type ErrorCode string const ( ErrorUnknownMessage ErrorCode = "unknown_message" ErrorUnsupportedVersion ErrorCode = "unsupported_version" ErrorDeviceNotFound ErrorCode = "device_not_found" ErrorDeviceUnavailable ErrorCode = "device_unavailable" ErrorInternal ErrorCode = "internal_error" ) // ErrorMessage reports a control protocol error. type ErrorMessage struct { Message Code ErrorCode `json:"code"` MessageText string `json:"message"` } /////////////////////////////////////////////////////////////////////////////// // Constructors /////////////////////////////////////////////////////////////////////////////// // NewHello creates a hello message. func NewHello() HelloMessage { return HelloMessage{ Message: Message{ Version: ProtocolVersion, Type: MessageHello, }, } } // NewHelloResponse creates a hello response message. func NewHelloResponse() HelloResponseMessage { return HelloResponseMessage{ Message: Message{ Version: ProtocolVersion, Type: MessageHelloResponse, }, } } // NewGetDevices creates a get-devices message. func NewGetDevices() GetDevicesMessage { return GetDevicesMessage{ Message: Message{ Version: ProtocolVersion, Type: MessageGetDevices, }, } } // NewDeviceList creates a device-list message from a list of remote // devices and their session-specific data ports. func NewDeviceList(devices []RemoteDeviceInfo) DeviceListMessage { return DeviceListMessage{ Message: Message{ Version: ProtocolVersion, Type: MessageDeviceList, }, Devices: devices, } } // NewError creates an error message. func NewError(code ErrorCode, message string) ErrorMessage { return ErrorMessage{ Message: Message{ Version: ProtocolVersion, Type: MessageError, }, Code: code, MessageText: message, } } // NewRemoteDeviceInfo converts a public configuration device description // into the transport representation and adds the session-specific data port. func NewRemoteDeviceInfo(device config.RemoteDevice, dataPort int) RemoteDeviceInfo { return RemoteDeviceInfo{ ID: device.ID, Name: device.Name, BaudRate: device.BaudRate, DataBits: device.DataBits, Parity: device.Parity, StopBits: device.StopBits, DataPort: dataPort, } } /////////////////////////////////////////////////////////////////////////////// // JSON /////////////////////////////////////////////////////////////////////////////// // EncodeMessage encodes a control message as JSON. func EncodeMessage(message interface{}) ([]byte, error) { if message == nil { return nil, fmt.Errorf("message is nil") } return json.Marshal(message) }