mirror of
https://github.com/tiennm99/goclaw.git
synced 2026-10-15 18:15:47 +00:00
* fix: recover whatsapp qr after deleted device * fix: whatsapp connect * fix whatsapp instance device scoping --------- Co-authored-by: Duy /zuey/ <duy@wearetopgroup.com>
107 lines
3.7 KiB
Go
107 lines
3.7 KiB
Go
package whatsapp
|
|
|
|
import (
|
|
"database/sql"
|
|
"encoding/json"
|
|
"fmt"
|
|
|
|
"go.mau.fi/whatsmeow/types"
|
|
|
|
"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"
|
|
)
|
|
|
|
// whatsappCredentials maps encrypted credentials JSON from channel_instances.
|
|
type whatsappCredentials struct {
|
|
DeviceJID string `json:"device_jid,omitempty"`
|
|
BridgeURL string `json:"bridge_url,omitempty"`
|
|
}
|
|
|
|
// whatsappInstanceConfig maps the non-secret config JSONB from the channel_instances table.
|
|
type whatsappInstanceConfig struct {
|
|
DMPolicy string `json:"dm_policy,omitempty"`
|
|
GroupPolicy string `json:"group_policy,omitempty"`
|
|
RequireMention *bool `json:"require_mention,omitempty"`
|
|
HistoryLimit int `json:"history_limit,omitempty"`
|
|
AllowFrom []string `json:"allow_from,omitempty"`
|
|
BlockReply *bool `json:"block_reply,omitempty"`
|
|
ChatBehavior *config.ChatBehaviorConfig `json:"chat_behavior,omitempty"`
|
|
}
|
|
|
|
// FactoryWithDB returns a ChannelFactory with DB access for whatsmeow auth state.
|
|
// dialect must be "pgx" (PostgreSQL) or "sqlite3" (SQLite/desktop).
|
|
func FactoryWithDB(db *sql.DB, pendingStore store.PendingMessageStore, dialect string) channels.ChannelFactory {
|
|
return FactoryWithDBAudio(db, pendingStore, dialect, nil, nil)
|
|
}
|
|
|
|
// FactoryWithDBAudio returns a ChannelFactory with DB access, STT support, and builtin-tools store
|
|
// for reading stt.whatsapp_enabled opt-in setting per message.
|
|
func FactoryWithDBAudio(db *sql.DB, pendingStore store.PendingMessageStore, dialect string,
|
|
audioMgr *audio.Manager, builtinToolStore store.BuiltinToolStore) channels.ChannelFactory {
|
|
return func(name string, creds json.RawMessage, cfg json.RawMessage,
|
|
msgBus *bus.MessageBus, pairingSvc store.PairingStore) (channels.Channel, error) {
|
|
|
|
var ic whatsappInstanceConfig
|
|
if len(cfg) > 0 {
|
|
if err := json.Unmarshal(cfg, &ic); err != nil {
|
|
return nil, fmt.Errorf("decode whatsapp config: %w", err)
|
|
}
|
|
}
|
|
|
|
var wc whatsappCredentials
|
|
if len(creds) > 0 {
|
|
if err := json.Unmarshal(creds, &wc); err != nil {
|
|
return nil, fmt.Errorf("decode whatsapp credentials: %w", err)
|
|
}
|
|
if wc.BridgeURL != "" {
|
|
return nil, fmt.Errorf("whatsapp: bridge_url is no longer supported - " +
|
|
"WhatsApp now runs natively via whatsmeow. Remove bridge_url from credentials")
|
|
}
|
|
}
|
|
|
|
if len(cfg) > 0 {
|
|
var legacy struct {
|
|
BridgeURL string `json:"bridge_url"`
|
|
}
|
|
if json.Unmarshal(cfg, &legacy) == nil && legacy.BridgeURL != "" {
|
|
return nil, fmt.Errorf("whatsapp: bridge_url is no longer supported - " +
|
|
"WhatsApp now runs natively via whatsmeow. Remove bridge_url from config")
|
|
}
|
|
}
|
|
|
|
waCfg := config.WhatsAppConfig{
|
|
Enabled: true,
|
|
AllowFrom: ic.AllowFrom,
|
|
DMPolicy: ic.DMPolicy,
|
|
GroupPolicy: ic.GroupPolicy,
|
|
RequireMention: ic.RequireMention,
|
|
HistoryLimit: ic.HistoryLimit,
|
|
BlockReply: ic.BlockReply,
|
|
ChatBehavior: ic.ChatBehavior,
|
|
}
|
|
// DB instances default to "pairing" for groups (secure by default).
|
|
if waCfg.GroupPolicy == "" {
|
|
waCfg.GroupPolicy = "pairing"
|
|
}
|
|
|
|
var opts []Option
|
|
if wc.DeviceJID != "" {
|
|
jid, err := types.ParseJID(wc.DeviceJID)
|
|
if err != nil {
|
|
return nil, fmt.Errorf("decode whatsapp credentials device_jid: %w", err)
|
|
}
|
|
opts = append(opts, WithDeviceJID(jid))
|
|
}
|
|
|
|
ch, err := New(waCfg, msgBus, pairingSvc, db, pendingStore, dialect, audioMgr, builtinToolStore, opts...)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
ch.SetName(name)
|
|
return ch, nil
|
|
}
|
|
}
|