101 lines
2.4 KiB
Go
101 lines
2.4 KiB
Go
/*
|
|
Package transport contains the network transport definitions for rs2322tcp.
|
|
|
|
This file implements the framing of control protocol messages. Control
|
|
messages are encoded as one JSON object per line (JSON Lines).
|
|
|
|
Project: rs2322tcp
|
|
Module: git.lang-dieter.de/rs2322tcp
|
|
*/
|
|
package transport
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"io"
|
|
)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Constants
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
const (
|
|
// MaximumControlMessageSize limits the size of one control message.
|
|
MaximumControlMessageSize = 64 * 1024
|
|
)
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Writer
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// WriteMessage writes one control message as a JSON object followed by
|
|
// a newline.
|
|
func WriteMessage(w io.Writer, message interface{}) error {
|
|
if w == nil {
|
|
return fmt.Errorf("writer is nil")
|
|
}
|
|
|
|
if message == nil {
|
|
return fmt.Errorf("message is nil")
|
|
}
|
|
|
|
data, err := json.Marshal(message)
|
|
if err != nil {
|
|
return fmt.Errorf("encode control message: %w", err)
|
|
}
|
|
|
|
if len(data) > MaximumControlMessageSize {
|
|
return fmt.Errorf("control message too large: %d bytes",
|
|
len(data))
|
|
}
|
|
|
|
data = append(data, '\n')
|
|
|
|
if _, err := w.Write(data); err != nil {
|
|
return fmt.Errorf("write control message: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
// Reader
|
|
///////////////////////////////////////////////////////////////////////////////
|
|
|
|
// ReadMessage reads exactly one JSON Lines control message.
|
|
//
|
|
// The target must be a pointer to the expected message structure.
|
|
func ReadMessage(r *bufio.Reader, target interface{}) error {
|
|
if r == nil {
|
|
return fmt.Errorf("reader is nil")
|
|
}
|
|
|
|
if target == nil {
|
|
return fmt.Errorf("target is nil")
|
|
}
|
|
|
|
data, err := r.ReadBytes('\n')
|
|
if err != nil {
|
|
if err == io.EOF && len(data) == 0 {
|
|
return io.EOF
|
|
}
|
|
|
|
if err == io.EOF {
|
|
return fmt.Errorf("incomplete control message: %w", err)
|
|
}
|
|
|
|
return fmt.Errorf("read control message: %w", err)
|
|
}
|
|
|
|
if len(data) > MaximumControlMessageSize {
|
|
return fmt.Errorf("control message too large: %d bytes",
|
|
len(data))
|
|
}
|
|
|
|
if err := json.Unmarshal(data, target); err != nil {
|
|
return fmt.Errorf("decode control message: %w", err)
|
|
}
|
|
|
|
return nil
|
|
}
|