202 lines
5.6 KiB
Go
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)
|
|
}
|