A lightweight multi-channel communication gateway designed for desktop app single-user scenarios, providing a unified WebSocket chat communication service access layer. Through standardized Channel interface abstraction, it achieves unified access and message forwarding for multiple instant messaging platforms.
A multi-channel communication gateway written in Go that enables unified message handling across different IM platforms.
gort is a lightweight, extensible gateway that bridges multiple instant messaging platforms with WebSocket clients. It provides a unified message format and a clean architecture for building chatbots and message processing systems.
- Multi-Channel Support: Connect to 10+ IM platforms through a unified interface
- DingTalk, Feishu, WeChat (domestic)
- Telegram, Slack, Discord (international)
- WhatsApp, Messenger (customer support)
- iMessage (macOS ecosystem)
- WeCom (enterprise)
- WebSocket Server: Push messages to connected clients in real-time
- Middleware Chain: Extensible middleware system for cross-cutting concerns
- Configuration Management: Flexible configuration via files, environment variables, or command-line
- Test-Driven Development: Comprehensive test coverage with clear examples
- Desktop App Focused: Optimized for single-user desktop scenarios
go get github.com/DotNetAge/gort- Go 1.23 or higher
- Make (optional, for using Makefile commands)
package main
import (
"context"
"log"
"github.com/DotNetAge/gort/pkg/channel"
"github.com/DotNetAge/gort/pkg/config"
"github.com/DotNetAge/gort/pkg/gateway"
"github.com/DotNetAge/gort/pkg/message"
"github.com/DotNetAge/gort/pkg/session"
)
func main() {
// Load configuration
cfg, err := config.Load("")
if err != nil {
log.Fatal(err)
}
// Create session manager
sessionMgr := session.NewManager(session.Config{
OnMessage: func(clientID string, msg *message.Message) {
log.Printf("Received from %s: %s", clientID, msg.Content)
},
})
// Create gateway
gw := gateway.New(gateway.Config{
WebSocketAddr: ":9000",
HTTPAddr: ":8080",
})
// Register channels
wechat := channel.NewMockChannel("wechat", channel.ChannelTypeWeChat)
gw.RegisterChannel(wechat)
// Register message handler
gw.RegisterChannelHandler(func(ctx context.Context, msg *message.Message) error {
log.Printf("Channel message: %+v", msg)
return nil
})
// Start gateway
if err := gw.Start(context.Background()); err != nil {
log.Fatal(err)
}
defer gw.Stop(context.Background())
// Keep running...
select {}
}gort supports JSON, YAML, and TOML configuration files. Create a config.yaml in your working directory:
server:
http_port: 8080
ws_port: 8081
webhook_path: /webhook
read_timeout: 30
write_timeout: 30
channels:
wechat:
enabled: true
app_id: your_app_id
dingtalk:
enabled: false
feishu:
enabled: false
log:
level: info
format: text
output: stdoutAll configuration values can be overridden with environment variables using the GORT_ prefix:
export GORT_SERVER_HTTP_PORT=9090
export GORT_SERVER_WS_PORT=9091
export GORT_LOG_LEVEL=debug
export GORT_CHANNELS_WECHAT_TOKEN=your_token
export GORT_CHANNELS_WECHAT_SECRET=your_secretConfiguration values are loaded with the following priority (highest to lowest):
- Command-line arguments
- Environment variables
- Configuration file
- Default values
┌─────────────────────────────────────────────────────────────┐
│ Gateway │
│ ┌─────────────────────────────────────────────────────┐ │
│ │ Middleware Chain │ │
│ │ [Logging] → [Trace] → [Auth] → [Your Middleware] │ │
│ └─────────────────────────────────────────────────────┘ │
│ │ │
│ ┌──────────────────┼──────────────────┐ │
│ ▼ ▼ ▼ │
│ ┌─────────────┐ ┌─────────────┐ ┌─────────────┐ │
│ │ WeChat │ │ DingTalk │ │ Feishu │ │
│ │ Channel │ │ Channel │ │ Channel │ │
│ └─────────────┘ └─────────────┘ └─────────────┘ │
│ │ │ │ │
└─────────┼──────────────────┼──────────────────┼───────────┘
▼ ▼ ▼
┌──────────┐ ┌──────────┐ ┌──────────┐
│ WeChat │ │ DingTalk │ │ Feishu │
│ Server │ │ Server │ │ Server │
└──────────┘ └──────────┘ └──────────┘
| Package | Description |
|---|---|
pkg/gateway |
Core coordinator that manages channels and message routing |
pkg/channel |
Protocol adapters for external IM platforms |
pkg/session |
WebSocket connection manager |
pkg/message |
Standard message format |
pkg/middleware |
Middleware chain for cross-cutting concerns |
pkg/config |
Configuration management with Viper |
| Channel | Access Method | Documentation |
|---|---|---|
| DingTalk (钉钉) | Webhook Robot | docs |
| Feishu (飞书) | Self-built App + Token | docs |
| Telegram | Bot Token | docs |
| WeChat (公众号) | Official Account + Token | docs |
| Business API | docs | |
| iMessage | macOS + imsg CLI | docs |
| Messenger | Page Access Token | docs |
| WeCom (企业微信) | Webhook Robot | docs |
| Slack | Bot Token | docs |
| Discord | Bot Token | docs |
// Create a new message
msg := message.NewMessage(
"msg_001", // ID
"wechat", // Channel ID
message.DirectionInbound, // Direction
message.UserInfo{ // From
ID: "user_001",
Name: "Alice",
Platform: "wechat",
},
"Hello, World!", // Content
message.MessageTypeText, // Type
)
// Set metadata
msg.SetMetadata("trace_id", "trace_123")
// Validate
if err := msg.Validate(); err != nil {
log.Fatal(err)
}// Create a channel
ch := channel.NewMockChannel("wechat", channel.ChannelTypeWeChat)
// Start the channel
err := ch.Start(ctx, func(ctx context.Context, msg *message.Message) error {
// Handle incoming message
return nil
})
// Send message to channel
err := ch.SendMessage(ctx, msg)
// Stop the channel
err := ch.Stop(ctx)// Create custom middleware
type MyMiddleware struct{}
func (m *MyMiddleware) Name() string {
return "MyMiddleware"
}
func (m *MyMiddleware) Handle(ctx context.Context, msg *message.Message, next middleware.Handler) error {
// Pre-processing
log.Printf("Processing message: %s", msg.ID)
// Call next handler
err := next(ctx, msg)
// Post-processing
log.Printf("Finished processing: %s", msg.ID)
return err
}
// Register middleware
gw.Use(&MyMiddleware{})# Run all tests
go test ./... -v
# Run tests with coverage
go test ./... -cover
# Run tests with coverage report
go test ./... -coverprofile=coverage.out
go tool cover -html=coverage.out
# Run benchmarks
go test ./... -bench=. -benchmemThe project maintains high test coverage:
| Package | Coverage |
|---|---|
| pkg/channel | 100% |
| pkg/config | 96% |
| pkg/gateway | 84% |
| pkg/message | 100% |
| pkg/middleware | 100% |
| pkg/session | 95% |
gort/
├── pkg/
│ ├── channel/ # Channel interface and implementations
│ │ ├── channel.go # Interface definitions
│ │ ├── wechat/ # WeChat channel
│ │ ├── dingtalk/ # DingTalk channel
│ │ ├── feishu/ # Feishu channel
│ │ ├── telegram/ # Telegram channel
│ │ ├── wecom/ # WeCom channel
│ │ ├── slack/ # Slack channel
│ │ ├── discord/ # Discord channel
│ │ ├── imessage/ # iMessage channel
│ │ ├── whatsapp/ # WhatsApp channel
│ │ └── messenger/ # Messenger channel
│ ├── config/ # Configuration management
│ │ ├── config.go
│ │ └── config_test.go
│ ├── gateway/ # Core gateway
│ │ ├── gateway.go
│ │ └── gateway_test.go
│ ├── message/ # Message types
│ │ ├── message.go
│ │ ├── errors.go
│ │ └── message_test.go
│ ├── middleware/ # Middleware system
│ │ ├── middleware.go
│ │ └── middleware_test.go
│ └── session/ # Session management
│ ├── manager.go
│ └── manager_test.go
├── docs/
│ └── design/ # Design documents
├── go.mod
├── go.sum
├── README.md
└── README_zh-CN.md
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature) - Write tests for your changes
- Ensure all tests pass (
go test ./...) - Commit your changes (
git commit -m 'Add amazing feature') - Push to the branch (
git push origin feature/amazing-feature) - Open a Pull Request
- Follow Go Code Review Comments
- Run
go fmtbefore committing - Ensure
go vetpasses - Maintain test coverage above 85%
For detailed documentation, please visit gort.rayainfo.cn
MIT License - see LICENSE file for details.