Major refactor to library
This commit is contained in:
299
README.md
299
README.md
@@ -1,15 +1,19 @@
|
||||
# WhatsHooked
|
||||
|
||||
A service that connects to WhatsApp and forwards messages to registered webhooks. Supports both personal WhatsApp accounts (via whatsmeow) and WhatsApp Business API. Enables two-way communication by allowing webhooks to respond with messages to be sent through WhatsApp.
|
||||
A Go library and service that connects to WhatsApp and forwards messages to registered webhooks. Supports both personal WhatsApp accounts (via whatsmeow) and WhatsApp Business API. Enables two-way communication by allowing webhooks to respond with messages to be sent through WhatsApp.
|
||||
|
||||
**Use WhatsHooked as:**
|
||||
- 📦 **Go Library** - Import into your own applications for programmatic WhatsApp integration
|
||||
- 🚀 **Standalone Server** - Run as a service with HTTP API and CLI management
|
||||
- 🔧 **Custom Integration** - Mount individual handlers in your existing HTTP servers
|
||||
|
||||

|
||||
|
||||
|
||||
[TODO LIST](TODO.md) - Things I still need to do
|
||||
|
||||
[Rules when using AI](AI_USE.md)
|
||||
|
||||
## Phase 1 Features
|
||||
## Features
|
||||
|
||||
- **Multi-Account Support**: Connect to multiple WhatsApp accounts simultaneously
|
||||
- **Dual Client Types**: Support for both personal WhatsApp (whatsmeow) and WhatsApp Business API
|
||||
@@ -20,19 +24,68 @@ A service that connects to WhatsApp and forwards messages to registered webhooks
|
||||
- **CLI Management**: Command-line tool for managing accounts and hooks
|
||||
- **Structured Logging**: JSON-based logging with configurable log levels
|
||||
- **Authentication**: HTTP Basic Auth and API key authentication for server endpoints
|
||||
- **Event Logging**: Optional event persistence to file, SQLite, or PostgreSQL
|
||||
- **Library Mode**: Use WhatsHooked as a Go library in your own applications
|
||||
- **Flexible Handlers**: Mount individual HTTP handlers in custom servers
|
||||
|
||||
## Quick Start
|
||||
|
||||
### As a Library
|
||||
|
||||
```go
|
||||
import "git.warky.dev/wdevs/whatshooked/pkg/whatshooked"
|
||||
|
||||
// File-based configuration
|
||||
wh, err := whatshooked.NewFromFile("config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer wh.Close()
|
||||
|
||||
// Start built-in server
|
||||
wh.StartServer()
|
||||
```
|
||||
|
||||
Or with programmatic configuration:
|
||||
|
||||
```go
|
||||
wh, err := whatshooked.New(
|
||||
whatshooked.WithServer("0.0.0.0", 8080),
|
||||
whatshooked.WithAuth("my-api-key", "", ""),
|
||||
whatshooked.WithWhatsmeowAccount("personal", "+1234567890", "./session", true),
|
||||
)
|
||||
defer wh.Close()
|
||||
wh.StartServer()
|
||||
```
|
||||
|
||||
### As a Standalone Server
|
||||
|
||||
```bash
|
||||
make build
|
||||
./bin/whatshook-server -config config.json
|
||||
```
|
||||
|
||||
## Architecture
|
||||
|
||||
The project uses an event-driven architecture with the following packages:
|
||||
|
||||
- **internal/config**: Configuration management and persistence
|
||||
- **internal/logging**: Structured logging using Go's slog package
|
||||
- **internal/events**: Event bus for publish/subscribe messaging between components
|
||||
- **internal/whatsapp**: WhatsApp client management (supports both whatsmeow and Business API)
|
||||
### Library Packages (pkg/)
|
||||
|
||||
- **pkg/whatshooked**: Main library entry point with NewFromFile() and New() constructors
|
||||
- **pkg/config**: Configuration management and persistence
|
||||
- **pkg/logging**: Pluggable structured logging interface
|
||||
- **pkg/events**: Event bus for publish/subscribe messaging between components
|
||||
- **pkg/whatsapp**: WhatsApp client management (supports both whatsmeow and Business API)
|
||||
- **whatsmeow/**: Personal WhatsApp client implementation
|
||||
- **businessapi/**: WhatsApp Business API client implementation
|
||||
- **internal/hooks**: Webhook management and message forwarding
|
||||
- **cmd/server**: Main server application
|
||||
- **pkg/hooks**: Webhook management and message forwarding
|
||||
- **pkg/handlers**: HTTP handlers that can be mounted in any server
|
||||
- **pkg/eventlogger**: Event persistence to file/SQLite/PostgreSQL
|
||||
- **pkg/utils**: Utility functions (phone formatting, etc.)
|
||||
|
||||
### Application Packages (cmd/)
|
||||
|
||||
- **cmd/server**: Standalone server application (thin wrapper around library)
|
||||
- **cmd/cli**: Command-line interface for management
|
||||
|
||||
### Event-Driven Architecture
|
||||
@@ -57,7 +110,186 @@ This architecture enables:
|
||||
- Context propagation for cancellation and timeout handling
|
||||
- Proper request lifecycle management across components
|
||||
|
||||
## Installation
|
||||
## Using WhatsHooked as a Library
|
||||
|
||||
### Installation
|
||||
|
||||
```bash
|
||||
go get git.warky.dev/wdevs/whatshooked/pkg/whatshooked
|
||||
```
|
||||
|
||||
### Example 1: Custom Server with Individual Handlers
|
||||
|
||||
Mount WhatsHooked handlers at custom paths in your existing HTTP server:
|
||||
|
||||
```go
|
||||
package main
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
"git.warky.dev/wdevs/whatshooked/pkg/whatshooked"
|
||||
)
|
||||
|
||||
func main() {
|
||||
// Initialize from config file
|
||||
wh, err := whatshooked.NewFromFile("config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer wh.Close()
|
||||
|
||||
// Get handlers
|
||||
h := wh.Handlers()
|
||||
|
||||
// Custom HTTP server with your own routing
|
||||
mux := http.NewServeMux()
|
||||
|
||||
// Mount WhatsHooked handlers at custom paths
|
||||
mux.HandleFunc("/api/v1/whatsapp/send", h.Auth(h.SendMessage))
|
||||
mux.HandleFunc("/api/v1/whatsapp/send/image", h.Auth(h.SendImage))
|
||||
mux.HandleFunc("/api/v1/accounts", h.Auth(h.Accounts))
|
||||
mux.HandleFunc("/healthz", h.Health)
|
||||
|
||||
// Your own handlers
|
||||
mux.HandleFunc("/api/v1/custom", yourCustomHandler)
|
||||
|
||||
http.ListenAndServe(":8080", mux)
|
||||
}
|
||||
```
|
||||
|
||||
### Example 2: Programmatic Configuration
|
||||
|
||||
Configure WhatsHooked entirely in code without a config file:
|
||||
|
||||
```go
|
||||
wh, err := whatshooked.New(
|
||||
whatshooked.WithServer("0.0.0.0", 8080),
|
||||
whatshooked.WithAuth("my-api-key", "", ""),
|
||||
whatshooked.WithWhatsmeowAccount(
|
||||
"personal",
|
||||
"+1234567890",
|
||||
"./sessions/personal",
|
||||
true, // show QR
|
||||
),
|
||||
whatshooked.WithBusinessAPIAccount(
|
||||
"business",
|
||||
"+9876543210",
|
||||
"phone-number-id",
|
||||
"access-token",
|
||||
"verify-token",
|
||||
),
|
||||
whatshooked.WithHook(config.Hook{
|
||||
ID: "webhook1",
|
||||
Name: "My Webhook",
|
||||
URL: "https://example.com/webhook",
|
||||
Method: "POST",
|
||||
Active: true,
|
||||
Events: []string{"message.received"},
|
||||
}),
|
||||
whatshooked.WithEventLogger([]string{"file", "sqlite"}, "./events"),
|
||||
whatshooked.WithLogLevel("debug"),
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer wh.Close()
|
||||
|
||||
// Use built-in server
|
||||
wh.StartServer()
|
||||
```
|
||||
|
||||
### Example 3: Embedded Library (No HTTP Server)
|
||||
|
||||
Use WhatsHooked purely as a library for programmatic WhatsApp access:
|
||||
|
||||
```go
|
||||
wh, err := whatshooked.NewFromFile("config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
defer wh.Close()
|
||||
|
||||
// Connect to WhatsApp accounts
|
||||
ctx := context.Background()
|
||||
if err := wh.ConnectAll(ctx); err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
// Listen for incoming messages
|
||||
wh.EventBus().Subscribe(events.EventMessageReceived, func(e events.Event) {
|
||||
fmt.Printf("Received message: %s from %s\n",
|
||||
e.Data["text"], e.Data["from"])
|
||||
|
||||
// Process message in your application
|
||||
processMessage(e.Data)
|
||||
})
|
||||
|
||||
// Send messages programmatically
|
||||
jid, _ := types.ParseJID("27834606792@s.whatsapp.net")
|
||||
err = wh.Manager().SendTextMessage(ctx, "account1", jid, "Hello from code!")
|
||||
```
|
||||
|
||||
### Example 4: Custom Authentication
|
||||
|
||||
Replace the default authentication with your own (e.g., JWT):
|
||||
|
||||
```go
|
||||
wh, err := whatshooked.NewFromFile("config.json")
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
h := wh.Handlers()
|
||||
|
||||
// Use custom JWT authentication
|
||||
h.WithAuthConfig(&handlers.AuthConfig{
|
||||
Validator: func(r *http.Request) bool {
|
||||
token := r.Header.Get("Authorization")
|
||||
return validateJWTToken(token) // your JWT validation
|
||||
},
|
||||
})
|
||||
|
||||
// Or disable auth entirely
|
||||
h.WithAuthConfig(&handlers.AuthConfig{
|
||||
Disabled: true,
|
||||
})
|
||||
```
|
||||
|
||||
### Library API
|
||||
|
||||
```go
|
||||
// Main WhatsHooked instance
|
||||
type WhatsHooked struct { ... }
|
||||
|
||||
// Constructors
|
||||
func NewFromFile(configPath string) (*WhatsHooked, error)
|
||||
func New(opts ...Option) (*WhatsHooked, error)
|
||||
|
||||
// Methods
|
||||
func (wh *WhatsHooked) Handlers() *handlers.Handlers // Get HTTP handlers
|
||||
func (wh *WhatsHooked) Manager() *whatsapp.Manager // Get WhatsApp manager
|
||||
func (wh *WhatsHooked) EventBus() *events.EventBus // Get event bus
|
||||
func (wh *WhatsHooked) HookManager() *hooks.Manager // Get hook manager
|
||||
func (wh *WhatsHooked) Config() *config.Config // Get configuration
|
||||
func (wh *WhatsHooked) ConnectAll(ctx context.Context) error // Connect all accounts
|
||||
func (wh *WhatsHooked) StartServer() error // Start built-in HTTP server
|
||||
func (wh *WhatsHooked) StopServer(ctx context.Context) error // Stop server
|
||||
func (wh *WhatsHooked) Close() error // Graceful shutdown
|
||||
|
||||
// Configuration Options
|
||||
func WithServer(host string, port int) Option
|
||||
func WithAuth(apiKey, username, password string) Option
|
||||
func WithWhatsmeowAccount(id, phoneNumber, sessionPath string, showQR bool) Option
|
||||
func WithBusinessAPIAccount(id, phoneNumber, phoneNumberID, accessToken, verifyToken string) Option
|
||||
func WithHook(hook config.Hook) Option
|
||||
func WithEventLogger(targets []string, fileDir string) Option
|
||||
func WithMedia(dataPath, mode, baseURL string) Option
|
||||
func WithLogLevel(level string) Option
|
||||
func WithDatabase(dbType, host string, port int, username, password, database string) Option
|
||||
func WithSQLiteDatabase(sqlitePath string) Option
|
||||
```
|
||||
|
||||
## Installation (Standalone Server)
|
||||
|
||||
### Build from source
|
||||
|
||||
@@ -161,6 +393,7 @@ Edit the configuration file to add your WhatsApp accounts and webhooks:
|
||||
- `method`: HTTP method (usually "POST")
|
||||
- `headers`: Optional HTTP headers
|
||||
- `active`: Whether this hook is enabled
|
||||
- `events`: List of event types to subscribe to (optional, defaults to all)
|
||||
- `description`: Optional description
|
||||
|
||||
### Server Authentication
|
||||
@@ -566,28 +799,41 @@ The server accepts both full JID format and plain phone numbers. When using plai
|
||||
```
|
||||
whatshooked/
|
||||
├── cmd/
|
||||
│ ├── server/ # Main server application
|
||||
│ │ ├── main.go
|
||||
│ │ ├── routes.go
|
||||
│ │ ├── routes_*.go # Route handlers
|
||||
│ │ └── routes_businessapi.go # Business API webhooks
|
||||
│ ├── server/ # Standalone server (thin wrapper)
|
||||
│ │ └── main.go
|
||||
│ └── cli/ # CLI tool
|
||||
├── internal/
|
||||
│ ├── config/ # Configuration management
|
||||
│ ├── events/ # Event bus and event types
|
||||
│ ├── logging/ # Structured logging
|
||||
│ ├── main.go
|
||||
│ └── commands_*.go
|
||||
├── pkg/ # Public library packages
|
||||
│ ├── whatshooked/ # Main library entry point
|
||||
│ │ ├── whatshooked.go # NewFromFile(), New()
|
||||
│ │ ├── options.go # Functional options
|
||||
│ │ └── server.go # Built-in HTTP server
|
||||
│ ├── handlers/ # HTTP handlers
|
||||
│ │ ├── handlers.go # Handler struct
|
||||
│ │ ├── middleware.go # Auth middleware
|
||||
│ │ ├── send.go # Send handlers
|
||||
│ │ ├── accounts.go # Account handlers
|
||||
│ │ ├── hooks.go # Hook handlers
|
||||
│ │ ├── media.go # Media handlers
|
||||
│ │ ├── health.go # Health handler
|
||||
│ │ └── businessapi.go # Business API webhook
|
||||
│ ├── config/ # Configuration types
|
||||
│ ├── events/ # Event bus
|
||||
│ ├── logging/ # Pluggable logging
|
||||
│ ├── whatsapp/ # WhatsApp client management
|
||||
│ │ ├── interface.go # Client interface
|
||||
│ │ ├── manager.go # Multi-client manager
|
||||
│ │ ├── whatsmeow/ # Personal WhatsApp (QR code)
|
||||
│ │ ├── whatsmeow/ # Personal WhatsApp
|
||||
│ │ │ └── client.go
|
||||
│ │ └── businessapi/ # WhatsApp Business API
|
||||
│ │ ├── client.go # API client
|
||||
│ │ ├── types.go # Request/response types
|
||||
│ │ ├── events.go # Webhook processing
|
||||
│ │ └── media.go # Media upload/download
|
||||
│ │ ├── client.go
|
||||
│ │ ├── types.go
|
||||
│ │ ├── events.go
|
||||
│ │ └── media.go
|
||||
│ ├── hooks/ # Webhook management
|
||||
│ └── utils/ # Utility functions (phone formatting, etc.)
|
||||
│ ├── eventlogger/ # Event persistence
|
||||
│ └── utils/ # Utility functions
|
||||
├── config.example.json # Example configuration
|
||||
└── go.mod # Go module definition
|
||||
```
|
||||
@@ -628,9 +874,8 @@ go test ./...
|
||||
go build ./...
|
||||
```
|
||||
|
||||
## Future Phases
|
||||
## Future Plans
|
||||
|
||||
### Phase 2 (Planned)
|
||||
- User level hooks and WhatsApp accounts
|
||||
- Web server with frontend UI
|
||||
- Enhanced authentication with user roles and permissions
|
||||
|
||||
Reference in New Issue
Block a user