Major refactor to library
This commit is contained in:
171
pkg/whatsapp/manager.go
Normal file
171
pkg/whatsapp/manager.go
Normal file
@@ -0,0 +1,171 @@
|
||||
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
|
||||
}
|
||||
Reference in New Issue
Block a user