yao/agent/robot/events/integrations/feishu/stream.go
Max 3eb43a59ab Enhance message handling for integrations with improved formatting and localization
- Add locale support for DingTalk and Discord integrations to ensure messages are sent in the correct language.
- Update message formatting logic in DingTalk and Discord to utilize dedicated formatting functions for Markdown.
- Implement image and file handling improvements in Feishu integration, allowing for better attachment processing and error handling.
- Refactor message sending methods to streamline the process and enhance code clarity across integrations.
2026-03-02 09:00:56 +08:00

116 lines
2.7 KiB
Go

package feishu
import (
"context"
"time"
larkcore "github.com/larksuite/oapi-sdk-go/v3/core"
"github.com/larksuite/oapi-sdk-go/v3/event/dispatcher"
larkim "github.com/larksuite/oapi-sdk-go/v3/service/im/v1"
larkws "github.com/larksuite/oapi-sdk-go/v3/ws"
fsapi "github.com/yaoapp/yao/integrations/feishu"
)
const reconnectDelay = 5 * time.Second
// eventLoop starts the Feishu WebSocket event subscription for a single bot.
// It automatically reconnects on failure.
func (a *Adapter) eventLoop(ctx context.Context, entry *botEntry) {
log.Info("feishu eventLoop started robot=%s app=%s", entry.robotID, entry.appID)
for {
select {
case <-ctx.Done():
log.Info("feishu eventLoop stopped robot=%s", entry.robotID)
return
case <-a.stopCh:
return
default:
}
err := a.runWSClient(ctx, entry)
if err != nil {
log.Error("feishu ws disconnected robot=%s: %v, reconnecting in %s", entry.robotID, err, reconnectDelay)
}
select {
case <-ctx.Done():
return
case <-a.stopCh:
return
case <-time.After(reconnectDelay):
}
}
}
func (a *Adapter) runWSClient(ctx context.Context, entry *botEntry) error {
eventHandler := dispatcher.NewEventDispatcher("", "")
eventHandler.OnP2MessageReceiveV1(func(ctx context.Context, event *larkim.P2MessageReceiveV1) error {
return a.onMessageReceive(ctx, entry, event)
})
cli := larkws.NewClient(entry.bot.AppID(), entry.bot.AppSecret(),
larkws.WithEventHandler(eventHandler),
larkws.WithLogLevel(larkcore.LogLevelWarn),
)
errCh := make(chan error, 1)
go func() {
errCh <- cli.Start(ctx)
}()
select {
case <-ctx.Done():
return ctx.Err()
case <-a.stopCh:
return nil
case err := <-errCh:
return err
}
}
func (a *Adapter) onMessageReceive(ctx context.Context, entry *botEntry, event *larkim.P2MessageReceiveV1) error {
if event == nil || event.Event == nil || event.Event.Message == nil {
return nil
}
msg := event.Event.Message
sender := event.Event.Sender
msgType := derefStr(msg.MessageType)
content := derefStr(msg.Content)
messageID := derefStr(msg.MessageId)
chatID := derefStr(msg.ChatId)
chatType := derefStr(msg.ChatType)
text, media := fsapi.ParseMessageContent(msgType, content)
cm := &fsapi.ConvertedMessage{
MessageID: messageID,
ChatID: chatID,
ChatType: chatType,
Text: text,
MediaItems: media,
EventID: event.EventV2Base.Header.EventID,
LanguageCode: "zh",
}
if sender != nil && sender.SenderId != nil {
cm.SenderID = derefStr(sender.SenderId.OpenId)
}
if cm.HasMedia() {
groups := []string{"feishu", entry.robotID}
entry.bot.ResolveMedia(ctx, cm, groups)
}
a.handleMessages(ctx, entry, []*fsapi.ConvertedMessage{cm})
return nil
}
func derefStr(s *string) string {
if s == nil {
return ""
}
return *s
}