add build constraints for feishu to support 32-bit builds

This commit is contained in:
PixelTux
2026-02-11 20:59:25 +01:00
parent 6ccd9d0a99
commit cddafb403a
2 changed files with 38 additions and 0 deletions

217
pkg/channels/feishu_64.go Normal file
View File

@@ -0,0 +1,217 @@
//go:build amd64 || arm64 || riscv64 || mips64 || ppc64
package channels
import (
"context"
"encoding/json"
"fmt"
"sync"
"time"
lark "github.com/larksuite/oapi-sdk-go/v3"
larkdispatcher "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"
"github.com/sipeed/picoclaw/pkg/bus"
"github.com/sipeed/picoclaw/pkg/config"
"github.com/sipeed/picoclaw/pkg/logger"
)
type FeishuChannel struct {
*BaseChannel
config config.FeishuConfig
client *lark.Client
wsClient *larkws.Client
mu sync.Mutex
cancel context.CancelFunc
}
func NewFeishuChannel(cfg config.FeishuConfig, bus *bus.MessageBus) (*FeishuChannel, error) {
base := NewBaseChannel("feishu", cfg, bus, cfg.AllowFrom)
return &FeishuChannel{
BaseChannel: base,
config: cfg,
client: lark.NewClient(cfg.AppID, cfg.AppSecret),
}, nil
}
func (c *FeishuChannel) Start(ctx context.Context) error {
if c.config.AppID == "" || c.config.AppSecret == "" {
return fmt.Errorf("feishu app_id or app_secret is empty")
}
dispatcher := larkdispatcher.NewEventDispatcher(c.config.VerificationToken, c.config.EncryptKey).
OnP2MessageReceiveV1(c.handleMessageReceive)
runCtx, cancel := context.WithCancel(ctx)
c.mu.Lock()
c.cancel = cancel
c.wsClient = larkws.NewClient(
c.config.AppID,
c.config.AppSecret,
larkws.WithEventHandler(dispatcher),
)
wsClient := c.wsClient
c.mu.Unlock()
c.setRunning(true)
logger.InfoC("feishu", "Feishu channel started (websocket mode)")
go func() {
if err := wsClient.Start(runCtx); err != nil {
logger.ErrorCF("feishu", "Feishu websocket stopped with error", map[string]interface{}{
"error": err.Error(),
})
}
}()
return nil
}
func (c *FeishuChannel) Stop(ctx context.Context) error {
c.mu.Lock()
if c.cancel != nil {
c.cancel()
c.cancel = nil
}
c.wsClient = nil
c.mu.Unlock()
c.setRunning(false)
logger.InfoC("feishu", "Feishu channel stopped")
return nil
}
func (c *FeishuChannel) Send(ctx context.Context, msg bus.OutboundMessage) error {
if !c.IsRunning() {
return fmt.Errorf("feishu channel not running")
}
if msg.ChatID == "" {
return fmt.Errorf("chat ID is empty")
}
payload, err := json.Marshal(map[string]string{"text": msg.Content})
if err != nil {
return fmt.Errorf("failed to marshal feishu content: %w", err)
}
req := larkim.NewCreateMessageReqBuilder().
ReceiveIdType(larkim.ReceiveIdTypeChatId).
Body(larkim.NewCreateMessageReqBodyBuilder().
ReceiveId(msg.ChatID).
MsgType(larkim.MsgTypeText).
Content(string(payload)).
Uuid(fmt.Sprintf("picoclaw-%d", time.Now().UnixNano())).
Build()).
Build()
resp, err := c.client.Im.V1.Message.Create(ctx, req)
if err != nil {
return fmt.Errorf("failed to send feishu message: %w", err)
}
if !resp.Success() {
return fmt.Errorf("feishu api error: code=%d msg=%s", resp.Code, resp.Msg)
}
logger.DebugCF("feishu", "Feishu message sent", map[string]interface{}{
"chat_id": msg.ChatID,
})
return nil
}
func (c *FeishuChannel) handleMessageReceive(_ context.Context, event *larkim.P2MessageReceiveV1) error {
if event == nil || event.Event == nil || event.Event.Message == nil {
return nil
}
message := event.Event.Message
sender := event.Event.Sender
chatID := stringValue(message.ChatId)
if chatID == "" {
return nil
}
senderID := extractFeishuSenderID(sender)
if senderID == "" {
senderID = "unknown"
}
content := extractFeishuMessageContent(message)
if content == "" {
content = "[empty message]"
}
metadata := map[string]string{}
if messageID := stringValue(message.MessageId); messageID != "" {
metadata["message_id"] = messageID
}
if messageType := stringValue(message.MessageType); messageType != "" {
metadata["message_type"] = messageType
}
if chatType := stringValue(message.ChatType); chatType != "" {
metadata["chat_type"] = chatType
}
if sender != nil && sender.TenantKey != nil {
metadata["tenant_key"] = *sender.TenantKey
}
logger.InfoCF("feishu", "Feishu message received", map[string]interface{}{
"sender_id": senderID,
"chat_id": chatID,
"preview": truncateString(content, 80),
})
c.HandleMessage(senderID, chatID, content, nil, metadata)
return nil
}
func extractFeishuSenderID(sender *larkim.EventSender) string {
if sender == nil || sender.SenderId == nil {
return ""
}
if sender.SenderId.UserId != nil && *sender.SenderId.UserId != "" {
return *sender.SenderId.UserId
}
if sender.SenderId.OpenId != nil && *sender.SenderId.OpenId != "" {
return *sender.SenderId.OpenId
}
if sender.SenderId.UnionId != nil && *sender.SenderId.UnionId != "" {
return *sender.SenderId.UnionId
}
return ""
}
func extractFeishuMessageContent(message *larkim.EventMessage) string {
if message == nil || message.Content == nil || *message.Content == "" {
return ""
}
if message.MessageType != nil && *message.MessageType == larkim.MsgTypeText {
var textPayload struct {
Text string `json:"text"`
}
if err := json.Unmarshal([]byte(*message.Content), &textPayload); err == nil {
return textPayload.Text
}
}
return *message.Content
}
func stringValue(v *string) string {
if v == nil {
return ""
}
return *v
}