diff --git a/docs/architecture.md b/docs/architecture.md index 105c0ec..1f9f3a2 100644 --- a/docs/architecture.md +++ b/docs/architecture.md @@ -37,8 +37,8 @@ The `Transport` manages a WebSocket server (gorilla/websocket) and outbound conn | Field | Default | Purpose | |-------|---------|---------| | `ListenAddr` | `:9091` | HTTP bind address | -| `WSPath` | `/ws` | WebSocket endpoint | -| `MaxConns` | 100 | Maximum concurrent connections | +| `WebSocketPath` | `/ws` | WebSocket endpoint | +| `MaxConnections` | 100 | Maximum concurrent connections | | `MaxMessageSize` | 1 MB | Read limit per message | | `PingInterval` | 30 s | Keepalive ping period | | `PongTimeout` | 10 s | Maximum time to wait for pong | @@ -56,7 +56,7 @@ The `Transport` manages a WebSocket server (gorilla/websocket) and outbound conn **Rate limiting**: Each `PeerConnection` holds a `PeerRateLimiter` (token bucket: 100 burst, 50 tokens/second refill). Messages from rate-limited peers are dropped in the read loop. -**MaxConns enforcement**: The handler tracks `pendingConns` (atomic counter) during the handshake phase in addition to established connections, preventing races where a surge of simultaneous inbounds could exceed the limit. +**MaxConnections enforcement**: The handler tracks `pendingHandshakeCount` (atomic counter) during the handshake phase in addition to established connections, preventing races where a surge of simultaneous inbounds could exceed the limit. **Keepalive**: A goroutine per connection ticks at `PingInterval`. If `LastActivity` has not been updated within `PingInterval + PongTimeout`, the connection is removed. @@ -244,7 +244,7 @@ A global logger instance is available via `logging.Debug(...)`, `logging.Info(.. | `Controller.pending` | `sync.RWMutex` | | `MessageDeduplicator.seen` | `sync.RWMutex` | | `Dispatcher.handlers` | `sync.RWMutex` | -| `Transport.pendingConns` | `atomic.Int32` | +| `Transport.pendingHandshakeCount` | `atomic.Int32` | The codebase is verified race-free under `go test -race`. diff --git a/docs/development.md b/docs/development.md index 8d2bd3b..196c370 100644 --- a/docs/development.md +++ b/docs/development.md @@ -233,7 +233,7 @@ Examples: ``` feat(dispatcher): implement UEPS threat circuit breaker -test(transport): add keepalive timeout and MaxConns enforcement tests +test(transport): add keepalive timeout and MaxConnections enforcement tests fix(peer): prevent data race in GracefulClose (P2P-RACE-1) ``` diff --git a/docs/history.md b/docs/history.md index 52ea3f2..5c42f56 100644 --- a/docs/history.md +++ b/docs/history.md @@ -28,7 +28,7 @@ Tests covered: - Encrypted message round-trip: SMSG encrypt on one side, decrypt on other - Message deduplication: duplicate UUID dropped silently - Rate limiting: burst of more than 100 messages, subsequent drops after token bucket empties -- MaxConns enforcement: 503 HTTP rejection when limit is reached +- MaxConnections enforcement: 503 HTTP rejection when limit is reached - Keepalive timeout: connection cleaned up after `PingInterval + PongTimeout` elapses - Graceful close: `MsgDisconnect` sent before underlying WebSocket close - Concurrent sends: no data races under `go test -race` (`writeMu` protects all writes) @@ -92,7 +92,7 @@ The `TagPayload` (0xFF) field now uses the same 2-byte length prefix as the othe ### No Resource Cleanup on Some Error Paths -`transport.handleWSUpgrade` does not clean up on handshake timeout (the `pendingConns` counter is decremented correctly via `defer`, but the underlying WebSocket connection may linger briefly before the read deadline fires). `transport.Connect` does not clean up the temporary connection object on handshake failure (the raw WebSocket `conn` is closed, but there is no registry or metrics cleanup for the partially constructed `PeerConnection`). +`transport.handleWebSocketUpgrade` does not clean up on handshake timeout (the `pendingHandshakeCount` counter is decremented correctly via `defer`, but the underlying WebSocket connection may linger briefly before the read deadline fires). `transport.Connect` does not clean up the temporary connection object on handshake failure (the raw WebSocket `conn` is closed, but there is no registry or metrics cleanup for the partially constructed `PeerConnection`). These are low-severity gaps. They do not cause goroutine leaks under the current implementation because the connection's read loop is not started until after a successful handshake. diff --git a/docs/transport.md b/docs/transport.md index 19a7987..5aad542 100644 --- a/docs/transport.md +++ b/docs/transport.md @@ -12,10 +12,10 @@ The `Transport` manages encrypted WebSocket connections between nodes. After an ```go type TransportConfig struct { ListenAddr string // ":9091" default - WSPath string // "/ws" -- WebSocket endpoint path + WebSocketPath string // "/ws" -- WebSocket endpoint path TLSCertPath string // Optional TLS for wss:// TLSKeyPath string - MaxConns int // Maximum concurrent connections (default 100) + MaxConnections int // Maximum concurrent connections (default 100) MaxMessageSize int64 // Maximum message size in bytes (default 1MB) PingInterval time.Duration // Keepalive interval (default 30s) PongTimeout time.Duration // Pong wait timeout (default 10s) @@ -26,7 +26,7 @@ Sensible defaults via `DefaultTransportConfig()`: ```go cfg := node.DefaultTransportConfig() -// ListenAddr: ":9091", WSPath: "/ws", MaxConns: 100 +// ListenAddr: ":9091", WebSocketPath: "/ws", MaxConnections: 100 // MaxMessageSize: 1MB, PingInterval: 30s, PongTimeout: 10s ``` @@ -123,9 +123,9 @@ const ( ## Incoming Connections -The transport exposes an HTTP handler at the configured `WSPath` that upgrades to WebSocket. Origin checks restrict browser clients to `localhost`, `127.0.0.1`, and `::1`; non-browser clients (no `Origin` header) are allowed. +The transport exposes an HTTP handler at the configured `WebSocketPath` that upgrades to WebSocket. Origin checks restrict browser clients to `localhost`, `127.0.0.1`, and `::1`; non-browser clients (no `Origin` header) are allowed. -The `MaxConns` limit is enforced before the WebSocket upgrade, counting both established and pending (mid-handshake) connections. Excess connections receive HTTP 503. +The `MaxConnections` limit is enforced before the WebSocket upgrade, counting both established and pending (mid-handshake) connections. Excess connections receive HTTP 503. ## Message Deduplication @@ -166,7 +166,7 @@ err = transport.Send(peerID, msg) err = transport.Broadcast(msg) // Query connections -count := transport.ConnectedPeers() +count := transport.ConnectedPeerCount() conn := transport.GetConnection(peerID) // Iterate over all connections diff --git a/docs/ueps.md b/docs/ueps.md index 2ba184a..09c0b71 100644 --- a/docs/ueps.md +++ b/docs/ueps.md @@ -25,8 +25,8 @@ Each field is encoded as a 1-byte tag, 2-byte big-endian length (uint16), and va | Tag | Constant | Value Size | Description | |-----|----------|------------|-------------| | `0x01` | `TagVersion` | 1 byte | Protocol version (default `0x09` for IPv9) | -| `0x02` | `TagCurrentLay` | 1 byte | Current network layer | -| `0x03` | `TagTargetLay` | 1 byte | Target network layer | +| `0x02` | `TagCurrentLayer` | 1 byte | Current network layer | +| `0x03` | `TagTargetLayer` | 1 byte | Target network layer | | `0x04` | `TagIntent` | 1 byte | Semantic intent token (routes the packet) | | `0x05` | `TagThreatScore` | 2 bytes | Threat score (0--65535, big-endian uint16) | | `0x06` | `TagHMAC` | 32 bytes | HMAC-SHA256 signature | diff --git a/logging/compat.go b/logging/compat.go deleted file mode 100644 index 74f014b..0000000 --- a/logging/compat.go +++ /dev/null @@ -1,27 +0,0 @@ -// SPDX-License-Identifier: EUPL-1.2 - -package logging - -// WithComponent returns a new Logger scoped to one component. -// Deprecated: Use ComponentLogger instead. -// -// transportLogger := logger.WithComponent("transport") -func (l *Logger) WithComponent(component string) *Logger { - return l.ComponentLogger(component) -} - -// Level returns the current log level. -// Deprecated: Use GetLevel instead. -// -// level := logger.Level() -func (l *Logger) Level() Level { - return l.GetLevel() -} - -// Global returns the global logger instance. -// Deprecated: Use GetGlobal instead. -// -// logger := Global() -func Global() *Logger { - return GetGlobal() -} diff --git a/logging/compat_test.go b/logging/compat_test.go deleted file mode 100644 index 1310c17..0000000 --- a/logging/compat_test.go +++ /dev/null @@ -1,39 +0,0 @@ -package logging - -import ( - "bytes" - "testing" - - core "dappco.re/go/core" -) - -func TestGetLevel_Good(t *testing.T) { - logger := New(Config{Output: &bytes.Buffer{}, Level: LevelWarn}) - if logger.GetLevel() != LevelWarn { - t.Errorf("GetLevel() = %v, want %v", logger.GetLevel(), LevelWarn) - } - if logger.GetLevel() != logger.Level() { - t.Error("GetLevel() and Level() should return the same value") - } -} - -func TestWithComponent_Good(t *testing.T) { - var buf bytes.Buffer - parent := New(Config{Output: &buf, Level: LevelInfo}) - child := parent.WithComponent("TestChild") - child.Info("test message") - if !core.Contains(buf.String(), "[TestChild]") { - t.Error("WithComponent should set the component name") - } -} - -func TestGetGlobal_Good(t *testing.T) { - var buf bytes.Buffer - logger := New(Config{Output: &buf, Level: LevelInfo}) - SetGlobal(logger) - got := GetGlobal() - if got != Global() { - t.Error("GetGlobal() and Global() should return the same logger") - } - SetGlobal(New(DefaultConfig())) -} diff --git a/node/compat.go b/node/compat.go deleted file mode 100644 index fce12ad..0000000 --- a/node/compat.go +++ /dev/null @@ -1,46 +0,0 @@ -// SPDX-License-Identifier: EUPL-1.2 - -// This file provides deprecated compatibility aliases and type aliases -// for spec compatibility. Canonical names are defined in their respective -// source files; these aliases exist so that code written against the spec -// documentation continues to compile. - -package node - -// NewNodeManagerWithPaths loads or creates a node identity store at explicit paths. -// Deprecated: Use NewNodeManagerFromPaths instead. -// -// nodeManager, err := NewNodeManagerWithPaths("/srv/p2p/private.key", "/srv/p2p/node.json") -func NewNodeManagerWithPaths(keyPath, configPath string) (*NodeManager, error) { - return NewNodeManagerFromPaths(keyPath, configPath) -} - -// NewPeerRegistryWithPath loads or creates a peer registry at an explicit path. -// Deprecated: Use NewPeerRegistryFromPath instead. -// -// peerRegistry, err := NewPeerRegistryWithPath("/srv/p2p/peers.json") -func NewPeerRegistryWithPath(peersPath string) (*PeerRegistry, error) { - return NewPeerRegistryFromPath(peersPath) -} - -// RegisterWithTransport installs the worker message handler on the transport. -// Deprecated: Use RegisterOnTransport instead. -// -// worker.RegisterWithTransport() -func (w *Worker) RegisterWithTransport() { - w.RegisterOnTransport() -} - -// ConnectedPeers returns the number of connected peers. -// Deprecated: Use ConnectedPeerCount instead. -// -// count := transport.ConnectedPeers() -func (t *Transport) ConnectedPeers() int { - return t.ConnectedPeerCount() -} - -// GetLogsPayload is an alias for LogsRequestPayload. -// Provided for spec compatibility. -// -// payload := GetLogsPayload{MinerName: "xmrig-0", Lines: 100} -type GetLogsPayload = LogsRequestPayload diff --git a/node/compat_test.go b/node/compat_test.go deleted file mode 100644 index 9b197aa..0000000 --- a/node/compat_test.go +++ /dev/null @@ -1,57 +0,0 @@ -package node - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestNewNodeManagerWithPaths_Good(t *testing.T) { - keyPath := t.TempDir() + "/private.key" - configPath := t.TempDir() + "/node.json" - - nm, err := NewNodeManagerWithPaths(keyPath, configPath) - require.NoError(t, err) - assert.NotNil(t, nm) - assert.False(t, nm.HasIdentity(), "fresh manager should have no identity") -} - -func TestNewPeerRegistryWithPath_Good(t *testing.T) { - peersPath := t.TempDir() + "/peers.json" - - pr, err := NewPeerRegistryWithPath(peersPath) - require.NoError(t, err) - assert.NotNil(t, pr) - assert.Equal(t, 0, pr.Count()) - pr.Close() -} - -func TestGetLogsPayload_Good(t *testing.T) { - var payload GetLogsPayload - payload.MinerName = "xmrig-0" - payload.Lines = 100 - payload.Since = 1234567890 - - var request LogsRequestPayload = payload - assert.Equal(t, "xmrig-0", request.MinerName) - assert.Equal(t, 100, request.Lines) - assert.Equal(t, int64(1234567890), request.Since) -} - -func TestTransportConnectedPeers_Good(t *testing.T) { - keyPath := t.TempDir() + "/private.key" - configPath := t.TempDir() + "/node.json" - peersPath := t.TempDir() + "/peers.json" - - nm, err := NewNodeManagerFromPaths(keyPath, configPath) - require.NoError(t, err) - - pr, err := NewPeerRegistryFromPath(peersPath) - require.NoError(t, err) - defer pr.Close() - - transport := NewTransport(nm, pr, DefaultTransportConfig()) - assert.Equal(t, transport.ConnectedPeerCount(), transport.ConnectedPeers()) - assert.Equal(t, 0, transport.ConnectedPeers()) -} diff --git a/node/levin/compat.go b/node/levin/compat.go deleted file mode 100644 index a88bdfb..0000000 --- a/node/levin/compat.go +++ /dev/null @@ -1,87 +0,0 @@ -// Copyright (c) 2024-2026 Lethean Contributors -// SPDX-License-Identifier: EUPL-1.2 - -// This file provides short-form aliases for Value constructors, -// matching the naming used in the spec documentation. - -package levin - -// Uint64Val creates a Value of TypeUint64. Short-form alias for Uint64Value. -// -// value := Uint64Val(42) -func Uint64Val(v uint64) Value { return Uint64Value(v) } - -// Uint32Val creates a Value of TypeUint32. Short-form alias for Uint32Value. -// -// value := Uint32Val(42) -func Uint32Val(v uint32) Value { return Uint32Value(v) } - -// Uint16Val creates a Value of TypeUint16. Short-form alias for Uint16Value. -// -// value := Uint16Val(42) -func Uint16Val(v uint16) Value { return Uint16Value(v) } - -// Uint8Val creates a Value of TypeUint8. Short-form alias for Uint8Value. -// -// value := Uint8Val(42) -func Uint8Val(v uint8) Value { return Uint8Value(v) } - -// Int64Val creates a Value of TypeInt64. Short-form alias for Int64Value. -// -// value := Int64Val(42) -func Int64Val(v int64) Value { return Int64Value(v) } - -// Int32Val creates a Value of TypeInt32. Short-form alias for Int32Value. -// -// value := Int32Val(42) -func Int32Val(v int32) Value { return Int32Value(v) } - -// Int16Val creates a Value of TypeInt16. Short-form alias for Int16Value. -// -// value := Int16Val(42) -func Int16Val(v int16) Value { return Int16Value(v) } - -// Int8Val creates a Value of TypeInt8. Short-form alias for Int8Value. -// -// value := Int8Val(42) -func Int8Val(v int8) Value { return Int8Value(v) } - -// BoolVal creates a Value of TypeBool. Short-form alias for BoolValue. -// -// value := BoolVal(true) -func BoolVal(v bool) Value { return BoolValue(v) } - -// DoubleVal creates a Value of TypeDouble. Short-form alias for DoubleValue. -// -// value := DoubleVal(3.14) -func DoubleVal(v float64) Value { return DoubleValue(v) } - -// StringVal creates a Value of TypeString. Short-form alias for StringValue. -// -// value := StringVal([]byte("hello")) -func StringVal(v []byte) Value { return StringValue(v) } - -// ObjectVal creates a Value of TypeObject. Short-form alias for ObjectValue. -// -// value := ObjectVal(Section{"id": StringVal([]byte("peer-1"))}) -func ObjectVal(s Section) Value { return ObjectValue(s) } - -// Uint64ArrayVal creates a typed array of uint64 values. Short-form alias for Uint64ArrayValue. -// -// value := Uint64ArrayVal([]uint64{1, 2, 3}) -func Uint64ArrayVal(vs []uint64) Value { return Uint64ArrayValue(vs) } - -// Uint32ArrayVal creates a typed array of uint32 values. Short-form alias for Uint32ArrayValue. -// -// value := Uint32ArrayVal([]uint32{1, 2, 3}) -func Uint32ArrayVal(vs []uint32) Value { return Uint32ArrayValue(vs) } - -// StringArrayVal creates a typed array of byte-string values. Short-form alias for StringArrayValue. -// -// value := StringArrayVal([][]byte{[]byte("a"), []byte("b")}) -func StringArrayVal(vs [][]byte) Value { return StringArrayValue(vs) } - -// ObjectArrayVal creates a typed array of Section values. Short-form alias for ObjectArrayValue. -// -// value := ObjectArrayVal([]Section{{"id": StringVal([]byte("peer-1"))}}) -func ObjectArrayVal(vs []Section) Value { return ObjectArrayValue(vs) } diff --git a/node/levin/compat_test.go b/node/levin/compat_test.go deleted file mode 100644 index 72de5f4..0000000 --- a/node/levin/compat_test.go +++ /dev/null @@ -1,66 +0,0 @@ -// Copyright (c) 2024-2026 Lethean Contributors -// SPDX-License-Identifier: EUPL-1.2 - -package levin - -import ( - "testing" - - "github.com/stretchr/testify/assert" - "github.com/stretchr/testify/require" -) - -func TestShortFormAliases_Good(t *testing.T) { - assert.Equal(t, Uint64Value(42), Uint64Val(42)) - assert.Equal(t, Uint32Value(42), Uint32Val(42)) - assert.Equal(t, Uint16Value(42), Uint16Val(42)) - assert.Equal(t, Uint8Value(42), Uint8Val(42)) - assert.Equal(t, Int64Value(-42), Int64Val(-42)) - assert.Equal(t, Int32Value(-42), Int32Val(-42)) - assert.Equal(t, Int16Value(-42), Int16Val(-42)) - assert.Equal(t, Int8Value(-42), Int8Val(-42)) - assert.Equal(t, BoolValue(true), BoolVal(true)) - assert.Equal(t, DoubleValue(3.14), DoubleVal(3.14)) - assert.Equal(t, StringValue([]byte("hello")), StringVal([]byte("hello"))) - - section := Section{"key": StringValue([]byte("value"))} - assert.Equal(t, ObjectValue(section), ObjectVal(section)) - - assert.Equal(t, Uint64ArrayValue([]uint64{1, 2}), Uint64ArrayVal([]uint64{1, 2})) - assert.Equal(t, Uint32ArrayValue([]uint32{1, 2}), Uint32ArrayVal([]uint32{1, 2})) - assert.Equal(t, StringArrayValue([][]byte{[]byte("a")}), StringArrayVal([][]byte{[]byte("a")})) - assert.Equal(t, ObjectArrayValue([]Section{section}), ObjectArrayVal([]Section{section})) -} - -func TestShortFormAliasesRoundTrip_Good(t *testing.T) { - s := Section{ - "u64": Uint64Val(0xCAFEBABE), - "str": StringVal([]byte("hello")), - "flag": BoolVal(true), - "obj": ObjectVal(Section{"nested": Int32Val(42)}), - } - - data, err := EncodeStorage(s) - require.NoError(t, err) - - decoded, err := DecodeStorage(data) - require.NoError(t, err) - - u64, err := decoded["u64"].AsUint64() - require.NoError(t, err) - assert.Equal(t, uint64(0xCAFEBABE), u64) - - str, err := decoded["str"].AsString() - require.NoError(t, err) - assert.Equal(t, []byte("hello"), str) - - flag, err := decoded["flag"].AsBool() - require.NoError(t, err) - assert.True(t, flag) - - obj, err := decoded["obj"].AsSection() - require.NoError(t, err) - nested, err := obj["nested"].AsInt32() - require.NoError(t, err) - assert.Equal(t, int32(42), nested) -} diff --git a/specs/logging.md b/specs/logging.md index 31de890..b3ba1ef 100644 --- a/specs/logging.md +++ b/specs/logging.md @@ -43,7 +43,7 @@ Structured logger with configurable output, severity filtering, and component sc | Name | Signature | Description | | --- | --- | --- | | `DefaultConfig` | `func DefaultConfig() Config` | Returns the default configuration: stderr output, `LevelInfo`, and no component label. | -| `New` | `func New(cfg Config) *Logger` | Creates a `Logger` from `cfg`, substituting the default stderr writer when `cfg.Output` is `nil`. | +| `New` | `func New(config Config) *Logger` | Creates a `Logger` from `config`, substituting the default stderr writer when `config.Output` is `nil`. | | `SetGlobal` | `func SetGlobal(l *Logger)` | Replaces the package-level global logger instance. | | `GetGlobal` | `func GetGlobal() *Logger` | Returns the current package-level global logger. | | `SetGlobalLevel` | `func SetGlobalLevel(level Level)` | Updates the minimum severity on the current global logger. | @@ -67,8 +67,7 @@ Structured logger with configurable output, severity filtering, and component sc | Name | Signature | Description | | --- | --- | --- | -| `ComponentLogger` | `func (l *Logger) ComponentLogger(component string) *Logger` | Returns a new logger scoped to `component`. Preferred over `WithComponent`. | -| `WithComponent` | `func (l *Logger) WithComponent(component string) *Logger` | Deprecated compatibility alias for `ComponentLogger`. | +| `ComponentLogger` | `func (l *Logger) ComponentLogger(component string) *Logger` | Returns a new logger scoped to `component`. | | `SetLevel` | `func (l *Logger) SetLevel(level Level)` | Sets the minimum severity that the logger will emit. | | `GetLevel` | `func (l *Logger) GetLevel() Level` | Returns the current minimum severity. | | `Debug` | `func (l *Logger) Debug(msg string, fields ...Fields)` | Logs `msg` at debug level after merging any supplied field maps. | diff --git a/specs/node-levin.md b/specs/node-levin.md index b5e8912..ca6b93c 100644 --- a/specs/node-levin.md +++ b/specs/node-levin.md @@ -48,7 +48,7 @@ type Value struct { } ``` -Tagged portable-storage value. The exported `Type` field identifies which internal scalar or array slot is populated; constructors such as `Uint64Val`, `StringVal`, and `ObjectArrayVal` create correctly-typed instances. +Tagged portable-storage value. The exported `Type` field identifies which internal scalar or array slot is populated; constructors such as `Uint64Value`, `StringValue`, and `ObjectArrayValue` create correctly-typed instances. ## Functions @@ -68,22 +68,22 @@ Tagged portable-storage value. The exported `Type` field identifies which intern | Name | Signature | Description | | --- | --- | --- | -| `Uint64Val` | `func Uint64Val(v uint64) Value` | Creates a scalar `Value` with `TypeUint64`. | -| `Uint32Val` | `func Uint32Val(v uint32) Value` | Creates a scalar `Value` with `TypeUint32`. | -| `Uint16Val` | `func Uint16Val(v uint16) Value` | Creates a scalar `Value` with `TypeUint16`. | -| `Uint8Val` | `func Uint8Val(v uint8) Value` | Creates a scalar `Value` with `TypeUint8`. | -| `Int64Val` | `func Int64Val(v int64) Value` | Creates a scalar `Value` with `TypeInt64`. | -| `Int32Val` | `func Int32Val(v int32) Value` | Creates a scalar `Value` with `TypeInt32`. | -| `Int16Val` | `func Int16Val(v int16) Value` | Creates a scalar `Value` with `TypeInt16`. | -| `Int8Val` | `func Int8Val(v int8) Value` | Creates a scalar `Value` with `TypeInt8`. | -| `BoolVal` | `func BoolVal(v bool) Value` | Creates a scalar `Value` with `TypeBool`. | -| `DoubleVal` | `func DoubleVal(v float64) Value` | Creates a scalar `Value` with `TypeDouble`. | -| `StringVal` | `func StringVal(v []byte) Value` | Creates a scalar `Value` with `TypeString`. The byte slice is stored without copying. | -| `ObjectVal` | `func ObjectVal(s Section) Value` | Creates a scalar `Value` with `TypeObject` that wraps a nested `Section`. | -| `Uint64ArrayVal` | `func Uint64ArrayVal(vs []uint64) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeUint64`. | -| `Uint32ArrayVal` | `func Uint32ArrayVal(vs []uint32) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeUint32`. | -| `StringArrayVal` | `func StringArrayVal(vs [][]byte) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeString`. | -| `ObjectArrayVal` | `func ObjectArrayVal(vs []Section) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeObject`. | +| `Uint64Value` | `func Uint64Value(v uint64) Value` | Creates a scalar `Value` with `TypeUint64`. | +| `Uint32Value` | `func Uint32Value(v uint32) Value` | Creates a scalar `Value` with `TypeUint32`. | +| `Uint16Value` | `func Uint16Value(v uint16) Value` | Creates a scalar `Value` with `TypeUint16`. | +| `Uint8Value` | `func Uint8Value(v uint8) Value` | Creates a scalar `Value` with `TypeUint8`. | +| `Int64Value` | `func Int64Value(v int64) Value` | Creates a scalar `Value` with `TypeInt64`. | +| `Int32Value` | `func Int32Value(v int32) Value` | Creates a scalar `Value` with `TypeInt32`. | +| `Int16Value` | `func Int16Value(v int16) Value` | Creates a scalar `Value` with `TypeInt16`. | +| `Int8Value` | `func Int8Value(v int8) Value` | Creates a scalar `Value` with `TypeInt8`. | +| `BoolValue` | `func BoolValue(v bool) Value` | Creates a scalar `Value` with `TypeBool`. | +| `DoubleValue` | `func DoubleValue(v float64) Value` | Creates a scalar `Value` with `TypeDouble`. | +| `StringValue` | `func StringValue(v []byte) Value` | Creates a scalar `Value` with `TypeString`. The byte slice is stored without copying. | +| `ObjectValue` | `func ObjectValue(s Section) Value` | Creates a scalar `Value` with `TypeObject` that wraps a nested `Section`. | +| `Uint64ArrayValue` | `func Uint64ArrayValue(vs []uint64) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeUint64`. | +| `Uint32ArrayValue` | `func Uint32ArrayValue(vs []uint32) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeUint32`. | +| `StringArrayValue` | `func StringArrayValue(vs [][]byte) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeString`. | +| `ObjectArrayValue` | `func ObjectArrayValue(vs []Section) Value` | Creates an array `Value` tagged as `ArrayFlag | TypeObject`. | ### `*Connection` methods diff --git a/specs/node.md b/specs/node.md index 87324b3..99f6eb8 100644 --- a/specs/node.md +++ b/specs/node.md @@ -32,7 +32,7 @@ | `RawMessage` | `type RawMessage []byte` | Raw JSON payload bytes preserved without eager decoding. | | `ResponseHandler` | `struct{}` | Helper for validating message envelopes and decoding typed responses. | | `Transport` | `struct{ /* unexported fields */ }` | WebSocket transport that manages listeners, connections, encryption, deduplication, and shutdown coordination. | -| `TransportConfig` | `struct{ ListenAddr string; WSPath string; TLSCertPath string; TLSKeyPath string; MaxConns int; MaxMessageSize int64; PingInterval time.Duration; PongTimeout time.Duration }` | Listener, TLS, sizing, and keepalive settings for `Transport`. | +| `TransportConfig` | `struct{ ListenAddr string; WebSocketPath string; TLSCertPath string; TLSKeyPath string; MaxConnections int; MaxMessageSize int64; PingInterval time.Duration; PongTimeout time.Duration }` | Listener, TLS, sizing, and keepalive settings for `Transport`. | | `Worker` | `struct{ DataDir string /* plus unexported fields */ }` | Inbound command handler for worker nodes. It tracks uptime, optional miner/profile integrations, and the base directory used for deployments. | ### Payload and integration types @@ -43,7 +43,7 @@ | `DeployPayload` | `struct{ BundleType string; Data []byte; Checksum string; Name string }` | Deployment request carrying STIM-encrypted bundle bytes (or other bundle data), checksum, and logical name. | | `DisconnectPayload` | `struct{ Reason string; Code int }` | Disconnect notice with human-readable reason and optional disconnect code. | | `ErrorPayload` | `struct{ Code int; Message string; Details string }` | Payload used by `MsgError` responses. | -| `GetLogsPayload` | `struct{ MinerName string; Lines int; Since int64 }` | Request for miner console output, optionally bounded by line count and a Unix timestamp. | +| `LogsRequestPayload` | `struct{ MinerName string; Lines int; Since int64 }` | Request for miner console output, optionally bounded by line count and a Unix timestamp. | | `HandshakeAckPayload` | `struct{ Identity NodeIdentity; ChallengeResponse []byte; Accepted bool; Reason string }` | Handshake reply containing the responder identity, optional challenge response, acceptance flag, and optional rejection reason. | | `HandshakePayload` | `struct{ Identity NodeIdentity; Challenge []byte; Version string }` | Handshake request containing node identity, optional authentication challenge, and protocol version. | | `LogsPayload` | `struct{ MinerName string; Lines []string; HasMore bool }` | Returned miner log lines plus an indicator that more lines are available. | @@ -88,17 +88,15 @@ | Name | Signature | Description | | --- | --- | --- | -| `DefaultTransportConfig` | `func DefaultTransportConfig() TransportConfig` | Returns the transport defaults: `:9091`, `/ws`, `MaxConns=100`, `MaxMessageSize=1<<20`, `PingInterval=30s`, and `PongTimeout=10s`. | +| `DefaultTransportConfig` | `func DefaultTransportConfig() TransportConfig` | Returns the transport defaults: `ListenAddr=:9091`, `WebSocketPath=/ws`, `MaxConnections=100`, `MaxMessageSize=1<<20`, `PingInterval=30s`, and `PongTimeout=10s`. | | `NewController` | `func NewController(node *NodeManager, peers *PeerRegistry, transport *Transport) *Controller` | Creates a controller, initialises its pending-response map, and installs its response handler on `transport`. | | `NewDispatcher` | `func NewDispatcher() *Dispatcher` | Creates an empty dispatcher with a debug-level component logger named `dispatcher`. | | `NewMessageDeduplicator` | `func NewMessageDeduplicator(ttl time.Duration) *MessageDeduplicator` | Creates a deduplicator that retains message IDs for the supplied TTL. | | `NewNodeManager` | `func NewNodeManager() (*NodeManager, error)` | Resolves XDG key and config paths, then loads an existing identity if present. | | `NewNodeManagerFromPaths` | `func NewNodeManagerFromPaths(keyPath, configPath string) (*NodeManager, error)` | Creates a node manager from explicit key and config paths. | -| `NewNodeManagerWithPaths` | `func NewNodeManagerWithPaths(keyPath, configPath string) (*NodeManager, error)` | Deprecated compatibility alias for `NewNodeManagerFromPaths`. | | `NewPeerRateLimiter` | `func NewPeerRateLimiter(maxTokens, refillRate int) *PeerRateLimiter` | Creates a token bucket seeded with `maxTokens` and refilled at `refillRate` tokens per second. | | `NewPeerRegistry` | `func NewPeerRegistry() (*PeerRegistry, error)` | Resolves the XDG peers path, loads any persisted peers, and builds the selection KD-tree. | | `NewPeerRegistryFromPath` | `func NewPeerRegistryFromPath(peersPath string) (*PeerRegistry, error)` | Creates a peer registry bound to `peersPath` with open authentication mode and an empty public-key allowlist. | -| `NewPeerRegistryWithPath` | `func NewPeerRegistryWithPath(peersPath string) (*PeerRegistry, error)` | Deprecated compatibility alias for `NewPeerRegistryFromPath`. | | `NewTransport` | `func NewTransport(node *NodeManager, registry *PeerRegistry, config TransportConfig) *Transport` | Creates a transport with lifecycle context, a 5-minute message deduplicator, and a WebSocket upgrader that only accepts local origins. | | `NewWorker` | `func NewWorker(node *NodeManager, transport *Transport) *Worker` | Creates a worker, records its start time for uptime reporting, and defaults `DataDir` to `xdg.DataHome`. | @@ -213,7 +211,7 @@ | `Connections` | `func (t *Transport) Connections() iter.Seq[*PeerConnection]` | Returns an iterator over active peer connections. | | `Broadcast` | `func (t *Transport) Broadcast(msg *Message) error` | Sends `msg` to every connected peer except the sender identified by `msg.From`. | | `GetConnection` | `func (t *Transport) GetConnection(peerID string) *PeerConnection` | Returns the active connection for `peerID`, or `nil` when not connected. | -| `ConnectedPeers` | `func (t *Transport) ConnectedPeers() int` | Returns the number of active peer connections. | +| `ConnectedPeerCount` | `func (t *Transport) ConnectedPeerCount() int` | Returns the number of active peer connections. | ### `*PeerConnection` methods @@ -231,7 +229,6 @@ | `SetProfileManager` | `func (w *Worker) SetProfileManager(manager ProfileManager)` | Installs the profile manager used during deployment handling. | | `HandleMessage` | `func (w *Worker) HandleMessage(conn *PeerConnection, msg *Message)` | Dispatches supported message types, sends normal replies on success, and emits `MsgError` responses when a handled command fails. | | `RegisterOnTransport` | `func (w *Worker) RegisterOnTransport()` | Registers `HandleMessage` as the transport's inbound message callback. | -| `RegisterWithTransport` | `func (w *Worker) RegisterWithTransport()` | Deprecated compatibility alias for `RegisterOnTransport`. | ### `*ProtocolError` methods diff --git a/ueps/compat.go b/ueps/compat.go deleted file mode 100644 index 2b81812..0000000 --- a/ueps/compat.go +++ /dev/null @@ -1,11 +0,0 @@ -// SPDX-License-Identifier: EUPL-1.2 - -package ueps - -// Short-form tag aliases for spec compatibility. -const ( - // TagCurrentLay is a short-form alias for TagCurrentLayer. - TagCurrentLay = TagCurrentLayer - // TagTargetLay is a short-form alias for TagTargetLayer. - TagTargetLay = TagTargetLayer -) diff --git a/ueps/compat_test.go b/ueps/compat_test.go deleted file mode 100644 index d57fc01..0000000 --- a/ueps/compat_test.go +++ /dev/null @@ -1,14 +0,0 @@ -package ueps - -import ( - "testing" - - "github.com/stretchr/testify/assert" -) - -func TestTagAliases_Good(t *testing.T) { - assert.Equal(t, TagCurrentLayer, TagCurrentLay) - assert.Equal(t, TagTargetLayer, TagTargetLay) - assert.Equal(t, 0x02, TagCurrentLay) - assert.Equal(t, 0x03, TagTargetLay) -}