172 lines
4.6 KiB
Go
172 lines
4.6 KiB
Go
package whatsapp
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"sync"
|
|
|
|
"git.warky.dev/wdevs/whatshooked/pkg/config"
|
|
"git.warky.dev/wdevs/whatshooked/pkg/events"
|
|
"git.warky.dev/wdevs/whatshooked/pkg/logging"
|
|
"git.warky.dev/wdevs/whatshooked/pkg/whatsapp/businessapi"
|
|
"git.warky.dev/wdevs/whatshooked/pkg/whatsapp/whatsmeow"
|
|
|
|
"go.mau.fi/whatsmeow/types"
|
|
)
|
|
|
|
// Manager manages multiple WhatsApp client connections
|
|
type Manager struct {
|
|
clients map[string]Client
|
|
mu sync.RWMutex
|
|
eventBus *events.EventBus
|
|
mediaConfig config.MediaConfig
|
|
config *config.Config
|
|
configPath string
|
|
onConfigUpdate func(*config.Config) error
|
|
}
|
|
|
|
// NewManager creates a new WhatsApp manager
|
|
func NewManager(eventBus *events.EventBus, mediaConfig config.MediaConfig, cfg *config.Config, configPath string, onConfigUpdate func(*config.Config) error) *Manager {
|
|
return &Manager{
|
|
clients: make(map[string]Client),
|
|
eventBus: eventBus,
|
|
mediaConfig: mediaConfig,
|
|
config: cfg,
|
|
configPath: configPath,
|
|
onConfigUpdate: onConfigUpdate,
|
|
}
|
|
}
|
|
|
|
// Connect establishes a connection to a WhatsApp account using the appropriate client type
|
|
func (m *Manager) Connect(ctx context.Context, cfg config.WhatsAppConfig) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
if _, exists := m.clients[cfg.ID]; exists {
|
|
return fmt.Errorf("client %s already connected", cfg.ID)
|
|
}
|
|
|
|
var client Client
|
|
var err error
|
|
|
|
// Factory pattern based on type
|
|
switch cfg.Type {
|
|
case "business-api":
|
|
client, err = businessapi.NewClient(cfg, m.eventBus, m.mediaConfig)
|
|
case "whatsmeow", "":
|
|
client, err = whatsmeow.NewClient(cfg, m.eventBus, m.mediaConfig)
|
|
default:
|
|
return fmt.Errorf("unknown client type: %s", cfg.Type)
|
|
}
|
|
|
|
if err != nil {
|
|
return fmt.Errorf("failed to create client: %w", err)
|
|
}
|
|
|
|
if err := client.Connect(ctx); err != nil {
|
|
return fmt.Errorf("failed to connect: %w", err)
|
|
}
|
|
|
|
m.clients[cfg.ID] = client
|
|
logging.Info("Client connected", "account_id", cfg.ID, "type", client.GetType())
|
|
return nil
|
|
}
|
|
|
|
// Disconnect disconnects a WhatsApp client
|
|
func (m *Manager) Disconnect(id string) error {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
client, exists := m.clients[id]
|
|
if !exists {
|
|
return fmt.Errorf("client %s not found", id)
|
|
}
|
|
|
|
if err := client.Disconnect(); err != nil {
|
|
return fmt.Errorf("failed to disconnect: %w", err)
|
|
}
|
|
|
|
delete(m.clients, id)
|
|
logging.Info("Client disconnected", "account_id", id)
|
|
return nil
|
|
}
|
|
|
|
// DisconnectAll disconnects all WhatsApp clients
|
|
func (m *Manager) DisconnectAll() {
|
|
m.mu.Lock()
|
|
defer m.mu.Unlock()
|
|
|
|
for id, client := range m.clients {
|
|
if err := client.Disconnect(); err != nil {
|
|
logging.Error("Failed to disconnect client", "account_id", id, "error", err)
|
|
} else {
|
|
logging.Info("Client disconnected", "account_id", id)
|
|
}
|
|
}
|
|
m.clients = make(map[string]Client)
|
|
}
|
|
|
|
// SendTextMessage sends a text message from a specific account
|
|
func (m *Manager) SendTextMessage(ctx context.Context, accountID string, jid types.JID, text string) error {
|
|
m.mu.RLock()
|
|
client, exists := m.clients[accountID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return fmt.Errorf("client %s not found", accountID)
|
|
}
|
|
|
|
_, err := client.SendTextMessage(ctx, jid, text)
|
|
return err
|
|
}
|
|
|
|
// SendImage sends an image message from a specific account
|
|
func (m *Manager) SendImage(ctx context.Context, accountID string, jid types.JID, imageData []byte, mimeType string, caption string) error {
|
|
m.mu.RLock()
|
|
client, exists := m.clients[accountID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return fmt.Errorf("client %s not found", accountID)
|
|
}
|
|
|
|
_, err := client.SendImage(ctx, jid, imageData, mimeType, caption)
|
|
return err
|
|
}
|
|
|
|
// SendVideo sends a video message from a specific account
|
|
func (m *Manager) SendVideo(ctx context.Context, accountID string, jid types.JID, videoData []byte, mimeType string, caption string) error {
|
|
m.mu.RLock()
|
|
client, exists := m.clients[accountID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return fmt.Errorf("client %s not found", accountID)
|
|
}
|
|
|
|
_, err := client.SendVideo(ctx, jid, videoData, mimeType, caption)
|
|
return err
|
|
}
|
|
|
|
// SendDocument sends a document message from a specific account
|
|
func (m *Manager) SendDocument(ctx context.Context, accountID string, jid types.JID, documentData []byte, mimeType string, filename string, caption string) error {
|
|
m.mu.RLock()
|
|
client, exists := m.clients[accountID]
|
|
m.mu.RUnlock()
|
|
|
|
if !exists {
|
|
return fmt.Errorf("client %s not found", accountID)
|
|
}
|
|
|
|
_, err := client.SendDocument(ctx, jid, documentData, mimeType, filename, caption)
|
|
return err
|
|
}
|
|
|
|
// GetClient returns a client by ID
|
|
func (m *Manager) GetClient(id string) (Client, bool) {
|
|
m.mu.RLock()
|
|
defer m.mu.RUnlock()
|
|
client, exists := m.clients[id]
|
|
return client, exists
|
|
}
|