@@ -12,6 +12,7 @@ import (
1212 "fmt"
1313 "io"
1414 "net/http"
15+ "runtime/debug"
1516 "strconv"
1617 "strings"
1718 "sync"
@@ -27,8 +28,11 @@ const (
2728 channelName = "wechat_ilink"
2829 channelType = "wechat_ilink"
2930 iLinkBotAPI = "/ilink/bot"
31+ iLinkAppID = "bot"
3032
3133 iLinkMessageTypeUser = 1
34+ iLinkMessageTypeBot = 2
35+ iLinkMessageStateFin = 2
3236 iLinkItemTypeText = 1
3337 iLinkItemTypeImage = 2
3438 iLinkItemTypeVoice = 3
@@ -201,8 +205,13 @@ func (c *Channel) Send(ctx context.Context, msg channel.OutgoingMessage) error {
201205 }
202206
203207 req := iLinkSendMessageRequest {
208+ BaseInfo : buildILinkBaseInfo (),
204209 Msg : iLinkOutgoingMessage {
205- ToUserID : msg .ChatID ,
210+ FromUserID : "" ,
211+ ToUserID : c .resolveILinkTargetUserID (msg ),
212+ ClientID : generateILinkClientID (),
213+ MessageType : iLinkMessageTypeBot ,
214+ MessageState : iLinkMessageStateFin ,
206215 ContextToken : c .resolveILinkContextToken (msg ),
207216 ItemList : []iLinkMessageItem {
208217 {
@@ -303,7 +312,8 @@ type iLinkResponseEnvelope struct {
303312}
304313
305314type iLinkGetUpdatesRequest struct {
306- GetUpdatesBuf string `json:"get_updates_buf"`
315+ GetUpdatesBuf string `json:"get_updates_buf"`
316+ BaseInfo iLinkBaseInfo `json:"base_info"`
307317}
308318
309319type iLinkGetUpdatesResponse struct {
@@ -314,11 +324,16 @@ type iLinkGetUpdatesResponse struct {
314324}
315325
316326type iLinkSendMessageRequest struct {
317- Msg iLinkOutgoingMessage `json:"msg"`
327+ BaseInfo iLinkBaseInfo `json:"base_info"`
328+ Msg iLinkOutgoingMessage `json:"msg"`
318329}
319330
320331type iLinkOutgoingMessage struct {
332+ FromUserID string `json:"from_user_id"`
321333 ToUserID string `json:"to_user_id"`
334+ ClientID string `json:"client_id"`
335+ MessageType int `json:"message_type"`
336+ MessageState int `json:"message_state"`
322337 ContextToken string `json:"context_token,omitempty"`
323338 ItemList []iLinkMessageItem `json:"item_list"`
324339}
@@ -348,6 +363,10 @@ type iLinkTextItem struct {
348363 Text string `json:"text"`
349364}
350365
366+ type iLinkBaseInfo struct {
367+ ChannelVersion string `json:"channel_version"`
368+ }
369+
351370type iLinkNamedItem struct {
352371 FileName string `json:"file_name,omitempty"`
353372 Name string `json:"filename,omitempty"`
@@ -435,7 +454,10 @@ func (c *Channel) handleILinkIncomingMessages(messages []iLinkMessage) {
435454
436455func (c * Channel ) ilinkGetUpdates (ctx context.Context , cursor string ) (iLinkGetUpdatesResponse , error ) {
437456 var resp iLinkGetUpdatesResponse
438- if err := c .postILinkJSON (ctx , "getupdates" , iLinkGetUpdatesRequest {GetUpdatesBuf : cursor }, & resp ); err != nil {
457+ if err := c .postILinkJSON (ctx , "getupdates" , iLinkGetUpdatesRequest {
458+ GetUpdatesBuf : cursor ,
459+ BaseInfo : buildILinkBaseInfo (),
460+ }, & resp ); err != nil {
439461 return resp , err
440462 }
441463 if err := validateILinkResponse (resp .iLinkResponseEnvelope ); err != nil {
@@ -463,6 +485,8 @@ func (c *Channel) postILinkJSON(ctx context.Context, endpoint string, payload an
463485 req .Header .Set ("AuthorizationType" , "ilink_bot_token" )
464486 req .Header .Set ("Authorization" , "Bearer " + strings .TrimSpace (c .config .BotToken ))
465487 req .Header .Set ("X-WECHAT-UIN" , c .ensureILinkUINHeader ())
488+ req .Header .Set ("iLink-App-Id" , iLinkAppID )
489+ req .Header .Set ("iLink-App-ClientVersion" , strconv .FormatUint (buildILinkClientVersion (resolveILinkChannelVersion ()), 10 ))
466490
467491 client := c .httpClient
468492 if client == nil {
@@ -502,6 +526,62 @@ func resolveILinkBotBaseURL(raw string) string {
502526 return baseURL + iLinkBotAPI
503527}
504528
529+ func buildILinkBaseInfo () iLinkBaseInfo {
530+ return iLinkBaseInfo {ChannelVersion : resolveILinkChannelVersion ()}
531+ }
532+
533+ func resolveILinkChannelVersion () string {
534+ if info , ok := debug .ReadBuildInfo (); ok {
535+ version := strings .TrimSpace (info .Main .Version )
536+ if version != "" && version != "(devel)" {
537+ return version
538+ }
539+ }
540+ return "unknown"
541+ }
542+
543+ func buildILinkClientVersion (version string ) uint64 {
544+ version = strings .TrimSpace (strings .TrimPrefix (version , "v" ))
545+ if version == "" || version == "unknown" {
546+ return 0
547+ }
548+ parts := strings .SplitN (version , "." , 3 )
549+ if len (parts ) < 3 {
550+ return 0
551+ }
552+ major , err := strconv .Atoi (parts [0 ])
553+ if err != nil {
554+ return 0
555+ }
556+ minor , err := strconv .Atoi (parts [1 ])
557+ if err != nil {
558+ return 0
559+ }
560+ patchPart := parts [2 ]
561+ for i , ch := range patchPart {
562+ if ch < '0' || ch > '9' {
563+ patchPart = patchPart [:i ]
564+ break
565+ }
566+ }
567+ if patchPart == "" {
568+ return 0
569+ }
570+ patch , err := strconv .Atoi (patchPart )
571+ if err != nil {
572+ return 0
573+ }
574+ return uint64 ((major << 16 ) | (minor << 8 ) | patch )
575+ }
576+
577+ func generateILinkClientID () string {
578+ var raw [12 ]byte
579+ if _ , err := rand .Read (raw [:]); err != nil {
580+ return fmt .Sprintf ("zimaos-ilink-%d" , time .Now ().UnixNano ())
581+ }
582+ return "zimaos-ilink-" + base64 .RawURLEncoding .EncodeToString (raw [:])
583+ }
584+
505585func validateILinkResponse (resp iLinkResponseEnvelope ) error {
506586 if resp .Ret != 0 {
507587 if strings .TrimSpace (resp .ErrMsg ) != "" {
@@ -545,6 +625,15 @@ func (c *Channel) resolveILinkContextToken(msg channel.OutgoingMessage) string {
545625 return c .ilinkContextTokens [msg .ChatID ]
546626}
547627
628+ func (c * Channel ) resolveILinkTargetUserID (msg channel.OutgoingMessage ) string {
629+ if msg .Metadata != nil {
630+ if raw , ok := msg .Metadata ["target_user_id" ].(string ); ok && strings .TrimSpace (raw ) != "" {
631+ return strings .TrimSpace (raw )
632+ }
633+ }
634+ return strings .TrimSpace (msg .ChatID )
635+ }
636+
548637func (c * Channel ) storeILinkContextToken (chatID , token string ) {
549638 chatID = strings .TrimSpace (chatID )
550639 token = strings .TrimSpace (token )
@@ -591,9 +680,10 @@ func (c *Channel) convertILinkMessage(msg iLinkMessage) (channel.Message, bool)
591680 Attachments : attachments ,
592681 Timestamp : timestamp ,
593682 Metadata : map [string ]interface {}{
594- "context_token" : msg .ContextToken ,
595- "session_id" : msg .SessionID ,
596- "to_user_id" : msg .ToUserID ,
683+ "context_token" : msg .ContextToken ,
684+ "session_id" : msg .SessionID ,
685+ "target_user_id" : fromUserID ,
686+ "to_user_id" : msg .ToUserID ,
597687 },
598688 }, true
599689}
0 commit comments