mirror of
https://github.com/YspCoder/clawgo.git
synced 2026-06-09 13:33:22 +08:00
add channel-specific build variants
This commit is contained in:
44
pkg/channels/channel_disabled.go
Normal file
44
pkg/channels/channel_disabled.go
Normal file
@@ -0,0 +1,44 @@
|
||||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
)
|
||||
|
||||
func errChannelDisabled(name string) error {
|
||||
return fmt.Errorf("%s channel is disabled at build time", name)
|
||||
}
|
||||
|
||||
type disabledChannel struct {
|
||||
name string
|
||||
}
|
||||
|
||||
func (c disabledChannel) Name() string {
|
||||
return c.name
|
||||
}
|
||||
|
||||
func (c disabledChannel) Start(ctx context.Context) error {
|
||||
return errChannelDisabled(c.name)
|
||||
}
|
||||
|
||||
func (c disabledChannel) Stop(ctx context.Context) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (c disabledChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
|
||||
return errChannelDisabled(c.name)
|
||||
}
|
||||
|
||||
func (c disabledChannel) IsRunning() bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c disabledChannel) IsAllowed(senderID string) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
func (c disabledChannel) HealthCheck(ctx context.Context) error {
|
||||
return errChannelDisabled(c.name)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_dingtalk
|
||||
|
||||
// ClawGo - Ultra-lightweight personal AI agent
|
||||
// DingTalk channel implementation using Stream Mode
|
||||
|
||||
|
||||
14
pkg/channels/dingtalk_stub.go
Normal file
14
pkg/channels/dingtalk_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_dingtalk
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type DingTalkChannel struct{ disabledChannel }
|
||||
|
||||
func NewDingTalkChannel(cfg config.DingTalkConfig, bus *bus.MessageBus) (*DingTalkChannel, error) {
|
||||
return nil, errChannelDisabled("dingtalk")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_discord
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
14
pkg/channels/discord_stub.go
Normal file
14
pkg/channels/discord_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_discord
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type DiscordChannel struct{ disabledChannel }
|
||||
|
||||
func NewDiscordChannel(cfg config.DiscordConfig, bus *bus.MessageBus) (*DiscordChannel, error) {
|
||||
return nil, errChannelDisabled("discord")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_feishu
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
14
pkg/channels/feishu_stub.go
Normal file
14
pkg/channels/feishu_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_feishu
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type FeishuChannel struct{ disabledChannel }
|
||||
|
||||
func NewFeishuChannel(cfg config.FeishuConfig, bus *bus.MessageBus) (*FeishuChannel, error) {
|
||||
return nil, errChannelDisabled("feishu")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_maixcam
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
14
pkg/channels/maixcam_stub.go
Normal file
14
pkg/channels/maixcam_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_maixcam
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type MaixCamChannel struct{ disabledChannel }
|
||||
|
||||
func NewMaixCamChannel(cfg config.MaixCamConfig, bus *bus.MessageBus) (*MaixCamChannel, error) {
|
||||
return nil, errChannelDisabled("maixcam")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_qq
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
14
pkg/channels/qq_stub.go
Normal file
14
pkg/channels/qq_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_qq
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type QQChannel struct{ disabledChannel }
|
||||
|
||||
func NewQQChannel(cfg config.QQConfig, bus *bus.MessageBus) (*QQChannel, error) {
|
||||
return nil, errChannelDisabled("qq")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_telegram
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
14
pkg/channels/telegram_stub.go
Normal file
14
pkg/channels/telegram_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_telegram
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type TelegramChannel struct{ disabledChannel }
|
||||
|
||||
func NewTelegramChannel(cfg config.TelegramConfig, bus *bus.MessageBus) (*TelegramChannel, error) {
|
||||
return nil, errChannelDisabled("telegram")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
@@ -9,7 +11,6 @@ import (
|
||||
"mime"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"os"
|
||||
"path/filepath"
|
||||
"strings"
|
||||
@@ -27,31 +28,6 @@ import (
|
||||
_ "modernc.org/sqlite"
|
||||
)
|
||||
|
||||
type WhatsAppBridgeStatus struct {
|
||||
State string `json:"state"`
|
||||
Connected bool `json:"connected"`
|
||||
LoggedIn bool `json:"logged_in"`
|
||||
BridgeAddr string `json:"bridge_addr"`
|
||||
UserJID string `json:"user_jid,omitempty"`
|
||||
PushName string `json:"push_name,omitempty"`
|
||||
Platform string `json:"platform,omitempty"`
|
||||
QRCode string `json:"qr_code,omitempty"`
|
||||
QRAvailable bool `json:"qr_available"`
|
||||
LastEvent string `json:"last_event,omitempty"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
InboundCount int `json:"inbound_count"`
|
||||
OutboundCount int `json:"outbound_count"`
|
||||
ReadReceiptCount int `json:"read_receipt_count"`
|
||||
LastInboundAt string `json:"last_inbound_at,omitempty"`
|
||||
LastOutboundAt string `json:"last_outbound_at,omitempty"`
|
||||
LastReadAt string `json:"last_read_at,omitempty"`
|
||||
LastInboundFrom string `json:"last_inbound_from,omitempty"`
|
||||
LastOutboundTo string `json:"last_outbound_to,omitempty"`
|
||||
LastInboundText string `json:"last_inbound_text,omitempty"`
|
||||
LastOutboundText string `json:"last_outbound_text,omitempty"`
|
||||
}
|
||||
|
||||
type WhatsAppBridgeService struct {
|
||||
addr string
|
||||
stateDir string
|
||||
@@ -818,36 +794,10 @@ func (s *WhatsAppBridgeService) closeWSClients() {
|
||||
}
|
||||
}
|
||||
|
||||
func ParseWhatsAppBridgeListenAddr(raw string) (string, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", fmt.Errorf("bridge url is required")
|
||||
}
|
||||
if strings.Contains(raw, "://") {
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse bridge url: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(u.Host) == "" {
|
||||
return "", fmt.Errorf("bridge url host is required")
|
||||
}
|
||||
return u.Host, nil
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) ServeLogout(w http.ResponseWriter, r *http.Request) {
|
||||
s.wrapHandler(s.handleLogout)(w, r)
|
||||
}
|
||||
|
||||
func BridgeStatusURL(raw string) (string, error) {
|
||||
return bridgeEndpointURL(raw, "status")
|
||||
}
|
||||
|
||||
func BridgeLogoutURL(raw string) (string, error) {
|
||||
return bridgeEndpointURL(raw, "logout")
|
||||
}
|
||||
|
||||
func normalizeWhatsAppRecipientJID(raw string) (types.JID, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
@@ -895,102 +845,3 @@ func extractWhatsAppMessageText(msg *waProto.Message) string {
|
||||
return ""
|
||||
}
|
||||
}
|
||||
|
||||
func bridgeEndpointURL(raw, endpoint string) (string, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", fmt.Errorf("bridge url is required")
|
||||
}
|
||||
if !strings.Contains(raw, "://") {
|
||||
raw = "ws://" + raw
|
||||
}
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse bridge url: %w", err)
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "wss":
|
||||
u.Scheme = "https"
|
||||
default:
|
||||
u.Scheme = "http"
|
||||
}
|
||||
u.Path = bridgeSiblingPath(u.Path, endpoint)
|
||||
u.RawQuery = ""
|
||||
u.Fragment = ""
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func bridgeSiblingPath(pathValue, endpoint string) string {
|
||||
pathValue = strings.TrimSpace(pathValue)
|
||||
if endpoint == "" {
|
||||
endpoint = "status"
|
||||
}
|
||||
if pathValue == "" || pathValue == "/" {
|
||||
return "/" + endpoint
|
||||
}
|
||||
trimmed := strings.TrimSuffix(pathValue, "/")
|
||||
if strings.HasSuffix(trimmed, "/ws") {
|
||||
return strings.TrimSuffix(trimmed, "/ws") + "/" + endpoint
|
||||
}
|
||||
return trimmed + "/" + endpoint
|
||||
}
|
||||
|
||||
func normalizeBridgeBasePath(basePath string) string {
|
||||
basePath = strings.TrimSpace(basePath)
|
||||
if basePath == "" || basePath == "/" {
|
||||
return "/"
|
||||
}
|
||||
if !strings.HasPrefix(basePath, "/") {
|
||||
basePath = "/" + basePath
|
||||
}
|
||||
return strings.TrimSuffix(basePath, "/")
|
||||
}
|
||||
|
||||
func joinBridgeRoute(basePath, endpoint string) string {
|
||||
basePath = normalizeBridgeBasePath(basePath)
|
||||
if basePath == "/" {
|
||||
return "/" + strings.TrimPrefix(endpoint, "/")
|
||||
}
|
||||
return basePath + "/" + strings.TrimPrefix(endpoint, "/")
|
||||
}
|
||||
|
||||
func isLocalRequest(r *http.Request) bool {
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isLocalRemoteAddr(strings.TrimSpace(r.RemoteAddr), addrs)
|
||||
}
|
||||
|
||||
func isLocalRemoteAddr(remoteAddr string, localAddrs []net.Addr) bool {
|
||||
host, _, err := net.SplitHostPort(strings.TrimSpace(remoteAddr))
|
||||
if err != nil {
|
||||
host = strings.TrimSpace(remoteAddr)
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
for _, addr := range localAddrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
if v.IP != nil && v.IP.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
case *net.IPAddr:
|
||||
if v.IP != nil && v.IP.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
56
pkg/channels/whatsapp_bridge_stub.go
Normal file
56
pkg/channels/whatsapp_bridge_stub.go
Normal file
@@ -0,0 +1,56 @@
|
||||
//go:build omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"context"
|
||||
"net/http"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type WhatsAppBridgeService struct {
|
||||
addr string
|
||||
stateDir string
|
||||
printQR bool
|
||||
status WhatsAppBridgeStatus
|
||||
}
|
||||
|
||||
func NewWhatsAppBridgeService(addr, stateDir string, printQR bool) *WhatsAppBridgeService {
|
||||
return &WhatsAppBridgeService{
|
||||
addr: strings.TrimSpace(addr),
|
||||
stateDir: strings.TrimSpace(stateDir),
|
||||
printQR: printQR,
|
||||
status: WhatsAppBridgeStatus{
|
||||
State: "disabled",
|
||||
BridgeAddr: strings.TrimSpace(addr),
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) Start(ctx context.Context) error {
|
||||
return errChannelDisabled("whatsapp")
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) StartEmbedded(ctx context.Context) error {
|
||||
return errChannelDisabled("whatsapp")
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) Stop() {}
|
||||
|
||||
func (s *WhatsAppBridgeService) RegisterRoutes(mux *http.ServeMux, basePath string) {}
|
||||
|
||||
func (s *WhatsAppBridgeService) StatusSnapshot() WhatsAppBridgeStatus {
|
||||
return s.status
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) ServeWS(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, errChannelDisabled("whatsapp").Error(), http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) ServeStatus(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, errChannelDisabled("whatsapp").Error(), http.StatusNotImplemented)
|
||||
}
|
||||
|
||||
func (s *WhatsAppBridgeService) ServeLogout(w http.ResponseWriter, r *http.Request) {
|
||||
http.Error(w, errChannelDisabled("whatsapp").Error(), http.StatusNotImplemented)
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
159
pkg/channels/whatsapp_common.go
Normal file
159
pkg/channels/whatsapp_common.go
Normal file
@@ -0,0 +1,159 @@
|
||||
package channels
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"net"
|
||||
"net/http"
|
||||
"net/url"
|
||||
"strings"
|
||||
)
|
||||
|
||||
type WhatsAppBridgeStatus struct {
|
||||
State string `json:"state"`
|
||||
Connected bool `json:"connected"`
|
||||
LoggedIn bool `json:"logged_in"`
|
||||
BridgeAddr string `json:"bridge_addr"`
|
||||
UserJID string `json:"user_jid,omitempty"`
|
||||
PushName string `json:"push_name,omitempty"`
|
||||
Platform string `json:"platform,omitempty"`
|
||||
QRCode string `json:"qr_code,omitempty"`
|
||||
QRAvailable bool `json:"qr_available"`
|
||||
LastEvent string `json:"last_event,omitempty"`
|
||||
LastError string `json:"last_error,omitempty"`
|
||||
UpdatedAt string `json:"updated_at"`
|
||||
InboundCount int `json:"inbound_count"`
|
||||
OutboundCount int `json:"outbound_count"`
|
||||
ReadReceiptCount int `json:"read_receipt_count"`
|
||||
LastInboundAt string `json:"last_inbound_at,omitempty"`
|
||||
LastOutboundAt string `json:"last_outbound_at,omitempty"`
|
||||
LastReadAt string `json:"last_read_at,omitempty"`
|
||||
LastInboundFrom string `json:"last_inbound_from,omitempty"`
|
||||
LastOutboundTo string `json:"last_outbound_to,omitempty"`
|
||||
LastInboundText string `json:"last_inbound_text,omitempty"`
|
||||
LastOutboundText string `json:"last_outbound_text,omitempty"`
|
||||
}
|
||||
|
||||
func ParseWhatsAppBridgeListenAddr(raw string) (string, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", fmt.Errorf("bridge url is required")
|
||||
}
|
||||
if strings.Contains(raw, "://") {
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse bridge url: %w", err)
|
||||
}
|
||||
if strings.TrimSpace(u.Host) == "" {
|
||||
return "", fmt.Errorf("bridge url host is required")
|
||||
}
|
||||
return u.Host, nil
|
||||
}
|
||||
return raw, nil
|
||||
}
|
||||
|
||||
func BridgeStatusURL(raw string) (string, error) {
|
||||
return bridgeEndpointURL(raw, "status")
|
||||
}
|
||||
|
||||
func BridgeLogoutURL(raw string) (string, error) {
|
||||
return bridgeEndpointURL(raw, "logout")
|
||||
}
|
||||
|
||||
func bridgeEndpointURL(raw, endpoint string) (string, error) {
|
||||
raw = strings.TrimSpace(raw)
|
||||
if raw == "" {
|
||||
return "", fmt.Errorf("bridge url is required")
|
||||
}
|
||||
if !strings.Contains(raw, "://") {
|
||||
raw = "ws://" + raw
|
||||
}
|
||||
u, err := url.Parse(raw)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("parse bridge url: %w", err)
|
||||
}
|
||||
switch u.Scheme {
|
||||
case "wss":
|
||||
u.Scheme = "https"
|
||||
default:
|
||||
u.Scheme = "http"
|
||||
}
|
||||
u.Path = bridgeSiblingPath(u.Path, endpoint)
|
||||
u.RawQuery = ""
|
||||
u.Fragment = ""
|
||||
return u.String(), nil
|
||||
}
|
||||
|
||||
func bridgeSiblingPath(pathValue, endpoint string) string {
|
||||
pathValue = strings.TrimSpace(pathValue)
|
||||
if endpoint == "" {
|
||||
endpoint = "status"
|
||||
}
|
||||
if pathValue == "" || pathValue == "/" {
|
||||
return "/" + endpoint
|
||||
}
|
||||
trimmed := strings.TrimSuffix(pathValue, "/")
|
||||
if strings.HasSuffix(trimmed, "/ws") {
|
||||
return strings.TrimSuffix(trimmed, "/ws") + "/" + endpoint
|
||||
}
|
||||
return trimmed + "/" + endpoint
|
||||
}
|
||||
|
||||
func normalizeBridgeBasePath(basePath string) string {
|
||||
basePath = strings.TrimSpace(basePath)
|
||||
if basePath == "" || basePath == "/" {
|
||||
return "/"
|
||||
}
|
||||
if !strings.HasPrefix(basePath, "/") {
|
||||
basePath = "/" + basePath
|
||||
}
|
||||
return strings.TrimSuffix(basePath, "/")
|
||||
}
|
||||
|
||||
func joinBridgeRoute(basePath, endpoint string) string {
|
||||
basePath = normalizeBridgeBasePath(basePath)
|
||||
if basePath == "/" {
|
||||
return "/" + strings.TrimPrefix(endpoint, "/")
|
||||
}
|
||||
return basePath + "/" + strings.TrimPrefix(endpoint, "/")
|
||||
}
|
||||
|
||||
func isLocalRequest(r *http.Request) bool {
|
||||
if r == nil {
|
||||
return false
|
||||
}
|
||||
addrs, err := net.InterfaceAddrs()
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
return isLocalRemoteAddr(strings.TrimSpace(r.RemoteAddr), addrs)
|
||||
}
|
||||
|
||||
func isLocalRemoteAddr(remoteAddr string, localAddrs []net.Addr) bool {
|
||||
host, _, err := net.SplitHostPort(strings.TrimSpace(remoteAddr))
|
||||
if err != nil {
|
||||
host = strings.TrimSpace(remoteAddr)
|
||||
}
|
||||
ip := net.ParseIP(host)
|
||||
if ip == nil {
|
||||
return false
|
||||
}
|
||||
if ip.IsLoopback() {
|
||||
return true
|
||||
}
|
||||
for _, addr := range localAddrs {
|
||||
if addr == nil {
|
||||
continue
|
||||
}
|
||||
switch v := addr.(type) {
|
||||
case *net.IPNet:
|
||||
if v.IP != nil && v.IP.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
case *net.IPAddr:
|
||||
if v.IP != nil && v.IP.Equal(ip) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
14
pkg/channels/whatsapp_stub.go
Normal file
14
pkg/channels/whatsapp_stub.go
Normal file
@@ -0,0 +1,14 @@
|
||||
//go:build omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
"github.com/YspCoder/clawgo/pkg/bus"
|
||||
"github.com/YspCoder/clawgo/pkg/config"
|
||||
)
|
||||
|
||||
type WhatsAppChannel struct{ disabledChannel }
|
||||
|
||||
func NewWhatsAppChannel(cfg config.WhatsAppConfig, bus *bus.MessageBus) (*WhatsAppChannel, error) {
|
||||
return nil, errChannelDisabled("whatsapp")
|
||||
}
|
||||
@@ -1,3 +1,5 @@
|
||||
//go:build !omit_whatsapp
|
||||
|
||||
package channels
|
||||
|
||||
import (
|
||||
|
||||
Reference in New Issue
Block a user