Documentation
¶
Overview ¶
Package mdns provides zero-configuration peer discovery for local networks. It uses mDNS/DNS-SD (Bonjour/Avahi) for automatic service advertisement and peer discovery without requiring manual configuration.
Package mdns provides zero-configuration peer discovery for local networks using mDNS/DNS-SD (Multicast DNS Service Discovery).
This enables automatic service advertisement and peer discovery without requiring manual configuration, DHCP, or central registries. Nodes on the same local network can find each other automatically.
Quick Start ¶
import "github.com/kinet-labs/mdns"
// Create discovery for your service
disc := mdns.New("_myservice._tcp", "node-1", 8080,
mdns.WithMetadata(map[string]string{
"version": "1.0.0",
"role": "worker",
}),
)
// Handle peer events
disc.OnPeer(func(peer *mdns.Peer, joined bool) {
if joined {
fmt.Printf("Peer joined: %s at %s\n", peer.NodeID, peer.Address())
} else {
fmt.Printf("Peer left: %s\n", peer.NodeID)
}
})
// Start discovery
if err := disc.Start(); err != nil {
log.Fatal(err)
}
defer disc.Stop()
// List all peers
for _, peer := range disc.Peers() {
fmt.Printf("Found: %s (%s)\n", peer.NodeID, peer.Get("version"))
}
Service Types ¶
Service types follow the DNS-SD naming convention:
_servicename._tcp (for TCP services) _servicename._udp (for UDP services)
Examples:
- _fhed._tcp - FHE daemon
- _mpcd._tcp - MPC daemon
- _kinetd._tcp - Kinet node
- _http._tcp - HTTP server
How It Works ¶
1. When Start() is called, the node registers itself via mDNS 2. A background goroutine periodically browses for other nodes 3. When new nodes are discovered, the OnPeer handler is called 4. When nodes go stale (not seen for 30s), they're removed
Use Cases ¶
- Zero-config FHE/MPC clusters
- Kinet node discovery for local testnets
- Local development environments
- IoT device discovery
- Microservice discovery in local networks
- Testing distributed systems locally
Limitations ¶
- Only works on local networks (mDNS is link-local)
- Requires multicast support on the network
- Not suitable for cross-network discovery (use Consul, etcd, etc.)
Example ¶
package main
import (
"fmt"
"log/slog"
"os"
"time"
"github.com/kinet-labs/mdns"
)
func main() {
// Create a discovery instance for your service
disc := mdns.New("_myservice._tcp", "node-1", 8080,
mdns.WithLogger(slog.New(slog.NewTextHandler(os.Stdout, nil))),
mdns.WithMetadata(map[string]string{
"version": "1.0.0",
"role": "worker",
}),
)
// Handle peer events
disc.OnPeer(func(peer *mdns.Peer, joined bool) {
if joined {
fmt.Printf("Peer joined: %s at %s (version: %s)\n",
peer.NodeID, peer.Address(), peer.Get("version"))
} else {
fmt.Printf("Peer left: %s\n", peer.NodeID)
}
})
// Start discovery
if err := disc.Start(); err != nil {
fmt.Printf("Failed to start: %v\n", err)
return
}
defer disc.Stop()
// List all discovered peers
time.Sleep(100 * time.Millisecond) // Allow time for discovery
fmt.Printf("Found %d peers\n", disc.PeerCount())
}
Output:
Index ¶
- Constants
- func LocalIPs() []net.IP
- type Discovery
- func (d *Discovery) NodeID() string
- func (d *Discovery) OnPeer(handler PeerHandler)
- func (d *Discovery) Peer(nodeID string) *Peer
- func (d *Discovery) PeerCount() int
- func (d *Discovery) Peers() []*Peer
- func (d *Discovery) ServiceType() string
- func (d *Discovery) Start() error
- func (d *Discovery) Stop()
- type Option
- type Peer
- type PeerHandler
Examples ¶
Constants ¶
const ( // DefaultDomain is the mDNS domain DefaultDomain = "local." // DefaultBrowseInterval is how often to scan for peers DefaultBrowseInterval = 5 * time.Second // DefaultBrowseTimeout is the timeout for each browse operation DefaultBrowseTimeout = 3 * time.Second // DefaultStaleTimeout is when peers are considered gone DefaultStaleTimeout = 30 * time.Second )
Variables ¶
This section is empty.
Functions ¶
Types ¶
type Discovery ¶
type Discovery struct {
// contains filtered or unexported fields
}
Discovery handles mDNS-based peer discovery for zero-config clustering.
func New ¶
New creates a new mDNS discovery instance.
serviceType should be in the format "_servicename._tcp" (e.g., "_fhed._tcp"). nodeID is a unique identifier for this node. port is the port this service is listening on.
func (*Discovery) OnPeer ¶
func (d *Discovery) OnPeer(handler PeerHandler)
OnPeer sets the handler for peer events.
func (*Discovery) Peers ¶
Peers returns all currently known peers.
Example ¶
package main
import (
"fmt"
"github.com/kinet-labs/mdns"
)
func main() {
disc := mdns.New("_fhed._tcp", "node-1", 8448)
if err := disc.Start(); err != nil {
return
}
defer disc.Stop()
// List all peers
for _, peer := range disc.Peers() {
fmt.Printf("Node: %s, Address: %s\n", peer.NodeID, peer.Address())
}
}
Output:
func (*Discovery) ServiceType ¶
ServiceType returns the service type being advertised.
type Option ¶
type Option func(*Discovery)
Option configures the Discovery instance.
func WithBrowseInterval ¶
WithBrowseInterval sets how often to scan for peers.
func WithBrowseTimeout ¶
WithBrowseTimeout sets the timeout for each browse operation.
func WithMetadata ¶
WithMetadata sets additional metadata to advertise.
func WithStaleTimeout ¶
WithStaleTimeout sets when peers are considered gone.
type Peer ¶
type Peer struct {
NodeID string // Unique node identifier
Addr string // IP address
Port int // Service port
Metadata map[string]string // Additional metadata from TXT records
LastSeen time.Time // Last time this peer was seen
}
Peer represents a discovered node on the network.
type PeerHandler ¶
PeerHandler is called when peers join or leave the network.