Interface scaffold for Reticulum-Go =================================== Use this file to add a new network interface under pkg/interfaces/. Follow an existing driver for patterns. Prefer UDP, TCP, or Pipe as templates. Authoritative docs and contracts -------------------------------- docs/en/interfaces.md pkg/interfaces/interface.go package Interface embeds common.NetworkInterface pkg/common/interfaces.go NetworkInterface contract pkg/common/config.go InterfaceConfig fields pkg/interfaces/fromconfig.go type switch factory pkg/interfaces/plugin.go external / pipe plugins pkg/interfaces/reconnect.go client reconnect helper COMPATIBILITY.md Python interop status Choose how the interface is delivered ------------------------------------- 1. In-tree driver (most common) - New type in pkg/interfaces - Wired through NewFromConfigWithContext - Documented in docs/en/interfaces.md and COMPATIBILITY.md 2. External plugin (no Go rebuild for operators) - RegisterExternalFactory for embedders - Or {config_dir}/interfaces/{Type}.json manifest (driver pipe) - Or executable {config_dir}/interfaces/{Type} as PipeInterface command - See docs/en/interfaces.md External interface plugins Do not invent a parallel packet path around Transport. Interfaces hand raw RNS packets to the packet callback. Framing and IFAC stay on the interface boundary. Packet paths (must match) ------------------------- Inbound: wire bytes -> ProcessIncoming -> IFAC unmask -> packetCallback -> Transport Outbound: Transport -> Send -> IFAC mask -> ProcessOutgoing -> wire BaseInterface.Send already applies IFAC outbound and updates TX stats. Concrete types override ProcessOutgoing to write the medium. ProcessIncoming on BaseInterface applies IFAC inbound then calls the callback. Never call BaseInterface.ProcessOutgoing for real traffic (it fails loud). Suggested file layout --------------------- pkg/interfaces/.go main type, Start, Stop, Send path pkg/interfaces/_test.go unit tests pkg/interfaces/_fuzz_test.go optional fuzz pkg/interfaces/_race_test.go optional race-focused tests pkg/interfaces/_stub.go build-tagged stub when unsupported pkg/interfaces/_.go OS-specific helpers when needed tests/interop/_live_test.go optional live interop (gated) Reuse existing helpers before inventing new ones: BaseInterface embedding reconnectDriver for dial clients HDLC helpers (tcp / pipe / serial patterns) ConnectivityNotifier hooks for up/down NormalizeMaxReconnectTries Required implementation checklist --------------------------------- Embed and identity - Embed BaseInterface (value, not pointer copy after use) - Set Name, Type, Enabled via NewBaseInterface - Set Mode from config (full default) - Honor ReceiveOnly / outgoing = no via SetOutgoingAllowed Lifecycle - Start() opens resources, sets Online, starts read loops - Stop() and Detach() close cleanly, idempotent where practical - Enable / Disable update Enabled and Online consistently - No goroutine leaks after Stop (tests often use leak checks) IO - ProcessOutgoing writes framed or raw bytes to the medium - Inbound path feeds ProcessIncoming (or equivalent that ends there) - Respect MTU and bitrate when the medium has limits - Apply IFAC only through the BaseInterface Send / ProcessIncoming path Config factory - Add case in NewFromConfigWithContext for the config type string - Map InterfaceConfig fields (do not invent parallel config structs unless the type needs a dedicated constructor args struct) - Add type to any post-create switch that applies common options (mode, IFAC, announce caps, ingress control) if required by that path - Unknown types fall through to loadExternalInterface Interop and docs - If matching a Python RNS interface, document keys and framing interop - If Go-only, say so in docs/en/interfaces.md (see QUIC, WebTransport) - Update COMPATIBILITY.md status row - Add a config example to docs/en/interfaces.md Config type naming ------------------ Config `type` strings are public. Match Python names when implementing a Python counterpart (UDPInterface, TCPClientInterface, ...). Go-only types still use the *Interface suffix for consistency. Modes and discovery ------------------- Modes are wire values in pkg/common (full through internal). gateway / roaming / internal participate in unknown-path discovery. recursive_prs = yes forces discovery on any mode. announces_from_internal = no blocks rebroadcast from internal next hops. Reconnect clients ----------------- For dial-style clients, reuse reconnect.go: max_reconnect_tries <= 0 means unlimited positive values cap attempts SetConnectivityHooks when the daemon should see down/up TCP clients may SetTunnelSynth for tunnel re-synthesis on reconnect Platform and build tags ----------------------- If the medium is unavailable on some GOOS or WASM: - Provide a stub file with build tags that returns a clear error - Document platform limits in docs/en/interfaces.md - Keep NewFromConfig wired so config parse still names the type Reference drivers ----------------- Simple datagram: udp.go Stream + HDLC: tcp.go, pipe.go, serial.go Discovery: auto.go Reconnect client: tcp.go + reconnect.go Plugin path: plugin.go, pipe.go Shared instance: local.go, pkg/sharedinstance Go-only modern: quic.go, webtransport.go, https.go, vsock.go Tests to include ---------------- Minimum - Construct from InterfaceConfig via NewFromConfig - Start / Stop without leak - Send while receive-only returns error - ProcessOutgoing / inbound callback round-trip with a fake peer or loopback Stronger - IFAC mask/unmask drop path - Reconnect success and exhausted paths - Race test under -race - Fuzz framing decoder if you add a parser - Live interop behind RUN_LIVE_INTEROP=1 or type-specific env Acceptance criteria ------------------- 1. Implements common.NetworkInterface via package Interface 2. Wired in fromconfig.go (or documented as plugin-only) 3. No BaseInterface.ProcessOutgoing used as real transmit 4. Start/Stop clean under unit tests 5. docs/en/interfaces.md section with config example 6. COMPATIBILITY.md updated when Python interop is claimed or deferred What not to do -------------- - Bypass Transport with a second mesh stack - Hold or copy BaseInterface by value after mutex use - Execute arbitrary Python plugins in-process (use pipe or RegisterExternalFactory) - Expose a new public Control API just to carry underlay bytes )