
    Q,jò                    B   d Z ddlmZ ddlZddlZddlmZ  ej        e          Z	dZ
ddZdddddddddZdddddZdddddZdd iZd!Ze d"e d#e d$e d%e d&e d'e d(e d)e d*e d+e d,e d-e d.d/Zd0ZdZdZ ej                    Zdad1Zdd3ZdZdZdZd4Zdd6Zdd9Zdd<Z dd>Z!dd@Z"ddAZ#ddCZ$ddGZ%dddMZ&dddNZ'dddPZ(ddRZ)	 	 ddd[Z*dd\Z+dd^Z,dd_Z-	 ddd`Z.ddeZ/ddfZ0ddhZ1ddjZ2ddlZ3ddmZ4ddoZ5ddpZ6ddrZ7ddsZ8ddtZ9ddvZ:ddwZ;ddxZ<ddyZ=ddzZ>dd|Z?dd}Z@ddZAddZB	 	 	 	 	 dddZC	 	 	 	 	 	 dddZD	 	 	 	 	 dddZE	 	 	 	 	 	 dddZF	 	 	 	 dddZGddZHddZIefddZJedfddZKddZLddZM	 	 dddZNddZOdS )us  
yuanbao_proto.py - Yuanbao WebSocket 协议编解码（纯 Python 实现）

协议层级：
  WebSocket frame
    └── ConnMsg (protobuf: trpc.yuanbao.conn_common.ConnMsg)
          ├── head: Head  (cmd_type, cmd, seq_no, msg_id, module, ...)
          └── data: bytes  (业务 payload，标准 protobuf)
                └── InboundMessagePush / SendC2CMessageReq / SendGroupMessageReq / ...
                      (trpc.yuanbao.yuanbao_conn.yuanbao_openclaw_proxy.*)

注意：conn 层（ConnMsg）本身是标准 protobuf，不是自定义二进制格式。
     conn.proto 注释里的自定义格式（magic+head_len+body_len）仅用于 quic/tcp，
     WebSocket 直接传 ConnMsg protobuf bytes（无粘包问题，每个 ws frame = 一条消息）。

实现方式：手写 varint / protobuf wire-format 编解码，不依赖第三方 protobuf 库。
    )annotationsN)OptionalFlabelstrdatabytesreturnNonec                    t           rmd                    d |d d         D                       }t          |          dk    rdnd}t                              d| t          |          ||z              d S d S )N c              3     K   | ]}|d V  	dS )02xN .0bs     E/home/thesage/.hermes/hermes-agent/gateway/platforms/yuanbao_proto.py	<genexpr>z_dbg.<locals>.<genexpr>$   s&      99!a::999999    @   z... z[yuanbao_proto] %s (%dB): %s)
DEBUG_MODEjoinlenloggerdebug)r   r   hex_strellipsiss       r   _dbgr   "   s     [((99tCRCy99999IINN553UCIIwQYGYZZZZZ[ [r   z trpc.yuanbao.conn_common.ConnMsgz$trpc.yuanbao.conn_common.AuthBindReqz$trpc.yuanbao.conn_common.AuthBindRspz trpc.yuanbao.conn_common.PingReqz trpc.yuanbao.conn_common.PingRspz#trpc.yuanbao.conn_common.KickoutMsgz%trpc.yuanbao.conn_common.DirectedPushz trpc.yuanbao.conn_common.PushMsg)ConnMsgAuthBindReqAuthBindRspPingReqPingRsp
KickoutMsgDirectedPushPushMsg         )RequestResponsePushPushAckz	auth-bindpingkickoutzupdate-meta)AuthBindPingKickout
UpdateMeta
ConnAccessconn_accessyuanbao_openclaw_proxyz.InboundMessagePushz.SendC2CMessageReqz.SendC2CMessageRspz.SendGroupMessageReqz.SendGroupMessageRspz.QueryGroupInfoReqz.QueryGroupInfoRspz.GetGroupMemberListReqz.GetGroupMemberListRspz.SendPrivateHeartbeatReqz.SendPrivateHeartbeatRspz.SendGroupHeartbeatReqz.SendGroupHeartbeatRsp)InboundMessagePushSendC2CMessageReqSendC2CMessageRspSendGroupMessageReqSendGroupMessageRspQueryGroupInfoReqQueryGroupInfoRspGetGroupMemberListReqGetGroupMemberListRspSendPrivateHeartbeatReqSendPrivateHeartbeatRspSendGroupHeartbeatReqSendGroupHeartbeatRsp   l    intc                 v    t           5  t          } t          dz   t          z  addd           n# 1 swxY w Y   | S )u9   生成递增序列号（线程安全，溢出时归零）r(   N)	_seq_lock_seq_counter_SEQ_MAX)vals    r   next_seq_norL   q   sz     
 5 5$q(H45 5 5 5 5 5 5 5 5 5 5 5 5 5 5 Js   .22   valuec                    | dk     r| dz  } g }	 | dz  }| dz  } | r|                     |dz             n|                     |           n<t          |          S )u(   将非负整数编码为 protobuf varintr       T         )appendr   )rN   outbitss      r   _encode_varintrW      s{    qyy**
Ct|! 	JJtd{####JJt ::r   postuple[int, int]c                    d}d}|t          |           k     rK| |         }|dz  }||dz  |z  z  }|dz  }|dz  sn(|dk    rt          d          |t          |           k     K||fS )u6   从 data[pos:] 解码 varint，返回 (value, new_pos)r   r(   rQ   rR   rS   r   zvarint too long)r   
ValueError)r   rX   resultshiftr   s        r   _decode_varintr^      s    FE
D		//Iq1t8%%
D 	B;;./// D		// 3;r   field_number	wire_typec                6    | dz  |z  }t          |          |z   S )u,   编码一个 protobuf field（tag + value）r*   )rW   )r_   r`   rN   tags       r   _encode_fieldrc      s$    1	
)C#&&r   sc                j    |                      d          }t          t          |                    |z   S )uH   编码 protobuf string 字段的 value 部分（length-prefixed UTF-8）utf-8)encoderW   r   )rd   encodeds     r   _encode_stringri      s,    hhwG#g,,'''11r   r   c                @    t          t          |                     | z   S )uA   编码 protobuf bytes 字段的 value 部分（length-prefixed）rW   r   r   s    r   _encode_bytesrm          #a&&!!A%%r   c                @    t          t          |                     | z   S )u)   编码嵌套 message（length-prefixed）rk   rl   s    r   _encode_messagerp      rn   r   "list[tuple[int, int, bytes | int]]c                   g }d}t          |           }||k     r(t          | |          \  }}|dz	  }|dz  }|t          k    r,t          | |          \  }}|                    |||f           n|t          k    r>t          | |          \  }}| |||z            }||z  }|                    |||f           n|t
          k    r+| ||dz            }|dz  }|                    |||f           nN|t          k    r+| ||dz            }|dz  }|                    |||f           nt          d| d|dz
             ||k     (|S )	u   
    解析 protobuf message 的所有字段，返回 [(field_number, wire_type, raw_value), ...]
    raw_value:
      - WT_VARINT: int
      - WT_LEN: bytes
      - WT_64BIT: bytes (8 bytes)
      - WT_32BIT: bytes (4 bytes)
    r   r*   rR         zunknown wire type z at pos r(   )r   r^   	WT_VARINTrT   WT_LENWT_64BITWT_32BITr[   )	r   fieldsrX   nrb   r_   r`   rK   lengths	            r   _parse_fieldsr|      s    F
CD		A
''!$,,Sax$J		!!%dC00HCMM<C89999&  (s33KFCsC&L()C6MCMM<C89999(""sC!G|$C1HCMM<C89999(""sC!G|$C1HCMM<C89999N)NNS1WNNOOO+ '', Mr   ry   listdict[int, list]c                r    i }| D ]1\  }}}|                     |g                               ||f           2|S )u\   将 fields 列表转为 {field_number: [value, ...]} 字典（repeated 字段会有多个）)
setdefaultrT   )ry   dfnwtrK   s        r   _fields_to_dictr      sJ    A / /B	R##RI....Hr   r   fdictdictr   defaultc                    |                      |          }|s|S |d         \  }}|t          k    r3t          |t          t          f          r|                    dd          S |S )u*   从 fields dict 取第一个 string 字段r   rf   replace)errors)getrv   
isinstancer   	bytearraydecoder   r   r   entriesr   rK   s         r   _get_stringr      sb    iimmG ajGB	V||
3	(:;;|zz')z444Nr   c                    |                      |          }|s|S |d         \  }}|t          k    rt          |t                    r|S |S )u*   从 fields dict 取第一个 varint 字段r   )r   ru   r   rF   r   s         r   _get_varintr      sL    iimmG ajGB	Y:c3//
Nr   r   c                    |                      |          }|s|S |d         \  }}|t          k    r+t          |t          t          f          rt          |          S |S )u1   从 fields dict 取第一个 bytes/message 字段r   )r   rv   r   r   r   r   s         r   
_get_bytesr      sX    iimmG ajGB	V||
3	(:;;|SzzNr   list[bytes]c                F    |                      |g           }d |D             S )u'   取所有 repeated bytes/message 字段c                H    g | ]\  }}|t           k    t          |           S r   )rv   r   )r   r   rK   s      r   
<listcomp>z'_get_repeated_bytes.<locals>.<listcomp>  s'    >>>72svE#JJr   )r   )r   r   r   s      r   _get_repeated_bytesr   
  s)    iiBG>>g>>>>r   cmd_typecmdseq_nomsg_idmoduleneed_ackboolstatusc           	     X   d}| dk    r&|t          dt          t          |                     z  }|r&|t          dt          t	          |                    z  }|dk    r&|t          dt          t          |                    z  }|r&|t          dt          t	          |                    z  }|r&|t          dt          t	          |                    z  }|r&|t          dt          t          d                    z  }|dk    r)|t          d	t          t          |d
z                      z  }|S )u   编码 ConnMsg.Headr   r   r(   r)   r*   rt   rM      
   rP   )rc   ru   rW   rv   ri   )r   r   r   r   r   r   r   bufs           r   _encode_headr   %  s#    C1}}}Q	>(+C+CDDD
 =}Qs(;(;<<<{{}Q	>&+A+ABBB @}Qv(>(>??? @}Qv(>(>??? >}Q	>!+<+<==={{}RN6DV;V,W,WXXXJr   c                :   t          t          |                     }t          |dd          t          |dd          t          |dd          t          |dd          t          |dd          t	          t          |dd                    t          |d	d          d
S )u!   解码 ConnMsg.Head，返回 dictr(   r   r)   r   r*   rt   rM   r   r   r   r   r   r   r   r   r   )r   r|   r   r   r   r   r   s     r   _decode_headr   A  s    M$//00Eq!,,5!R((eQ**eQ++eQ++UAq1122eR++  r   msg_typec                    t          | d|dd          }t          dt          t          |                    }|r&|t          dt          t	          |                    z  }t          d|           |S )u  
    编码 ConnMsg（简化接口，对应任务要求的签名）。

    Args:
        msg_type: cmd_type（CMD_TYPE 枚举值）
        seq_no:   序列号
        data:     内层 payload bytes（业务 protobuf）

    Returns:
        ConnMsg 编码后的 bytes
    r   )r   r   r   r   r   r(   r)   encode_conn_msgr   rc   rv   rp   rm   r   )r   r   r   
head_bytesr   s        r   r   r   O  s~       J 6?:#>#>
?
?C =}Qd(;(;<<<	C   Jr   c                    t          d|            t          t          |                     }t          |d          }t          |d          }|rt	          |          n	dddddddd}|d         |d	         ||d
S )u  
    解码 ConnMsg，返回 {msg_type, seq_no, data, head}。

    Returns:
        {
          "msg_type": int,      # cmd_type
          "seq_no":   int,
          "data":     bytes,    # 内层 payload
          "head":     dict,     # 完整 head 字段
        }
    decode_conn_msgr(   r)   r   r   Fr   r   r   )r   r   r   head)r   r   r|   r   r   )r   r   r   payloadr   s        r   r   r   i  s     		D!!!M$//00EE1%%J""G'1 <
###bArQ8 8D
 $x.	  r   c                    t          | |||||          }t          dt          t          |                    }|r&|t          dt          t	          |                    z  }t          d|           |S )u   
    编码完整的 ConnMsg（含 cmd/msg_id/module 等 head 字段）。
    比 encode_conn_msg 提供更多 head 控制。
    )r   r   r   r   r   r   r(   r)   encode_conn_msg_fullr   )	r   r   r   r   r   r   r   r   r   s	            r   r   r     s       J 6?:#>#>
?
?C =}Qd(;(;<<<	%%%Jr   servicemethodreq_idbodyc                Z    t          t          d         |t                      || |          S )us  
    将业务 payload 包装为 ConnMsg bytes。

    Args:
        service: 模块名（head.module），如 "yuanbao_openclaw_proxy"
        method:  命令字（head.cmd），如 "send_c2c_message"
        req_id:  消息 ID（head.msg_id）
        body:    已编码的业务 protobuf bytes

    Returns:
        ConnMsg bytes（可直接发送到 WebSocket）
    r+   r   r   r   r   r   r   )r   CMD_TYPErL   r   r   r   r   s       r   encode_biz_msgr     s6      )$}}   r   c                    t          |           }|d         }|d         |d         |d         |d         |d         t          d         k    |dS )	u  
    解码 ConnMsg bytes，返回业务层信息。

    Returns:
        {
          "service":     str,    # head.module
          "method":      str,    # head.cmd
          "req_id":      str,    # head.msg_id
          "body":        bytes,  # 内层 biz payload
          "is_response": bool,   # cmd_type == 1 (Response)
          "head":        dict,   # 完整 head
        }
    r   r   r   r   r   r   r,   )r   r   r   r   is_responser   )r   r   )r   r\   r   s      r   decode_biz_msgr     sZ     T""F&>D>u+x.vJ'8J+??  r   keyc           
         d}| r3|t          dt          t          t          |                               z  }|r3|t          dt          t          t          |                              z  }|S )zUEncode a single entry of a protobuf map<string, string> (field 1 key, field 2 value).r   r(   r)   )rc   rv   ri   r   )r   rN   r   s      r   _encode_map_entryr     sf    
C
 B}Qs3xx(@(@AAA D}Qs5zz(B(BCCCJr   tuple[str, str]c                z    t          t          |                     }t          |d          t          |d          fS )zPDecode a single entry of a protobuf map<string, string>, returning (key, value).r(   r)   r   r|   r   r   s     r   _decode_map_entryr     s6    M$//00Eua  +eQ"7"777r   contentc                $   d}dD ]P\  }}|                      |d          }|r3|t          |t          t          t	          |                              z  }QdD ]P\  }}|                      |d          }|r3|t          |t
          t          t          |                              z  }Q|                      d          pg D ]}d}dD ]P\  }}|                     |d          }	|	r3|t          |t
          t          t          |	                              z  }Q|                     dd          }
|
r&|t          d	t          t          |
                    z  }|t          d
t          t          |                    z  }|                      d          }t          |t                    rj|                                D ]U\  }}t          t	          |          t	          |                    }|t          dt          t          |                    z  }V|S )Nr   )r(   text)r)   uuid)rt   r   )rM   desc)r   ext)rR   sound)r   url)   	file_namer   )r*   image_format)	   index)   	file_sizer   image_info_arrayr(   type)r)   size)r*   width)rt   heightr   rM   rs   ext_map  )r   rc   rv   ri   r   ru   rW   rF   rp   r   r   itemsr   )r   r   r   r   vimgimg_bufifnikeyivr   r   kentry_bytess                 r   _encode_msg_contentr     s   
C E EC KKR   	E=V^CFF-C-CDDDCI H HCKKQ 	H=Ys1vv0F0FGGGC{{-..4" 	B 	BP 	R 	RICq!!B R=iB9P9PQQQggeR   	E}Qs0C0CDDDG}Q(@(@AAAkk)$$G'4   LMMOO 	L 	LDAq+CFFCFF;;K=fok.J.JKKKCCJr   c                6   t          t          |                     }i }dD ]\  }}t          ||          }|r|||<   dD ]\  }}t          ||          }|r|||<   g }t	          |d          D ]m}t          t          |                    }i }	dD ]\  }
}t          ||
          }|r||	|<   t          |d          }|r||	d<   |	r|                    |	           n|r||d<   i }t	          |d          D ]}t          |          \  }}|r|||<   |r||d	<   |S )
Nr   r   rs   r   rM   r   r   r   r   )r   r|   r   r   r   rT   r   )r   r   r   r   r   r   imgs	img_bytesifdictr   r   r   r   r   r   r   r   s                    r   _decode_msg_contentr   )  s   M$//00EG  C r"" 	GCLI  Cr"" 	GCLD(22  	 y!9!9::P 	 	ICVS))B D	&!$$ 	CJ 	KK +&*"# G*5#66   --1 	GAJ %$	Nr   elementc                    d}|                      dd          }|r&|t          dt          t          |                    z  }|                      di           }|r5t	          |          }|t          dt          t          |                    z  }|S )Nr   r   r   r(   msg_contentr)   )r   rc   rv   ri   r   rp   )r   r   r   r   content_bytess        r   _encode_msg_body_elementr   V  s    
C{{:r**H B}Qx(@(@AAAkk-,,G H+G44}Q(F(FGGGJr   c                    t          t          |                     }t          |dd          }t          |d          }|rt	          |          ni }||dS )Nr(   r   r)   )r   r   )r   r|   r   r   r   )r   r   r   r   r   s        r   _decode_msg_body_elementr   b  s]    M$//00E5!R((Hua((M4AI!-000rG 999r   trace_idc                P    | sdS t          dt          t          |                     S )Nr   r(   )rc   rv   ri   )r   s    r   _encode_log_extr   n  s)     sFN8$<$<===r   c                |    t          t          |                     }t          |d          t          |d          dS )zDecode a single ImMsgSeq sub-message (field 17 of InboundMessagePush).

    ImMsgSeq proto fields:
      1: msg_seq (uint64)
      2: msg_id  (string)
    r(   r)   )msg_seqr   )r   r|   r   r   r   s     r   _decode_im_msg_seqr   t  sB     M$//00Eua((eQ''  r   c                ^    t          t          |                     }dt          |d          iS )Nr   r(   r   r   s     r   _decode_log_extr    s,    M$//00EE1--..r   Optional[dict]c                v   	 t          d|            t          t          |                     }g }t          |d          D ]$}|                    t          |                     %t          |d          }|r#t          |                              dd          nd}t          |d          }d |D             pd}i d	t          |d
          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d          dt          |d           d!|d"t          |d#          d$t          |d%          d&t          |d'          d(|t          |d)          t          |d*          |d+}d, |                                D             S # t          $ r-}	t          rt                              d-|	           Y d}	~	dS d}	~	ww xY w).u  
    解析入站消息推送的 biz payload（InboundMessagePush proto bytes）。

    Args:
        data: ConnMsg.data 字段的 bytes（即 biz payload）

    Returns:
        {
          "from_account":  str,
          "to_account":    str (可选),
          "group_code":    str (可选，群消息才有),
          "group_id":      str (可选),
          "group_name":    str (可选),
          "msg_key":       str,
          "msg_id":        str,
          "msg_seq":       int,
          "msg_random":    int,
          "msg_time":      int,
          "sender_nickname": str,
          "msg_body":      [{"msg_type": str, "msg_content": dict}, ...],
          "callback_command": str,
          "cloud_custom_data": str,
          "bot_owner_id":  str,
          "claw_msg_type": int,
          "private_from_group_code": str,
          "trace_id":      str,
          "recall_msg_seq_list": [{"msg_seq": int, "msg_id": str}, ...] 或 None,
        }
        或 None（解析失败）
    zdecode_inbound_push input      r   r   rE   c                ,    g | ]}t          |          S r   )r   r   s     r   r   z'decode_inbound_push.<locals>.<listcomp>  s!    MMM1!44MMMr   Ncallback_commandr(   from_accountr)   
to_accountr*   sender_nicknamert   group_idrM   
group_coder   
group_namerR   r   rs   
msg_randomr   msg_timer   msg_keyr   r   r   msg_bodycloud_custom_data   
event_time   bot_owner_id   recall_msg_seq_list      )claw_msg_typeprivate_from_group_coder   c                &    i | ]\  }}|s|d v ||S )>   r   r  r   r   r   r   s      r   
<dictcomp>z'decode_inbound_push.<locals>.<dictcomp>  s.    UUUA1U=T8T8T18T8T8Tr   z.[yuanbao_proto] decode_inbound_push failed: %s)r   r   r|   r   rT   r   r   r  r   r   r   r   	Exceptionr   r   r   )
r   r   r  el_byteslog_ext_bytesr   recall_seq_rawr  r\   es
             r   decode_inbound_pushr%    s   >)($///d 3 344+E266 	@ 	@HOO4X>>????"5"--IV^?=1155j"EEE\^,UB77MMnMMMUQU
E1 5 5
Kq11
 +eQ//
 {5!44	

 E1--
 +eQ//
 +eQ//
 {5!,,
 +eQ//
 E2..
 {5"--
 k%,,
 
  UB!7!7
 +eR00
  Kr22!
" "#6#
$ )33'25"'='= )
 
 
. VUUUUU    	NLLI1MMMttttts   G>H 
H8"H33H8c                (   t          t          |                     }i }t          |d          }|r||d<   t          |d          }|r||d<   t          |d          }|r||d<   t          |d          }|r||d<   t          |d	          }|r||d
<   |S )zZDecode a single Multimedia sub-message into the dict shape expected by _format_multimedia.r(   r   r)   r   rt   r   rM   r   r  media_id)r   r|   r   r   )r   r   mediamtyper   r   r   r'  s           r   _decode_forward_multimediar*    s    M$//00EEq!!E f
eQ

C
 eE1%%I '&kE1%%I '&k5"%%H %$jLr   c                    t          t          |                     }dt          |d          i}t          |d          }|r||d<   d t	          |d          D             }|r||d<   |S )zGDecode a single MsgContent sub-message into {type, text?, multimedia?}.r   r(   r)   r   c                ,    g | ]}t          |          S r   )r*  r   s     r   r   z/_decode_forward_msg_content.<locals>.<listcomp>/  s.       *+"1%%  r   r*   
multimedia)r   r|   r   r   r   )r   r   r   r   r-  s        r   _decode_forward_msg_contentr.  (  s    M$//00E[223Gua  D  /B5!/L/L  J  + *Nr   c                    t          t          |                     }t          |d          t          |d          t          |d          d t	          |d          D             dS )zLDecode a single ForwardMsg sub-message into {sender, plainText, msgContent}.r(   r)   r*   c                ,    g | ]}t          |          S r   )r.  r   s     r   r   z'_decode_forward_msg.<locals>.<listcomp>>  s.     
 
 
/0'**
 
 
r   rt   )sendertime	plainText
msgContent)r   r|   r   r   r   r   s     r   _decode_forward_msgr5  7  ss    M$//00EeQ''E1%% **
 
4Gq4Q4Q
 
 
	  r   c           	     `   	 t          t          |                     }t          |d          t          |d          t          |d          t          |d          d t	          |d          D             dS # t
          $ r-}t          rt                              d|           Y d	}~d	S d	}~ww xY w)
al  Parse ForwardMsgData protobuf bytes (the base64-decoded ext_map value).

    Args:
        data: ForwardMsgData protobuf bytes, after base64 decoding.

    Returns:
        A dict matching the structure consumed by
        ``ForwardedRecordsParseMiddleware.build_forward_text``
        (``sub_type`` / ``nick_name`` / ``msg`` list); ``None`` on parse failure.
    r(   r)   r*   rt   c                ,    g | ]}t          |          S r   )r5  r   s     r   r   z+decode_forward_msg_data.<locals>.<listcomp>V  s!    RRRq'**RRRr   rM   )sub_type
begin_timeend_time	nick_namemsgz2[yuanbao_proto] decode_forward_msg_data failed: %sN)	r   r|   r   r   r   r   r   r   r   )r   r   r$  s      r   decode_forward_msg_datar=  D  s    d 3 344#E1--%eQ//#E1--$UA..RR4Gq4Q4QRRR
 
 	
     	RLLMqQQQttttts   A3A6 6
B- "B((B-r(  c                V   d}dD ]P\  }}|                      |d          }|r3|t          |t          t          t	          |                              z  }QdD ]P\  }}|                      |d          }|r3|t          |t
          t          t          |                              z  }Q|S )Nr   )r   )r)   r   )rt   r   )r  r'  r   ))rM   r   )r   r   )rR   r   r   )r   rc   rv   ri   r   ru   rW   rF   )r(  r   r   r   r   s        r   _encode_forward_multimediar?  ^  s    
CP E ECIIc2 	E=V^CFF-C-CDDDCB H HCIIc1 	H=Ys1vv0F0FGGGCJr   c                   t          dt          t          t          |                     dd                                        }|                     dd          }|r3|t          dt
          t          t          |                              z  }|                     d          pg D ]5}|t          dt
          t          t          |                              z  }6|S )	Nr(   r   r   r   r   r)   r-  r*   )
rc   ru   rW   rF   r   rv   ri   r   rp   r?  )r   r   r   r(  s       r   _encode_forward_msg_contentrA  k  s    
9nSVQ9O9O5P5P&Q&Q
R
RC;;vr""D C}Qs4yy(A(ABBB\**0b \ \}Q8RSX8Y8Y(Z(Z[[[Jr   r<  c                f   d}|                      dd          }|r3|t          dt          t          t	          |                              z  }|                      dd          }|r3|t          dt
          t          t          |                              z  }|                      dd          }|r3|t          d	t          t          t	          |                              z  }|                      d
          pg D ]5}|t          dt          t          t          |                              z  }6|S )Nr   r1  r   r(   r2  r   r)   r3  r*   r4  rt   )
r   rc   rv   ri   r   ru   rW   rF   rp   rA  )r<  r   r1  time_valplainmcs         r   _encode_forward_msgrF  u  s   
CWWXr""F E}Qs6{{(C(CDDDwwvq!!H J}Q	>#h--+H+HIIIGGK$$E D}Qs5zz(B(BCCCggl##)r Z Z}Q8STV8W8W(X(XYYYJr   c                d   t          dt          t          t          |                     dd                                        }dD ]P\  }}|                     |d          }|r3|t          |t          t          t          |                              z  }Q|                     dd          }|r3|t          dt
          t          t          |                              z  }|                     d          pg D ]5}|t          d	t
          t          t          |                              z  }6|S )
zEncode ForwardMsgData protobuf bytes (inverse of ``decode_forward_msg_data``).

    Mainly used to build mock / test data; production code never needs to encode this.
    r(   r8  r   ))r)   r9  )r*   r:  r;  r   rt   r<  rM   )
rc   ru   rW   rF   r   rv   ri   r   rp   rF  )r   r   r   r   r   nickr<  s          r   encode_forward_msg_datarI    s   
 9nS*a9P9P5Q5Q&R&R
S
SC7 H HCHHS! 	H=Ys1vv0F0FGGGC88K$$D C}Qs4yy(A(ABBBxx$" S S}Q8KC8P8P(Q(QRRRJr   r	  r  r  r  r   Optional[int]r  c           	        d}|r&|t          dt          t          |                    z  }|t          dt          t          |                     z  }|r&|t          dt          t          |                    z  }|r&|t          dt          t	          |                    z  }|D ]7}	t          |	          }
|t          dt          t          |
                    z  }8|r&|t          dt          t          |                    z  }|&|t          d	t          t	          |                    z  }|r5t          |          }|t          d
t          t          |                    z  }|S )aC  
    Encode a SendC2CMessageReq biz payload.

    SendC2CMessageReq fields:
      1: msg_id (string)
      2: to_account (string)
      3: from_account (string)
      4: msg_random (uint32)
      5: msg_body (repeated MsgBodyElement)
      6: group_code (string)
      7: msg_seq (uint64)
      8: log_ext (LogInfoExt)
    r   r(   r)   r*   rt   rM   r   NrR   rs   )rc   rv   ri   ru   rW   r   rp   r   )r	  r  r  r   r  r   r  r   r   elr!  	log_bytess               r   _encode_send_c2c_reqrN    s^   . C @}Qv(>(>???=FN:$>$>???C F}Q|(D(DEEE G}Q	>*+E+EFFF C C+B//}Q(A(ABBB D}Qz(B(BCCC}Q	>'+B+BCCC D#H--	}Q	(B(BCCCJr   random
ref_msg_idc	           	        d}	|r&|	t          dt          t          |                    z  }	|	t          dt          t          |                     z  }	|r&|	t          dt          t          |                    z  }	|r&|	t          dt          t          |                    z  }	|r&|	t          dt          t          |                    z  }	|D ]7}
t          |
          }|	t          dt          t	          |                    z  }	8|r&|	t          dt          t          |                    z  }	|&|	t          d
t
          t          |                    z  }	|r5t          |          }|	t          dt          t	          |                    z  }	|	S )a`  
    Encode a SendGroupMessageReq biz payload.

    SendGroupMessageReq fields:
      1: msg_id (string)
      2: group_code (string)
      3: from_account (string)
      4: to_account (string)
      5: random (string)
      6: msg_body (repeated MsgBodyElement)
      7: ref_msg_id (string)
      8: msg_seq (uint64)
      9: log_ext (LogInfoExt)
    r   r(   r)   r*   rt   rM   r   rR   Nrs   r   )rc   rv   ri   r   rp   ru   rW   r   )r  r  r  r   r	  rO  r   rP  r   r   rL  r!  rM  s                r   _encode_send_group_reqrR    s   2 C @}Qv(>(>???=FN:$>$>???C F}Q|(D(DEEE D}Qz(B(BCCC @}Qv(>(>??? C C+B//}Q(A(ABBB D}Qz(B(BCCC}Q	>'+B+BCCC D#H--	}Q	(B(BCCCJr   c           
         t          | |||||||          }t          d|           |pdt                       }	t          t          d         dt                      |	t
          |          S )a  
    Encode a C2C send-message request and return the full ConnMsg bytes
    (ready to be sent over WebSocket).

    Args:
        to_account:   recipient account
        msg_body:     list of message-body elements; each item is
                      {"msg_type": str, "msg_content": dict}.
                      Example: [{"msg_type": "TIMTextElem", "msg_content": {"text": "hello"}}]
        from_account: sender account (the bot account)
        msg_id:       unique message ID (req_id is used when empty)
        msg_random:   random number for de-duplication
        msg_seq:      message sequence number (optional)
        group_code:   filled in for the "private chat originating from a group" case
        trace_id:     trace ID for request tracing

    Returns:
        ConnMsg bytes
    )r	  r  r  r   r  r   r  r   zencode_send_c2c biz payloadc2c_r+   send_c2c_messager   )rN  r   rL   r   r   _BIZ_PKG)
r	  r  r  r   r  r   r  r   	biz_bytesr   s
             r   encode_send_c2c_messagerX    s    : %!	 	 	I 		&	222--kmm--F)$}}   r   c	                    t          | ||||||||	  	        }	t          d|	           |pdt                       }
t          t          d         dt                      |
t
          |	          S )ad  
    Encode a group send-message request and return the full ConnMsg bytes
    (ready to be sent over WebSocket).

    Args:
        group_code:   group ID
        msg_body:     list of message-body elements
        from_account: sender account (the bot account)
        msg_id:       unique message ID
        to_account:   targeted recipient (usually empty)
        random:       random string for de-duplication
        msg_seq:      message sequence number
        ref_msg_id:   ID of the referenced (quoted) message
        trace_id:     trace ID for request tracing

    Returns:
        ConnMsg bytes
    )	r  r  r  r   r	  rO  r   rP  r   zencode_send_group biz payloadgrp_r+   send_group_messager   )rR  r   rL   r   r   rV  )r  r  r  r   r	  rO  r   rP  r   rW  r   s              r   encode_send_group_messager\  )  s    : '!
 
 
I 		()444--kmm--F)$ }}   r   biz_iduidsourcetokenapp_versionoperation_systembot_version	route_envc	           
        t          dt          t          |                    t          dt          t          |                    z   t          dt          t          |                    z   }	d}
|r&|
t          dt          t          |                    z  }
|r&|
t          dt          t          |                    z  }
|
t          dt          t          t          t                                        z  }
|r&|
t          dt          t          |                    z  }
t          dt          t          |                     t          dt          t          |	                    z   t          dt          t          |
                    z   }|r&|t          dt          t          |                    z  }t          t          d         t          d	         t                      |t          d
         |          S )u0  
    构造 auth-bind 请求 ConnMsg bytes。

    AuthBindReq fields:
      1: biz_id (string)
      2: auth_info (message AuthInfo: uid=1, source=2, token=3)
      3: device_info (message DeviceInfo: app_version=1, app_operation_system=2, instance_id=10, bot_version=24)
      5: env_name (string)
    r(   r)   r*   r   r      rM   r+   r1   r5   r   )rc   rv   ri   r   HERMES_INSTANCE_IDrp   r   r   CMDrL   MODULE)r]  r^  r_  r`  r   ra  rb  rc  rd  auth_bufdev_bufreq_bufs               r   encode_auth_bindrm  a  s   , 	a!4!455
6>&#9#9
:
:	;
6>%#8#8
9
9	:  G I=FN;,G,GHHH N=FN;K,L,LMMM}R<N8O8O)P)PQQQG J=V^K-H-HIII 	a!7!788
6?8#<#<
=
=	>
6?7#;#;
<
<	= 
  G=FN9,E,EFFF)$
O}}l#   r   c                    t          t          d         t          d         t                      | t          d         d          S )u:   构造 ping 请求 ConnMsg bytes（PingReq 为空消息）r+   r2   r5   r   r   )r   r   rh  rL   ri  )r   s    r   encode_pingro    s=    )$K}}l#   r   original_headc           
         t          t          d         |                     dd          t                      |                     dd          |                     dd          d          S )u   构造 push ACK 回包r.   r   r   r   r   r   r   )r   r   r   rL   )rp  s    r   encode_push_ackrr    sd    )$eR((}}  2..  2..   r   	heartbeatc                *   t          dt          t          |                     t          dt          t          |                    z   t          dt          t	          |                    z   }dt                       }t          t          d||          S )u   
    编码 SendPrivateHeartbeatReq，返回完整 ConnMsg bytes。

    SendPrivateHeartbeatReq fields:
      1: from_account (string)
      2: to_account   (string)
      3: heartbeat    (varint: RUNNING=1, FINISH=2)
    r(   r)   r*   hb_priv_send_private_heartbeatr   rc   rv   ri   ru   rW   rL   r   rV  )r  r	  rs  r   r   s        r   encode_send_private_heartbeatrx    s     	a!=!=>>
6>*#=#=
>
>	?
9nY&?&?
@
@	A 
 (''F'	   r   	send_timec                   ddl }|p#t          |                                 dz            }t          dt          t	          |                     t          dt          t	          d                    z   t          dt          t	          |                    z   t          dt
          t          |                    z   t          d	t
          t          |                    z   }d
t                       }t          t          d||          S )u;  
    编码 SendGroupHeartbeatReq，返回完整 ConnMsg bytes。

    SendGroupHeartbeatReq fields:
      1: from_account (string)
      2: to_account   (string)  — 群场景留空
      3: group_code   (string)
      4: send_time    (int64, ms timestamp)
      5: heartbeat    (varint: RUNNING=1, FINISH=2)
    r   Ni  r(   r)   r   r*   rt   rM   hb_grp_send_group_heartbeatr   )
r2  rF   rc   rv   ri   ru   rW   rL   r   rV  )r  r  rs  ry  _timetsr   r   s           r   encode_send_group_heartbeatr    s      		.c%**,,-..Ba!=!=>>
6>"#5#5
6
6	7
6>*#=#=
>
>	? 9nR&8&8
9
9	: 9nY&?&?
@
@		A  '{}}&&F%	   r   c                    t          dt          t          |                     }dt                       }t	          t
          d||          S )u~   
    编码 QueryGroupInfoReq，返回完整 ConnMsg bytes。

    QueryGroupInfoReq fields:
      1: group_code (string)
    r(   qgi_query_group_infor   )rc   rv   ri   rL   r   rV  )r  r   r   s      r   encode_query_group_infor    sQ     6>*#=#=
>
>C#KMM##F!	   r   c                N   	 t          t          |                     }t          |dd          }t          |d          }d|i}|r||d<   |                    dg           }|r|d         d         nd}|rt          |t          t          f          rpt          t          |                    }t          |d          pd|d	<   t          |d          pd|d
<   t          |d          pd|d<   t          |dd          |d<   nd|d	<   d|d
<   d|d<   d|d<   |S # t          $ r Y dS w xY w)u)  
    解码 QueryGroupInfoRsp biz payload。

    Proto 结构（对齐 TS biz-codec / member.ts queryGroupInfo）：

      message QueryGroupInfoRsp {
        int32  code       = 1;
        string message    = 2;
        GroupInfo group_info = 3;   // 嵌套 message
      }

      message GroupInfo {
        string group_name            = 1;
        string group_owner_user_id   = 2;
        string group_owner_nickname  = 3;
        uint32 group_size            = 4;
      }

    Returns:
        解码后的 dict，或 None（解析失败）
    r(   r   r)   codemessager*   r   r   r  owner_idowner_nicknamert   member_countN)	r   r|   r   r   r   r   r   r   r   )r   r   r  r<  r\   
gi_entriesgi_bytesgis           r   decode_query_group_info_rspr    sl   ,d 3 3445!Q''%##~ 	$ #F9 YYq"%%
'1::a=##s 
	'
8eY-?@@ 
	' x!8!899B#.r1#5#5#;F< !,R!3!3!9rF:'22q'9'9'?RF#$%0Q%:%:F>""#%F< !#F:')F#$%&F>"   tts   DD 
D$#D$   offsetlimitc                6   t          dt          t          |                     }|r&|t          dt          t	          |                    z  }|t          dt          t	          |                    z  }dt                       }t          t          d||          S )u   
    编码 GetGroupMemberListReq，返回完整 ConnMsg bytes。

    GetGroupMemberListReq fields:
      1: group_code (string)
      2: offset     (uint32)
      3: limit      (uint32)
    r(   r)   r*   gml_get_group_member_listr   rw  )r  r  r  r   r   s        r   encode_get_group_member_listr  <  s     6>*#=#=
>
>C C}Q	>&+A+ABBB=I~e'<'<===C#KMM##F&	   r   c           
     ^   	 t          t          |                     }t          |dd          }g }t          |d          D ]}t          t          |                    }t	          |d          t	          |d          t          |d          t          |d          t	          |d          d}|                    d |                                D                        |t	          |d          |t          |d          t          t          |d                    d	S # t          $ r Y d
S w xY w)u  
    解码 GetGroupMemberListRsp biz payload。

    GetGroupMemberListRsp fields:
      1: code         (int32)
      2: message      (string)
      3: members      (repeated message MemberInfo)
      4: next_offset  (uint32)
      5: is_complete  (bool/varint)

    MemberInfo fields:
      1: user_id      (string)
      2: nickname     (string)
      3: role         (uint32)  — 0=member, 1=admin, 2=owner
      4: join_time    (uint32)
      5: name_card    (string)  — 群昵称

    Returns:
        {
          "code": int,
          "message": str,
          "members": [{"user_id": str, "nickname": str, "role": int, ...}, ...],
          "next_offset": int,
          "is_complete": bool,
        }
        或 None（解析失败）
    r(   r   r*   r)   rt   rM   )user_idnicknamerole	join_time	name_cardc                *    i | ]\  }}|s|d k    ||S )r  r   r  s      r   r  z4decode_get_group_member_list_rsp.<locals>.<dictcomp>  s(    PPPTQqPAKKAqKKKr   )r  r  membersnext_offsetis_completeN)	r   r|   r   r   r   rT   r   r   r   )r   r   r  r  member_bytesmdictmembers          r    decode_get_group_member_list_rspr  V  sG   8d 3 3445!Q''/q99 		R 		RL#M,$?$?@@E&ua00'q11#E1--(22(22 F NNPPV\\^^PPPQQQQ "5!,,&ua00E1 5 566
 
 	
    tts   DD 
D,+D,)r   r   r   r   r	   r
   )r	   rF   )rN   rF   r	   r   )r   r   rX   rF   r	   rY   )r_   rF   r`   rF   rN   r   r	   r   )rd   r   r	   r   )r   r   r	   r   )r   r   r	   rq   )ry   r}   r	   r~   )r   )r   r   r   rF   r   r   r	   r   )r   )r   r   r   rF   r   rF   r	   rF   )r   )r   r   r   rF   r   r   r	   r   )r   r   r   rF   r	   r   )Fr   )r   rF   r   r   r   rF   r   r   r   r   r   r   r   rF   r	   r   )r   r   r	   r   )r   rF   r   rF   r   r   r	   r   )F)r   rF   r   r   r   rF   r   r   r   r   r   r   r   r   r	   r   )
r   r   r   r   r   r   r   r   r	   r   )r   r   rN   r   r	   r   )r   r   r	   r   )r   r   r	   r   )r   r   r	   r   )r   r   r	   r   )r   r   r	   r  )r(  r   r	   r   )r<  r   r	   r   )r   r   r	   r   )r   r   Nr   r   )r	  r   r  r   r  r}   r   r   r  rF   r   rJ  r  r   r   r   r	   r   )r   r   r   Nr   r   )r  r   r  r   r  r}   r   r   r	  r   rO  r   r   rJ  rP  r   r   r   r	   r   )r	  r   r  r}   r  r   r   r   r  rF   r   rJ  r  r   r   r   r	   r   )r  r   r  r}   r  r   r   r   r	  r   rO  r   r   rJ  rP  r   r   r   r	   r   )r   r   r   r   )r]  r   r^  r   r_  r   r`  r   r   r   ra  r   rb  r   rc  r   rd  r   r	   r   )r   r   r	   r   )rp  r   r	   r   )r  r   r	  r   rs  rF   r	   r   )
r  r   r  r   rs  rF   ry  rF   r	   r   )r  r   r	   r   )r   r  )r  r   r  rF   r  rF   r	   r   )P__doc__
__future__r   logging	threadingtypingr   	getLogger__name__r   r   r   PB_MSG_TYPESr   rh  ri  rV  BIZ_SERVICESrg  WS_HEARTBEAT_RUNNINGWS_HEARTBEAT_FINISHLockrH   rI   rJ   rL   ru   rw   rv   rx   rW   r^   rc   ri   rm   rp   r|   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  r%  r*  r.  r5  r=  r?  rA  rF  rI  rN  rR  rX  r\  rm  ro  rr  rx  r  r  r  r  r  r   r   r   <module>r     s   $ # " " " " "           		8	$	$ 
[ [ [ [ 299117;1	 	 	  	  -
 $%:::$888$888&<<<&<<<$888$888 (@@@ (@@@"*DDD"*DDD (@@@ (@@@ "      IN	    		
   "    ' ' ' '2 2 2 2& & & &
& & & &
" " " "J               ? ? ? ?B     8      4   F     P   .   h   8 8 8 8   B% % % %Z	 	 	 	: : : :> > > >   / / / /@H H H H`   ,   
 
 
 
   4
 
 
 
          2 !) ) ) ) )` !- - - - -h !0 0 0 0 0n !1 1 1 1 1| 3 3 3 3 3l	 	 	 		 	 	 	& *    < *	    L   "0 0 0 0r     44 4 4 4 4 4r   