Router¶
The Router is the central component for managing providers and routing messages.
Creating a Router¶
import (
"log/slog"
"github.com/plexusone/omnichat/provider"
)
logger := slog.Default()
router := provider.NewRouter(logger)
Registering Providers¶
router.Register(discordProvider)
router.Register(telegramProvider)
router.Register(whatsappProvider)
Connection Management¶
Connect All Providers¶
Disconnect All Providers¶
Connect Individual Provider¶
Message Handling¶
OnMessage¶
Register handlers for incoming messages:
Parameters:
filter- AFilterFuncthat determines which messages to handlehandler- AMessageHandlerfunction
Example:
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
log.Printf("Received: %s", msg.Content)
return nil
})
Filters¶
All¶
Match all messages:
DMOnly¶
Match only direct messages:
GroupOnly¶
Match only group/channel messages:
FromProviders¶
Match messages from specific providers:
// Single provider
router.OnMessage(provider.FromProviders("discord"), handler)
// Multiple providers
router.OnMessage(provider.FromProviders("discord", "telegram"), handler)
Custom Filters¶
Create custom filters:
// Only messages containing "help"
helpFilter := func(msg provider.IncomingMessage) bool {
return strings.Contains(strings.ToLower(msg.Content), "help")
}
router.OnMessage(helpFilter, helpHandler)
Combining Filters¶
// DMs from Discord only
discordDMs := func(msg provider.IncomingMessage) bool {
return msg.ProviderName == "discord" && msg.IsDM
}
router.OnMessage(discordDMs, handler)
Sending Messages¶
Send¶
Send to a specific provider and chat:
Parameters:
ctx- Context for cancellationproviderName- Provider identifier (e.g., "discord", "telegram")chatID- Chat/channel identifiermessage-OutgoingMessageto send
Example:
Broadcast¶
Send to multiple providers simultaneously:
targets := map[string]string{
"discord": "123456789",
"telegram": "987654321",
"whatsapp": "1234567890@s.whatsapp.net",
}
router.Broadcast(ctx, targets, provider.OutgoingMessage{
Content: "Announcement to all platforms!",
})
Reply to Messages¶
Reply to the incoming message:
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
return router.Send(ctx, msg.ProviderName, msg.ChatID, provider.OutgoingMessage{
Content: "This is a reply!",
ReplyTo: msg.ID,
})
})
Agent Integration¶
SetAgent¶
Set an agent for processing messages:
type Agent interface {
Process(ctx context.Context, input string) (string, error)
}
router.SetAgent(myAgent)
ProcessWithVoice¶
Handle voice messages with transcription:
See Voice Processing for details.
Error Handling¶
Handlers can return errors:
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
if err := processMessage(msg); err != nil {
return fmt.Errorf("processing failed: %w", err)
}
return nil
})
Errors are logged by the router but don't stop message processing.
Multiple Handlers¶
Register multiple handlers for the same filter:
// Logger handler
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
log.Printf("[%s] %s: %s", msg.ProviderName, msg.SenderName, msg.Content)
return nil
})
// Response handler
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
return router.Send(ctx, msg.ProviderName, msg.ChatID, provider.OutgoingMessage{
Content: "Got it!",
})
})
Handlers are called in registration order.
Provider Access¶
Get Provider by Name¶
List All Providers¶
Context Values¶
The context passed to handlers may contain:
- Logger from router configuration
- Provider-specific metadata
router.OnMessage(provider.All(), func(ctx context.Context, msg provider.IncomingMessage) error {
// Access context values if needed
return nil
})
Best Practices¶
- Use specific filters - Avoid
All()when you only need certain messages - Handle errors - Return errors from handlers for logging
- Keep handlers fast - Use goroutines for long-running operations
- Disconnect on shutdown - Always call
DisconnectAll()on exit
// Graceful shutdown
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
go func() {
<-sigCh
router.DisconnectAll(ctx)
os.Exit(0)
}()
Next Steps¶
- Voice Processing - Handle voice messages
- Testing - Mock providers for tests