Skip to content
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
64 changes: 62 additions & 2 deletions pkg/channels/feishu/feishu_64.go
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ import (
"net/http"
"os"
"path/filepath"
"strings"
"sync"
"sync/atomic"

Expand Down Expand Up @@ -112,6 +113,7 @@ func (c *FeishuChannel) Stop(ctx context.Context) error {
}

// Send sends a message using Interactive Card format for markdown rendering.
// Falls back to plain text message if card sending fails (e.g., table limit exceeded).
func (c *FeishuChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
if !c.IsRunning() {
return channels.ErrNotRunning
Expand All @@ -124,9 +126,38 @@ func (c *FeishuChannel) Send(ctx context.Context, msg bus.OutboundMessage) error
// Build interactive card with markdown content
cardContent, err := buildMarkdownCard(msg.Content)
if err != nil {
return fmt.Errorf("feishu send: card build failed: %w", err)
// If card build fails, fall back to plain text
return c.sendText(ctx, msg.ChatID, msg.Content)
}
return c.sendCard(ctx, msg.ChatID, cardContent)

// First attempt: try sending as interactive card
err = c.sendCard(ctx, msg.ChatID, cardContent)
if err == nil {
return nil
}

// Check if error is due to card table limit (error code 11310)
// See: https://open.feishu.cn/document/server-docs/im-api/message-content-description/create_json
errMsg := err.Error()
isCardLimitError := strings.Contains(errMsg, "11310")

if isCardLimitError {
logger.WarnCF("feishu", "Card send failed (table limit), falling back to text message", map[string]any{
"chat_id": msg.ChatID,
"error": errMsg,
})
Comment on lines +144 to +148

// Second attempt: fall back to plain text message
textErr := c.sendText(ctx, msg.ChatID, msg.Content)
if textErr == nil {
return nil
}
// If text also fails, return the text error
return textErr
}

// For other errors, return the original card error
return err
}

// EditMessage implements channels.MessageEditor.
Expand Down Expand Up @@ -715,6 +746,35 @@ func (c *FeishuChannel) sendCard(ctx context.Context, chatID, cardContent string
return nil
}

// sendText sends a plain text message to a chat (fallback when card fails).
func (c *FeishuChannel) sendText(ctx context.Context, chatID, text string) error {
content, _ := json.Marshal(map[string]string{"text": text})

req := larkim.NewCreateMessageReqBuilder().
ReceiveIdType(larkim.ReceiveIdTypeChatId).
Body(larkim.NewCreateMessageReqBodyBuilder().
ReceiveId(chatID).
MsgType(larkim.MsgTypeText).
Content(string(content)).
Build()).
Build()

resp, err := c.client.Im.V1.Message.Create(ctx, req)
if err != nil {
return fmt.Errorf("feishu send text: %w", channels.ErrTemporary)
}

if !resp.Success() {
return fmt.Errorf("feishu text api error (code=%d msg=%s): %w", resp.Code, resp.Msg, channels.ErrTemporary)
}

logger.DebugCF("feishu", "Feishu text message sent (fallback)", map[string]any{
"chat_id": chatID,
})

return nil
}

// sendImage uploads an image and sends it as a message.
func (c *FeishuChannel) sendImage(ctx context.Context, chatID string, file *os.File) error {
// Upload image to get image_key
Expand Down
Loading