Documentation
¶
Overview ¶
Package model defines the Network, Chan, Msg, User, and Prefix domain types.
Index ¶
- Constants
- func IP2Hex(address string) string
- func IsPublicAvatarURL(value string) bool
- func IsSupportedUserMetadataKey(key string) bool
- func MetadataValueValid(key, value string) bool
- func ParseMonitorLimit(value string, ok bool) *int
- func SendNickSafe(c *irc.Connection, nick string)
- func SendPartSafe(c *irc.Connection, channel, message string)
- func SendQuitSafe(c *irc.Connection, message string)
- func StripLineTerminators(s string) string
- func SupportedUserMetadataKeys() []string
- type BrowserInfo
- type Chan
- func (c *Chan) ClearUsers()
- func (c *Chan) FindMessage(id int) *Msg
- func (c *Chan) FindMessageByMsgid(msgid string) *Msg
- func (c *Chan) FindUser(nick string) *User
- func (c *Chan) GetSortedUsers(prefix *Prefix) []*User
- func (c *Chan) GetUser(nick string) *User
- func (c *Chan) IsLoggable() bool
- func (c *Chan) IsOperator(net *Network) bool
- func (c *Chan) PushMessage(hub *wsproto.Hub, msg *Msg, nextID func() int, opts PushOptions)
- func (c *Chan) RemoveUser(u *User)
- func (c *Chan) ReplaceUsers(users map[string]*User)
- func (c *Chan) SetMuteStatus(muted bool)
- func (c *Chan) SetUser(u *User)
- type ChanOptions
- type ChanState
- type ChanType
- type IgnoreListItem
- type LinkPreview
- type ListChannelEntry
- type MessageCursor
- type MessageType
- type Msg
- type Network
- func (n *Network) AddChannel(newChan *Chan) int
- func (n *Network) AddIgnoredUser(nick, ident, hostname string)
- func (n *Network) ApplyServerOptions(conn *irc.Connection)
- func (n *Network) AvatarOverrideValue() *string
- func (n *Network) AvatarValue() string
- func (n *Network) BuildConnectOptions(cfg *config.Loaded, browser BrowserInfo, clientCert *tls.Certificate) irc.ConnectOptions
- func (n *Network) ChannelNames() []string
- func (n *Network) ClearAvatarOverride(defaultAvatar string)
- func (n *Network) ConfigureAvatar(defaultAvatar string, override *string)
- func (n *Network) ConsumeSilentBanlistRequest(chanName string) bool
- func (n *Network) GetChannel(name string) *Chan
- func (n *Network) GetLobby() *Chan
- func (n *Network) GetUserMetadata(nick string) (UserMetadata, bool)
- func (n *Network) HasAvatarOverride() bool
- func (n *Network) IsIgnoredUser(nick, ident, hostname string) bool
- func (n *Network) MarkSilentBanlistRequest(chanName string)
- func (n *Network) Monitor(target string)
- func (n *Network) MonitorBatch(targets []string)
- func (n *Network) Quit(message string, defaultLeaveMessage string, sts STSLookup)
- func (n *Network) RemoveChannel(target *Chan)
- func (n *Network) RemoveIgnoredUser(nick, ident, hostname string) bool
- func (n *Network) RemoveMonitor(target string)
- func (n *Network) RenameMonitor(oldTarget, newTarget string)
- func (n *Network) RenameUserMetadata(oldNick, newNick string)
- func (n *Network) ResetMonitorState()
- func (n *Network) SetAvatarOverride(avatar string)
- func (n *Network) SetAvatarValue(avatar string)
- func (n *Network) SetDefaultAvatar(avatar string)
- func (n *Network) SetNick(nick string)
- func (n *Network) SetUserMetadata(nick string, metadata UserMetadata)
- func (n *Network) SetUserMetadataValue(nick string, fallback UserMetadata, key, value string) (UserMetadata, bool)
- func (n *Network) Validate(cfg *config.Loaded, sts STSLookup, hub *wsproto.Hub, nextID func() int) bool
- type NetworkOptions
- type Prefix
- type PrefixEntry
- type PushOptions
- type STSLookup
- type ServerOptions
- type SpecialChanType
- type User
- type UserInMessage
- type UserMetadata
Constants ¶
const ( MetadataAvatar = "avatar" MetadataDisplayName = "display-name" MetadataHomepage = "homepage" MetadataColor = "color" MetadataStatus = "status" )
const AvatarMessageTag = "+relay/avatar"
AvatarMessageTag is the vendor-prefixed client-only tag used by Relay to share an avatar URL on message-tags-capable networks that do not support persistent IRC metadata.
const MessageIDTag = "msgid"
MessageIDTag is the IRCv3 message-ids tag. It is carried by the message-tags capability and has no separate capability of its own.
Variables ¶
This section is empty.
Functions ¶
func IP2Hex ¶
IP2Hex mirrors Helper.ip2hex: an IPv4 address as 8 lowercase hex digits, or "00000000" for anything else (including IPv6 - "no ipv6 support" per the original).
func IsPublicAvatarURL ¶
IsPublicAvatarURL reports whether an avatar URL is suitable for IRC metadata or message tags. Those protocols share a URL, not the image bytes, so relative paths and loopback/private addresses cannot work for users on other Relay instances.
func MetadataValueValid ¶
MetadataValueValid validates values before they are sent to IRC or rendered as a URL/CSS color in the browser. Empty values remove a metadata key.
func ParseMonitorLimit ¶
ParseMonitorLimit mirrors connection.ts's parseMonitorLimit: nil means unsupported (the server never sent a MONITOR ISUPPORT token, i.e. ok is false), 0 means explicitly disabled, a negative value means supported with no limit (a value-less or empty token), and a positive value is the real per-connection target limit.
func SendNickSafe ¶
func SendNickSafe(c *irc.Connection, nick string)
SendNickSafe, SendPartSafe, and SendQuitSafe wrap the underlying irc.Connection's SendNick/SendPart/SendQuit, stripping CR/LF from the free-form argument first. Every call site in this codebase that sends a nick change, part message, or quit message should go through these rather than the raw *irc.Connection methods directly.
func SendPartSafe ¶
func SendPartSafe(c *irc.Connection, channel, message string)
func SendQuitSafe ¶
func SendQuitSafe(c *irc.Connection, message string)
func StripLineTerminators ¶
StripLineTerminators removes any CR/LF characters from s. IRC lines are CRLF-terminated, and some server/client parsers additionally treat a lone \r or \n as a line break on its own, so any free-form user text folded into a raw IRC line must have both stripped first - otherwise it can smuggle a second, attacker-chosen command onto the wire (e.g. a /kick reason or /part message containing an embedded line break).
func SupportedUserMetadataKeys ¶
func SupportedUserMetadataKeys() []string
Types ¶
type BrowserInfo ¶
BrowserInfo carries the connecting browser's IP/hostname/security state, needed to populate WEBIRC and (with useHexIp) the IRC username. Stage 6 will source this from Client.Config.Browser once Client owns network connections.
type Chan ¶
type Chan struct {
ID int `json:"id"`
Messages []*Msg `json:"messages"`
Name string `json:"name"`
Key string `json:"key"`
Topic string `json:"topic"`
FirstUnread int `json:"firstUnread"`
Unread int `json:"unread"`
Highlight int `json:"highlight"`
Muted bool `json:"muted"`
Type ChanType `json:"type"`
State ChanState `json:"state"`
Special SpecialChanType `json:"special,omitempty"`
Closed bool `json:"closed,omitempty"`
NumUsers int `json:"num_users,omitempty"`
// Data mirrors Chan.data: the special-channel payload (ban/invite/
// channel-list rows) shown by list.go/modelist.go.
Data any `json:"data,omitempty"`
// OldestMessageCursor is server-internal (Chan.oldestMessageCursor is
// likewise never part of SharedChan - only its presence/absence feeds
// the synthetic totalMessages field a filtered clone computes).
OldestMessageCursor *MessageCursor `json:"-"`
// Users is server-internal - SharedChan carries no per-channel user
// list; "names"/"users" travel over their own dedicated events instead.
Users map[string]*User `json:"-"` // keyed by lowercased nick
// UserAway caches the away message last seen for a query window's peer
// (query channels have no Users map entry to hang this off of - see
// away.ts), so a repeated AWAY line with the same text doesn't push a
// duplicate message. Despite chan.ts's `userAway?: boolean` type
// annotation, the runtime value is always the away message string (or
// "" when back) - the Go port follows the actual behavior. Server-
// internal, not part of SharedChan.
UserAway string `json:"-"`
// JitsiUsers/JitsiURL mirror Chan.jitsiUsers/jitsiUrl: nicks currently
// in this channel's Jitsi call (tracked via +relay/jitsi TAGMSG tags,
// see irchandlers/jitsi.go) and the room URL, if any. Server-internal -
// travels to the client via its own "jitsi:users" event, not SharedChan.
JitsiUsers []string `json:"-"`
JitsiURL string `json:"-"`
// IsOnline mirrors Chan.isOnline: for a query window, whether its
// MONITOR target is currently known to be connected - nil means
// "never monitored/unknown" (mirrors both TS's `undefined` before the
// first MONITOR reply and its explicit `null` reset on disconnect; Go
// has no reason to distinguish the two). Server-internal - the client
// derives its own copy from the "users:online"/"users:offline"/
// "user:away" events (see monitor.go/away.go), not from SharedChan.
IsOnline *bool `json:"-"`
// contains filtered or unexported fields
}
Chan mirrors server/models/chan.ts - this stage's slice of it: the channel's own history buffer, user list, and the pushMessage/history-trim mechanics that don't depend on Client. Full Client-orchestrated concerns (multi-session "is this channel open" tracking via attachedClients, message-storage indexing, ZNC playback requests) land with Stage 6/8 once Client owns IRC state; PushOptions is the seam those stages hook into.
func (*Chan) ClearUsers ¶
func (c *Chan) ClearUsers()
ClearUsers mirrors the `chan.users = new Map()` reset done when we're kicked or disconnect from a channel - the server no longer tells us who's in it.
func (*Chan) FindMessage ¶
FindMessage mirrors Chan.findMessage.
func (*Chan) FindMessageByMsgid ¶
FindMessageByMsgid mirrors Chan.findMessageByMsgid.
func (*Chan) GetSortedUsers ¶
GetSortedUsers mirrors Chan.getSortedUsers: users ordered by descending mode priority (per prefix's declared order), then case-insensitively by nick within the same mode. A nil or empty prefix returns users unsorted (matching the "no irc.network.options.PREFIX yet" early-return in chan.ts).
func (*Chan) GetUser ¶
GetUser mirrors Chan.getUser: an existing user, or a fresh zero-value one (never stored) if the channel has no record of nick.
func (*Chan) IsLoggable ¶
IsLoggable mirrors Chan.isLoggable (distinct from Msg.IsLoggable, which gates on the individual message's type).
func (*Chan) IsOperator ¶
IsOperator mirrors Chan.isOperator: whether the network's own nick holds a channel mode at or above "@" (op) in this channel, per the network's declared PREFIX priority order.
func (*Chan) PushMessage ¶
PushMessage mirrors Chan.pushMessage: assigns the message its ID (via nextID, standing in for Client's shared idMsg counter until Client owns IRC state), updates unread/highlight/firstUnread counters, broadcasts a "msg" event to every subscriber on hub, and - unless running in public mode - appends to history and trims to MaxHistory.
The public-mode short-circuit matters: Node emits the "msg" event to the browser regardless of public mode, but never appends to `this.messages` in public mode at all ("Never store messages in public mode as the session is completely destroyed when the page gets closed" - chan.ts). Persistence (messageStorage.index) is a Stage 8 concern and isn't ported here yet.
func (*Chan) ReplaceUsers ¶
ReplaceUsers mirrors the `chan.users = newUsers` wholesale replacement names.ts does once a NAMES reply finishes.
func (*Chan) SetMuteStatus ¶
SetMuteStatus mirrors Chan.setMuteStatus.
type ChanOptions ¶
type ChanOptions struct {
Name string
Key string
Muted bool
Type ChanType
Special SpecialChanType
Data any
// State overrides the default ChanParted, mirroring the `state`
// override client.createChannel({state: ChanState.JOINED, ...}) passes
// for a brand-new channel created directly from a self-join (see
// join.ts / irchandlers/join.go) rather than a lazily-opened query/list
// window, which should stay PARTED (the zero value) until actually
// joined.
State ChanState
}
ChanOptions configures NewChan.
type ChanState ¶
type ChanState int
ChanState mirrors client/js/types/chan.ts's ChanState enum (int-valued in TS too, so the numeric values must match).
type IgnoreListItem ¶
type IgnoreListItem struct {
Nick string
Ident string
Hostname string
// When is the unix-millisecond time this entry was added (Date.now()
// in ignore.ts), shown by /ignorelist.
When int64
}
IgnoreListItem mirrors server/models/network.ts's IgnoreListItem: a hostmask pattern (each field may contain '*'/'?' wildcards) to silently drop matching messages from.
type LinkPreview ¶
type LinkPreview struct {
Type string `json:"type"`
Head string `json:"head"`
Body string `json:"body"`
Thumb string `json:"thumb"`
Size int `json:"size"`
Link string `json:"link"`
Shown *bool `json:"shown"`
Error string `json:"error,omitempty"`
Message string `json:"message,omitempty"`
Media string `json:"media,omitempty"`
MediaType string `json:"mediaType,omitempty"`
MaxSize int `json:"maxSize,omitempty"`
ThumbActualURL string `json:"thumbActualUrl,omitempty"`
}
LinkPreview mirrors client/js/types/msg.ts's LinkPreview.
type ListChannelEntry ¶
type ListChannelEntry struct {
Channel string `json:"channel"`
NumUsers int `json:"num_users"`
Topic string `json:"topic"`
}
ListChannelEntry mirrors one row accumulated into Network.chanCache from RPL_LIST (322).
type MessageCursor ¶
MessageCursor is a keyset pagination cursor into sqlite storage (Stage 8) for the oldest message not yet loaded into Chan.Messages. Mirrors Chan.oldestMessageCursor; nil means storage has confirmed no earlier history exists.
type MessageType ¶
type MessageType string
MessageType mirrors client/js/types/msg.ts's MessageType enum exactly - the string values are sent to the client and (Stage 8) persisted to storage, so they must match byte-for-byte.
const ( MessageUnhandled MessageType = "unhandled" MessageAction MessageType = "action" MessageAway MessageType = "away" MessageBack MessageType = "back" MessageError MessageType = "error" MessageInvite MessageType = "invite" MessageJoin MessageType = "join" MessageKick MessageType = "kick" MessageLogin MessageType = "login" MessageLogout MessageType = "logout" MessageMessage MessageType = "message" MessageMode MessageType = "mode" MessageModeChannel MessageType = "mode_channel" MessageModeUser MessageType = "mode_user" // RPL_UMODEIS MessageMonospaceBlock MessageType = "monospace_block" MessageNick MessageType = "nick" MessageNotice MessageType = "notice" MessagePart MessageType = "part" MessageQuit MessageType = "quit" MessageCTCP MessageType = "ctcp" MessageCTCPRequest MessageType = "ctcp_request" MessageChghost MessageType = "chghost" MessageTopic MessageType = "topic" MessageTopicSetBy MessageType = "topic_set_by" MessageWhois MessageType = "whois" MessageRaw MessageType = "raw" MessagePlugin MessageType = "plugin" MessageWallops MessageType = "wallops" )
type Msg ¶
type Msg struct {
From *UserInMessage `json:"from,omitempty"`
ID int `json:"id"`
SearchID int `json:"searchId,omitempty"`
NetworkUUID string `json:"networkUuid,omitempty"`
ChannelName string `json:"channelName,omitempty"`
Msgid string `json:"msgid,omitempty"`
ReplyTo string `json:"replyTo,omitempty"`
Reactions map[string][]string `json:"reactions,omitempty"`
Previews []LinkPreview `json:"previews"`
Text string `json:"text"`
Type MessageType `json:"type"`
Self bool `json:"self"`
Time time.Time `json:"time"`
Encrypted bool `json:"encrypted,omitempty"`
EncryptionError string `json:"encryptionError,omitempty"`
Hostmask string `json:"hostmask,omitempty"`
Target *UserInMessage `json:"target,omitempty"`
NewNick string `json:"new_nick,omitempty"`
Highlight bool `json:"highlight,omitempty"`
ShowInActive bool `json:"showInActive,omitempty"`
NewIdent string `json:"new_ident,omitempty"`
NewHost string `json:"new_host,omitempty"`
CTCPMessage string `json:"ctcpMessage,omitempty"`
Command string `json:"command,omitempty"`
InvitedYou bool `json:"invitedYou,omitempty"`
Gecos string `json:"gecos,omitempty"`
Account string `json:"account,omitempty"`
Error string `json:"error,omitempty"`
Nick string `json:"nick,omitempty"`
Channel string `json:"channel,omitempty"`
Reason string `json:"reason,omitempty"`
RawModes any `json:"raw_modes,omitempty"`
When *time.Time `json:"when,omitempty"`
Whois any `json:"whois,omitempty"`
Users []string `json:"users,omitempty"`
StatusmsgGroup string `json:"statusmsgGroup,omitempty"`
Params []string `json:"params,omitempty"`
}
Msg mirrors server/models/msg.ts's Msg (the kitchen-sink shape shared by every message-shaped event: chat lines, joins/parts, mode changes, errors, WHOIS results, and more - each populating only the fields relevant to its MessageType, exactly like the Node side).
func NewMsg ¶
NewMsg mirrors Msg's constructor: From/Target are deep-copied (mode+nick only) rather than referencing the caller's value, since a Msg is a point-in-time snapshot of who sent it - it must not change retroactively if that user's live state (e.g. a mode change) changes later. Type defaults to MessageMessage and Time to now, matching the JS _.defaults/ `this.time = new Date()` fallback.
func (*Msg) FindPreview ¶
func (m *Msg) FindPreview(link string) *LinkPreview
FindPreview mirrors Msg.findPreview.
type Network ¶
type Network struct {
UUID string
Name string
Nick string
Host string
Port int
TLS bool
UserDisconnected bool
Password string
AwayMessage string
Commands []string
Username string
Realname string
LeaveMessage string
SASL string // "", "plain", or "external"
SASLAccount string
SASLPassword string
Avatar string `json:"-"`
AvatarOverride *string `json:"-"`
// Metadata caches server-provided user metadata for the lifetime of this
// network, so it can be applied when users arrive in NAMES/JOIN events.
Metadata map[string]UserMetadata `json:"-"`
Channels []*Chan
ProxyHost string
ProxyPort int
ProxyUsername string
ProxyPassword string
ProxyEnabled bool
// KeepNick is the nick to restore once available again (e.g. after a
// collision), or "" if none is pending - mirrors Network.keepNick's
// string-or-null.
KeepNick string
HighlightRegex *regexp.Regexp
ServerOptions ServerOptions
// MonitorList/ToBeMonitored mirror Network.monitorList/toBeMonitored:
// lower-cased MONITOR targets currently sent to the server, and ones
// queued behind the server's advertised limit (ServerOptions.Monitor),
// respectively. See Monitor/MonitorBatch/RemoveMonitor/RenameMonitor.
MonitorList []string
ToBeMonitored []string
Bridge *ircbridge.Bridge
// IsPartyline is true only for the synthetic, IRC-less network hosting
// the partyline channel (Stage 10); Bridge is permanently nil for it.
IsPartyline bool
// IgnoreList mirrors Network.ignoreList: hostmask patterns whose
// messages are silently dropped (see IsIgnoredUser).
IgnoreList []IgnoreListItem
// ChanCache mirrors Network.chanCache: accumulates RPL_LIST rows
// between "list start" and "list end" before being flushed to the
// channel-list special window (see irchandlers/list.go).
ChanCache []ListChannelEntry
// TypingDisabledChannels mirrors Network.typingDisabledChannels:
// lower-cased channel names the server has told us reject messages
// (ERR_CANNOTSENDTOCHAN or the non-standard 415), so typing
// notifications stop being sent there.
TypingDisabledChannels map[string]bool
// SilentBanlistRequests mirrors Network.silentBanlistRequests: a
// pending-count per lower-cased channel name of banlist refreshes
// triggered internally (e.g. after a MODE +b) that shouldn't pop open
// the legacy "Ban list for #chan" window when they complete.
SilentBanlistRequests map[string]int
// LastListRequest mirrors Network.lastListRequest: when /list last ran,
// enforcing list.ts's 10-second request cooldown. Zero means never.
LastListRequest time.Time
// PendingWhoisPopup has no Node equivalent - a fork-only marker (keyed
// lower-case by nick) set by incommands' whois-popup command right
// before sending WHOIS, consumed once by irchandlers.handleWhoisEnd to
// decide whether that lookup's result goes out as an ephemeral popup
// event (WhoisDialog.vue) instead of the classic pushed buffer message.
// Typing /whois directly never sets this, so it keeps the classic
// behavior; only UI-triggered lookups (the "User information" context
// menu action) do.
PendingWhoisPopup map[string]bool
// contains filtered or unexported fields
}
Network mirrors server/models/network.ts - this stage's slice of it: config/state fields, validate()/lockNetwork enforcement, ISUPPORT-derived serverOptions, STS interaction, and ownership of the ircbridge.Bridge for its connection. Actually driving the connection (join-after-registration, message routing into Chan.PushMessage, ignore-list filtering) is Stage 6's job, wired through Bridge.Subscribe.
func NewNetwork ¶
func NewNetwork(opts NetworkOptions) *Network
NewNetwork mirrors Network's constructor, including prepending the lobby channel with the same "start muted if every existing channel is muted" heuristic.
func (*Network) AddChannel ¶
AddChannel mirrors Network.addChannel: inserts newChan at its sorted position among existing CHANNEL/QUERY entries (special channels and the lobby are left in place, never sorted against), or appends it if it's itself special.
func (*Network) AddIgnoredUser ¶
AddIgnoredUser mirrors ignore.ts's `network.ignoreList.push({...hostmask, when: Date.now()})`.
func (*Network) ApplyServerOptions ¶
func (n *Network) ApplyServerOptions(conn *irc.Connection)
ApplyServerOptions mirrors the parts of createIrcFramework/network.ts that populate serverOptions from ISUPPORT, called by Stage 6's connection handler once the bridge's underlying connection has processed RPL_ISUPPORT.
func (*Network) AvatarOverrideValue ¶
AvatarOverrideValue returns a copy of the explicit per-network avatar override, or nil when the network inherits the account default.
func (*Network) AvatarValue ¶
AvatarValue returns the local Relay avatar, which may be a private /uploads/ path and therefore unsuitable for IRC metadata.
func (*Network) BuildConnectOptions ¶
func (n *Network) BuildConnectOptions(cfg *config.Loaded, browser BrowserInfo, clientCert *tls.Certificate) irc.ConnectOptions
BuildConnectOptions mirrors setIrcFrameworkOptions + createWebIrc: turns this Network's config into the irc library's ConnectOptions (plus its SASL/WebIRC/Socks5 sub-options). cfg supplies the WEBIRC entries and the useHexIp setting; browser supplies the connecting client's IP/hostname for WEBIRC; clientCert is required for SASL EXTERNAL (see irc.ConnectOptions's own doc comment on why).
func (*Network) ChannelNames ¶
ChannelNames returns the non-lobby channel names, for callers (Stage 6's connection handler) that explicitly JOIN each one after registration - BuildConnectOptions deliberately leaves ConnectOptions.Channels empty since, like Node's createIrcFramework, joining happens as an explicit post-registration step (so per-channel keys can be sent), not as part of the connection handshake itself.
func (*Network) ClearAvatarOverride ¶
ClearAvatarOverride makes the network inherit the supplied account default.
func (*Network) ConfigureAvatar ¶
ConfigureAvatar applies the account default and an optional persisted network override while constructing a network.
func (*Network) ConsumeSilentBanlistRequest ¶
ConsumeSilentBanlistRequest mirrors Network.consumeSilentBanlistRequest: reports whether this banlist reply corresponds to a pending silent request, decrementing (or clearing) its count if so.
func (*Network) GetChannel ¶
GetChannel mirrors Network.getChannel: a case-insensitive name lookup that always skips the lobby (index 0).
func (*Network) GetUserMetadata ¶
func (n *Network) GetUserMetadata(nick string) (UserMetadata, bool)
GetUserMetadata returns the cached metadata for nick without exposing the map to callers. Metadata is updated by both IRC and websocket handlers.
func (*Network) HasAvatarOverride ¶
HasAvatarOverride reports whether this network has an explicit avatar setting, including an explicit empty value that hides the account default.
func (*Network) IsIgnoredUser ¶
IsIgnoredUser mirrors Network.isIgnoredUser: whether data's hostmask matches any entry in the ignore list, wildcards allowed in each field.
func (*Network) MarkSilentBanlistRequest ¶
MarkSilentBanlistRequest mirrors Network.markSilentBanlistRequest.
func (*Network) Monitor ¶
Monitor mirrors Network.monitor: adds target to the server's MONITOR list, or queues it in ToBeMonitored if the server-advertised limit is already reached. A no-op before registration or on a network where MONITOR is unsupported/disabled (ServerOptions.Monitor nil or 0).
func (*Network) MonitorBatch ¶
MonitorBatch mirrors Network.monitorBatch: adds every target at once, queuing whatever doesn't fit under the server-advertised limit, and chunking the rest into as few "MONITOR + ..." lines as fit under IRC's line-length limit.
func (*Network) Quit ¶
Quit mirrors Network.quit: refreshes any active STS policy's expiration (reconnecting shouldn't reset the countdown to re-check STS) and sends QUIT with the first non-empty of message, this network's LeaveMessage, or the server-wide default.
func (*Network) RemoveChannel ¶
RemoveChannel mirrors the `network.channels = _.without(network.channels, chan)` step of Client.part/Client.quit - removing chan from this network's channel list. A no-op if chan isn't present (or is the lobby, which callers must never pass here).
func (*Network) RemoveIgnoredUser ¶
RemoveIgnoredUser mirrors ignore.ts's /unignore lookup: removes the first ignore-list entry whose wildcard pattern matches nick/ident/hostname (Helper.compareHostmask), reporting whether one was found and removed.
func (*Network) RemoveMonitor ¶
RemoveMonitor mirrors Network.removeMonitor: stops monitoring target, promoting the next queued ToBeMonitored target (if any) into its freed slot.
func (*Network) RenameMonitor ¶
RenameMonitor mirrors Network.renameMonitor: swaps a monitored (or queued) target for a new name in place, preserving its slot, or monitors newTarget fresh if oldTarget wasn't tracked at all.
func (*Network) RenameUserMetadata ¶
RenameUserMetadata moves cached metadata when the server changes a nick.
func (*Network) ResetMonitorState ¶
func (n *Network) ResetMonitorState()
ResetMonitorState mirrors connection.ts's "socket close" handler clearing all MONITOR bookkeeping: the server has forgotten our monitor list along with the rest of the connection, so tracking it as still active would be wrong, and ServerOptions.Monitor itself resets to nil (unknown) until the next connection's ISUPPORT re-establishes it.
func (*Network) SetAvatarOverride ¶
SetAvatarOverride gives this network its own avatar, including an explicit empty value to hide the account default.
func (*Network) SetAvatarValue ¶
func (*Network) SetDefaultAvatar ¶
SetDefaultAvatar updates the inherited avatar without changing an explicit network override.
func (*Network) SetNick ¶
SetNick mirrors Network.setNick: updates the nick and rebuilds the case-insensitive highlight regex used to detect mentions in message text.
func (*Network) SetUserMetadata ¶
func (n *Network) SetUserMetadata(nick string, metadata UserMetadata)
SetUserMetadata stores the cached metadata for nick.
func (*Network) SetUserMetadataValue ¶
func (n *Network) SetUserMetadataValue(nick string, fallback UserMetadata, key, value string) (UserMetadata, bool)
SetUserMetadataValue updates one metadata key atomically. If nick has no cached entry, fallback supplies locally-known values such as an uploaded avatar that is not shareable over IRC.
func (*Network) Validate ¶
func (n *Network) Validate(cfg *config.Loaded, sts STSLookup, hub *wsproto.Hub, nextID func() int) bool
Validate mirrors Network.validate: cleans/clamps user-supplied fields, enforces lockNetwork/public-mode overrides, and applies an active STS policy. On a hard failure it pushes an error Msg to the lobby (mirroring the `error()` closure in network.ts) and returns false; the STS-upgrade case pushes an informational Msg but still returns true, matching the TS control flow exactly (that branch has no `return false` in the original).
type NetworkOptions ¶
type NetworkOptions struct {
UUID string
Name string
Nick string
Host string
Port int
TLS bool
Password string
Username string
Realname string
SASL string
SASLAccount string
SASLPassword string
// Channels are pre-existing channels to restore (e.g. loaded from a
// user's saved config); the lobby is prepended automatically and must
// not be included here.
Channels []*Chan
Commands []string
ProxyEnabled bool
ProxyHost string
ProxyPort int
ProxyUsername string
ProxyPassword string
LeaveMessage string
AwayMessage string
UserDisconnected bool
}
NetworkOptions configures NewNetwork.
type Prefix ¶
type Prefix struct {
Prefix []PrefixEntry `json:"prefix"`
ModeToSymbol map[string]string `json:"modeToSymbol"`
Symbols []string `json:"symbols"`
}
Prefix tracks a server's PREFIX ISUPPORT token: the ordered mode/symbol pairs, a mode->symbol lookup, and the plain symbol list. Mirrors server/models/prefix.ts field-for-field (including the outer/inner both being named "prefix", matching client/js/types/network.ts's SharedPrefix) - this whole struct is round-tripped to the client verbatim as part of a network's serverOptions.
func NewPrefix ¶
func NewPrefix(entries []PrefixEntry) *Prefix
NewPrefix builds a Prefix from its ordered entries (highest priority first), matching Prefix's constructor. A nil entries is treated as empty.
func (*Prefix) Update ¶
func (p *Prefix) Update(entries []PrefixEntry)
Update replaces the prefix list and recomputes the derived lookups, mirroring Prefix.update/_update_internals.
type PrefixEntry ¶
PrefixEntry pairs a channel-membership mode letter with the nick prefix symbol the server displays for it, in priority order (highest first). Field names/JSON tags match client/js/types/network.ts's SharedPrefixObject.
type PushOptions ¶
type PushOptions struct {
IsOpen bool
IncreasesUnread bool
MaxHistory int
Public bool
// NotificationCategories mirrors the `notificationCategories` argument
// pushMessage forwards straight into the emitted "msg" event, letting
// the client decide whether to show a desktop notification/play a
// sound without recomputing eligibility itself. nil (the zero value)
// omits the key entirely, matching Node's `undefined` when the caller
// (message.ts) determines the message isn't notification-eligible.
NotificationCategories []string
// Index mirrors the `this.writeUserLog(client, msg)` call
// pushMessage itself makes (chan.ts) - a Client-level concern (message
// storage) this package doesn't own, wired in by internal/session via
// this seam instead. Never called in public mode, matching writeUserLog
// only ever running after pushMessage's own public-mode early return.
Index func(msg *Msg)
}
PushOptions carries the parts of pushMessage's behavior that depend on Client state not yet wired up in this stage. IsOpen mirrors the `attachedClients` "is this channel open in any session" check; MaxHistory mirrors Config.values.maxHistory (negative disables trimming); Public mirrors Config.values.public.
type STSLookup ¶
type STSLookup interface {
// Get reports the port an active STS policy for host demands, if any.
Get(host string) (port int, ok bool)
// RefreshExpiration extends an active policy's expiry, mirroring
// https://ircv3.net/specs/extensions/sts#rescheduling-expiry-on-disconnect.
RefreshExpiration(host string)
}
STSLookup abstracts the STS policy store (internal/sts, built in Stage 10) so Network doesn't have to depend on it before it exists. Passing nil simply skips the STS-upgrade check in Validate/Quit.
type ServerOptions ¶
type ServerOptions struct {
ChanTypes []string `json:"CHANTYPES"`
Prefix *Prefix `json:"PREFIX"`
Network string `json:"NETWORK"`
// Monitor mirrors serverOptions.MONITOR's `number | null`: nil means
// the server never sent a MONITOR ISUPPORT token (unsupported), 0
// means it explicitly advertised a limit of zero (disabled), a
// negative value means "supported, no limit" (a value-less or empty
// MONITOR token), and a positive value is the real per-connection
// target limit. See ParseMonitorLimit.
Monitor *int `json:"MONITOR"`
}
ServerOptions mirrors Network.serverOptions - the subset of ISUPPORT the client needs (CHANTYPES/PREFIX/NETWORK), populated from the irc library's ISUPPORT accessors once the bridge connects (see ApplyServerOptions; Stage 6's connection handler calls it on RPL_ISUPPORT).
type SpecialChanType ¶
type SpecialChanType string
SpecialChanType mirrors client/js/types/chan.ts's SpecialChanType enum.
const ( SpecialBanList SpecialChanType = "list_bans" SpecialInviteList SpecialChanType = "list_invites" SpecialChannelList SpecialChanType = "list_channels" SpecialIgnoreList SpecialChanType = "list_ignored" SpecialPartyline SpecialChanType = "partyline" )
type User ¶
type User struct {
Nick string `json:"nick"`
Modes []string `json:"modes"`
Away string `json:"away,omitempty"`
Account string `json:"account,omitempty"`
Avatar string `json:"avatar,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Homepage string `json:"homepage,omitempty"`
Color string `json:"color,omitempty"`
Status string `json:"status,omitempty"`
LastMessage int64 `json:"lastMessage"`
}
User represents one nick's per-channel state: which membership modes they hold there, away status, and when they last spoke. Mirrors server/models/user.ts.
func NewUser ¶
NewUser mirrors User's constructor: modeLetters are raw IRC mode letters (e.g. "o", "v") as reported by the irc library, converted to the server's display symbols via prefix. A nil prefix is treated as empty (no known symbols), matching `new Prefix([])` in chan.ts's getUser.
type UserInMessage ¶
type UserInMessage struct {
Mode string `json:"mode"`
Nick string `json:"nick,omitempty"`
Avatar string `json:"avatar,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Homepage string `json:"homepage,omitempty"`
Color string `json:"color,omitempty"`
Status string `json:"status,omitempty"`
}
UserInMessage is a shallow, point-in-time snapshot of a user's mode/nick embedded in a Msg's From/Target fields - deliberately copied rather than pointing at the live *User (see NewMsg), so a later nick or mode change doesn't retroactively rewrite history. Mirrors client/js/types/msg.ts's UserInMessage.
type UserMetadata ¶
type UserMetadata struct {
Avatar string `json:"avatar,omitempty"`
DisplayName string `json:"displayName,omitempty"`
Homepage string `json:"homepage,omitempty"`
Color string `json:"color,omitempty"`
Status string `json:"status,omitempty"`
}
UserMetadata is the subset of IRCv3 user metadata Relay understands and presents in its UI. The JSON names are the client-facing names; the wire keys are the constants above.
func (*UserMetadata) Set ¶
func (m *UserMetadata) Set(key, value string) bool
func (UserMetadata) Value ¶
func (m UserMetadata) Value(key string) string