Documentation
¶
Overview ¶
Package incommands ports server/plugins/inputs/*.ts: the client-initiated slash commands (/join, /msg, /nick, etc). Node registers each module in a `Map<string, Plugin>` keyed by every alias it handles (server/plugins/ inputs/index.ts) and Client.input looks up `cmd` in that map, gating on `allowDisconnected` before invoking `plugin.input.apply(client, [network, chan, cmd, args, opts])`. Dispatch (registry.go) is that same lookup+gate, and each *.go file below mirrors one *.ts file's `input` function.
Node's `input` runs with `this` bound to the owning Client, which is how alias.ts reads/writes `this.config.clientSettings.aliases`, several commands call `this.save()`, and quit.ts/connect.ts reach into `this.networks`/`this.connectToNetwork`. internal/auth.Client does not yet own any live Network/Chan state (see its doc comment - server/client.ts's `networks` field is round-tripped as opaque JSON until a later stage wires real ownership), so this package cannot depend on a concrete Client. What each command needs from it is threaded through Deps instead, following the same nil-tolerant interface-seam pattern internal/irchandlers uses for STSUpdater:
- Deps.Save persists the owning client's on-disk config; nil until Client ownership lands (client.save() becomes a no-op meanwhile).
- Deps.Aliases abstracts config.clientSettings.aliases for alias.go; nil until the same wiring lands.
- Deps.Connect/Deps.ConnectToNetwork stand in for `irc.connect()` and `client.connectToNetwork(...)` - dialing a fresh underlying connection is an orchestration concern (wiring ircbridge.NewBridge + irchandlers.Register + a goroutine running Bridge.Run) that doesn't exist as a callable unit yet outside tests; nil reports a clear "not available yet" error instead of silently no-op'ing.
Self-echo fabrication (msg.ts/notice.ts/action.ts's "if the network doesn't echo our own messages back, simulate it" branches, needed so the sender sees their own line without a server-assigned msgid when echo-message isn't negotiated) is done by publishing a synthetic event through ircbridge.Bridge.Publish, so it flows through the exact same irchandlers dispatch real events do rather than duplicating message-building logic here.
Not ported here, consistently: chan.loadMessages (Stage 8), and Chan. destroy's link-preview dereferencing (tied to Stage 9's prefetch reference counting) - each is the same kind of Client/later-stage concern irchandlers already deferred past Stage 6. client.mentions bookkeeping and ClientCertificate.remove are wired, via Deps.RemoveMentions/ Deps.RemoveNetwork respectively.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func Commands ¶
func Commands() []string
Commands returns every registered command name (without the leading '/'), mirroring index.ts's getCommands (minus the client-side-only and pass-through names, which aren't this package's concern).
func Dispatch ¶
func Dispatch(deps Deps, network *model.Network, chn *model.Chan, cmd string, args []string, opts InputOpts) (ok bool)
Dispatch mirrors the userInputs.get(cmd) lookup, the connected/ allowDisconnected gate, and the invocation in Client.input (server/client.ts). ok reports whether cmd matched a registered command at all - a caller still needs to fall back to the pass-through commands list and the raw-IRC-line default Client.input applies for anything else, neither of which is this package's concern.
Types ¶
type AliasStore ¶
AliasStore abstracts the per-client alias list (config.clientSettings. aliases in server/client.ts) alias.go needs to read and persist. See the package doc comment for why this is a seam rather than a concrete Client dependency.
type Deps ¶
type Deps struct {
Hub *wsproto.Hub
Cfg *config.Loaded
NextID func() int
// Stats renders Relay's local-only /relaystats output. It must not write to
// the IRC connection; the command displays the returned text as a local
// notice in the current Relay window.
Stats func(network *model.Network) string
StatsEnabled func() bool
// NextChanID mirrors Client.createChannel's per-account channel id
// counter - see internal/irchandlers.Deps's identical field for why
// every openChannel call needs one.
NextChanID func() int
// STS lets disconnect.go/quit.go refresh an active policy's expiration
// on quit, mirroring Network.Quit's sts parameter. nil is accepted
// (skips the refresh) exactly like model.Network.Validate/Quit already
// tolerate a nil STSLookup pending Stage 10's internal/sts.
STS model.STSLookup
// Save persists the owning client's on-disk config (client.save() in
// Node). nil until Client owns live Network/Chan state - see the
// package doc comment.
Save func()
// Aliases backs alias.go. nil until Client ownership lands.
Aliases AliasStore
Encryption EncryptionStore
// Connect dials a fresh underlying connection for an existing,
// currently-disconnected network (connect.ts's no-args branch,
// `irc.connect()`). nil reports "not available yet" rather than
// silently doing nothing - see the package doc comment.
Connect func(network *model.Network) error
// ConnectToNetwork adds and connects a brand new network (connect.ts's
// with-args branch, `client.connectToNetwork(...)`). nil reports "not
// available yet".
ConnectToNetwork func(host, port string, tls bool) error
// RemoveNetwork mirrors quit.ts's `this.networks = _.without(this.networks,
// network)` + `ClientCertificate.remove(network.uuid)` tail end: drops the
// network from the owning client and cleans up its client certificate.
// nil until Client ownership lands - see the package doc comment.
RemoveNetwork func(network *model.Network)
// RemoveMentions mirrors Client.part's `client.mentions = client.
// mentions.filter((msg) => !(msg.chanId === chan.id))` line, called by
// part.go's partChannel. nil until Client ownership lands.
RemoveMentions func(chanID int)
// IsOpen mirrors chan.pushMessage's own `_.find(client.attachedClients,
// {openChannel: chanId})` lookup (Client.IsChannelOpen) - see
// internal/irchandlers.Deps's identical field. nil is treated as
// "never open".
IsOpen func(chanID int) bool
// LoadHistory mirrors msg.ts's `newChan.loadMessages(this, network)`
// call right after opening a new query window - seeds it from
// message-storage history the same way internal/session.
// loadChannelMessages does at startup/network-add, via the seam
// pattern this Deps struct uses throughout (this package can't import
// internal/session, which owns the real implementation, without an
// import cycle - session already imports this package to wire up
// Dispatch). nil skips the load, leaving the channel empty exactly
// like before this seam existed.
LoadHistory func(network *model.Network, chn *model.Chan)
}
Deps carries every dependency a command handler needs, gathered in one place so Dispatch's signature doesn't grow a parameter per command file - the same shape internal/irchandlers.Deps uses for the same reason.
type EncryptionStore ¶
type EncryptionStore interface {
Generate(networkID, target string) (string, error)
Set(networkID, target, encodedKey string) error
SetPassphrase(networkID, target, passphrase string) (string, error)
Remove(networkID, target string) (bool, error)
List(networkID string) []string
Encrypt(networkID, kind, target, plaintext string) (string, error)
Enabled(networkID, target string) bool
}
EncryptionStore is the account-scoped key and wire-format seam. The session package owns persistence and master-key protection; commands only need target-scoped operations and message encryption.
type InputOpts ¶
type InputOpts struct {
ReplyTo string
// ShowEncryptionKey delivers a generated key directly to the requesting
// WebSocket. It must not be rendered as a chat message because chat
// history is persisted.
ShowEncryptionKey func(target, key string)
}
InputOpts mirrors PluginInputOpts: the one extra per-call option Client. input threads through (the client-supplied message id a "say" is a reply to, used by msg.go to tag the outgoing PRIVMSG with a +reply tag).