herald

package module
v1.2.0 Latest Latest
Warning

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

Go to latest
Published: Feb 1, 2026 License: MIT Imports: 20 Imported by: 0

README

Herald Library Documentation

Overview

Herald is a Go-based peer-to-peer messaging library designed to facilitate secure, reliable, and decentralized communication between peers. It supports direct peer-to-peer messaging, broadcast messaging, heartbeats for online status, and peer lifecycle hooks.

The library uses Ed25519 cryptography for signing and verifying messages, and supports pluggable transport layers (such as RabbitMQ).

Installation

go get github.com/abolfazlalz/herald

Core Concepts

Peer

A peer is any instance of Herald running in the network. Peers have:

  • A unique ID (string)
  • Public key
  • Optional routing key (for transport)

Message Types

Herald defines several types of messages:

  • MessageTypeAnnounce: Announces a new peer.
  • MessageTypeMessage: Standard message between peers.
  • MessageTypeACK: Acknowledgment message.
  • MessageTypeOffline: Indicates that a peer has gone offline. Other peers should update their registry/state accordingly.

Envelope

All messages are wrapped in an Envelope:

type Envelope struct {
    ID         string
    Version    int
    Type       EventType
    SenderID   string
    ReceiverID string
    Timestamp  int64
    Payload    []byte
    Signature  []byte
}

Envelopes are signed and verified using Ed25519 for authenticity.

API

Creating a Herald Instance

import "github.com/abolfazlalz/herald/transport"

transport, _ := transport.NewRabbitMQ("amqp://guest:guest@localhost:5672/", "myQueue")
privateKey := []byte{/* your 64-byte Ed25519 private key */}
h := herald.New(transport, privateKey)

Starting the Library

ctx := context.Background()
err := h.Start(ctx)
if err != nil {
    log.Fatal(err)
}

This initializes the peer, starts heartbeats, listens for messages, and manages the peer lifecycle.

Sending Messages

Send to a specific peer
h.SendToPeer(ctx, "peer-id", []byte("Hello!"))
Broadcast message
h.Broadcast(ctx, []byte("Hello everyone!"))
Send and wait for ACK
err := h.SendAndWait(ctx, "peer-id", payload, 5*time.Second)
if err != nil {
    log.Println("Failed to receive ack:", err)
}

Subscribing to Messages

sub := h.Subscribe(ctx, herald.MessageTypeMessage, 10)
for msg := range sub.C {
    fmt.Println("Received message:", msg.Payload)
}

Hooks for Peer Lifecycle

h.OnPeerJoin(func(ctx context.Context, peerID string) {
    fmt.Println(peerID, "joined")
})

h.OnPeerLeave(func(ctx context.Context, peerID string) {
    fmt.Println(peerID, "left")
})

Closing a Peer

h.Close(ctx)

This sends an offline message to peers and closes all channels.

Middleware

Herald supports middleware for processing incoming messages:

  • VerifySignature(): Checks signature of message.
  • UpdateLastOnline(): Updates peer's last online timestamp.
  • CheckMessageAccess(): Aborts processing if the message is not addressed to this peer.

Transport Interface

Herald uses a pluggable Transport interface:

type Transport interface {
    PublishBroadcast(ctx context.Context, data []byte) error
    PublishDirect(ctx context.Context, routingKey string, data []byte) error
    SubscribeBroadcast(ctx context.Context) (<-chan []byte, error)
    SubscribeDirect(ctx context.Context, peerID string) (<-chan []byte, error)
    Close() error
}

RabbitMQ is provided as a reference implementation (transport/rabbitmq.go).

Security

Herald uses Ed25519:

  • KeyPair: represents public/private keys.
  • Signer: signs messages.
  • Verifier: verifies messages.

Heartbeat

Herald periodically sends heartbeat messages to indicate online status.

Peer Registry

Manages the list of known peers and their last online timestamp.

Example

ctx := context.Background()
transport, _ := transport.NewRabbitMQ("amqp://guest:guest@localhost:5672/", "myQueue")
h, _ := herald.New(transport)

h.OnPeerJoin(func(ctx context.Context, id string){ fmt.Println("Peer joined:", id) })

go h.Start(ctx)

h.Broadcast(ctx, []byte("Hello world!"))

License

MIT License

Documentation

Index

Constants

View Source
const (
	// PeerTimeout defines the duration after which a peer is considered offline.
	PeerTimeout           = 5 * time.Second
	MessageTimeout        = 10 * time.Second
	PeerConnectingTimeout = 5 * time.Second
)

Variables

View Source
var (
	ErrUnknownPeer      = errors.New("unknown peer")
	ErrInvalidSignature = errors.New("invalid signature")
	ErrUnauthorized     = errors.New("unauthorized")
	ErrSelfMessage      = errors.New("self message")
	ErrInvalidMessage   = errors.New("invalid message")
	ErrMessageTimeout   = errors.New("message timeout")
	ErrAckTimeout       = errors.New("ack timeout")
	ErrInvalidEventType = errors.New("invalid event type")
)

Functions

This section is empty.

Types

type HandlerFunc added in v1.2.0

type HandlerFunc func(*MessageContext, *Message)

type Herald

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

Herald represents the main P2P engine that handles messaging, heartbeat, peer registry, and hooks for join/leave events.

func New

func New(transport transport.Transport, opts *Option) (*Herald, error)

New creates a new Herald instance, generating a key pair and setting up default handlers.

func (*Herald) Broadcast added in v1.1.0

func (h *Herald) Broadcast(ctx context.Context, payload []byte)

Broadcast sends a message to all peers.

func (*Herald) Close

func (h *Herald) Close(ctx context.Context) error

Close sends an offline message and shuts down the Herald instance.

func (*Herald) ID

func (h *Herald) ID() string

ID returns the unique identifier of this Herald instance.

func (*Herald) OnPeerJoin

func (h *Herald) OnPeerJoin(hook PeerHook)

OnPeerJoin registers a hook for when a peer joins.

func (*Herald) OnPeerLeave

func (h *Herald) OnPeerLeave(hook PeerHook)

OnPeerLeave registers a hook for when a peer leaves.

func (*Herald) Peers

func (h *Herald) Peers() []string

Peers returns a list of peer IDs currently in the registry.

func (*Herald) SendToPeer

func (h *Herald) SendToPeer(ctx context.Context, peerID string, payload []byte) error

SendToPeer sends a message to a specific peer.

func (*Herald) Start

func (h *Herald) Start(ctx context.Context) error

Start runs the Herald engine, subscribes to messages, performs handshake, starts heartbeat, and manages message sending/receiving.

func (*Herald) Subscribe

func (h *Herald) Subscribe(ctx context.Context, event MessageType, handler HandlerFunc)

Subscribe subscribes to a specific message type with a buffered channel.

type Hook

type Hook struct {
	OnPeerJoin  []PeerHook
	OnPeerLeave []PeerHook
}

type Log added in v1.1.0

type Log interface {
	Debug(ctx context.Context, msg string, args ...any)
	Info(ctx context.Context, msg string, args ...any)
	Error(ctx context.Context, msg string, args ...any)
	Warn(ctx context.Context, msg string, args ...any)
}

func NewDiscardLogs added in v1.1.0

func NewDiscardLogs() Log

func NewLogger added in v1.1.0

func NewLogger(option *slog.HandlerOptions) Log

func NewLogs added in v1.1.0

func NewLogs(logger *slog.Logger) Log

type Message

type Message struct {
	ID      string
	From    string
	To      string
	Type    MessageType
	Payload []byte
}

type MessageContext

type MessageContext struct {
	context.Context
	// contains filtered or unexported fields
}

func NewMessageContext

func NewMessageContext(ctx context.Context) *MessageContext

func (*MessageContext) Abort

func (ctx *MessageContext) Abort()

func (*MessageContext) IsAborted

func (ctx *MessageContext) IsAborted() bool

type MessageType

type MessageType string
const (
	MessageTypeAnnounce MessageType = "announce"
	MessageTypeMessage  MessageType = "message"
	MessageTypeACK      MessageType = "ack"
	MessageTypeOffline  MessageType = "offline"
)

func (MessageType) GetType

func (mt MessageType) GetType() message.EventType

type Middleware

type Middleware func(ctx *MessageContext, herald *Herald, env *message.Envelope) error

func CheckMessageAccess

func CheckMessageAccess() Middleware

func UpdateLastOnline

func UpdateLastOnline() Middleware

func VerifySignature

func VerifySignature() Middleware

type Option added in v1.1.0

type Option struct {
	Logger Log
}

type PeerHook

type PeerHook func(ctx context.Context, peerID string)

type Subscription

type Subscription struct {
	C <-chan Message
	// contains filtered or unexported fields
}

Directories

Path Synopsis
hi command
internal

Jump to

Keyboard shortcuts

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