mirror of
https://github.com/memohai/Memoh.git
synced 2026-04-27 07:16:19 +09:00
ca5c6a1866
- Rename chat module to conversation with flow-based architecture - Move channelidentities into channel/identities subpackage - Add channel/route for routing logic - Add message service with event hub - Add MCP providers: container, directory, schedule - Refactor Feishu/Telegram adapters with directory and stream support - Add platform management page and channel badges in web UI - Update database schema for conversations, messages and channel routes - Add @memoh/shared package for cross-package type definitions
121 lines
3.1 KiB
Go
121 lines
3.1 KiB
Go
// feishu-echo is a minimal Feishu bot that connects via WebSocket and counts received events.
|
|
// Used to verify whether message loss is due to our app logic or network/Feishu delivery.
|
|
//
|
|
// Usage:
|
|
//
|
|
// FEISHU_APP_ID=xxx FEISHU_APP_SECRET=xxx FEISHU_ENCRYPT=xxx FEISHU_VERIFY=xxx go run ./cmd/feishu-echo
|
|
package main
|
|
|
|
import (
|
|
"context"
|
|
"log"
|
|
"os"
|
|
"os/signal"
|
|
"strings"
|
|
"sync/atomic"
|
|
"time"
|
|
|
|
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
|
|
larkws "github.com/larksuite/oapi-sdk-go/v3/ws"
|
|
|
|
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
|
|
)
|
|
|
|
type eventCounts struct {
|
|
messageReceive atomic.Int64
|
|
messageRead atomic.Int64
|
|
reactionCreated atomic.Int64
|
|
reactionDeleted atomic.Int64
|
|
}
|
|
|
|
func (c *eventCounts) log() {
|
|
log.Printf("[feishu-echo] counts: receive=%d read=%d reaction_created=%d reaction_deleted=%d",
|
|
c.messageReceive.Load(), c.messageRead.Load(), c.reactionCreated.Load(), c.reactionDeleted.Load())
|
|
}
|
|
|
|
func main() {
|
|
appID := strings.TrimSpace(os.Getenv("FEISHU_APP_ID"))
|
|
appSecret := strings.TrimSpace(os.Getenv("FEISHU_APP_SECRET"))
|
|
encryptKey := strings.TrimSpace(os.Getenv("FEISHU_ENCRYPT"))
|
|
verifyToken := strings.TrimSpace(os.Getenv("FEISHU_VERIFY"))
|
|
|
|
if appID == "" || appSecret == "" {
|
|
log.Fatal("FEISHU_APP_ID and FEISHU_APP_SECRET are required")
|
|
}
|
|
|
|
log.Printf("[feishu-echo] starting with app_id=%s (encrypt=%v, verify=%v)", appID, encryptKey != "", verifyToken != "")
|
|
|
|
counts := new(eventCounts)
|
|
eventDispatcher := dispatcher.NewEventDispatcher(verifyToken, encryptKey)
|
|
|
|
eventDispatcher.OnP2MessageReceiveV1(func(_ context.Context, _ *larkim.P2MessageReceiveV1) error {
|
|
counts.messageReceive.Add(1)
|
|
counts.log()
|
|
return nil
|
|
})
|
|
|
|
eventDispatcher.OnP2MessageReadV1(func(_ context.Context, _ *larkim.P2MessageReadV1) error {
|
|
counts.messageRead.Add(1)
|
|
counts.log()
|
|
return nil
|
|
})
|
|
|
|
eventDispatcher.OnP2MessageReactionCreatedV1(func(_ context.Context, _ *larkim.P2MessageReactionCreatedV1) error {
|
|
counts.reactionCreated.Add(1)
|
|
counts.log()
|
|
return nil
|
|
})
|
|
|
|
eventDispatcher.OnP2MessageReactionDeletedV1(func(_ context.Context, _ *larkim.P2MessageReactionDeletedV1) error {
|
|
counts.reactionDeleted.Add(1)
|
|
counts.log()
|
|
return nil
|
|
})
|
|
|
|
client := larkws.NewClient(
|
|
appID,
|
|
appSecret,
|
|
larkws.WithEventHandler(eventDispatcher),
|
|
)
|
|
|
|
ctx, cancel := context.WithCancel(context.Background())
|
|
defer cancel()
|
|
|
|
go func() {
|
|
sig := make(chan os.Signal, 1)
|
|
signal.Notify(sig, os.Interrupt)
|
|
<-sig
|
|
log.Println("[feishu-echo] interrupt, shutting down")
|
|
cancel()
|
|
counts.log()
|
|
os.Exit(0)
|
|
}()
|
|
|
|
const reconnectDelay = 3 * time.Second
|
|
run:
|
|
for {
|
|
if ctx.Err() != nil {
|
|
break run
|
|
}
|
|
log.Println("[feishu-echo] connecting to Feishu WebSocket...")
|
|
err := client.Start(ctx)
|
|
if ctx.Err() != nil {
|
|
break run
|
|
}
|
|
if err != nil {
|
|
log.Printf("[feishu-echo] client error: %v; reconnecting in %v", err, reconnectDelay)
|
|
} else {
|
|
log.Printf("[feishu-echo] connection closed; reconnecting in %v", reconnectDelay)
|
|
}
|
|
timer := time.NewTimer(reconnectDelay)
|
|
select {
|
|
case <-ctx.Done():
|
|
timer.Stop()
|
|
break run
|
|
case <-timer.C:
|
|
}
|
|
}
|
|
counts.log()
|
|
log.Println("[feishu-echo] stopped")
|
|
}
|