* feat(platform): add Weixin personal (ilink) long-poll channel Implement weixin platform against ilink bot HTTP API (getUpdates + sendMessage), matching the OpenClaw openclaw-weixin backend. - Text, quoted text, and voice messages with ASR text; media-only inbound gets a placeholder until CDN decrypt is added - Persist get_updates_buf and per-peer context_token under data_dir - allow_from, optional proxy/SKRouteTag, session pause on errcode -14 - ReplyContextReconstructor for cron; FormattingInstructionProvider - Inject cc_data_dir/cc_project into all platform options for state paths - Build tag no_weixin; Makefile + docs + config.example.toml * feat(weixin): ilink QR setup CLI, CDN encrypt/decrypt, and Chinese docs - Add cc-connect weixin setup/bind/new with get_bot_qrcode + get_qrcode_status flow - Config helpers EnsureProjectWithWeixinPlatform / SaveWeixinPlatformCredentials - Inbound CDN decrypt and outbound ImageSender/FileSender via getuploadurl - Document weixin.md (ZH), usage guides, README/INSTALL links Made-with: Cursor * fix(weixin): remove unused netError type for golangci-lint Made-with: Cursor --------- Co-authored-by: Claude <noreply@anthropic.com>
58 lines
1.2 KiB
Go
58 lines
1.2 KiB
Go
package weixin
|
|
|
|
import (
|
|
"fmt"
|
|
"strings"
|
|
)
|
|
|
|
func isMediaItemType(t int) bool {
|
|
switch t {
|
|
case messageItemImage, messageItemVoice, messageItemFile, messageItemVideo:
|
|
return true
|
|
default:
|
|
return false
|
|
}
|
|
}
|
|
|
|
// bodyFromItemList extracts user-visible text from Weixin item_list (text, quotes, voice ASR).
|
|
func bodyFromItemList(items []messageItem) string {
|
|
if len(items) == 0 {
|
|
return ""
|
|
}
|
|
for _, item := range items {
|
|
switch item.Type {
|
|
case messageItemText:
|
|
if item.TextItem == nil {
|
|
continue
|
|
}
|
|
text := strings.TrimSpace(item.TextItem.Text)
|
|
ref := item.RefMsg
|
|
if ref == nil {
|
|
return text
|
|
}
|
|
if ref.MessageItem != nil && isMediaItemType(ref.MessageItem.Type) {
|
|
return text
|
|
}
|
|
var parts []string
|
|
if ref.Title != "" {
|
|
parts = append(parts, ref.Title)
|
|
}
|
|
if ref.MessageItem != nil {
|
|
refBody := bodyFromItemList([]messageItem{*ref.MessageItem})
|
|
if refBody != "" {
|
|
parts = append(parts, refBody)
|
|
}
|
|
}
|
|
if len(parts) == 0 {
|
|
return text
|
|
}
|
|
return fmt.Sprintf("[引用: %s]\n%s", strings.Join(parts, " | "), text)
|
|
case messageItemVoice:
|
|
if item.VoiceItem != nil && strings.TrimSpace(item.VoiceItem.Text) != "" {
|
|
return strings.TrimSpace(item.VoiceItem.Text)
|
|
}
|
|
}
|
|
}
|
|
return ""
|
|
}
|