lansync

package
v0.3.22 Latest Latest
Warning

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

Go to latest
Published: Jul 15, 2026 License: MIT Imports: 15 Imported by: 0

Documentation

Overview

Package lansync shares a goplexcli media cache between machines on the same LAN. Each participating process advertises itself via mDNS and serves its cache over HTTP; a peer can discover the others, find whichever has the freshest cache, and pull it — far faster than a full reindex from Plex for a large library.

The HTTP endpoint is intentionally unauthenticated (LAN-only, user opt-in): it exposes library metadata (titles, file paths, server URLs) but never Plex tokens, which live in config rather than the cache.

It is GUI-agnostic: the Wails GUI, the `goplexcli sync serve` daemon, and the `goplexcli sync pull` command all use it. Progress is reported through a caller-supplied callback rather than any UI framework.

Index

Constants

View Source
const (
	// ServiceType is the mDNS service goplexcli instances advertise for cache sync.
	ServiceType = "_goplexcli-sync._tcp"
	// Domain is the mDNS domain used for discovery.
	Domain = "local."

	// DefaultPort is the well-known port the sync server binds by default, so a
	// peer can be addressed directly (e.g. `sync pull --peer host`) without
	// knowing a random port. If it's already in use, an ephemeral port is used
	// instead and mDNS is relied on for discovery.
	DefaultPort = 47820
)

Variables

This section is empty.

Functions

func NormalizePeerAddr added in v0.3.8

func NormalizePeerAddr(addr string) string

NormalizePeerAddr appends DefaultPort to a bare host (e.g. "ghost-2.local") so users can name a machine without remembering the port.

func Pull

func Pull(ctx context.Context, p Peer) (*cache.Cache, error)

Pull downloads a peer's gzipped cache, decompresses it, atomically replaces the local media.json, refreshes the freshness sidecar to match, and returns the loaded cache.

Types

type Meta

type Meta struct {
	Instance    string    `json:"instance"`
	Count       int       `json:"count"`
	LastUpdated time.Time `json:"lastUpdated"`
}

Meta is a peer's cache freshness summary, returned by /cache/meta.

func FetchMeta

func FetchMeta(ctx context.Context, p Peer) (Meta, error)

FetchMeta fetches a peer's freshness summary.

type MetaFunc

type MetaFunc func() Meta

MetaFunc supplies the local cache freshness (Count + LastUpdated). The server stamps Instance itself, so implementations can leave it zero.

func CacheMetaFunc

func CacheMetaFunc() MetaFunc

CacheMetaFunc adapts internal/cache's LoadMeta into a MetaFunc — the freshness source for headless servers (the CLI daemon) that don't hold an in-memory cache. A missing sidecar reports as empty (older than anything).

type Peer

type Peer struct {
	Instance string
	Addr     string // "host:port" using the first IPv4 address
}

Peer is a discovered instance we can query and pull from.

func Discover

func Discover(ctx context.Context, excludeInstance string) ([]Peer, error)

Discover browses the LAN for peers, excluding excludeInstance (pass the local server's instance so a process that also serves doesn't pull from itself; pass "" for a pull-only process). It blocks up to discoverFor.

func (Peer) Host

func (p Peer) Host() string

Host returns a friendly machine name for the peer (the hostname without the PID suffix baked into the instance name).

type Result

type Result struct {
	Updated  bool         // a newer cache was pulled
	UpToDate bool         // peers found, but none newer than local
	Source   string       // friendly hostname the cache came from (when Updated)
	Cache    *cache.Cache // the pulled cache (non-nil when Updated)
}

Result reports the outcome of SyncFromLAN.

func SyncFromLAN

func SyncFromLAN(ctx context.Context, excludeInstance string, local Meta, progress func(string)) (Result, error)

SyncFromLAN discovers peers (excluding excludeInstance), finds the one whose cache is newest and strictly newer than local, and pulls it. progress, if non-nil, is called with human-readable status lines. Errors are returned with user-facing messages.

func SyncFromPeer added in v0.3.8

func SyncFromPeer(ctx context.Context, addr string, local Meta, progress func(string)) (Result, error)

SyncFromPeer pulls from an explicitly addressed peer, bypassing mDNS discovery entirely — the reliable path when multicast is blocked but the host is directly reachable (e.g. `--peer ghost-2.local`). It pulls only if the peer's cache is newer than local.

type Server

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

Server advertises this machine's cache on the LAN and serves it to peers.

func NewServer

func NewServer(metaFn MetaFunc) *Server

NewServer creates a Server that reports freshness via metaFn.

func (*Server) AdvertiseError

func (s *Server) AdvertiseError() error

AdvertiseError returns the mDNS registration error, if any. A non-nil value means the server is reachable but won't be auto-discovered, so peers would need another way to learn its address.

func (*Server) Close

func (s *Server) Close(ctx context.Context)

Close stops advertising and shuts the server down.

func (*Server) Instance

func (s *Server) Instance() string

Instance returns this server's unique mDNS instance name (empty until Start).

func (*Server) Port

func (s *Server) Port() int

Port returns the bound TCP port (0 until Start succeeds).

func (*Server) Start

func (s *Server) Start() error

Start binds the server on DefaultPort (falling back to an ephemeral port if it's taken) and advertises it via mDNS.

func (*Server) StartOn added in v0.3.8

func (s *Server) StartOn(port int) error

StartOn binds a LAN-reachable HTTP server on the given port (0 = ephemeral) and advertises it via mDNS. If a non-zero port is already in use it falls back to an ephemeral port rather than failing. It returns an error only when serving cannot start at all; a failure to advertise is recorded in AdvertiseError and does not stop serving.

Jump to

Keyboard shortcuts

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