rpc

package
v1.0.1 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 22, 2026 License: Apache-2.0 Imports: 14 Imported by: 0

README

Tiny-P2P RPC Framework

Ein leichtgewichtiges, bidirektionales RPC-Framework für Go, das auf WebSockets basiert und echtes Peer-to-Peer Verhalten in Microservice-Architekturen ermöglicht.

Architektur-Übersicht

Das Framework ist in zwei Schichten unterteilt:

  • Transport-Layer: Abstrahiert die Netzwerk-Verbindung (WebSockets).
  • RPC-Layer: Verwaltet die JSON-RPC Logik, IDs und Handler.

Features

  • Symmetrisch: Beide Seiten können gleichzeitig Anfragen senden und empfangen.
  • Resilient: Integrierter Exponential-Backoff für automatische Wiederverbindung.
  • Standardkonform: Implementiert JSON-RPC 2.0 Spezifikation inklusive des data-Feldes für detaillierte Fehlermeldungen.
  • Typsicher: Nutzung von Go Generics für Parameter-Binding.

Schnellstart

1. Verbindung herstellen
provider := &transport.WSProvider{}
// Als Client (mit Reconnect-Logik)
peer := rpc.NewPeer(nil, provider, "ws://localhost:8080/ws")
go peer.Listen(ctx)

2. Methoden aufrufen
result, err := peer.Call(ctx, "math.add", []int{5, 10})

3. Auf Benachrichtigungen reagieren
peer.Register("system.alert", func(ctx context.Context, p json.RawMessage) (any, error) {
    msg, _ := rpc.Bind[string](p)
    fmt.Println("Alert:", msg)
    return nil, nil
})

Documentation

Overview

The rpc package implements a bidirectional JSON-RPC 2.0 protocol using abstract connections.

Unlike traditional client-server RPC, this package allows symmetrical peer-to-peer communication. Each endpoint can both register methods (server role) and call methods on the partner (client role).

Key features: - Support for call (request/response) and notify (fire-and-forget). - Robust error handling with standardized JSON-RPC error codes. - Generic bind function for type-safe unmarshaling without reflection. - Support for automatic reconnect logic on connection failure.

Example of registering a handler:

node.Register("sum", func(ctx context.Context, params json.RawMessage) (any, error) {
    vals, _ := rpc.Bind[[]int](params)
    return vals[0] + vals[1], nil
})

Index

Constants

View Source
const (
	ParseError     = -32700
	InvalidRequest = -32600
	MethodNotFound = -32601
	InvalidParams  = -32602
	InternalError  = -32603

	// Custom Business / Auth Errors
	UnAuthorized     = -32001
	NotAuthorized    = -32002
	InvalidOrExpired = -32003
)

Standard JSON-RPC 2.0 Error Codes

Variables

View Source
var StdError = map[int]string{
	ParseError:       "Parse error",
	InvalidRequest:   "Invalid Request",
	MethodNotFound:   "Method not found",
	InvalidParams:    "Invalid params",
	InternalError:    "Internal error",
	UnAuthorized:     "Unauthorized",
	NotAuthorized:    "Not authorized",
	InvalidOrExpired: "Invalid or expired token",
}

Functions

This section is empty.

Types

type AuthParams

type AuthParams struct {
	Username string `json:"username,omitempty"`
	Password string `json:"password,omitempty"`
	Token    string `json:"token,omitempty"`
}

type AuthResult

type AuthResult struct {
	Status   string `json:"status"`
	Token    string `json:"token,omitempty"`
	Username string `json:"username,omitempty"`
}

type DummyAuthenticator

type DummyAuthenticator struct{}

Default/Fallback Provider (for Demos or Tests)

func (*DummyAuthenticator) Authenticate

func (d *DummyAuthenticator) Authenticate(ctx context.Context, username, password string) bool

type JsonRPCerror

type JsonRPCerror struct {
	Code    int    `json:"code"`
	Message string `json:"message"`
	Data    any    `json:"data,omitempty"`
}

func NewRPCErrorFromNexError

func NewRPCErrorFromNexError(code int, err *errors.Error) *JsonRPCerror

NewRPCErrorFromNexError converts a nexutils/errors.Error into a JsonRPCerror. The nexutils error object is cleanly included in the 'Data' field.

type JsonRPChandler

type JsonRPChandler func(p *Peer, req JsonRPCrequest) (any, *JsonRPCerror)

type JsonRPCrequest

type JsonRPCrequest struct {
	JSONRPC string          `json:"jsonrpc"`
	Method  string          `json:"method"`
	Params  json.RawMessage `json:"params,omitempty"`
	ID      json.RawMessage `json:"id,omitempty"`
}

func (*JsonRPCrequest) IsResponse

func (req *JsonRPCrequest) IsResponse() bool

IsResponse checks whether it is a JSON-RPC response to a request of its own.

func (*JsonRPCrequest) UnmarshalParams

func (req *JsonRPCrequest) UnmarshalParams(v any) error

UnmarshalParams is a convenient helper method for parsing JSON-RPC parameters directly into a target struct or variable.

type JsonRPCresponse

type JsonRPCresponse struct {
	JSONRPC string          `json:"jsonrpc"`
	Result  any             `json:"result,omitempty"`
	Error   *JsonRPCerror   `json:"error,omitempty"`
	Method  string          `json:"method,omitempty"`
	ID      json.RawMessage `json:"id,omitempty"`
}

type ManagedClient

type ManagedClient struct {
	// contains filtered or unexported fields
}

ManagedClient manages a P2P connection, including auto-reconnect and session handling.

func NewManagedClient

func NewManagedClient(node *Node, targetURL string, cfg ReconnectConfig) *ManagedClient

func (*ManagedClient) Call

func (mc *ManagedClient) Call(ctx context.Context, method string, params any, resultTarget any) *JsonRPCerror

Call forwards calls only when the connection is fully ready.

func (*ManagedClient) Close

func (mc *ManagedClient) Close()

Close closes permanently terminates the client.

func (*ManagedClient) GetPeer

func (mc *ManagedClient) GetPeer() *Peer

GetPeer returns the current peer (or nil).

func (*ManagedClient) IsClosed

func (mc *ManagedClient) IsClosed() bool

func (*ManagedClient) IsReady

func (mc *ManagedClient) IsReady() bool

func (*ManagedClient) SetCredentials

func (mc *ManagedClient) SetCredentials(username, password string)

SetCredentials stores access credentials for automatic login and re-authentication processes.

func (*ManagedClient) Start

func (mc *ManagedClient) Start()

"Start" initiates the connection and the monitoring loop in the background.

type Node

type Node struct {
	// contains filtered or unexported fields
}

func NewNode

func NewNode(opts Options) *Node

func (*Node) Broadcast

func (n *Node) Broadcast(method string, params any)

Broadcast sends a notification signal to ALL connected peers.

func (*Node) BroadcastAuthorized

func (n *Node) BroadcastAuthorized(method string, params any)

BroadcastAuthorized sends a notification signal ONLY to authenticated peers.

func (*Node) BroadcastFilter

func (n *Node) BroadcastFilter(method string, params any, filter PeerFilter)

BroadcastFilter sends a notification signal to all peers to which the filter applies.

func (*Node) BroadcastToUsers

func (n *Node) BroadcastToUsers(method string, params any, usernames []string)

BroadcastToUsers sends a notification signal to a specific list of usernames.

func (*Node) ConnectToPeer

func (n *Node) ConnectToPeer(targetURL string) (*Peer, error)

func (*Node) ConnectWithAutoReconnect

func (n *Node) ConnectWithAutoReconnect(targetURL string, cfg ReconnectConfig) *ManagedClient

ConnectWithAutoReconnect creates a ManagedClient that autonomously connects, authenticates, and manages reconnections in the background.

func (*Node) RegisterHandler

func (n *Node) RegisterHandler(method string, h JsonRPChandler)

func (*Node) SetAuthenticator

func (n *Node) SetAuthenticator(auth UserAuthenticator)

func (*Node) Start

func (n *Node) Start() error

func (*Node) Stop

func (n *Node) Stop() error

type Options

type Options struct {
	Addr              string
	HeartbeatInterval time.Duration
	ShutdownDelay     time.Duration
	WriteReadLimit    int64
}

type Peer

type Peer struct {
	ID   string
	Role PeerRole
	// contains filtered or unexported fields
}

func NewPeer

func NewPeer(conn *websocket.Conn, remoteAddr string) *Peer

func (*Peer) Call

func (p *Peer) Call(ctx context.Context, method string, params any, resultTarget any) *JsonRPCerror

Call sends a request to the peer and waits synchronously for the response.

func (*Peer) Close

func (p *Peer) Close()

func (*Peer) IsAuthorized

func (p *Peer) IsAuthorized() bool

func (*Peer) Notify

func (p *Peer) Notify(method string, params any) error

Notify sends a message without an ID to the peer (fire-and-forget; no response expected).

func (*Peer) RemoteAddr

func (p *Peer) RemoteAddr() string

func (*Peer) Send

func (p *Peer) Send(msg any)

func (*Peer) SetAuth

func (p *Peer) SetAuth(username, token string, ttl time.Duration)

func (*Peer) Start

func (p *Peer) Start()

func (*Peer) Username

func (p *Peer) Username() string

type PeerFilter

type PeerFilter func(p *Peer) bool

Broadcast functionality PeerFilter is a function that determines whether a peer should receiv e a signal.

type PeerRole

type PeerRole int
const (
	RoleInbound PeerRole = iota
	RoleOutbound
)

type ReconnectConfig

type ReconnectConfig struct {
	InitialInterval time.Duration
	MaxInterval     time.Duration
	Multiplier      float64
	MaxRetries      int // 0 = infinite
}

type Router

type Router struct {
	// contains filtered or unexported fields
}

func (*Router) RegisterHandler

func (r *Router) RegisterHandler(method string, h JsonRPChandler)

func (*Router) SetAuthenticator

func (r *Router) SetAuthenticator(auth UserAuthenticator)

SetAuthenticator allows the injection of any user management system.

type SessionData

type SessionData struct {
	Username string
	Expires  time.Time
}

type UserAuthenticator

type UserAuthenticator interface {
	// Authenticate checks the username and password.
	// Returns true if the credentials are correct.
	Authenticate(ctx context.Context, username, password string) bool
}

UserAuthenticator must be implemented by every user management system.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL