
    `gjò                    h   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
d`d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d*ZdZdZ ej*                         Zdad+Zdad,ZdZdZdZd-Zdbd.Zdcd/Zddd0Z ded1Z!dfd2Z"dfd3Z#dgd4Z$dhd5Z%didjd6Z&dkdld7Z'dmdnd8Z(dod9Z)	 	 dp	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dqd:Z*drd;Z+dsd<Z,drd=Z-	 dt	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 dud>Z.dvd?Z/drd@Z0dwdAZ1dxdBZ2dydCZ3drdDZ4dzdEZ5drdFZ6d{dGZ7drdHZ8drdIZ9d|dJZ:drdKZ;drdLZ<drdMZ=d|dNZ>d}dOZ?dydPZ@d~dQZAddRZB	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddSZC	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddTZD	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddUZE	 	 	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddVZF	 	 	 	 d	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 ddWZGddXZHddYZIef	 	 	 	 	 	 	 ddZZJedf	 	 	 	 	 	 	 	 	 dd[ZKdd\ZLd|d]ZM	 	 d	 	 	 	 	 	 	 dd^ZNd|d_ZOy)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)OptionalFc                    t         rRdj                  d |d d D              }t        |      dkD  rdnd}t        j	                  d| t        |      ||z          y y )N c              3  $   K   | ]  }|d  
 yw)02xN ).0bs     R/root/.hermes/venv/lib/python3.12/site-packages/gateway/platforms/yuanbao_proto.py	<genexpr>z_dbg.<locals>.<genexpr>$   s     9!aW:9s   @   z... z[yuanbao_proto] %s (%dB): %s)
DEBUG_MODEjoinlenloggerdebug)labeldatahex_strellipsiss       r   _dbgr   "   sR    ((9tCRy99IN53UCIwQYGYZ     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    c                 j    t         5  t        } t        dz   t        z  addd       | S # 1 sw Y    S xY w)u9   生成递增序列号（线程安全，溢出时归零）r#   N)	_seq_lock_seq_counter_SEQ_MAX)vals    r   next_seq_norF   q   s9     
 5$q(H45 J5 Js   (2   c                    | dk  r| dz  } g }	 | dz  }| dz  } | r|j                  |dz         n|j                  |       	 t        |      S ?)u(   将非负整数编码为 protobuf varintr                )appendbytes)valueoutbitss      r   _encode_varintrR      s_    qy**
C
t|!JJtd{#JJt: r   c                    d}d}|t        |       k  rC| |   }|dz  }||dz  |z  z  }|dz  }|dz  s	 ||fS |dk\  rt        d      |t        |       k  rC||fS )u6   从 data[pos:] 解码 varint，返回 (value, new_pos)r   r#   rJ   rK   rL   r   zvarint too long)r   
ValueError)r   posresultshiftr   s        r   _decode_varintrX      s    FE
D	/Iq1t8%%
D 3; B;.// D	/ 3;r   c                .    | dz  |z  }t        |      |z   S )u,   编码一个 protobuf field（tag + value）r%   )rR   )field_number	wire_typerO   tags       r   _encode_fieldr]      s!    1	
)C#&&r   c                R    | j                  d      }t        t        |            |z   S )uH   编码 protobuf string 字段的 value 部分（length-prefixed UTF-8）utf-8)encoderR   r   )sencodeds     r   _encode_stringrc      s$    hhwG#g,''11r   c                0    t        t        |             | z   S )uA   编码 protobuf bytes 字段的 value 部分（length-prefixed）rR   r   r   s    r   _encode_bytesrg          #a&!A%%r   c                0    t        t        |             | z   S )u)   编码嵌套 message（length-prefixed）re   rf   s    r   _encode_messagerj      rh   r   c                   g }d}t        |       }||k  rt        | |      \  }}|dz	  }|dz  }|t        k(  r$t        | |      \  }}|j                  |||f       n|t        k(  r1t        | |      \  }}| |||z    }||z  }|j                  |||f       nj|t
        k(  r"| ||dz    }|dz  }|j                  |||f       n?|t        k(  r"| ||dz    }|dz  }|j                  |||f       nt        d| d|dz
         ||k  r|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%   rK         zunknown wire type z at pos r#   )r   rX   	WT_VARINTrM   WT_LENWT_64BITWT_32BITrT   )	r   fieldsrU   nr\   rZ   r[   rE   lengths	            r   _parse_fieldsru      sD    F
CD	A
'!$,Sax$J		!%dC0HCMM<C89& (s3KFCsC&L)C6MCMM<C89("sC!G$C1HCMM<C89("sC!G$C1HCMM<C891)HS1WINOO+ ', Mr   c                f    i }| D ])  \  }}}|j                  |g       j                  ||f       + |S )u\   将 fields 列表转为 {field_number: [value, ...]} 字典（repeated 字段会有多个）)
setdefaultrM   )rr   dfnwtrE   s        r   _fields_to_dictr{      s>    A /B	R##RI./Hr   c                    | j                  |      }|s|S |d   \  }}|t        k(  r)t        |t        t        f      r|j                  dd      S |S )u*   从 fields dict 取第一个 string 字段r   r_   replace)errors)getro   
isinstancerN   	bytearraydecodefdictry   defaultentriesrz   rE   s         r   _get_stringr      sQ    iimGajGB	V|
3	(:;zz')z44Nr   c                v    | j                  |      }|s|S |d   \  }}|t        k(  rt        |t              r|S |S )u*   从 fields dict 取第一个 varint 字段r   )r   rn   r   intr   s         r   _get_varintr      s>    iimGajGB	Y:c3/
Nr   c                    | j                  |      }|s|S |d   \  }}|t        k(  r!t        |t        t        f      rt        |      S |S )u1   从 fields dict 取第一个 bytes/message 字段r   )r   ro   r   rN   r   r   s         r   
_get_bytesr      sH    iimGajGB	V|
3	(:;SzNr   c                    | j                  |g       }|D cg c]  \  }}|t        k(  st        |       c}}S c c}}w )u'   取所有 repeated bytes/message 字段)r   ro   rN   )r   ry   r   rz   rE   s        r   _get_repeated_bytesr   
  s4    iiBG&->72svE#J>>>s   ;;c           	        d}| dk7  r|t        dt        t        |             z  }|r|t        dt        t	        |            z  }|dk7  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k7  r |t        d	t        t        |d
z              z  }|S )u   编码 ConnMsg.Headr   r   r#   r$   r%   rm   rG      
   rI   )r]   rn   rR   ro   rc   )cmd_typecmdseq_nomsg_idmoduleneed_ackstatusbufs           r   _encode_headr   %  s     C1}}Q	>(+CDD
}Qs(;<<{}Q	>&+ABB}Qv(>??}Qv(>??}Q	>!+<=={}RN6DV;V,W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%   rm   rG   r   r   r   r   r   r   r   r   r   )r{   ru   r   r   boolr   r   s     r   _decode_headr   A  st    M$/0Eq!,5!R(eQ*eQ+eQ+UAq12eR+ r   c                    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   r]   ro   rj   rg   r   )msg_typer   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{   ru   r   r   )r   r   r   payloadr   s        r   r   r   i  sx     		D!M$/0EE1%J"G'1<
#bArQ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   c                B    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_TYPErF   servicemethodreq_idbodys       r   encode_biz_msgr     s*      )$} r   c                f    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   rV   r   s      r   decode_biz_msgr     sR     T"F&>D>u+x.vJ'8J+?? r   c           
         d}| r&|t        dt        t        t        |                   z  }|r&|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$   )r]   ro   rc   str)keyrO   r   s      r   _encode_map_entryr     sJ    
C
}Qs3x(@AA}Qs5z(BCCJr   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{   ru   r   r   s     r   _decode_map_entryr     s*    M$/0Eua +eQ"777r   c                d   d}dD ]@  \  }}| j                  |d      }|s|t        |t        t        t	        |                  z  }B dD ]@  \  }}| j                  |d      }|s|t        |t
        t        t        |                  z  }B | j                  d      xs g D ]  }d}dD ]@  \  }}|j                  |d      }	|	s|t        |t
        t        t        |	                  z  }B |j                  dd      }
|
r|t        d	t        t        |
            z  }|t        d
t        t        |            z  } | j                  d      }t        |t              rS|j                         D ]@  \  }}t        t	        |      t	        |            }|t        dt        t        |            z  }B |S )Nr   )r#   text)r$   uuid)rm   r   )rG   desc)r   ext)rK   sound)r   url)   	file_namer   )r%   image_format)	   index)   	file_sizer   image_info_arrayr#   type)r$   size)r%   width)rm   heightr   rG   rl   ext_map  )r   r]   ro   rc   r   rn   rR   r   rj   r   dictitemsr   )contentr   ry   r   vimgimg_bufifnikeyivr   r   kentry_bytess                 r   _encode_msg_contentr     s   
C EC KKR =V^CF-CDDCE J HCKKQ=Ys1v0FGGCH
 {{-.4" 	BP 	RICq!B=iB9PQQ	R ggeR }Qs0CDDG}Q(@AA	B kk)$G'4 MMO 	LDAq+CFCF;K=fok.JKKC	L Jr   c                   t        t        |             }i }dD ]  \  }}t        ||      }|s|||<    dD ]  \  }}t        ||      }|s|||<    g }t	        |d      D ]]  }t        t        |            }i }	dD ]  \  }
}t        ||
      }|s||	|<    t        |d      }|r||	d<   |	sM|j                  |	       _ |r||d<   i }t	        |d      D ]  }t        |      \  }}|s|||<    |r||d	<   |S )
Nr   r   rl   r   rG   r   r   r   r   )r{   ru   r   r   r   rM   r   )r   r   r   ry   r   r   imgs	img_bytesifdictr   r   r   r   r   r   r   r   s                    r   _decode_msg_contentr   )  sQ   M$/0EG C r"GCL J Cr"GCL D(2 	 y!9:P 	ICVS)BD		 &!$CJKK &*"# G*5#6  -1GAJ $	Nr   c                    d}| j                  dd      }|r|t        dt        t        |            z  }| j                  di       }|r(t	        |      }|t        dt        t        |            z  }|S )Nr   r   r   r#   msg_contentr$   )r   r]   ro   rc   r   rj   )elementr   r   r   content_bytess        r   _encode_msg_body_elementr   V  sl    
C{{:r*H}Qx(@AAkk-,G+G4}Q(FGGJr   c                    t        t        |             }t        |dd      }t        |d      }|rt	        |      ni }||dS )Nr#   r   r$   )r   r   )r{   ru   r   r   r   )r   r   r   r   r   s        r   _decode_msg_body_elementr   b  sE    M$/0E5!R(Hua(M4A!-0rG 99r   c                <    | syt        dt        t        |             S )Nr   r#   )r]   ro   rc   )trace_ids    r   _encode_log_extr   n  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{   ru   r   r   r   s     r   _decode_im_msg_seqr   t  s1     M$/0Eua(eQ' r   c                F    t        t        |             }dt        |d      iS )Nr   r#   r   r   s     r   _decode_log_extr     s#    M$/0EE1-..r   c                   	 t        d|        t        t        |             }g }t        |d      D ]  }|j	                  t        |              t        |d      }|rt        |      j                  dd      nd}t        |d      }|D cg c]  }t        |       c}xs 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*}	|	j                         D 
ci c]  \  }
}|s|
d+v s|
| c}}
S c c}w c c}}
w # t        $ r&}t        rt        j!                  d,|       Y d}~y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   r@   Ncallback_commandr#   from_accountr$   
to_accountr%   sender_nicknamerm   group_idrG   
group_coder   
group_namerK   r   rl   
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   >   r   r  z.[yuanbao_proto] decode_inbound_push failed: %s)r   r{   ru   r   rM   r   r   r   r   r   r   r   r   	Exceptionr   r   r   )r   r   r  el_byteslog_ext_bytesr   recall_seq_rawr   r  rV   r   r   es                r   decode_inbound_pushr    sV   >)($/d 34+E26 	@HOO4X>?	@ #5"-IV?=155j"E\^,UB7>LM1!4MUQU
E1 5
Kq1
 +eQ/
 {5!4	

 E1-
 +eQ/
 +eQ/
 {5!,
 +eQ/
 E2.
 {5"-
 k%,
 
  UB!7
 +eR0
  Kr2!
" "#6#
$ )3'25"'= )
. "(UA1=T8T1UU3 N2 V LLI1Ms=   BF> 
F3C?F> F8*F8/F> 3F> >	G-G((G-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   rm   r   rG   r   r  media_id)r{   ru   r   r   )r   r   mediamtyper   r   r   r  s           r   _decode_forward_multimediar    s    M$/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<   t	        |d      D cg c]  }t        |       }}|r||d<   |S c c}w )zGDecode a single MsgContent sub-message into {type, text?, multimedia?}.r   r#   r$   r   r%   
multimedia)r{   ru   r   r   r   r  )r   r   r   r   r   r  s         r   _decode_forward_msg_contentr  (  sz    M$/0E[23Gua D/B5!/L*+"1%J   *Ns   A!c           	         t        t        |             }t        |d      t        |d      t        |d      t	        |d      D cg c]  }t        |       c}dS c c}w )zLDecode a single ForwardMsg sub-message into {sender, plainText, msgContent}.r#   r$   r%   rm   )sendertime	plainText
msgContent)r{   ru   r   r   r   r  )r   r   r   s      r   _decode_forward_msgr#  7  s^    M$/0EeQ'E1% *4Gq4Q
/0'*
	 
s   A
c           
     <   	 t        t        |             }t        |d      t        |d      t        |d      t        |d      t	        |d      D cg c]  }t        |       c}dS c c}w # t        $ r&}t        rt        j                  d|       Y d}~y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%   rm   rG   )sub_type
begin_timeend_time	nick_namemsgz2[yuanbao_proto] decode_forward_msg_data failed: %sN)
r{   ru   r   r   r   r#  r  r   r   r   )r   r   r   r  s       r   decode_forward_msg_datar*  D  s    d 34#E1-%eQ/#E1-$UA.4Gq4QRq'*R
 	

 S LLMqQs*   AA, A'"A, 'A, ,	B5BBc                   d}dD ]@  \  }}| j                  |d      }|s|t        |t        t        t	        |                  z  }B dD ]@  \  }}| j                  |d      }|s|t        |t
        t        t        |                  z  }B |S )Nr   )r   )r$   r   )rm   r   )r  r  r   ))rG   r   )r   r   )rK   r   r   )r   r]   ro   rc   r   rn   rR   r   )r  r   ry   r   r   s        r   _encode_forward_multimediar,  ^  s    
CP ECIIc2=V^CF-CDDCE C HCIIc1=Ys1v0FGGCH Jr   c                `   t        dt        t        t        | j	                  dd                        }| j	                  dd      }|r&|t        dt
        t        t        |                  z  }| j	                  d      xs g D ](  }|t        dt
        t        t        |                  z  }* |S )	Nr#   r   r   r   r   r$   r  r%   )
r]   rn   rR   r   r   ro   rc   r   rj   r,  )r   r   r   r  s       r   _encode_forward_msg_contentr.  k  s    
9nSVQ9O5P&Q
RC;;vr"D}Qs4y(ABB\*0b \}Q8RSX8Y(Z[[\Jr   c                   d}| j                  dd      }|r&|t        dt        t        t	        |                  z  }| j                  dd      }|r&|t        dt
        t        t        |                  z  }| j                  dd      }|r&|t        d	t        t        t	        |                  z  }| j                  d
      xs g D ](  }|t        dt        t        t        |                  z  }* |S )Nr   r  r   r#   r   r   r$   r!  r%   r"  rm   )
r   r]   ro   rc   r   rn   rR   r   rj   r.  )r)  r   r  time_valplainmcs         r   _encode_forward_msgr3  u  s    
CWWXr"F}Qs6{(CDDwwvq!H}Q	>#h-+HIIGGK$E}Qs5z(BCCggl#)r Z}Q8STV8W(XYYZJr   c                   t        dt        t        t        | j	                  dd                        }dD ]@  \  }}| j	                  |d      }|s|t        |t        t        t        |                  z  }B | j	                  dd      }|r&|t        dt
        t        t        |                  z  }| j	                  d      xs g D ](  }|t        d	t
        t        t        |                  z  }* |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#   r%  r   ))r$   r&  )r%   r'  r(  r   rm   r)  rG   )
r]   rn   rR   r   r   ro   rc   r   rj   r3  )r   r   ry   r   r   nickr)  s          r   encode_forward_msg_datar6    s    
 9nS*a9P5Q&R
SC7 HCHHS!=Ys1v0FGGCH 88K$D}Qs4y(ABBxx$" S}Q8KC8P(QRRSJr   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 ]*  }	t        |	      }
|t        dt        t        |
            z  }, |r|t        dt        t        |            z  }||t        dt        t	        |            z  }|r(t        |      }|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%   rm   rG   r   rK   rl   )r]   ro   rc   rn   rR   r   rj   r   )r   r   r  r   r  r   r   r   r   elr  	log_bytess               r   _encode_send_c2c_reqr:    s
   . C}Qv(>??=FN:$>??C}Q|(DEE}Q	>*+EFF C+B/}Q(ABBC }Qz(BCC}Q	>'+BCC#H-	}Q	(BCCJr   c	           	     j   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 ]*  }
t        |
      }|	t        dt        t	        |            z  }	, |r|	t        dt        t        |            z  }	||	t        d	t
        t        |            z  }	|r(t        |      }|	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%   rm   rG   r   rK   rl   r   )r]   ro   rc   r   rj   rn   rR   r   )r   r   r  r   r   randomr   
ref_msg_idr   r   r8  r  r9  s                r   _encode_send_group_reqr>    s%   2 C}Qv(>??=FN:$>??C}Q|(DEE}Qz(BCC}Qv(>?? C+B/}Q(ABBC }Qz(BCC}Q	>'+BCC#H-	}Q	(BCCJr   c           
         t        | |||||||      }t        d|       |xs 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   )r:  r   rF   r   r   _BIZ_PKG)
r   r  r   r   r  r   r   r   	biz_bytesr   s
             r   encode_send_c2c_messagerD    sl    : %!	I 		&	2-km_-F)$} r   c	                    t        | ||||||||	      }	t        d|	       |xs 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   r<  r   r=  r   zencode_send_group biz payloadgrp_r&   send_group_messager   )r>  r   rF   r   r   rB  )r   r  r   r   r   r<  r   r=  r   rC  r   s              r   encode_send_group_messagerH  )  so    : '!
I 		()4-km_-F)$ } r   c	           
        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      rG   r&   r,   r0   r   )r]   ro   rc   r   HERMES_INSTANCE_IDrj   r   r   CMDrF   MODULE)biz_iduidsourcetokenr   app_versionoperation_systembot_version	route_envauth_bufdev_bufreq_bufs               r   encode_auth_bindrY  a  sM   , 	a!45
6>&#9
:	;
6>%#8
9	:  G=FN;,GHH=FN;K,LMM}R<N8O)PQQG=V^K-HII 	a!78
6?8#<
=	>
6?7#;
<	= 
 =FN9,EFF)$
O}l# r   c                ^    t        t        d   t        d   t               | t        d   d      S )u:   构造 ping 请求 ConnMsg bytes（PingReq 为空消息）r&   r-   r0   r   r   )r   r   rL  rF   rM  )r   s    r   encode_pingr[    s1    )$K}l# r   c           
         t        t        d   | j                  dd      t               | j                  dd      | j                  dd      d      S )u   构造 push ACK 回包r)   r   r   r   r   r   r   )r   r   r   rF   )original_heads    r   encode_push_ackr^    sO    )$eR(}  2.  2. r   c                    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   r]   ro   rc   rn   rR   rF   r   rB  )r   r   	heartbeatr   r   s        r   encode_send_private_heartbeatrd    sp     	a!=>
6>*#=
>	?
9nY&?
@	A 
 'F'	 r   c                   ddl }|xs t        |j                         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%   rm   rG   hb_grp_send_group_heartbeatr   )
r   r   r]   ro   rc   rn   rR   rF   r   rB  )r   r   rc  	send_time_timetsr   r   s           r   encode_send_group_heartbeatrk    s      		.c%**,-.Ba!=>
6>"#5
6	7
6>*#=
>	? 9nR&8
9	: 9nY&?
@		A  {}o&F%	 r   c                v    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   )r]   ro   rc   rF   r   rB  )r   r   r   s      r   encode_query_group_inforo    s>     6>*#=
>CKM?#F!	 r   c                   	 t        t        |             }t        |dd      }t        |d      }d|i}|r||d<   |j	                  dg       }|r|d   d   nd}|rut        |t        t        f      r_t        t        |            }t        |d      xs d|d	<   t        |d      xs d|d
<   t        |d      xs d|d<   t        |dd      |d<   |S d|d	<   d|d
<   d|d<   d|d<   |S # t        $ r Y y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_nicknamerm   member_countN)	r{   ru   r   r   r   r   rN   r   r  )r   r   rq  r)  rV   
gi_entriesgi_bytesgis           r   decode_query_group_info_rspry    s)   ,d 345!Q'%#~ #F9 YYq"%
'1:a=#s
8eY-?@ x!89B#.r1#5#;F< !,R!3!9rF:'22q'9'?RF#$%0Q%:F>"  $&F< !#F:')F#$%&F>" s   CC% C% %	C10C1c                    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   rb  )r   offsetlimitr   r   s        r   encode_get_group_member_listr  <  sq     6>*#=
>C}Q	>&+ABB=I~e'<==CKM?#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}|j                  |j                         D ci c]  \  }}|s|dk(  s|| c}}        |t	        |d      |t        |d      t        t        |d            d	S c c}}w # t        $ r Y y
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$   rm   rG   )user_idnicknamerole	join_time	name_cardr  )rq  rr  membersnext_offsetis_completeN)	r{   ru   r   r   r   rM   r   r   r  )	r   r   rq  r  member_bytesmdictmemberr   r   s	            r    decode_get_group_member_list_rspr  V  s   8d 345!Q'/q9 		RL#M,$?@E&ua0'q1#E1-(2(2F NNV\\^PTQqAKAqDPQ		R "5!,&ua0E1 56
 	
 Q  s*   BC4  C.0C.58C4 .C4 4	D ?D )r   r   r   rN   returnNone)r  r   )rO   r   r  rN   )r   rN   rU   r   r  ztuple[int, int])rZ   r   r[   r   rO   rN   r  rN   )ra   r   r  rN   )r   rN   r  rN   )r   rN   r  z"list[tuple[int, int, bytes | int]])rr   listr  zdict[int, list])r   )r   r   ry   r   r   r   r  r   )r   )r   r   ry   r   r   r   r  r   )r   )r   r   ry   r   r   rN   r  rN   )r   r   ry   r   r  zlist[bytes])Fr   )r   r   r   r   r   r   r   r   r   r   r   r   r   r   r  rN   )r   rN   r  r   )r   r   r   r   r   rN   r  rN   )F)r   r   r   r   r   r   r   r   r   r   r   rN   r   r   r  rN   )
r   r   r   r   r   r   r   rN   r  rN   )r   r   rO   r   r  rN   )r   rN   r  ztuple[str, str])r   r   r  rN   )r   r   r  rN   )r   r   r  rN   )r   rN   r  zOptional[dict])r  r   r  rN   )r)  r   r  rN   )r   r   r  rN   )r   r   Nr   r   )r   r   r   r   r  r  r   r   r  r   r   Optional[int]r   r   r   r   r  rN   )r   r   r   Nr   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  rN   )r   r   r  r  r   r   r   r   r   r   r<  r   r   r  r=  r   r   r   r  rN   )r   r   r   r   )rN  r   rO  r   rP  r   rQ  r   r   r   rR  r   rS  r   rT  r   rU  r   r  rN   )r   r   r  rN   )r]  r   r  rN   )r   r   r   r   rc  r   r  rN   )
r   r   r   r   rc  r   rh  r   r  rN   )r   r   r  rN   )r      )r   r   r}  r   r~  r   r  rN   )P__doc__
__future__r   logging	threadingtypingr   	getLogger__name__r   r   r   PB_MSG_TYPESr   rL  rM  rB  BIZ_SERVICESrK  WS_HEARTBEAT_RUNNINGWS_HEARTBEAT_FINISHLockrB   rC   rD   rF   rn   rp   ro   rq   rR   rX   r]   rc   rg   rj   ru   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.  r3  r6  r:  r>  rD  rH  rY  r[  r^  rd  rk  ro  ry  r  r  r	   r   r   <module>r     s  $ #   			8	$ 
[ 299117;1	 	 	 -
 $%J&9:$:%78$:%78&Z';<&Z';<$:%78$:%78 (z)?@ (z)?@"*+CD"*+CD (z)?@ (z)?@"      INN	 		
" '2&
&
"J?B 	  	
    84F 	  	
    P.h8B%Z	:>/@H`,
4
 2 !))) ) 	)
 ) ) ) ) )` !--- - 	-
 - - - - - -h !000 0 	0
 0 0 0 0 0n !111 1 	1
 1 1 1 1 1 1| 33	3 3 	3
 3 3 3 3 3 3l		& *  	< *	  	
 L"0r   	44r   