Files
whatshooked/pkg/whatshooked/whatshooked.go
Hein d80a6433b9
Some checks failed
CI / Test (1.23) (push) Failing after -22m52s
CI / Test (1.22) (push) Failing after -22m44s
CI / Build (push) Successful in -25m59s
CI / Lint (push) Successful in -25m47s
Fixed mqtt bug where phone number is not formatted
2025-12-30 01:00:42 +02:00

170 lines
4.2 KiB
Go

package whatshooked
import (
"context"
"git.warky.dev/wdevs/whatshooked/pkg/config"
"git.warky.dev/wdevs/whatshooked/pkg/eventlogger"
"git.warky.dev/wdevs/whatshooked/pkg/events"
"git.warky.dev/wdevs/whatshooked/pkg/handlers"
"git.warky.dev/wdevs/whatshooked/pkg/hooks"
"git.warky.dev/wdevs/whatshooked/pkg/logging"
"git.warky.dev/wdevs/whatshooked/pkg/whatsapp"
)
// WhatsHooked is the main library instance
type WhatsHooked struct {
config *config.Config
configPath string
eventBus *events.EventBus
whatsappMgr *whatsapp.Manager
hookMgr *hooks.Manager
eventLogger *eventlogger.Logger
handlers *handlers.Handlers
server *Server // Optional built-in server
}
// NewFromFile creates a WhatsHooked instance from a config file
func NewFromFile(configPath string) (*WhatsHooked, error) {
cfg, err := config.Load(configPath)
if err != nil {
return nil, err
}
// Initialize logging from config
logging.Init(cfg.LogLevel)
return newWithConfig(cfg, configPath)
}
// New creates a WhatsHooked instance with programmatic config
func New(opts ...Option) (*WhatsHooked, error) {
cfg := &config.Config{
Server: config.ServerConfig{
Host: "localhost",
Port: 8080,
},
Media: config.MediaConfig{
DataPath: "./data/media",
Mode: "link",
},
LogLevel: "info",
}
// Apply options
for _, opt := range opts {
opt(cfg)
}
// Initialize logging from config
logging.Init(cfg.LogLevel)
return newWithConfig(cfg, "")
}
// newWithConfig is the internal constructor
func newWithConfig(cfg *config.Config, configPath string) (*WhatsHooked, error) {
wh := &WhatsHooked{
config: cfg,
configPath: configPath,
eventBus: events.NewEventBus(),
}
// Initialize WhatsApp manager
wh.whatsappMgr = whatsapp.NewManager(
wh.eventBus,
cfg.Media,
cfg,
configPath,
func(updatedCfg *config.Config) error {
if configPath != "" {
return config.Save(configPath, updatedCfg)
}
return nil
},
)
// Initialize hook manager
wh.hookMgr = hooks.NewManager(wh.eventBus)
wh.hookMgr.LoadHooks(cfg.Hooks)
wh.hookMgr.Start()
// Initialize event logger if enabled
if cfg.EventLogger.Enabled && len(cfg.EventLogger.Targets) > 0 {
logger, err := eventlogger.NewLogger(cfg.EventLogger, cfg.Database, wh.whatsappMgr, cfg.Server.DefaultCountryCode)
if err == nil {
wh.eventLogger = logger
wh.eventBus.SubscribeAll(func(event events.Event) {
wh.eventLogger.Log(event)
})
logging.Info("Event logger initialized", "targets", cfg.EventLogger.Targets)
} else {
logging.Error("Failed to initialize event logger", "error", err)
}
}
// Create handlers
wh.handlers = handlers.New(wh.whatsappMgr, wh.hookMgr, cfg, configPath)
return wh, nil
}
// ConnectAll connects to all configured WhatsApp accounts
func (wh *WhatsHooked) ConnectAll(ctx context.Context) error {
for _, waCfg := range wh.config.WhatsApp {
if err := wh.whatsappMgr.Connect(ctx, waCfg); err != nil {
logging.Error("Failed to connect to WhatsApp", "account_id", waCfg.ID, "error", err)
// Continue connecting to other accounts even if one fails
}
}
return nil
}
// Handlers returns the HTTP handlers instance
func (wh *WhatsHooked) Handlers() *handlers.Handlers {
return wh.handlers
}
// Manager returns the WhatsApp manager
func (wh *WhatsHooked) Manager() *whatsapp.Manager {
return wh.whatsappMgr
}
// EventBus returns the event bus
func (wh *WhatsHooked) EventBus() *events.EventBus {
return wh.eventBus
}
// HookManager returns the hook manager
func (wh *WhatsHooked) HookManager() *hooks.Manager {
return wh.hookMgr
}
// Config returns the configuration
func (wh *WhatsHooked) Config() *config.Config {
return wh.config
}
// Close shuts down all components gracefully
func (wh *WhatsHooked) Close() error {
wh.whatsappMgr.DisconnectAll()
if wh.eventLogger != nil {
return wh.eventLogger.Close()
}
return nil
}
// StartServer starts the built-in HTTP server (convenience method)
func (wh *WhatsHooked) StartServer() error {
wh.server = NewServer(wh)
return wh.server.Start()
}
// StopServer stops the built-in HTTP server
func (wh *WhatsHooked) StopServer(ctx context.Context) error {
if wh.server != nil {
return wh.server.Stop(ctx)
}
return nil
}