Documentation
¶
Index ¶
- func GenerateBindCode() (string, error)
- func RegisterCommand(spec CommandSpec)
- type AuditEntry
- type AuditRecorder
- type BindCodeConsumer
- type BindingInfo
- type BindingLookup
- type Button
- type CommandHandler
- type CommandRegistry
- type CommandRegistryAPI
- type CommandReply
- type CommandSource
- type CommandSpec
- type MessageChain
- type RateLimitSpec
- type RateLimiter
- type RateLimiterAPI
- type Replier
- type Reply
- type SessionState
- type SessionStore
- type SessionStoreAPI
- type Source
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func GenerateBindCode ¶
GenerateBindCode generates an 8-character unambiguous binding code using CSPRNG. Uses charset without 0/O/1/l/I to reduce user error in manual entry. Returns error only on crypto/rand failure (should be extremely rare).
func RegisterCommand ¶
func RegisterCommand(spec CommandSpec)
Types ¶
type AuditEntry ¶
type AuditEntry struct {
NotificationConfID uint
ChannelType string
ChannelUserID string
Command string
Args map[string]any
Result string
LatencyMs int64
}
AuditEntry is the audit row written by the chain.
type AuditRecorder ¶
type AuditRecorder interface {
Record(ctx context.Context, e AuditEntry) error
}
AuditRecorder writes a single audit row. Implemented by app.AuditService.
type BindCodeConsumer ¶
type BindCodeConsumer interface {
ConsumeCode(ctx context.Context, code, channelType, channelUserID string) error
}
BindCodeConsumer consumes a /bind <code> request. Implemented by app.BindingService.
type BindingInfo ¶
type BindingInfo struct {
ID uint
ConfID uint
ChannelType string
ChannelUserID string
ReplyLang string
PtAdmin bool
Allowed bool
}
BindingInfo is the subset of binding data needed by the chain. Defined locally (instead of importing internal/app) to avoid an import cycle: internal/app already imports internal/chatops for GenerateBindCode.
type BindingLookup ¶
type BindingLookup interface {
FindByChannelUser(ctx context.Context, channelType, channelUserID string) (BindingInfo, bool, error)
}
BindingLookup resolves a (channel, user) pair to a BindingInfo.
type CommandHandler ¶
type CommandRegistry ¶
type CommandRegistry struct {
// contains filtered or unexported fields
}
func DefaultRegistry ¶
func DefaultRegistry() *CommandRegistry
func NewCommandRegistry ¶
func NewCommandRegistry() *CommandRegistry
func (*CommandRegistry) Get ¶
func (r *CommandRegistry) Get(name string) (CommandSpec, bool)
func (*CommandRegistry) List ¶
func (r *CommandRegistry) List() []CommandSpec
func (*CommandRegistry) Register ¶
func (r *CommandRegistry) Register(spec CommandSpec)
type CommandRegistryAPI ¶
type CommandRegistryAPI interface {
Get(name string) (CommandSpec, bool)
List() []CommandSpec
}
CommandRegistryAPI abstracts CommandRegistry so the chain can be tested without depending on the concrete registry implementation.
type CommandReply ¶
type CommandReply = Reply
type CommandSource ¶
type CommandSource = Source
type CommandSpec ¶
type CommandSpec struct {
Name string
Description string
Aliases []string
AdminOnly bool
Handler CommandHandler
RateLimit *RateLimitSpec
}
type MessageChain ¶
type MessageChain struct {
// contains filtered or unexported fields
}
MessageChain dispatches inbound messages through the permission gate per plan T22 (binding → allowed → command parse → session → registry → ratelimit → admin check → handler).
func NewMessageChain ¶
func NewMessageChain( registry CommandRegistryAPI, bindings BindingLookup, bindCoder BindCodeConsumer, audit AuditRecorder, rl RateLimiterAPI, sessions SessionStoreAPI, replier Replier, ) *MessageChain
NewMessageChain wires the dependencies. replier may be nil when there is no outbound channel (e.g. CLI debugging).
func (*MessageChain) Process ¶
func (mc *MessageChain) Process(ctx context.Context, msg notify.InboundMessage) error
Process is the inbound entry point. It returns an error only on unrecoverable conditions (lookup failure, nil handler); business denies are surfaced via audit + reply, never as errors.
type RateLimitSpec ¶
type RateLimiter ¶
type RateLimiter struct {
// contains filtered or unexported fields
}
func NewRateLimiter ¶
func NewRateLimiter() *RateLimiter
func (*RateLimiter) Allow ¶
func (rl *RateLimiter) Allow(channel, userID, command string) bool
type RateLimiterAPI ¶
RateLimiterAPI abstracts RateLimiter for the chain.
type SessionState ¶
type SessionState struct {
Step string
Data string
Handler CommandHandler
ExpiresAt time.Time
}
type SessionStore ¶
type SessionStore struct {
// contains filtered or unexported fields
}
func NewSessionStore ¶
func NewSessionStore() *SessionStore
func (*SessionStore) Clear ¶
func (s *SessionStore) Clear(channel string, confID uint, userID string)
func (*SessionStore) Pending ¶
func (s *SessionStore) Pending(channel string, confID uint, userID string) (SessionState, bool)
func (*SessionStore) Set ¶
func (s *SessionStore) Set(channel string, confID uint, userID string, state SessionState, ttl time.Duration)
func (*SessionStore) Stop ¶
func (s *SessionStore) Stop()
type SessionStoreAPI ¶
type SessionStoreAPI interface {
Pending(channel string, confID uint, userID string) (SessionState, bool)
Set(channel string, confID uint, userID string, state SessionState, ttl time.Duration)
Clear(channel string, confID uint, userID string)
}
SessionStoreAPI abstracts SessionStore for the chain.