whatsapp

package
v1.18.3 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Apr 27, 2026 License: MIT Imports: 25 Imported by: 0

Documentation

Overview

Package whatsapp – dedup.go provides a message deduplication cache to filter out duplicate messages during WhatsApp reconnections.

Package whatsapp – events.go processes incoming WhatsApp events from whatsmeow and converts them into unified DevClaw IncomingMessage types.

Package whatsapp – health.go implements proactive health monitoring for the WhatsApp connection to detect and recover from silent disconnects.

Package whatsapp – media.go handles media upload, download, and message building for images, audio, video, documents, and stickers.

Package whatsapp implements the WhatsApp channel for DevClaw using whatsmeow — a native Go WhatsApp Web API library. No Node.js, no Baileys.

Features:

  • QR code login with persistent session
  • Send/receive text, images, audio, video, documents, stickers
  • Group message support
  • Reply and quoting
  • Reactions (emoji)
  • Typing indicators and read receipts
  • Media upload/download with encryption
  • Automatic reconnection with backoff
  • Connection state management and events

This is a core channel (compiled into the binary, not a plugin).

Index

Constants

This section is empty.

Variables

This section is empty.

Functions

func IsValidJID added in v1.13.0

func IsValidJID(jid string) bool

IsValidJID checks if a JID looks valid (basic validation). This is exported for use by API handlers.

Types

type AccessControlConfig added in v1.13.0

type AccessControlConfig struct {
	// DefaultPolicy: "allow" (anyone), "deny" (only authorized), or "ask" (ask once).
	DefaultPolicy string `yaml:"default_policy"`

	// Owners have full control.
	Owners []string `yaml:"owners"`

	// Admins can manage users.
	Admins []string `yaml:"admins"`

	// Allowed users can interact.
	AllowedUsers []string `yaml:"allowed_users"`

	// Blocked users cannot interact.
	BlockedUsers []string `yaml:"blocked_users"`

	// Allowed groups can interact.
	AllowedGroups []string `yaml:"allowed_groups"`

	// Blocked groups cannot interact.
	BlockedGroups []string `yaml:"blocked_groups"`

	// Pending message sent to unauthorized users.
	PendingMessage string `yaml:"pending_message"`
}

AccessControlConfig defines who can use the bot.

type Config

type Config struct {
	// InstanceID identifies this instance ("" for default, e.g. "business" for named).
	// Set automatically from the config key in whatsapp_instances.
	InstanceID string `yaml:"instance_id,omitempty"`

	// SessionDir is the directory for session persistence (SQLite).
	// Ignored if DatabasePath is set.
	SessionDir string `yaml:"session_dir"`

	// DatabasePath is the path to the SQLite database file for session storage.
	// If set, the WhatsApp session tables (prefixed with whatsmeow_) will be
	// stored in this database alongside other devclaw data.
	// If empty, defaults to {SessionDir}/whatsapp.db.
	DatabasePath string `yaml:"database_path"`

	// Trigger is the keyword that activates the bot (e.g. "@devclaw").
	Trigger string `yaml:"trigger"`

	// RespondToGroups enables responding in group chats.
	RespondToGroups bool `yaml:"respond_to_groups"`

	// RespondToDMs enables responding in direct messages.
	RespondToDMs bool `yaml:"respond_to_dms"`

	// AutoRead marks incoming messages as read.
	AutoRead bool `yaml:"auto_read"`

	// SendTyping sends typing indicators while processing.
	SendTyping bool `yaml:"send_typing"`

	// MediaDir is the directory for downloaded media files.
	MediaDir string `yaml:"media_dir"`

	// MaxMediaSizeMB is the maximum media file size to process.
	MaxMediaSizeMB int `yaml:"max_media_size_mb"`

	// ReconnectBackoff is the initial backoff duration for reconnection.
	ReconnectBackoff time.Duration `yaml:"reconnect_backoff"`

	// MaxReconnectAttempts is the maximum number of reconnection attempts (0 = unlimited).
	MaxReconnectAttempts int `yaml:"max_reconnect_attempts"`

	// HealthMonitor configures proactive connection health monitoring.
	HealthMonitor HealthMonitorConfig `yaml:"health_monitor"`

	// Access control configuration.
	Access AccessControlConfig `yaml:"access"`

	// Group policies configuration.
	GroupPolicies GroupPoliciesConfig `yaml:"group_policies"`
}

Config holds WhatsApp channel configuration.

func DefaultConfig

func DefaultConfig() Config

DefaultConfig returns a Config with sensible defaults.

type ConnectionEvent

type ConnectionEvent struct {
	State     ConnectionState `json:"state"`
	Previous  ConnectionState `json:"previous,omitempty"`
	Timestamp time.Time       `json:"timestamp"`
	Reason    string          `json:"reason,omitempty"`
	Details   map[string]any  `json:"details,omitempty"`
}

ConnectionEvent represents a connection state change event.

type ConnectionObserver

type ConnectionObserver interface {
	OnConnectionChange(evt ConnectionEvent)
}

ConnectionObserver receives connection state changes.

type ConnectionState

type ConnectionState string

ConnectionState represents the current connection state.

const (
	StateDisconnected ConnectionState = "disconnected"
	StateConnecting   ConnectionState = "connecting"
	StateConnected    ConnectionState = "connected"
	StateReconnecting ConnectionState = "reconnecting"
	StateWaitingQR    ConnectionState = "waiting_qr"
	StateQRScanned    ConnectionState = "qr_scanned"
	StateLoggingOut   ConnectionState = "logging_out"
	StateBanned       ConnectionState = "banned"
)

type GroupPoliciesConfig added in v1.13.0

type GroupPoliciesConfig struct {
	// Default policies for unconfigured groups.
	// Multiple policies are combined with OR logic.
	DefaultPolicies []string `yaml:"default_policies"`

	// Legacy DefaultPolicy for backwards compatibility.
	// Deprecated: Use DefaultPolicies instead.
	DefaultPolicy string `yaml:"default_policy"`

	// Specific group policies.
	Groups []GroupPolicyConfig `yaml:"groups"`
}

GroupPoliciesConfig defines group-specific activation policies.

type GroupPolicyConfig added in v1.13.0

type GroupPolicyConfig struct {
	// ID is the group JID.
	ID string `yaml:"id"`

	// Name is optional display name.
	Name string `yaml:"name"`

	// Policies: list of "always", "mention", "reply", "keyword", "disabled", "allowlist".
	// Multiple policies are combined with OR logic (respond if ANY policy matches).
	Policies []string `yaml:"policies"`

	// Legacy Policy field for backwards compatibility.
	// Deprecated: Use Policies instead.
	Policy string `yaml:"policy"`

	// Keywords that trigger the bot (for policy="keyword").
	Keywords []string `yaml:"keywords"`

	// Allowed users (for policy="allowlist").
	AllowedUsers []string `yaml:"allowed_users"`

	// Workspace override for this group.
	Workspace string `yaml:"workspace"`
}

GroupPolicyConfig defines policy for a specific group.

type HealthMonitorConfig added in v1.12.0

type HealthMonitorConfig struct {
	// Enabled turns on proactive health monitoring.
	Enabled bool `yaml:"enabled"`

	// CheckInterval is how often to perform health checks.
	// Default: 30s
	CheckInterval time.Duration `yaml:"check_interval"`

	// MaxSilentDuration is the maximum time without any activity before
	// a health check is considered failed.
	// Default: 5m
	MaxSilentDuration time.Duration `yaml:"max_silent_duration"`

	// ForceReconnectAfter is the maximum silent duration before forcing
	// a preventive reconnection, regardless of client.IsConnected() result.
	// This handles "half-open" TCP connections where the socket appears
	// connected but is actually dead.
	// Default: 30m (0 = disabled)
	ForceReconnectAfter time.Duration `yaml:"force_reconnect_after"`
}

HealthMonitorConfig configures proactive connection health monitoring.

func DefaultHealthMonitorConfig added in v1.12.0

func DefaultHealthMonitorConfig() HealthMonitorConfig

DefaultHealthMonitorConfig returns sensible defaults.

type QREvent

type QREvent struct {
	// Type is "code", "success", "timeout", "error", or "refresh".
	Type string `json:"type"`
	// Code is the raw QR code string (only for Type == "code").
	Code string `json:"code,omitempty"`
	// Message is a human-readable description.
	Message string `json:"message,omitempty"`
	// ExpiresAt is when the QR code expires.
	ExpiresAt time.Time `json:"expires_at,omitempty"`
	// SecondsLeft is seconds until expiration.
	SecondsLeft int `json:"seconds_left,omitempty"`
}

QREvent represents a QR code event sent to observers.

type QREventEnhanced

type QREventEnhanced struct {
	Type        string    `json:"type"`                   // "code", "success", "timeout", "error", "refresh"
	Code        string    `json:"code,omitempty"`         // Raw QR code string
	Message     string    `json:"message"`                // Human-readable message
	ExpiresAt   time.Time `json:"expires_at,omitempty"`   // When QR code expires
	SecondsLeft int       `json:"seconds_left,omitempty"` // Seconds until expiration
	Attempts    int       `json:"attempts,omitempty"`     // Number of QR attempts
}

QREventEnhanced represents an enhanced QR code event with more details.

type WhatsApp

type WhatsApp struct {
	// contains filtered or unexported fields
}

WhatsApp implements the channels.Channel, channels.MediaChannel, channels.PresenceChannel, and channels.ReactionChannel interfaces.

func New

func New(cfg Config, logger *slog.Logger) *WhatsApp

New creates a new WhatsApp channel instance.

func (*WhatsApp) AddConnectionObserver

func (w *WhatsApp) AddConnectionObserver(obs ConnectionObserver)

AddConnectionObserver registers a connection observer.

func (*WhatsApp) AutoReadEnabled added in v1.13.0

func (w *WhatsApp) AutoReadEnabled() bool

AutoReadEnabled returns true if AutoRead is configured.

func (*WhatsApp) BaseType added in v1.16.0

func (w *WhatsApp) BaseType() string

BaseType returns "whatsapp".

func (*WhatsApp) BlockUser added in v1.13.0

func (w *WhatsApp) BlockUser(jid string)

BlockUser blocks a user.

func (*WhatsApp) CanResponse added in v1.13.0

func (w *WhatsApp) CanResponse(msg *channels.IncomingMessage) (bool, string)

CanResponse checks if the sender is allowed to interact with the bot.

func (*WhatsApp) Connect

func (w *WhatsApp) Connect(ctx context.Context) error

Connect establishes the WhatsApp Web connection via whatsmeow. If no existing session is found, the QR login process runs in the background (non-blocking) so the server can start immediately. The QR code is streamed to web UI observers for scanning via browser.

func (*WhatsApp) Disconnect

func (w *WhatsApp) Disconnect() error

Disconnect gracefully closes the WhatsApp connection.

func (*WhatsApp) DownloadMedia

func (w *WhatsApp) DownloadMedia(ctx context.Context, msg *channels.IncomingMessage) ([]byte, string, error)

DownloadMedia downloads media from an incoming message.

func (*WhatsApp) GetAccessConfig added in v1.13.0

func (w *WhatsApp) GetAccessConfig() any

GetAccessConfig returns the current access control configuration.

func (*WhatsApp) GetGroupPolicies added in v1.13.0

func (w *WhatsApp) GetGroupPolicies() any

GetGroupPolicies returns the current group policies configuration.

func (*WhatsApp) GetGroupPolicy added in v1.13.0

func (w *WhatsApp) GetGroupPolicy(groupJID string) *GroupPolicyConfig

GetGroupPolicy returns the policy for a group.

func (*WhatsApp) GetJoinedGroups added in v1.13.0

func (w *WhatsApp) GetJoinedGroups() ([]channels.WhatsAppJoinedGroup, error)

GetJoinedGroups returns all groups the bot is a member of.

func (*WhatsApp) GetState

func (w *WhatsApp) GetState() ConnectionState

GetState returns the current connection state (public API).

func (*WhatsApp) GrantAccess added in v1.13.0

func (w *WhatsApp) GrantAccess(jid string, level string)

GrantAccess grants access to a user.

func (*WhatsApp) Health

func (w *WhatsApp) Health() channels.HealthStatus

Health returns the WhatsApp channel health status.

func (*WhatsApp) InstanceID added in v1.16.0

func (w *WhatsApp) InstanceID() string

InstanceID returns the instance identifier ("" for default).

func (*WhatsApp) IsBotMessage added in v1.16.0

func (w *WhatsApp) IsBotMessage(chatID, messageID string) bool

IsBotMessage returns true if the given message was sent by the bot. Implements channels.SentMessageTracker.

func (*WhatsApp) IsConnected

func (w *WhatsApp) IsConnected() bool

IsConnected returns true if WhatsApp is connected.

func (*WhatsApp) ListGroupPolicies added in v1.13.0

func (w *WhatsApp) ListGroupPolicies() map[string]*GroupPolicyConfig

ListGroupPolicies returns all configured group policies.

func (*WhatsApp) ListGroupPoliciesForConfig added in v1.13.0

func (w *WhatsApp) ListGroupPoliciesForConfig() []channels.GroupPolicyConfig

ListGroupPoliciesForConfig returns all group policies as a slice for config persistence. This implements WhatsAppAccessManager interface.

func (*WhatsApp) Logout

func (w *WhatsApp) Logout() error

Logout logs out and clears the session.

func (*WhatsApp) MarkAsked added in v1.13.0

func (w *WhatsApp) MarkAsked(jid string)

MarkAsked marks a user as having received the pending message.

func (*WhatsApp) MarkRead

func (w *WhatsApp) MarkRead(ctx context.Context, chatID string, messageIDs []string) error

MarkRead marks messages as read.

func (*WhatsApp) Name

func (w *WhatsApp) Name() string

Name returns the channel name. For the default instance this is "whatsapp"; for named instances it returns "whatsapp:<instance_id>".

func (*WhatsApp) NeedsQR

func (w *WhatsApp) NeedsQR() bool

NeedsQR returns true if the WhatsApp session is not linked (needs QR scan).

func (*WhatsApp) Receive

func (w *WhatsApp) Receive() <-chan *channels.IncomingMessage

Receive returns the incoming messages channel.

func (*WhatsApp) ReplaceAccessList added in v1.13.0

func (w *WhatsApp) ReplaceAccessList(owners, admins, allowedUsers, blockedUsers []string, defaultPolicy, pendingMessage string)

ReplaceAccessList replaces the entire access list atomically.

func (*WhatsApp) RequestNewQR

func (w *WhatsApp) RequestNewQR(_ context.Context) error

RequestNewQR disconnects and reconnects to generate a fresh QR code. This is used when the web UI needs a new QR after timeout. A default timeout of 2 minutes is applied. The goroutine is bound to the instance lifecycle (w.ctx) so it stops on Disconnect/deletion. Only one QR generation can run at a time (guarded by qrGuard).

func (*WhatsApp) RevokeAccess added in v1.13.0

func (w *WhatsApp) RevokeAccess(jid string)

RevokeAccess revokes access from a user.

func (*WhatsApp) SaveMediaToFile

func (w *WhatsApp) SaveMediaToFile(ctx context.Context, msg *channels.IncomingMessage) (string, error)

SaveMediaToFile downloads and saves media to disk.

func (*WhatsApp) Send

func (w *WhatsApp) Send(ctx context.Context, to string, msg *channels.OutgoingMessage) error

Send sends a text message to the specified JID.

func (*WhatsApp) SendMedia

func (w *WhatsApp) SendMedia(ctx context.Context, to string, media *channels.MediaMessage) error

SendMedia sends a media message (image, audio, video, document, sticker).

func (*WhatsApp) SendPresence

func (w *WhatsApp) SendPresence(ctx context.Context, available bool) error

SendPresence updates the bot's online/offline status. Also measures latency for health reporting.

func (*WhatsApp) SendReaction

func (w *WhatsApp) SendReaction(ctx context.Context, chatID, messageID, emoji string) error

SendReaction sends an emoji reaction to a message.

func (*WhatsApp) SendTyping

func (w *WhatsApp) SendTyping(ctx context.Context, to string) error

SendTyping sends a typing indicator.

func (*WhatsApp) SendTypingEnabled added in v1.13.0

func (w *WhatsApp) SendTypingEnabled() bool

SendTypingEnabled returns true if SendTyping is configured.

func (*WhatsApp) SetAutoRead added in v1.13.0

func (w *WhatsApp) SetAutoRead(enabled bool)

SetAutoRead enables or disables auto-read behavior.

func (*WhatsApp) SetDefaultPolicy added in v1.13.0

func (w *WhatsApp) SetDefaultPolicy(policy string)

SetDefaultPolicy updates the default access policy.

func (*WhatsApp) SetGroupDefaultPolicy added in v1.13.0

func (w *WhatsApp) SetGroupDefaultPolicy(policy string)

SetGroupDefaultPolicy updates the default group policy.

func (*WhatsApp) SetGroupPolicy added in v1.13.0

func (w *WhatsApp) SetGroupPolicy(groupJID string, policy any)

SetGroupPolicy sets a policy for a group. Accepts either *GroupPolicyConfig or map[string]any for API compatibility.

func (*WhatsApp) SetSendTyping added in v1.13.0

func (w *WhatsApp) SetSendTyping(enabled bool)

SetSendTyping enables or disables send-typing behavior.

func (*WhatsApp) SetTrigger added in v1.13.0

func (w *WhatsApp) SetTrigger(trigger string)

SetTrigger sets the trigger word for the bot.

func (*WhatsApp) ShouldRespond added in v1.13.0

func (w *WhatsApp) ShouldRespond(msg *channels.IncomingMessage, trigger string) bool

ShouldRespond checks if the bot should respond to a group message. Supports multiple policies combined with OR logic.

func (*WhatsApp) StartHealthMonitor added in v1.12.0

func (w *WhatsApp) StartHealthMonitor(ctx context.Context, cfg HealthMonitorConfig)

StartHealthMonitor starts the proactive health monitoring goroutine. It runs until the context is cancelled.

func (*WhatsApp) StartPinger added in v1.12.0

func (w *WhatsApp) StartPinger(ctx context.Context)

StartPinger sends periodic presence updates to keep connection alive.

func (*WhatsApp) SubscribeQR

func (w *WhatsApp) SubscribeQR() (chan QREvent, func())

SubscribeQR registers a channel to receive QR code events. Returns an unsubscribe function.

func (*WhatsApp) TriggerValue added in v1.13.0

func (w *WhatsApp) TriggerValue() string

TriggerValue returns the configured trigger word.

func (*WhatsApp) UnblockUser added in v1.13.0

func (w *WhatsApp) UnblockUser(jid string)

UnblockUser unblocks a user.

func (*WhatsApp) UpdateLastMsgTime added in v1.12.0

func (w *WhatsApp) UpdateLastMsgTime()

UpdateLastMsgTime updates the last activity timestamp. This should be called whenever we receive a message or other activity.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL