rs2322tcp/internal/transport/control.go
2026-08-10 10:38:14 +02:00

202 lines
5.6 KiB
Go

/*
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)
}