partyline

package
v1.5.1-0...-475df33 Latest Latest
Warning

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

Go to latest
Published: Aug 10, 2026 License: MIT Imports: 6 Imported by: 0

Documentation

Overview

Package partyline implements the server-side synthetic cross-account chat feature (partyline.ts): a virtual, IRC-less "network" every local account gets, whose one channel fans messages/reactions out to every other local account instead of an IRC server.

What's deliberately NOT ported here: broadcastJitsi/jitsiJoin/jitsiLeave/ jitsiLeaveAll. Those need Chan.JitsiActive/JitsiHeartbeat fields that don't exist yet (internal/model/chan.go only tracks JitsiUsers/JitsiURL, enough for the IRC-TAGMSG-driven path in internal/irchandlers/jitsi.go) and are only reachable from the jitsi:join/jitsi:leave socket handlers, which aren't ported yet either (Stage 11 territory). sendPushNotification integration is deferred the same way internal/irchandlers defers it (see that package's Deps doc comment) - internal/webpush exists as of this stage, but wiring it into every call site is left for when Client ownership of sessions/subscriptions lands.

Index

Constants

View Source
const NetworkUUID = "a11ce000-0000-4000-8000-000000000001"

NetworkUUID is PARTYLINE_NETWORK_UUID from partyline.ts: fixed rather than random, since the virtual network is rebuilt from scratch on every server restart (never persisted) but message storage keys logged history by (network.uuid, channel.name) - a random UUID here would orphan every previously logged message on each restart.

Variables

This section is empty.

Functions

func Chan

func Chan(network *model.Network) *model.Chan

Chan returns the account's partyline channel from a network built by NewNetwork, mirroring partyline.ts's getChan (`client.partylineNetwork ?.channels[1]` - index 1, since index 0 is always the lobby NewNetwork prepends).

func NewNetwork

func NewNetwork(networkName, chanName, ownerNick string, nextID func() int) *model.Network

NewNetwork mirrors ensureChannel's construction of a fresh partyline Network + its one channel for one account (the caller is responsible for the "idempotent, already have one" half of ensureChannel - checking whether an account already has a partyline network is a Client-ownership concern this package doesn't have a seam for yet).

nextID mirrors client.idChan++, called twice in the same order Node's ensureChannel does: once for the (unused but still ID-bearing) lobby channel, then for the partyline channel itself.

func ReactMessage

func ReactMessage(sender Target, targets []Target, msgid, reaction string)

ReactMessage mirrors partyline.ts's reactMessage: toggles sender's reaction on msgid in every target's own copy of the message that shares it, fanning the new reaction state out via "msg:reaction".

func SendMessage

func SendMessage(deps Deps, sender Target, targets []Target, text, replyTo string)

SendMessage mirrors partyline.ts's sendMessage: fans a chat message out to every target's own copy of the partyline channel, reusing Chan.PushMessage per recipient so unread counters and history trimming all happen exactly like a normal channel message.

func SyncPresence

func SyncPresence(targets []Target, attached func(Target) bool)

SyncPresence mirrors partyline.ts's syncPresence: rebuilds every account's view of "who's online" (any account with at least one attached session) as synthetic Users in its own partyline channel. attached reports whether t currently has any browser session connected, mirroring `Object.keys(c.attachedClients).length > 0`.

Types

type Deps

type Deps struct {
	Cfg    *config.Loaded
	NextID func() int
}

Deps bundles the config-derived values SendMessage needs, mirroring the same Cfg/NextID seam internal/irchandlers.Deps and internal/incommands. Deps use for the identical purpose.

type Target

type Target interface {
	// Name is the account's username (sender.name in partyline.ts).
	Name() string
	// PartylineChan returns this account's own partyline channel (see
	// Chan), or nil if it doesn't have one - callers skip nil targets the
	// same way getChan's undefined return causes partyline.ts's `if
	// (!targetChan) continue` to skip them.
	PartylineChan() *model.Chan
	// Emit sends one named event to every session this account currently
	// has attached, mirroring Client.emit.
	Emit(event string, payload any)
}

Target is the slice of one local account (Client, once it owns IRC/ partyline state) this package needs: enough to fan a message/reaction/ presence update out to that one account's own partyline channel and its own attached browser sessions, without this package needing a concrete Client type. Implementations must be safe to compare with == (SendMessage/ReactMessage use identity to detect "sender is also this recipient", mirroring Node's `target === sender`) - a pointer receiver satisfies this trivially.

Jump to

Keyboard shortcuts

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