mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 12:14:17 +00:00
115 lines
4.5 KiB
Go
115 lines
4.5 KiB
Go
package discord
|
|
|
|
import (
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"github.com/nextlevelbuilder/goclaw/internal/audio"
|
|
"github.com/nextlevelbuilder/goclaw/internal/bus"
|
|
"github.com/nextlevelbuilder/goclaw/internal/channels"
|
|
"github.com/nextlevelbuilder/goclaw/internal/config"
|
|
"github.com/nextlevelbuilder/goclaw/internal/store"
|
|
)
|
|
|
|
// discordCreds maps the credentials JSON from the channel_instances table.
|
|
type discordCreds struct {
|
|
Token string `json:"token"`
|
|
}
|
|
|
|
// discordInstanceConfig maps the non-secret config JSONB from the channel_instances table.
|
|
type discordInstanceConfig struct {
|
|
DMPolicy string `json:"dm_policy,omitempty"`
|
|
GroupPolicy string `json:"group_policy,omitempty"`
|
|
AllowFrom []string `json:"allow_from,omitempty"`
|
|
RequireMention *bool `json:"require_mention,omitempty"`
|
|
HistoryLimit *int `json:"history_limit,omitempty"`
|
|
BlockReply *bool `json:"block_reply,omitempty"`
|
|
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
|
|
MediaMaxBytes int64 `json:"media_max_bytes,omitempty"`
|
|
STTProxyURL string `json:"stt_proxy_url,omitempty"`
|
|
STTAPIKey string `json:"stt_api_key,omitempty"`
|
|
STTTenantID string `json:"stt_tenant_id,omitempty"`
|
|
STTTimeoutSeconds int `json:"stt_timeout_seconds,omitempty"`
|
|
VoiceAgentID string `json:"voice_agent_id,omitempty"`
|
|
}
|
|
|
|
// Factory creates a Discord channel from DB instance data (no extra stores).
|
|
func Factory(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore) (channels.Channel, error) {
|
|
return buildChannel(name, creds, cfg, msgBus, pairingSvc, nil, nil, nil, nil)
|
|
}
|
|
|
|
// FactoryWithStores returns a ChannelFactory that includes agent, configPerm, and pending message stores.
|
|
func FactoryWithStores(agentStore store.AgentStore, configPermStore store.ConfigPermissionStore, pendingStore store.PendingMessageStore) channels.ChannelFactory {
|
|
return FactoryWithStoresAndAudio(agentStore, configPermStore, pendingStore, nil)
|
|
}
|
|
|
|
// FactoryWithStoresAndAudio returns a ChannelFactory with all stores and STT support.
|
|
func FactoryWithStoresAndAudio(agentStore store.AgentStore, configPermStore store.ConfigPermissionStore, pendingStore store.PendingMessageStore, audioMgr *audio.Manager) channels.ChannelFactory {
|
|
return func(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore) (channels.Channel, error) {
|
|
return buildChannel(name, creds, cfg, msgBus, pairingSvc, agentStore, configPermStore, pendingStore, audioMgr)
|
|
}
|
|
}
|
|
|
|
func buildChannel(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore,
|
|
agentStore store.AgentStore, configPermStore store.ConfigPermissionStore,
|
|
pendingStore store.PendingMessageStore, audioMgr *audio.Manager) (channels.Channel, error) {
|
|
|
|
var c discordCreds
|
|
if len(creds) > 0 {
|
|
if err := json.Unmarshal(creds, &c); err != nil {
|
|
return nil, fmt.Errorf("decode discord credentials: %w", err)
|
|
}
|
|
}
|
|
if c.Token == "" {
|
|
return nil, fmt.Errorf("discord token is required")
|
|
}
|
|
|
|
var ic discordInstanceConfig
|
|
if len(cfg) > 0 {
|
|
if err := json.Unmarshal(cfg, &ic); err != nil {
|
|
return nil, fmt.Errorf("decode discord config: %w", err)
|
|
}
|
|
}
|
|
|
|
dcCfg := config.DiscordConfig{
|
|
Enabled: true,
|
|
Token: c.Token,
|
|
AllowFrom: ic.AllowFrom,
|
|
DMPolicy: ic.DMPolicy,
|
|
GroupPolicy: ic.GroupPolicy,
|
|
RequireMention: ic.RequireMention,
|
|
HistoryLimit: resolveHistoryLimit(ic.HistoryLimit),
|
|
BlockReply: ic.BlockReply,
|
|
ChatBehavior: ic.ChatBehavior,
|
|
MediaMaxBytes: ic.MediaMaxBytes,
|
|
STTProxyURL: ic.STTProxyURL,
|
|
STTAPIKey: ic.STTAPIKey,
|
|
STTTenantID: ic.STTTenantID,
|
|
STTTimeoutSeconds: ic.STTTimeoutSeconds,
|
|
VoiceAgentID: ic.VoiceAgentID,
|
|
}
|
|
|
|
// DB instances default to "pairing" for groups (secure by default).
|
|
if dcCfg.GroupPolicy == "" {
|
|
dcCfg.GroupPolicy = "pairing"
|
|
}
|
|
|
|
ch, err := New(dcCfg, msgBus, pairingSvc, agentStore, configPermStore, pendingStore, audioMgr)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
ch.SetName(name)
|
|
return ch, nil
|
|
}
|
|
|
|
func resolveHistoryLimit(limit *int) int {
|
|
if limit == nil {
|
|
return channels.DefaultGroupHistoryLimit
|
|
}
|
|
return *limit
|
|
}
|