
    i7                      U d Z ddlmZ ddlZddlZddlZddlZddlZddlZddl	Z	ddl
Z
ddlZddlZddlZddlZddlZddlmZ ddlmZ ddlmZmZmZmZmZ ddlmZmZ  ej        e          Z	 ddlZdZ n# e!$ r dZd	Z Y nw xY w	 dd
l"m#Z# ddl$m%Z%m&Z&m'Z' dZ(n# e!$ r dZ#dZ%dZ&dZ'd	Z(Y nw xY wddl)m*Z*m+Z+ ddl,m-Z- ddl.m/Z/m0Z0m1Z1m2Z2m3Z3m4Z4m5Z5 ddl6m7Z7 ddl8m9Z9 dZ:dZ;dZ<dZ=dZ>dZ?dZ@dZAdZBdZCdZDdZEdZFdZGdZHdZId ZJd!ZKd"ZLd#ZMd$ZNd%ZOdd-ZPd.ZQd!ZRd ZSd/ZTi ZUd0eVd1<   dd3ZWd.ZXd!ZYd ZZd/Z[d4Z\d.Z]d!Z^d!Z_d.Z`d!Za e
jb        d5          Zc e
jb        d6          Zd e
jb        d7          Ze e
jb        d8          Zfdd9Zgddd@ZhddBZidddGZjddJZkddLZlddNZmddOZnddPZoddTZpddWZqddYZrdZd[dd_ZsddaZt G db dc          Zu G dd de          ZvddhZwddkZxddmZyddpZzdduZ{ddvZ|ddxZ}dd}Z~ddZddZddZddZddddZ eh d          ZdeVd<   ddZddZddZddZddZddZddZddZddZddZddZddZddZddZ	 dddZdddZddZddZddZddZddZdddddZ G d de/          ZddddƄZdS )a{  
Weixin platform adapter.

Connects Hermes Agent to WeChat personal accounts via Tencent's iLink Bot API.

Design notes:
- Long-poll ``getupdates`` drives inbound delivery.
- Every outbound reply must echo the latest ``context_token`` for the peer.
- Media files move through an AES-128-ECB encrypted CDN protocol.
- QR login is exposed as a helper for the gateway setup wizard.
    )annotationsN)datetime)Path)AnyDictListOptionalTuple)quoteurlparseTF)default_backend)Cipher
algorithmsmodes)PlatformPlatformConfig)MessageDeduplicator)BasePlatformAdapterMessageEventMessageType
SendResultcache_audio_from_bytescache_document_from_bytescache_image_from_bytes)get_hermes_home)atomic_json_writezhttps://ilinkai.weixin.qq.comz%https://novac2c.cdn.weixin.qq.com/c2cbotz2.2.0i  zilink/bot/getupdateszilink/bot/sendmessagezilink/bot/sendtypingzilink/bot/getconfigzilink/bot/getuploadurlzilink/bot/get_bot_qrcodezilink/bot/get_qrcode_statusi  i:  i'           ii,  ret'Optional[int]'errcodeerrmsg'Optional[str]'returnboolc                f    | t           k    r|t           k    rdS |pd                                dk    S )zTrue when iLink returns ret=-2 / errcode=-2 with 'unknown error',
    which is a stale-session signal (same as errcode=-14) rather than
    a genuine rate limit.F unknown error)RATE_LIMIT_ERRCODElower)r"   r$   r%   s      ?/home/longshao/.hermes/hermes-agent/gateway/platforms/weixin.py_is_stale_session_retr/   `   s;        W0B%B%BuLb!!_44          Dict[str, Any]_LIVE_ADAPTERS Optional['aiohttp.TCPConnector']c                     	 ddl } ddl}n# t          $ r Y dS w xY wt          sdS |                     |                                          }t          j        |          S )a  Return a TCPConnector with a certifi CA bundle, or None if certifi is unavailable.

    Tencent's iLink server (``ilinkai.weixin.qq.com``) is not verifiable against
    some system CA stores (notably Homebrew's OpenSSL on macOS Apple Silicon).
    When ``certifi`` is installed, use its Mozilla CA bundle to guarantee
    verification. Otherwise fall back to aiohttp's default (which honors
    ``SSL_CERT_FILE`` env var via ``trust_env=True``).
    r   N)cafile)ssl)r8   certifiImportErrorAIOHTTP_AVAILABLEcreate_default_contextwhereaiohttpTCPConnector)r8   r9   ssl_ctxs      r.   _make_ssl_connectorrA   s   s|    


   tt t(((@@GG,,,,s    
   z^(#{1,6})\s+(.+?)\s*$z3^\s*\|?(?:\s*:?-{3,}:?\s*\|)+\s*:?-{3,}:?\s*\|?\s*$z^```([^\n`]*)\s*$z\[([^\]]+)\]\(([^)]+)\)c                     t           ot          S )z?Return True when runtime dependencies for Weixin are available.)r;   CRYPTO_AVAILABLE r0   r.   check_weixin_requirementsrF      s    1!11r0      valueOptional[str]keepintstrc                    t          | pd                                          }|sdS t          |          |k    r|S |d |         S )Nr*   ?)rL   striplen)rH   rJ   raws      r.   _safe_idrR      sP    
ekr


 
 
"
"C s
3xx4
uu:r0   payloadc                0    t          j        | dd          S )NF),:)ensure_ascii
separators)jsondumps)rS   s    r.   _json_dumpsr[      s    :gEjIIIIr0      databytes
block_sizec                X    |t          |           |z  z
  }| t          |g|z            z   S N)rP   r^   )r]   r_   pad_lens      r.   
_pkcs7_padrc      s1    CII
23G%	G+,,,,r0   	plaintextkeyc                   t          t          j        |          t          j                    t                                }|                                }|                    t          |                     |	                                z   S )Nbackend)
r   r   AESr   ECBr   	encryptorupdaterc   finalize)rd   re   cipherrk   s       r.   _aes128_ecb_encryptro      sj    JN3''o>O>OPPPF  ""IJy1122Y5G5G5I5IIIr0   
ciphertextc                   t          t          j        |          t          j                    t                                }|                                }|                    |           |                                z   }|s|S |d         }d|cxk    rdk    r4n n1|	                    t          |g          |z            r|d |          S |S )Nrg   r1   r\   )r   r   ri   r   rj   r   	decryptorrl   rm   endswithr^   )rp   re   rn   rs   paddedrb   s         r.   _aes128_ecb_decryptrv      s    JN3''o>O>OPPPF  ""Ij))I,>,>,@,@@F RjGGrfooeWI.>.>.HIIixi  Mr0   sizec                    | dz   dz   dz  dz  S )Nr1      r\   rE   )rw   s    r.   _aes_padded_sizerz      s    AX]r!R''r0   c                     t          j        dt          j        d                    d         } t	          j        t          |                               d                                        d          S )Nz>Ir2   r   utf-8ascii)	structunpacksecretstoken_bytesbase64	b64encoderL   encodedecoderH   s    r.   _random_wechat_uinr      sV    M$ 3A 6 677:ECJJ--g6677>>wGGGr0   c                     dt           iS )Nchannel_version)CHANNEL_VERSIONrE   r0   r.   
_base_infor      s    //r0   tokenbodyDict[str, str]c           	         ddt          t          |                    d                              t                      t          t          t
                    d}| rd|  |d<   |S )Nzapplication/jsonilink_bot_tokenr|   )Content-TypeAuthorizationTypezContent-LengthzX-WECHAT-UINiLink-App-IdiLink-App-ClientVersionzBearer Authorization)rL   rP   r   r   ILINK_APP_IDILINK_APP_CLIENT_VERSION)r   r   headerss      r.   _headersr      sl    *.c$++g"6"67788*,,$#&'?#@#@ G  5#4U#4#4 Nr0   hermes_homer   c                ^    t          |           dz  dz  }|                    dd           |S )NweixinaccountsT)parentsexist_ok)r   mkdir)r   paths     r.   _account_dirr      s4    x'*4DJJtdJ+++Kr0   
account_idc                ,    t          |           | dz  S )Nz.jsonr   r   r   s     r.   _account_filer      s    $$*';';';;;r0   r*   )user_idbase_urlr   Nonec                   |||t          j        dt          j                              d}t          | |          }t	          ||           	 |                    d           dS # t          $ r Y dS w xY w)z,Persist account credentials for later reuse.z%Y-%m-%dT%H:%M:%SZ)r   r   r   saved_ati  N)timestrftimegmtimer   r   chmodOSError)r   r   r   r   r   rS   r   s          r.   save_weixin_accountr      s     M"6FF	 G j11DdG$$$

5   s   A$ $
A21A2Optional[Dict[str, Any]]c                    t          | |          }|                                sdS 	 t          j        |                    d                    S # t
          $ r Y dS w xY w)z#Load persisted account credentials.Nr|   encoding)r   existsrY   loads	read_text	Exceptionr   r   r   s      r.   load_weixin_accountr      sk    j11D;;== tz$..'.::;;;   tts   'A 
AAc                  J    e Zd ZdZddZddZdd
ZddZddZddZ	ddZ
dS )ContextTokenStorez<Disk-backed ``context_token`` cache keyed by account + peer.r   rL   c                <    t          |          | _        i | _        d S ra   )r   _root_cache)selfr   s     r.   __init__zContextTokenStore.__init__  s    !+..
&(r0   r   r'   r   c                    | j         | dz  S )Nz.context-tokens.json)r   )r   r   s     r.   _pathzContextTokenStore._path  s    zz?????r0   r   c                    | d| S )NrV   rE   r   r   r   s      r.   _keyzContextTokenStore._key  s    ((w(((r0   r   c                8   |                      |          }|                                sd S 	 t          j        |                    d                    }nA# t
          $ r4}t                              dt          |          |           Y d }~d S d }~ww xY wd}|	                                D ]?\  }}t          |t                    r%|r#|| j        |                     ||          <   |dz  }@|r+t                              d|t          |                     d S d S )Nr|   r   z3weixin: failed to restore context tokens for %s: %sr   r1   z+weixin: restored %d context token(s) for %s)r   r   rY   r   r   r   loggerwarningrR   items
isinstancerL   r   r   info)r   r   r   r]   excrestoredr   r   s           r.   restorezContextTokenStore.restore  s5   zz*%%{{}} 	F	:dnngn>>??DD 	 	 	NNPRZ[eRfRfhklllFFFFF	 "jjll 	 	NGU%%% % >CDIIj'::;A 	gKKExQYZdQeQefffff	g 	gs   (A 
B )BBrI   c                ^    | j                             |                     ||                    S ra   )r   getr   r   s      r.   r   zContextTokenStore.get'  s$    {tyyW==>>>r0   r   c                l    || j         |                     ||          <   |                     |           d S ra   )r   r   _persist)r   r   r   r   s       r.   setzContextTokenStore.set*  s4    6;DIIj'223j!!!!!r0   c                &   | dfd| j                                         D             }	 t          |                     |          |           d S # t          $ r4}t
                              dt          |          |           Y d }~d S d }~ww xY w)NrV   c                p    i | ]2\  }}|                               |t                    d          |3S ra   )
startswithrP   ).0re   rH   prefixs      r.   
<dictcomp>z.ContextTokenStore._persist.<locals>.<dictcomp>0  sP     
 
 
U~~f%%
F
 
 
r0   z3weixin: failed to persist context tokens for %s: %s)r   r   r   r   r   r   r   rR   )r   r   rS   r   r   s       @r.   r   zContextTokenStore._persist.  s    !!!
 
 
 
"k//11
 
 

	mdjj44g>>>>> 	m 	m 	mNNPRZ[eRfRfhklllllllll	ms   #A 
B)BBN)r   rL   )r   rL   r'   r   )r   rL   r   rL   r'   rL   )r   rL   r'   r   )r   rL   r   rL   r'   rI   )r   rL   r   rL   r   rL   r'   r   )__name__
__module____qualname____doc__r   r   r   r   r   r   r   rE   r0   r.   r   r   	  s        FF) ) ) )@ @ @ @) ) ) )g g g g"? ? ? ?" " " "
m 
m 
m 
m 
m 
mr0   r   c                  ,    e Zd ZdZdddZdd
ZddZdS )TypingTicketCachez3Short-lived typing ticket cache from ``getconfig``.     @ttl_secondsfloatc                "    || _         i | _        d S ra   )_ttl_secondsr   )r   r   s     r.   r   zTypingTicketCache.__init__>  s    '46r0   r   rL   r'   rI   c                    | j                             |          }|sd S t          j                    |d         z
  | j        k    r| j                             |d            d S |d         S )Nr1   r   )r   r   r   r   pop)r   r   entrys      r.   r   zTypingTicketCache.getB  sc    (( 	49;;q!T%666KOOGT***4Qxr0   ticketr   c                @    |t          j                     f| j        |<   d S ra   )r   r   )r   r   r   s      r.   r   zTypingTicketCache.setK  s     &	4Gr0   N)r   )r   r   )r   rL   r'   rI   )r   rL   r   rL   r'   r   )r   r   r   r   r   r   r   rE   r0   r.   r   r   ;  s[        ==7 7 7 7 7   5 5 5 5 5 5r0   r   cdn_base_urlencrypted_query_paramc                T    |                      d           dt          |d           S )N/z /download?encrypted_query_param=r*   saferstripr   )r   r   s     r.   _cdn_download_urlr   O  s3    !!#&&ooNcjlHmHmHmooor0   upload_paramfilekeyc                x    |                      d           dt          |d           dt          |d           S )Nr   z/upload?encrypted_query_param=r*   r   z	&filekey=r   )r   r   r   s      r.   _cdn_upload_urlr   S  sV    s## 	. 	."'2">">">	. 	.'+++	. 	.r0   aes_key_b64c                R   t          j        |           }t          |          dk    r|S t          |          dk    rL|                    dd          }|r3t	          d |D                       rt
                              |          S t          dt          |           d          )	Nr\       r}   ignore)errorsc              3     K   | ]}|d v V  	dS )0123456789abcdefABCDEFNrE   )r   chs     r.   	<genexpr>z!_parse_aes_key.<locals>.<genexpr>a  s(      FF266FFFFFFr0   zunexpected aes_key format (z decoded bytes))r   	b64decoderP   r   allr^   fromhex
ValueError)r   decodedtexts      r.   _parse_aes_keyr	  [  s    {++G
7||r
7||r~~gh~77 	'CFFFFFFF 	'==&&&
P3w<<PPP
Q
QQr0   messageTuple[str, str]c                   t          |                     d          p|                     d          pd                                          }t          |                     d          pd                                          }t          |          p"|o |o||k    o|                     d          dk    }|r*d|p%|p#t          |                     d          pd          fS d	t          |                     d          pd          fS )
Nroom_idchat_room_idr*   
to_user_idmsg_typer1   groupfrom_user_iddm)rL   r   rO   r(   )r
  r   r  r  is_groups        r.   _guess_chat_typer  f  s    '++i((MGKK,G,GM2NNTTVVGW[[..4"55;;==JG}}y!x
!xzZ?W!x\c\g\ghr\s\swx\xH XW:WW[[5P5P5VTV1W1WWWW[[006B7777r0   session'aiohttp.ClientSession'endpoint
timeout_msc                 K   t          i |dt                      i          }|                    d           d| }t          j        |dz            }|                     ||t          ||          |          4 d {V }	|	                                 d {V }
|	j        s%t          d| d|	j
         d|
d d	                    t          j        |
          cd d d           d {V  S # 1 d {V swxY w Y   d S )
N	base_infor     totalr]   r   timeoutziLink POST  HTTP :    )r[   r   r   r>   ClientTimeoutpostr   r  okRuntimeErrorstatusrY   r   )r  r   r  rS   r   r  r   urlr   responserQ   s              r.   	_api_postr+  o  s      ='=;
==>>D__S!!
.
.H
.
.C#*t*;<<<G||CdHUD4I4ISZ|[[       _gMMOO######{ 	][X[[X_[[PSTXUXTXPY[[\\\z#	                             s   AC00
C:=C:c                 K   |                     d           d| }t          t          t                    d}t	          j        |dz            }|                     |||          4 d {V }|                                 d {V }|j        s%t          d| d|j
         d|d d	                    t          j        |          cd d d           d {V  S # 1 d {V swxY w Y   d S )
Nr   )r   r   r  r  )r   r   z
iLink GET r!  r"  r#  )r   r   rL   r   r>   r$  r   r  r&  r'  r(  rY   r   )	r  r   r  r  r)  r   r   r*  rQ   s	            r.   _api_getr-    s      __S!!
.
.H
.
.C$#&'?#@#@ G #*t*;<<<G{{3{AA       XMMOO######{ 	\ZHZZHOZZsSWTWSWyZZ[[[z#	                             s   /AC
C&)C&sync_bufc                  K   	 t          | |t          d|i||           d {V S # t          j        $ r	 dg |dcY S w xY w)Nget_updates_bufr   r  rS   r   r  r   )r"   msgsr0  )r+  EP_GET_UPDATESasyncioTimeoutError)r  r   r   r.  r  s        r.   _get_updatesr6    s      
C#&1!
 
 
 
 
 
 
 
 
 	
  C C C"BBBBBCs   !& >>tor  context_token	client_idc                  K   |r|                                 st          d          d||t          t          t          d|idgd}|r||d<   t          | |t          d|i|t                     d	{V S )
zSend a text message via iLink sendmessage API.

    Returns the raw API response dict (may contain error codes like
    ``errcode: -14`` for session expiry that the caller can inspect).
    z%_send_message: text must not be emptyr*   r  )type	text_itemr  r  r9  message_typemessage_state	item_listr8  msgr1  N)rO   r  MSG_TYPE_BOTMSG_STATE_FINISH	ITEM_TEXTr+  EP_SEND_MESSAGEAPI_TIMEOUT_MS)r  r   r   r7  r  r8  r9  r
  s           r.   _send_messagerG    s        Btzz|| B@AAA$)(~FFG G  1#0   !         r0   r  typing_ticketr(  c          	     \   K   t          | |t          |||d|t                     d {V  d S )N)ilink_user_idrH  r(  r1  )r+  EP_SEND_TYPINGCONFIG_TIMEOUT_MS)r  r   r   r  rH  r(  s         r.   _send_typingrM    sk       '*
 

 $           r0   c               f   K   d|i}|r||d<   t          | |t          ||t                     d {V S )NrJ  r8  r1  )r+  EP_GET_CONFIGrL  )r  r   r   r   r8  rS   s         r.   _get_configrP    sk        /8G 1#0 $         r0   
media_typerawsize
rawfilemd5filesize
aeskey_hexc       	        b   K   t          | |t          ||||||d|	d|t                     d {V S )NT)r   rQ  r  rR  rS  rT  no_need_thumbaeskeyr1  )r+  EP_GET_UPLOAD_URLrF  )
r  r   r   r  rQ  r   rR  rS  rT  rU  s
             r.   _get_upload_urlrZ    sp       "$$$ ! 	
 	
 !         r0   
upload_urlc          	     $  K   t          j        d          }|                     ||ddi|          4 d{V }|j        dk    r~|j                            d          }|r.|                                 d{V  |cddd          d{V  S |                                 d{V }t          d	|dd                    |                                 d{V }t          d
|j         d|dd                    # 1 d{V swxY w Y   dS )u   Upload encrypted media to the CDN.

    Accepts either a constructed CDN URL (from upload_param) or a direct
    upload_full_url — both use POST with the raw ciphertext as the body.
    x   r  r   application/octet-streamr  Nr#  zx-encrypted-paramz-CDN upload missing x-encrypted-param header: zCDN upload HTTP r"  )	r>   r$  r%  r(  r   r   readr  r'  )r  rp   r[  r   r*  encrypted_paramrQ   s          r.   _upload_ciphertextra    s      ##...G||JZ.RlAmw~| 	N 	N 	N 	N 	N 	N 	N  DL?c!!&.223FGGO 'mmoo%%%%%%%&	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N !''''''CZsSWTWSWyZZ[[[MMOO######LhoLLTcTLLMMM	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	N 	Ns   AC?A0C??
D	D	      N@)timeout_secondsr)  rc  r   c                 K   t          j        |          }|                     ||          4 d {V }|                                 |                                 d {V cd d d           d {V  S # 1 d {V swxY w Y   d S )Nr  r   )r>   r$  r   raise_for_statusr_  )r  r)  rc  r   r*  s        r.   _download_bytesrg  4  s      #/:::G{{3{00 % % % % % % %H!!###]]__$$$$$$% % % % % % % % % % % % % % % % % % % % % % % % % % % % % %s   .A66
B B >   wx.qlogo.cnmmbiz.qpic.cnres.wx.qq.commmbiz.qlogo.cnthirdwx.qlogo.cnilinkai.weixin.qq.comnovac2c.cdn.weixin.qq.comzfrozenset[str]_WEIXIN_CDN_ALLOWLISTc                   	 t          |           }|j                                        }|j        pd}n%# t          $ r}t          d|           |d}~ww xY w|dvrt          d|d          |t          vrt          d|d          dS )	zDRaise ValueError if *url* does not point at a known WeChat CDN host.r*   zUnparseable media URL: N)httphttpsz Media URL has disallowed scheme z ; only http/https are permitted.zMedia URL host zG is not in the WeChat CDN allowlist. Refusing to fetch to prevent SSRF.)r   schemer-   hostnamer   r  ro  )r)  parsedrs  hostr   s        r.   _assert_weixin_cdn_urlrw  M  s    E#$$&&$" E E E:3::;;DE &&&YvYYY
 
 	
 (((1d 1 1 1
 
 	
 )(s   14 
AAAitemc                Z    |                      |          pi                      d          pi S )Nmedia)r   )rx  re   s     r.   _media_referencer{  a  s*    HHSMMR$$W--33r0   full_urlc                 K   |r't          | t          ||          |           d {V }n9|r(t          |           t          | ||           d {V }nt          d          |rt	          |t          |                    }|S )N)r)  rc  z7media item had neither encrypt_query_param nor full_url)rg  r   rw  r'  rv   r	  )r  r   r   r   r|  rc  rQ   s          r.   _download_and_decrypt_mediar~  e  s        
V#!,0EFF+
 
 
 
 
 
 
 
 

 
 Vx(((#G?[[[[[[[[[TUUU D!#~k'B'BCCJr0   filenamec                :    t          j        |           d         pdS )Nr   r^  )	mimetypes
guess_type)r  s    r.   _mime_from_filenamer  ~  s    ))!,J0JJr0   line	List[str]c                    |                                  }|                    d          r
|dd          }|                    d          r
|d d         }d |                    d          D             S )N|r1   rr   c                6    g | ]}|                                 S rE   rO   )r   cells     r.   
<listcomp>z$_split_table_row.<locals>.<listcomp>  s     444TDJJLL444r0   )rO   r   rt   split)r  rows     r.   _split_table_rowr    so    
**,,C
~~c !""g
||C #2#h44SYYs^^4444r0   c                   t                               |           }|s|                                 S t          |                    d                    }|                    d                                          }|dk    rd| dS d| dS )Nr1   r      【u   】z**)
_HEADER_REmatchr   rP   r  rO   )r  r  leveltitles       r.   _rewrite_headers_for_weixinr    s    T""E {{}}AEKKNN  ""EzzU>>>r0   linesc                   t          |           dk     rd                    |           S t          | d                   }d | dd          D             }|r|sd                    |           S g }|D ]A}g }t          |          D ]W\  }}|t          |          k    r n>|pd|dz    }||                                         }	|	r|                    ||	f           X|sot          |          dk    r'|d         \  }}	|                    d| d|	            t          |          dk    rN|d         \  }}	|d         \  }
}|                    d| d|	            |                    d	|
 d|            
d
                    d |D                       }|                    d|            C|rd                    |          nd                    |           S )Nr   
r   c                T    g | ]%}|                                 t          |          &S rE   )rO   r  r   r  s     r.   r  z3_rewrite_table_block_for_weixin.<locals>.<listcomp>  s.    NNNDN!$''NNNr0   zColumn r1   z- r"  z   | c              3  *   K   | ]\  }}| d | V  dS )r"  NrE   )r   labelrH   s      r.   r  z2_rewrite_table_block_for_weixin.<locals>.<genexpr>  s4      KK\UE0000KKKKKKr0   )rP   joinr  	enumeraterO   append)r  r   	body_rowsformatted_rowsr  pairsidxheaderr  rH   other_labelother_valuesummarys                r.   _rewrite_table_block_for_weixinr    s,   
5zzA~~yyuQx((GNNE!""INNNI  )  yy "N . .$W-- 	- 	-KCc#hh11a11EHNN$$E -eU^,,, 	u::?? 8LE5!!"7u"7"7"7"7888u::?? 8LE5',Qx$K!!"7u"7"7"7"7888!!"C{"C"Ck"C"CDDD**KKUKKKKKn7nn----(6L499^$$$DIIe<L<LLr0   contentc                   |                                  }g }d}d}|D ]}|                                }t                              |                                          r| }|                    |           d}]|r|                    |           u|                                s!|dz  }|dk    r|                    d           d}|                    |           d                    |                                          S )NFr   r1   r*   r  
splitlinesr   	_FENCE_REr  rO   r  r  )r  r  resultin_code_block	blank_runraw_liner  s          r.   _normalize_markdown_blocksr    s
     EFMI    ??4::<<(( 	 --MMM$I 	MM$zz|| 	NIA~~b!!!	d99V""$$$r0   c                   | sg S g }|                                  }g }d}|D ][}|                                }t                              |                                          r|s>|r<|                    d                    |                                                     g }|                    |           | }|s<|                    d                    |                                                     g }|r|                    |           |                                s@|r<|                    d                    |                                                     g }F|                    |           ]|r:|                    d                    |                                                     d |D             S )NFr  c                    g | ]}||S rE   rE   )r   blocks     r.   r  z*_split_markdown_blocks.<locals>.<listcomp>  s    ///e/E///r0   r  )r  blocksr  currentr  r  r  s          r.   _split_markdown_blocksr    s    	F  EGM    ??4::<<(( 		  W dii006688999NN4    --M  dii006688999 	NN4   zz|| 	 dii006688999t 2dii((..00111//v////r0   c                h   g }t          |           D ]}t                              |                                d                                                   r|                    |           ]g }|                                D ]}|                                }|                                s?|r<|                    d                    |                                                     g }it          |          o|	                    d          }|r|                    |           |r:|                    d                    |                                                     |g}|r:|                    d                    |                                                     d |D             S )aQ  Split formatted content into chat-friendly delivery units.

    Weixin can render Markdown, but chat readability is better when top-level
    line breaks become separate messages. Keep fenced code blocks intact and
    attach indented continuation lines to the previous top-level line so nested
    list items do not get torn apart.
    r   r   	c                    g | ]}||S rE   rE   )r   units     r.   r  z4_split_delivery_units_for_weixin.<locals>.<listcomp>!  s    +++Td+D+++r0   )
r  r  r  r  rO   r  r   r  r(   r   )r  unitsr  r  r  r  is_continuations          r.    _split_delivery_units_for_weixinr    s    E'00 5 5??5++--a0668899 	LL((** 	 	H??$$D::<<  !LL7!3!3!9!9!;!;<<< G"7mmP0C0CK0P0PO t$$$ 9TYYw//5577888fGG 	5LL7++1133444++U++++r0   c                P   |                                  }|sdS t          |          dk    rdS |                     d          rdS |                    d          rdS t                              |          rdS t          j        d|          rdS t          j        d|          rdS dS )z?Return True when a line looks like a standalone chat utterance.F0   r  )>-*r  #r  z^\*\*[^*]+\*\*$z^\d+\.\sT)rO   rP   r   _TABLE_RULE_REr  rer  strippeds     r.   "_looks_like_chatty_line_for_weixinr  $  s    zz||H u
8}}ru{## u;<< uH%% u	x"H-- u	xX&& u4r0   c                    |                                  }|sdS t                              |          rdS t          |          dk    o|                    d          S )z5Return True when a short line behaves like a heading.FT   )rV   u   ：)rO   r  r  rP   rt   r  s     r.   #_looks_like_heading_line_for_weixinr  8  s[    zz||H u!! tx==BB8#4#4\#B#BBr0   r  c                    d |                                  D             }dt          |          cxk    rdk    sn dS t          |d                   rdS t          d |D                       S )z<Split only chat-like multiline blocks into separate bubbles.c                :    g | ]}|                                 |S rE   r  r  s     r.   r  z=_should_split_short_chat_block_for_weixin.<locals>.<listcomp>D  s%    AAAdDJJLLATAAAr0   r      Fr   c              3  4   K   | ]}t          |          V  d S ra   )r  r  s     r.   r  z<_should_split_short_chat_block_for_weixin.<locals>.<genexpr>I  s+      JJD1$77JJJJJJr0   )r  rP   r  r  )r  r  s     r.   )_should_split_short_chat_block_for_weixinr  B  s    AAe..00AAAEE

au*5844 uJJEJJJJJJr0   
max_lengthc                |   t          |           |k    r| gS g }d}t          |           D ]z}|s|n| d| }t          |          |k    r|}#|r|                    |           d}t          |          |k    r|}R|                    t	          j        ||                     {|r|                    |           |S )Nr*   z

)rP   r  r  extendr   truncate_message)r  r  packedr  r  	candidates         r.    _pack_markdown_blocks_for_weixinr  L  s    
7||z!!yFG'00 O O!(EEE.E.Ee.E.E	y>>Z''G 	MM'"""Gu::##G):5*MMNNNN gMr0   split_per_linec                   | sg S |rt          |           |k    rd| vr| gS g }t          |           D ]N}t          |          |k    r|                    |           +|                    t	          ||                     Od |D             p| gS t          |           |k    r+t          |           rd t          |           D             n| gS t	          | |          p| gS )u  Split content into sequential Weixin messages.

    *compact* (default): Keep everything in a single message whenever it fits
    within the platform limit, even when the author used explicit line breaks.
    Only fall back to block-aware packing when the payload exceeds
    ``max_length``.

    *per_line* (``split_per_line=True``): Legacy behavior — top-level line
    breaks become separate chat messages; oversized units still use
    block-aware packing.

    The active mode is controlled via ``config.yaml`` ->
    ``platforms.weixin.extra.split_multiline_messages`` (``true`` / ``false``)
    or the env var ``WEIXIN_SPLIT_MULTILINE_MESSAGES``.
    r  c                    g | ]}||S rE   rE   r   cs     r.   r  z3_split_text_for_weixin_delivery.<locals>.<listcomp>  s    '''aQ''''r0   c                    g | ]}||S rE   rE   )r   us     r.   r  z3_split_text_for_weixin_delivery.<locals>.<listcomp>  s    GGG1QGQGGGr0   )rP   r  r  r  r  r  )r  r  r  chunksr  s        r.   _split_text_for_weixin_deliveryr  c  s    $  	 
5w<<:%%$g*=*=94W== 	N 	ND4yyJ&&d###MM:4LLMMMM''6'''4G94
 7||z!! 9AAGG8AAGGGG	

 ,GZ@@MWIMr0   r   defaultc                   | |S t          | t                    r| S t          | t          t          f          rt          |           S t	          |                                                                           }|s|S |dv rdS |dv rdS |S )zBCoerce a config value to bool, tolerating strings like ``"true"``.N>   1onyestrueT>   0noofffalseF)r   r(   rK   r   rL   rO   r-   )rH   r  r  s      r.   _coerce_boolr    s    }% %#u&& E{{u::##%%D )))t***uNr0   r@  List[Dict[str, Any]]c                   | D ]}|                     d          t          k    rpt          |                     d          pi                      d          pd          }|                     d          pi }|                     d          pi }|                     d          }|t          t          t
          t          fv r;|                     d          pd}|rd| d	nd
}| |                                 c S |rg }|                     d          r(|                    t          |d                              t          |g          }	|	r|                    |	           |r/dd
                    |           d	|                                 c S |c S | D ]_}|                     d          t          k    r?t          |                     d          pi                      d          pd          }
|
r|
c S `dS )Nr;  r<  r  r*   ref_msgmessage_itemr  u   [引用媒体: z]
u   [引用媒体]
u	   [引用: r  
voice_item)r   rD  rL   
ITEM_IMAGE
ITEM_VIDEO	ITEM_FILE
ITEM_VOICErO   r  _extract_textr  )r@  rx  r  refref_itemref_typer  r   partsref_text
voice_texts              r.   r  r    s&     88Fy((--388@@FBGGD((9%%+Cww~..4"H||F++HJ
IzJJJ((.B9>V555555DV ($((..00000 L#%777## 4LLS\!2!2333((44 +LL*** LCuzz%'8'8CCTCCIIKKKKKKKK% )&  " "88Fz))dhh|44:??GGM2NNJ "!!!!2r0   media_typesr   c                V   t          d | D                       rt          j        S t          d | D                       rt          j        S t          d | D                       rt          j        S | rt          j        S |                    d          rt          j        S t          j        S )Nc              3  @   K   | ]}|                     d           V  dS )image/Nr   r   ms     r.   r  z+_message_type_from_media.<locals>.<genexpr>  .      
7
7a1<<!!
7
7
7
7
7
7r0   c              3  @   K   | ]}|                     d           V  dS )video/Nr  r  s     r.   r  z+_message_type_from_media.<locals>.<genexpr>  r  r0   c              3  @   K   | ]}|                     d           V  dS )audio/Nr  r  s     r.   r  z+_message_type_from_media.<locals>.<genexpr>  r  r0   r   )	anyr   PHOTOVIDEOVOICEDOCUMENTr   COMMANDTEXT)r  r  s     r.   _message_type_from_mediar    s    

7
7;
7
7
777 !  

7
7;
7
7
777 !  

7
7;
7
7
777 !   $##s #""r0   c                ,    t          |           | dz  S )Nz
.sync.jsonr   r   s     r.   _sync_buf_pathr    s    $$*'@'@'@@@r0   c                    t          | |          }|                                sdS 	 t          j        |                    d                                        dd          S # t          $ r Y dS w xY w)Nr*   r|   r   r0  )r  r   rY   r   r   r   r   r   s      r.   _load_sync_bufr    s}    +z22D;;== rz$..'.::;;??@QSUVVV   rrs   ;A$ $
A21A2c                J    t          | |          }t          |d|i           d S )Nr0  )r  r   )r   r   r.  r   s       r.   _save_sync_bufr    s-    +z22Dd.9:::::r0   3i  )bot_typerc  r  Optional[Dict[str, str]]c               d  K   t           st          d          t          j        dt	                                4 d{V }	 t          |t          t           d| t                     d{V }nD# t          $ r7}t                              d|           Y d}~ddd          d{V  dS d}~ww xY wt          |                    d          pd	          }t          |                    d
          pd	          }|s.t                              d           	 ddd          d{V  dS |r|n|}t          d           |rt          |           	 ddl}	|	                                }
|
                    |           |
                    d           |
                    d           n*# t          $ r}t          d| d           Y d}~nd}~ww xY wt)          j                    |z   }t          }d}t)          j                    |k     r	 t          ||t*           d| t                     d{V }nv# t,          j        $ r t-          j        d           d{V  Y mt          $ r?}t                              d|           t-          j        d           d{V  Y d}~d}~ww xY wt          |                    d          pd          }|dk    rt          dd	d           n|dk    rt          d           n|dk    r-t          |                    d          pd	          }|rd| }n|dk    r|dz  }|dk    r#t          d            	 ddd          d{V  dS t          d!| d"           	 t          |t          t           d| t                     d{V }t          |                    d          pd	          }t          |                    d
          pd	          }|r|n|}|rt          |           	 ddl}|                                }
|
                    |           |
                    d           |
                    d           n# t          $ r Y nw xY wnQ# t          $ r7}t                              d#|           Y d}~ddd          d{V  dS d}~ww xY w|d$k    rt          |                    d%          pd	          }t          |                    d&          pd	          }t          |                    d'          pt                    }t          |                    d(          pd	          }|r|s.t                              d)           	 ddd          d{V  dS t5          | ||||*           t          d+|            ||||d*cddd          d{V  S t-          j        d           d{V  t)          j                    |k     t          d,           	 ddd          d{V  dS # 1 d{V swxY w Y   dS )-z
    Run the interactive iLink QR login flow.

    Returns a credential dict on success, or ``None`` if login fails or times out.
    z'aiohttp is required for Weixin QR loginT	trust_env	connectorNz
?bot_type=)r   r  r  z#weixin: failed to fetch QR code: %sqrcoder*   qrcode_img_contentz"weixin: QR response missing qrcodeu(   
请使用微信扫描以下二维码：r   )fit)invertu    （终端二维码渲染失败: u-   ，请直接打开上面的二维码链接）z?qrcode=r1   zweixin: QR poll error: %sr(  wait.)endflushscanedu%   
已扫码，请在微信里确认...scaned_but_redirectredirect_hosthttps://expiredr   u1   
二维码多次过期，请重新执行登录。u'   
二维码已过期，正在刷新... (z/3)zweixin: QR refresh failed: %s	confirmedilink_bot_id	bot_tokenbaseurlrJ  z:weixin: QR confirmed but credential payload was incomplete)r   r   r   r   u!   
微信连接成功，account_id=u   
微信登录超时。)r;   r'  r>   ClientSessionrA   r-  ILINK_BASE_URLEP_GET_BOT_QRQR_TIMEOUT_MSr   r   errorrL   r   printr"  QRCodeadd_datamakeprint_asciir   EP_GET_QR_STATUSr4  r5  sleepr   r   )r   r  rc  r  qr_respr   qrcode_value
qrcode_urlqr_scan_datar"  qr_qr_excdeadlinecurrent_base_urlrefresh_countstatus_respr(  r,  _qrcoder   r   r   r   s                          r.   qr_loginrJ    s	       FDEEE$t?R?T?TUUU v v v v v v vY`		$')??X??(	        GG  	 	 	LL>DDD444v v v v v v v v v v v v v v	 7;;x006B77%9::@bAA
 	LL=>>>!v v v v v v v v v v v v v v( &0Azz\9::: 	*	mMMMBKK%%%GGGNN$N'''' 	m 	m 	mkWkkkllllllll	m 9;;0)ikkH$$$,- 0HH,HH,	% % %       '   mA&&&&&&&&&   :C@@@mA&&&&&&&&&
 22<f==Fcr.....8##>????000 #KOOO$D$D$J K K  B'A-'A'A$9$$" 1$$NOOOIv v v v v v v v v v v v v vJ SSSSTTT $,!/$1!G!GX!G!G#0	% % %      G $'w{{8'<'<'B#C#CL!$W[[1E%F%F%L"!M!MJ1;#M::L! *j)))0000$^^--L111D)))d3333$          LL!@#FFF444yv v v v v v v v v v v v v vt  ;&& !@!@!FBGG
KOOK88>B??{y99K^LLkooo>>D"EE!    LL!]^^^Iv v v v v v v v v v v v v vJ $)%#    G:GGHHH"," (&	 [v v v v v v v v v v v v v vf -"""""""""Y ikkH$$\ 	'(((mv v v v v v v v v v v v v v v v v v v v v v v v v v v v v vs	  X-A10X1
B2;B-X-B22A(X-&XAF.-X.
G8GXG:X(H98X9)J,"X$	J,-5J'"X'J,,B-X,X BQ9AQ'&Q9'
Q41Q93Q44Q97X9
R:R5X5R::B>X,X
AX
X),X)c                  R    e Zd ZdZdZdZdG fdZedHd            ZdIdZ	dJdZ
dJdZdKdZdKdZdLdZdMdZdNdZdNdZdOd ZdNd!ZdPd$ZdQd&ZdRd*Z	 	 dSdTd0ZdUdVd1ZdWd2Z	 	 dSdXd5Z	 	 	 dYdZd7Z	 	 	 	 d[d\d:Z	 	 	 dYd]d<Z	 	 	 dYd^d>Zd_d@Z	 d`dadCZ d`dbdDZ!dcdEZ"dddFZ# xZ$S )eWeixinAdapterz3Native Hermes adapter for Weixin personal accounts.i  Fconfigr   c                ,
   t                                          |t          j                   |j        pi }t          t                                }|| _        t          |          | _	        t                      | _        d | _        d | _        d | _        t          t                     | _        t          |                    d          pt'          j        dd                                                    | _        t          |j        p)|                    d          pt'          j        dd                                                    | _        t          |                    d          pt'          j        dt2                                                                                  d	          | _        t          |                    d
          pt'          j        dt8                                                                                  d	          | _        t=          |                    d          pt'          j        dd                    | _        tA          |                    d          pt'          j        dd                    | _!        t=          |                    d          pt'          j        dd                    | _"        t          |                    d          pt'          j        dd                                                    #                                | _$        t          |                    d          pt'          j        dd                                                    #                                | _%        |                    d          }|t'          j        dd          }|                    d          }|t'          j        dd          }| &                    |          | _'        | &                    |          | _(        tS          |                    d          pt'          j        d           d!"          | _*        | j        r| j        stW          || j                  }|rt          |                    d          pd                                          | _        t          |                    d          p| j                                                                      d	          | _        d S d S d S d S )#N)r   r   WEIXIN_ACCOUNT_IDr*   r   WEIXIN_TOKENr   WEIXIN_BASE_URLr   r   WEIXIN_CDN_BASE_URLsend_chunk_delay_secondsWEIXIN_SEND_CHUNK_DELAY_SECONDSz1.5send_chunk_retriesWEIXIN_SEND_CHUNK_RETRIES4send_chunk_retry_delay_seconds%WEIXIN_SEND_CHUNK_RETRY_DELAY_SECONDSz1.0	dm_policyWEIXIN_DM_POLICYopengroup_policyWEIXIN_GROUP_POLICYdisabled
allow_fromWEIXIN_ALLOWED_USERSgroup_allow_fromWEIXIN_GROUP_ALLOWED_USERSsplit_multiline_messagesWEIXIN_SPLIT_MULTILINE_MESSAGESF)r  ),superr   r   WEIXINextrarL   r   _hermes_homer   _token_storer   _typing_cache_poll_session_send_session
_poll_taskr   MESSAGE_DEDUP_TTL_SECONDS_dedupr   osgetenvrO   _account_idr   _tokenr4  r   	_base_urlrR  _cdn_base_urlr   _send_chunk_delay_secondsrK   _send_chunk_retries_send_chunk_retry_delay_secondsr-   
_dm_policy_group_policy_coerce_list_allow_from_group_allow_fromr  _split_multiline_messagesr   )r   rM  rh  r   r`  rb  	persisted	__class__s          r.   r   zWeixinAdapter.__init__o  sV   111"/++,,'-k::.00>B>B26)6OPPPuyy66\")DWY[:\:\]]ccee&,]%))G*<*<]	.Z\@]@]^^ddffUYYz22bbi@QSa6b6bcciikkrrsvww IIn%%^3HJ])^)^
 

%''&&++ 	 */II011hRY?`bg5h5h*
 *
& $'II*++Zry9TVY/Z/Z$
 $
  05II677 Iy@%HH0
 0
, eii44]	BTV\8]8]^^ddffllnn >!:!:!jbiH]_i>j>jkkqqssyy{{YY|,,
#92>>J 99%788#!y)ErJJ,,Z88!%!2!23C!D!D)5II011 <y:;;*
 *
 *
&  	fDK 	f+K9IJJI f!)--"8"8">B??EEGG!$Y]]:%>%>%P$.!Q!Q!W!W!Y!Y!`!`ad!e!e		f 	f 	f 	ff fr0   rH   r   r'   r  c                X   | g S t          | t                    rd |                     d          D             S t          | t          t          t
          f          rd | D             S t          |                                           r"t          |                                           gng S )Nc                ^    g | ]*}|                                 |                                 +S rE   r  r   rx  s     r.   r  z.WeixinAdapter._coerce_list.<locals>.<listcomp>  s-    NNNTNDJJLLNNNr0   rU   c                    g | ]D}t          |                                          #t          |                                          ES rE   )rL   rO   r  s     r.   r  z.WeixinAdapter._coerce_list.<locals>.<listcomp>  s=    MMM$3t99??;L;LMCIIOO%%MMMr0   )r   rL   r  listtupler   rO   r   s    r.   r|  zWeixinAdapter._coerce_list  s    =IeS!! 	ONNU[[-=-=NNNNedE3/00 	NMM%MMMM'*5zz'7'7'9'9AE

  ""##rAr0   r(   c                  K   t                      s=d}|                     d|d           t                              d| j        |           dS | j        s=d}|                     d|d           t                              d| j        |           dS | j        s=d}|                     d	|d           t                              d| j        |           dS 	 |                     d
| j        d          sdS n8# t          $ r+}t          	                    d| j        |           Y d }~nd }~ww xY wt          j        dt                                | _        t          j        dt                                | _        | j                            | j                   t#          j        |                                 d          | _        |                                  | t,          | j        <   t                              d| j        t1          | j                  | j                   | j        dk    r&t                              d| j        | j                   dS )Nz<Weixin startup failed: aiohttp and cryptography are requiredweixin_missing_dependencyF)	retryablez[%s] %sz/Weixin startup failed: WEIXIN_TOKEN is requiredweixin_missing_tokenz4Weixin startup failed: WEIXIN_ACCOUNT_ID is requiredweixin_missing_accountzweixin-bot-tokenzWeixin bot tokenz+[%s] Token lock unavailable (non-fatal): %sTr  zweixin-poll)namez![%s] Connected account=%s base=%sr_  a  [%s] WEIXIN_GROUP_POLICY=%s is set, but QR-login connects an iLink bot identity (e.g. ...@im.bot) which typically cannot be invited into ordinary WeChat groups. iLink usually does not deliver ordinary-group events for these accounts, so group messages may never reach Hermes regardless of this policy. If group delivery doesn't work, the limitation is on the iLink side, not in Hermes.)rF   _set_fatal_errorr   r   r  rt  rs  _acquire_platform_lockr   debugr>   r3  rA   rl  rm  rj  r   r4  create_task
_poll_looprn  _mark_connectedr4   r   rR   ru  r{  r   r
  r   s      r.   connectzWeixinAdapter.connect  s^     (** 	TG!!"=wRW!XXXNN9di9995{ 	GG!!"8'U!SSSNN9di9995 	LG!!":Gu!UUUNN9di9995	X../A4;Pbcc u 	X 	X 	XLLF	SVWWWWWWWW	X %2TM`MbMbccc$2TM`MbMbccc!!$"2333!-doo.?.?mTTT&*t{#7HTM]D^D^`d`nooo++NN! 	"	 	 	 ts   C6 6
D+ !D&&D+r   c                  K   t                               | j        d            d| _        | j        rV| j                                        s=| j                                         	 | j         d {V  n# t          j        $ r Y nw xY wd | _        | j	        r+| j	        j
        s| j	                                         d {V  d | _	        | j        r+| j        j
        s| j                                         d {V  d | _        |                                  |                                  t                              d| j                   d S )NFz[%s] Disconnected)r4   r   rt  _runningrn  donecancelr4  CancelledErrorrl  closedcloserm  _release_platform_lock_mark_disconnectedr   r   r  )r   s    r.   
disconnectzWeixinAdapter.disconnect  ss     4;---? 	4?#7#7#9#9 	O""$$$o%%%%%%%%)    	-d&8&? 	-$**,,,,,,,,,! 	-d&8&? 	-$**,,,,,,,,,!##%%%!!!'33333s   $A2 2BBc           
       K   | j         J t          | j        | j                  }t          }d}| j        r	 t          | j         | j        | j        ||           d {V }|	                    d          }t          |t                    r|dk    r|}|	                    dd          }|	                    dd          }|dvs|dvr|t          k    s/|t          k    s$t          |||	                    d                    r>t                              d| j                   t#          j        d	           d {V  d}|d
z  }t                              d| j        |||	                    dd          |t(                     t#          j        |t(          k    rt*          nt,                     d {V  |t(          k    rd}d}t/          |	                    d          pd          }|r|}t1          | j        | j        |           |	                    d          pg D ])}	t#          j        |                     |	                     *n# t"          j        $ r Y d S t8          $ ru}
|d
z  }t                              d| j        |t(          |
           t#          j        |t(          k    rt*          nt,                     d {V  |t(          k    rd}Y d }
~
nd }
~
ww xY w| j        d S d S )Nr   )r   r   r.  r  longpolling_timeout_msr"   r$   )r   Nr%   z,[%s] Session expired; pausing for 10 minutesiX  r1   z:[%s] getUpdates failed ret=%s errcode=%s errmsg=%s (%d/%d)r*   r0  r2  z[%s] poll error (%d/%d): %s)rl  r  ri  rs  LONG_POLL_TIMEOUT_MSr  r6  ru  rt  r   r   rK   SESSION_EXPIRED_ERRCODEr/   r   r7  r  r4  r>  r   MAX_CONSECUTIVE_FAILURESBACKOFF_DELAY_SECONDSRETRY_DELAY_SECONDSrL   r  r  _process_message_safer  r   )r   r.  r  consecutive_failuresr*  suggested_timeoutr"   r$   new_sync_bufr
  r   s              r.   r  zWeixinAdapter._poll_loop  s     !---!$"3T5EFF)
 m 4	-3-!-&!^+%)" " "       %-LL1I$J$J!/55 3:Ka:O:O!2Jll5!,,",,y!44i''7)+C+C666'E\:\:\4S'8<<PXCYCYZZ ;]%SUYU^___%mC000000000/0, (A-(NNT	 Xr22,0   "-AUYqAqAq(=(=  xK  L  L  L  L  L  L  L  L  L+/GGG/0,'($"8<<0A#B#B#HbII R+H"4#4d6FQQQ'||F339r M MG'(B(B7(K(KLLLLM)    - - -$)$:DIG[]uwz{{{m=QUm=m=m$9$9  tG  H  H  H  H  H  H  H  H  H'+CCC+,(-_ m 4	- 4	- 4	- 4	- 4	-s-   DI	 ?BI	 BI	 	K	K$A+KKr
  r3   c           
        K   	 |                      |           d {V  d S # t          $ rO}t                              d| j        t          |                    d                    |d           Y d }~d S d }~ww xY w)Nz([%s] unhandled inbound error from=%s: %sr  T)exc_info)_process_messager   r   r7  r  rR   r   r  s      r.   r  z#WeixinAdapter._process_message_safe&  s      	K''00000000000 	K 	K 	KLLCTYPXY`YdYdesYtYtPuPuwz  FJL  K  K  K  K  K  K  K  K  K	Ks   ! 
A:AA55A:c                  K   | j         J t          |                    d          pd                                          }|sd S || j        k    rd S t          |                    d          pd                                          }|r| j                            |          rd S t          || j                  \  }}|dk    r$| j        dk    rd S | j        dk    r|| j	        vrd S n| 
                    |          sd S t          |                    d          pd                                          }|r!| j                            | j        ||           t          j        |                     ||pd                      |                    d          pg }t!          |          }g }	g }
|D ]}}|                     ||	|
           d {V  |                    d	          pi }|                    d
          }t%          |t&                    r|                     ||	|
           d {V  ~|s|	sd S |                     ||||          }t+          |t-          |
|          |||pd |	|
t/          j                              }t2                              d| j        t9          |          |j        t=          |	                     |                     |           d {V  d S )Nr  r*   
message_idr  r_  	allowlistr8  r@  r  r  )chat_id	chat_typer   	user_name)r  r>  sourceraw_messager  
media_urlsr  	timestampz%[%s] inbound from=%s type=%s media=%d) rl  rL   r   rO   rs  rp  is_duplicater  r{  r~  _is_dm_allowedrj  r   r4  r  _maybe_fetch_typing_ticketr  _collect_mediar   dictbuild_sourcer   r  r   nowr   r   r  rR   r  rP   handle_message)r   r
  	sender_idr  r  effective_chat_idr8  r@  r  media_pathsr  rx  ref_messager  r  events                   r.   r  zWeixinAdapter._process_message,  sM     !---N339r::@@BB	 	F(((F\228b99??AA
 	$+22:>> 	F'7AQ'R'R$	$!Z//![005FdNd5d5d$$Y// 	FGKK88>B??EEGG 	N!!$"2I}MMMD;;I}G\X\]]^^^KK,,2	Y''!#!# 	N 	ND%%dKEEEEEEEEE((9--3K"~66H(D)) N))(KMMMMMMMMM 	K 	F""%	 # 
 
 1+tDD!)T"#lnn	
 	
 	
 	;TYQZH[H[]c]mors~oo  	A  	A  	A!!%(((((((((((r0   r  rL   c                H    | j         dk    rdS | j         dk    r	|| j        v S dS )Nr_  Fr  T)rz  r}  )r   r  s     r.   r  zWeixinAdapter._is_dm_allowedh  s4    ?j((5?k)) 000tr0   rx  r  r  c                  K   |                     d          }|t          k    rK|                     |           d {V }|r,|                    |           |                    d           d S d S |t          k    rK|                     |           d {V }|r,|                    |           |                    d           d S d S |t          k    rN|                     |           d {V \  }}|r,|                    |           |                    |           d S d S |t          k    rI| 	                    |           d {V }|r.|                    |           |                    d           d S d S d S )Nr;  z
image/jpegz	video/mp4z
audio/silk)
r   r  _download_imager  r  _download_videor  _download_filer  _download_voice)r   rx  r  r  	item_typer   mime
voice_paths           r.   r  zWeixinAdapter._collect_mediao  s     HHV$$	
""--d33333333D 1""4(((""<000001 1 *$$--d33333333D 0""4((("";/////0 0 )###22488888888JD$ )""4(((""4((((() ) *$$#33D99999999J 1"":...""<00000	 %$1 1r0   rI   c                  K   t          |d          }	 t          | j        | j        |                    d          |                    d          pi                     d          rtt          j        t                              t          |                    d          pi                     d                                        
                    d          p|                    d          |                    d          d           d {V }t          |d	          S # t          $ r,}t                              d
| j        |           Y d }~d S d }~ww xY w)N
image_itemencrypt_query_paramrX  r}   aes_keyr|  g      >@r   r   r   r|  rc  .jpgz[%s] image download failed: %s)r{  r~  rl  rv  r   r   r   r^   r  rL   r   r   r   r   r   r  r   rx  rz  r]   r   s        r.   r  zWeixinAdapter._download_image  s_      |44	4"!/&+ii0E&F&F!XXl339r>>xHH w$U]]38N8N8TRT7Y7YZb7c7c3d3d%e%effmmnuvv(99Y'':.. $	 	 	 	 	 	 	 	 	D *$777 	 	 	NN;TYLLL44444	s   DD   
E*!EEc           	     v  K   t          |d          }	 t          | j        | j        |                    d          |                    d          |                    d          d           d {V }t          |d          S # t          $ r,}t                              d| j	        |           Y d }~d S d }~ww xY w)	N
video_itemr  r  r|  g      ^@r  z	video.mp4z[%s] video download failed: %s)
r{  r~  rl  rv  r   r   r   r   r   r  r  s        r.   r  zWeixinAdapter._download_video  s       |44	4"!/&+ii0E&F&F!IIi00:.. %        D -T;??? 	 	 	NN;TYLLL44444	s   A-B 
B8!B33B8Tuple[Optional[str], str]c           	     "  K   |                     d          pi }|                     d          pi }t          |                     d          pd          }t          |          }	 t          | j        | j        |                     d          |                     d          |                     d          d	           d {V }t          ||          |fS # t          $ r/}t          	                    d
| j
        |           d |fcY d }~S d }~ww xY w)N	file_itemrz  	file_namezdocument.binr  r  r|  rb  r  z[%s] file download failed: %s)r   rL   r  r~  rl  rv  r   r   r   r   r  )r   rx  r  rz  r  r  r]   r   s           r.   r  zWeixinAdapter._download_file  s9     HH[))/R	g&&,"y}}[11C^DD"8,,	4"!/&+ii0E&F&F!IIi00:.. $        D -T8<<dBB 	 	 	NN:DIsKKK:	s   %A/C 
D$D	D	Dc           	       K   |                     d          pi }|                     d          pi }|                     d          rd S 	 t          | j        | j        |                     d          |                     d          |                     d          d           d {V }t	          |d	          S # t
          $ r,}t                              d
| j        |           Y d }~d S d }~ww xY w)Nr  rz  r  r  r  r|  rb  r  .silkz[%s] voice download failed: %s)	r   r~  rl  rv  r   r   r   r   r  )r   rx  r  rz  r]   r   s         r.   r  zWeixinAdapter._download_voice  s     XXl++1r
w''-2>>&!! 	4	4"!/&+ii0E&F&F!IIi00:.. $        D *$888 	 	 	NN;TYLLL44444	s   	A-B7 7
C-!C((C-r   r8  c                  K   | j         r| j        sd S | j                            |          rd S 	 t	          | j         | j        | j        ||           d {V }t          |                    d          pd          }|r| j                            ||           d S d S # t          $ r:}t          
                    d| j        t          |          |           Y d }~d S d }~ww xY w)N)r   r   r   r8  rH  r*   z [%s] getConfig failed for %s: %s)rl  rt  rk  r   rP  ru  rL   r   r   r   r  r  rR   )r   r   r8  r*  rH  r   s         r.   r  z(WeixinAdapter._maybe_fetch_typing_ticket  s6     ! 	 	F!!'** 	F	`("k+        H  _ = = CDDM ?"&&w>>>>>? ? 	` 	` 	`LL;TYQXHYHY[^_________	`s   A*B 
C"(/CC"r  c                8    t          || j        | j                  S ra   )r  MAX_MESSAGE_LENGTHr  r   r  s     r.   _split_textzWeixinAdapter._split_text  s!    .T,d.L
 
 	
r0   r  chunkr9  c                 K   d}d}t          | j        dz             D ]}	 t          | j        | j        | j        ||||           d{V }|rt          |t                    r|                    d          }	|                    d          }
|	|	dvs|
|
dvr|	t          k    p.|
t          k    p#t          |	|
|                    d                    }|rv|st|rrd	}d}| j        j                            | j                            | j        |          d           t                               d
| j        t'          |                     2|	t(          k    p
|
t(          k    }|r|                    d          p|                    d          pd}t+          d|	 d|
 d|           }|| j        k    r n1| j        dz  }t                               d| j        t'          |          |           t/          j        |           d{V  |                    d          p|                    d          pd}t+          d|	 d|
 d|            dS # t2          $ r}|}|| j        k    rY d}~ nx| j        |dz   z  }t                               d| j        t'          |          |dz   | j        dz   ||           |dk    rt/          j        |           d{V  Y d}~d}~ww xY w|J |)uh  Send a single text chunk with per-chunk retry and backoff.

        On session-expired errors (errcode -14), automatically retries
        *without* ``context_token`` — iLink accepts tokenless sends as a
        degraded fallback, which keeps cron-initiated push messages working
        even when no user message has refreshed the session recently.
        NFr1   r   r   r7  r  r8  r9  r"   r$   )r   r%   Tz;[%s] session expired for %s; retrying without context_tokenrA  zrate limitedz$iLink sendmessage rate limited: ret=z	 errcode=z errmsg=r   z8[%s] rate limited for %s; backing off %.1fs before retryr+   ziLink sendmessage error: ret=zA[%s] send chunk failed to=%s attempt=%d/%d, retrying in %.2fs: %sr   )rangerx  rG  rm  ru  rt  r   r  r   r  r/   rj  r   r   r   rs  r   r   r  rR   r,   r'  ry  r4  r>  r   )r   r  r  r8  r9  
last_errorretried_without_tokenattemptrespr"   r$   is_session_expiredis_rate_limitedr%   r&  r   s                   r.   _send_text_chunkzWeixinAdapter._send_text_chunk  s      +/
 %T59:: K	. K	.GJ.*&!^+"/'          .JtT22 .((5//C"hhy11GCtOOATY`hlYlYl#:: W&*AAW4S'488HCUCUVV + . 
%6K 
%P] 
%481,0M -488 $ 1 6 6t7G Q QSW   #NN ] $	8G+<+<   %  #55 =&*<< ( + %%)XXh%7%7%\488E??%\nF *6 ns n nU\ n nfl n n* *J  '$*BBB %#'#G!#KD"NN Z $	8G+<+<d   #*-"5"55555555$!%(!3!3!Ytxx!Y/*cCcc'cc[acc    . . . 
d666EEEEE;w{KWIW%%aK,q0   !88!----------.  %%%s4   D,IA'I:AIAI
K( K#3A*K##K(Nreply_tometadatar   r   c                   K    j         r j        st          dd          S  j                             j                  }d }                     |          \  }}                     |          \  }	}
                     |
          \  }}h dh dh ddd fd}	 |D ]Q\  }}	  |||           d {V  # t          $ r,}t                              d j        ||           Y d }~Jd }~ww xY w|D ]O}	  ||d           d {V  # t          $ r,}t                              d j        ||           Y d }~Hd }~ww xY wd                                           |                    D             }t          |          D ]\  }}dt!          j                    j         }                     |||           d {V  |}|t)          |          dz
  k     r* j        dk    rt-          j         j                   d {V  t          d|          S # t          $ rW}t                              d j        t3                    |           t          dt5          |                    cY d }~S d }~ww xY w)NFNot connectedsuccessr7  >   .m4a.mp3.ogg.wav.flac.opus>   .3gp.avi.mkv.mov.mp4.webm>   .gifr  .png.jpeg.webpr   rL   is_voicer(   r'   r   c                p  K   t          |           j                                        }|s|v r                     |            d {V  d S |v r                     |            d {V  d S |v r                     |            d {V  d S                     |            d {V  d S )N)r  
audio_pathr  )r  
video_pathr  )r  
image_pathr  )r  	file_pathr  )r   suffixr-   
send_voice
send_videosend_image_filesend_document)	r   r  ext_AUDIO_EXTS_IMAGE_EXTS_VIDEO_EXTSr  r  r   s	      r.   _deliver_mediaz*WeixinAdapter.send.<locals>._deliver_media[  s     t**#))++C ]3+--oog$QYoZZZZZZZZZZZ##oog$QYoZZZZZZZZZZZ##**7tV^*___________((DS[(\\\\\\\\\\\r0   z%[%s] media delivery failed for %s: %s)r  z*[%s] local file delivery failed for %s: %sc                >    g | ]}||                                 |S rE   r  r  s     r.   r  z&WeixinAdapter.send.<locals>.<listcomp>v  s0    iiiAYZi_`_f_f_h_hiaiiir0   hermes-weixin-)r  r  r8  r9  r1   r   Tr  r  z[%s] send failed to=%s: %sF)r   rL   r  r(   r'   r   )rm  rt  r   rj  r   rs  extract_mediaextract_imagesextract_local_filesr   r   r   r  r  format_messager  uuiduuid4hexr  rP   rw  r4  r>  r7  rR   rL   )r   r  r  r  r  r8  last_message_idmedia_filescleaned_content_image_cleanedlocal_filesfinal_contentr  
media_pathr  r   r  r  r  r  r9  r  r  r  s   ``  `                 @@@r.   sendzWeixinAdapter.sendF  s      ! 	D 	De?CCCC)--d.>HH)- (,'9'9''B'B$_..??=%)%=%=m%L%L"]HHHGGG@@@		] 		] 		] 		] 		] 		] 		] 		] 		] 		] 		] 		]	=(3 h h$
Hh(.X>>>>>>>>>>  h h hNN#JDIWacfggggggggh ) l l	l(.UCCCCCCCCCCC  l l lNN#OQUQZ\egjkkkkkkkkl ji!1!1$2E2Em2T2T!U!UiiiF'// 
H 
H
U?TZ\\-=??	++#"/'	 ,          #,Vq((T-Ka-O-O!-(FGGGGGGGGGdGGGG 	= 	= 	=LL5ty(7BSBSUXYYYe3s88<<<<<<<<<	=st   +H% 3CH% 
C<"C72H% 7C<<H% DH% 
E""E	H% 	ECH% %
J/AJ;JJc                T  K   | j         r| j        sd S | j                            |          }|sd S 	 t	          | j         | j        | j        ||t                     d {V  d S # t          $ r:}t          	                    d| j
        t          |          |           Y d }~d S d }~ww xY w)Nr   r   r  rH  r(  z#[%s] typing start failed for %s: %s)rm  rt  rk  r   rM  ru  TYPING_STARTr   r   r  r  rR   )r   r  r  rH  r   s        r.   send_typingzWeixinAdapter.send_typing  s      ! 	 	F*..w77 	F
	c"k"+#             	c 	c 	cLL>	8T[K\K\^abbbbbbbbb	c   /A# #
B'-/B""B'c                T  K   | j         r| j        sd S | j                            |          }|sd S 	 t	          | j         | j        | j        ||t                     d {V  d S # t          $ r:}t          	                    d| j
        t          |          |           Y d }~d S d }~ww xY w)Nr(  z"[%s] typing stop failed for %s: %s)rm  rt  rk  r   rM  ru  TYPING_STOPr   r   r  r  rR   )r   r  rH  r   s       r.   stop_typingzWeixinAdapter.stop_typing  s      ! 	 	F*..w77 	F
	b"k"+"             	b 	b 	bLL=ty(SZJ[J[]`aaaaaaaaa	br+  	image_urlcaptionc                  K   |                     d          r|                     |           d {V }d}nV|                    dd          }t          j                            |          st          j                            |          }d}	 |                     ||||           d {V 	 |rG|rFt          j                            |          r(	 t          j	        |           S # t          $ r Y S w xY wS S S # |rG|rFt          j                            |          r(	 t          j	        |           w # t          $ r Y w w xY ww w w xY w)N)zhttp://r-  Tzfile://r*   F)r0  r  )r   _download_remote_mediareplacerq  r   isabsabspathr  r   unlinkr   )r   r  r/  r0  r  r  r  cleanups           r.   
send_imagezWeixinAdapter.send_image  s       788 	"99)DDDDDDDDIGG!)))R88I7==++ 7GOOI66	G	++GYZb+ccccccccc 9 	)B)B Ii((((   D  w 9 	)B)B Ii((((   D  sB   C8 C%%
C21C28$ED21E2
D?<E>D??Er  c                H   K   ~~|                      ||||           d {V S )N)r  r  r0  r  )r  )r   r  r  r0  r  r  kwargss          r.   r  zWeixinAdapter.send_image_file  sT       f'' 	 ( 
 
 
 
 
 
 
 
 	
r0   r  r  c                v  K   ~~~~| j         r| j        st          dd          S 	 |                     |||pd           d {V }t          d|          S # t          $ rW}	t
                              d| j        t          |          |	           t          dt          |	                    cY d }	~	S d }	~	ww xY w)NFr  r  r*   Tr  z#[%s] send_document failed to=%s: %s
rm  rt  r   
_send_filer   r   r7  r  rR   rL   )
r   r  r  r0  r  r  r  r:  r  r   s
             r.   r  zWeixinAdapter.send_document  s       x6! 	D 	De?CCCC	=#w	7=bQQQQQQQQJdzBBBB 	= 	= 	=LL>	8T[K\K\^abbbe3s88<<<<<<<<<	=   /A 
B8!AB3-B83B8r  c                n  K   | j         r| j        st          dd          S 	 |                     |||pd           d {V }t          d|          S # t          $ rW}t
                              d| j        t          |          |           t          dt          |                    cY d }~S d }~ww xY w)NFr  r  r*   Tr  z [%s] send_video failed to=%s: %sr<  )r   r  r  r0  r  r  r  r   s           r.   r  zWeixinAdapter.send_video  s       ! 	D 	De?CCCC	=#w
GMrRRRRRRRRJdzBBBB 	= 	= 	=LL;TYQXHYHY[^___e3s88<<<<<<<<<	=s   /A 
B4AB/)B4/B4r  c                v  K   | j         r| j        st          dd          S |pd}	 |                     |||d           d {V }t          d|          S # t          $ rW}t
                              d| j        t          |          |           t          dt          |                    cY d }~S d }~ww xY w)	NFr  r  z[voice message as attachment]Tforce_file_attachmentr  z [%s] send_voice failed to=%s: %sr<  )	r   r  r  r0  r  r  fallback_captionr  r   s	            r.   r
  zWeixinAdapter.send_voice  s      ! 	D 	De?CCCC
 #E&E
	=# &*	  /          J dzBBBB 	= 	= 	=LL;TYQXHYHY[^___e3s88<<<<<<<<<	=r>  r)  c                d  K   ddl m}  ||          st          d|           | j        J | j                            |t          j        d                    4 d {V }|                                 |                                 d {V }t          |
                    dd          d                   j        pd	}d d d           d {V  n# 1 d {V swxY w Y   t          j        d
|          5 }|                    |           |j        cd d d            S # 1 swxY w Y   d S )Nr   )is_safe_urlz&Blocked unsafe URL (SSRF protection): r    r  re  rN   r1   z.binF)deleter	  )tools.url_safetyrE  r  rm  r   r>   r$  rf  r_  r   r  r	  tempfileNamedTemporaryFilewriter  )r   r)  rE  r*  r]   r	  handles          r.   r2  z$WeixinAdapter._download_remote_media  s4     000000{3 	MKcKKLLL!---%))#w7LSU7V7V7V)WW 	A 	A 	A 	A 	A 	A 	A[c%%'''!((((((D#))C++A.//6@&F	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A 	A (fEEE 	LL;	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	 	s%   $AC
C"C<D%%D),D)r   rB  c                d  K   | j         | j        J t          |                                          }|                     ||          \  }}t          j        d          }t          j        d          }	t          |          }
t          j
        |                                          }t          | j         | j        | j        ||||
|t          |
          |	                                
  
         d {V }t!          |                    d          pd          }t!          |                    d          pd          }t%          ||	          }|r|}n+|rt'          | j        ||          }nt+          d|           t-          | j         ||           d {V }| j                            | j        |          }t3          j        |	                                                    d	                                        d	          }||t          |          |
t          |          j        |d
}|t<          k    r$|                    d          rd|d<   d|d<   d|d<    |di |}d }|rYdtA          j!                    j         }tE          | j         | j        | j        || #                    |          ||           d {V  dtA          j!                    j         }tI          | j         | j        tJ          dd||tL          tN          |gd|rd|ini i| j        tP                     d {V  |S )NrA  r\   )	r   r   r  rQ  r   rR  rS  rT  rU  r   r*   upload_full_urlz@getUploadUrl returned neither upload_param nor upload_full_url: )rp   r[  r}   )r  aes_key_for_apiciphertext_sizeplaintext_sizer  rS  r  r  encode_typei]  sample_ratebits_per_sampler  r  rA  r=  r8  r1  rE   ))rm  rt  r   
read_bytes_outbound_media_builderr   	token_hexr   rP   hashlibmd5	hexdigestrZ  ru  rz   r  rL   r   ro   r   rv  r'  ra  rj  rs  r   r   r   r   r  MEDIA_VOICErt   r  r  rG  r  r+  rE  rB  rC  rF  )r   r  r   r0  rB  rd   rQ  item_builderr   r  rR  rS  upload_responser   rM  rp   r[  r   r8  rN  item_kwargs
media_itemr  s                          r.   r=  zWeixinAdapter._send_file$  s      !-$+2I2IIJJ))++	#'#?#?\q#?#r#r 
L#B''%b))i..[++5577
 /^+!!%g..{{}}!
 !
 !
 
 
 
 
 
 
 ?..~>>D"EEo112CDDJKK(G<<

  	u(JJ 	u();\7SSJJsbqssttt&8!!'
 '
 '
 !
 !
 !
 !
 !
 !

 )--d.>HH !*7;;==+?+?+H+HIIPPQXYY#8.":%T

$
 
 $$w)?)?$)*K&).K&-/K)*!\00K00
 
	Atz||/?AAO"k((11+)          >4:<<+;==^$$&")!0$0%5",  <IP77b
 +%!
 
 
 	
 	
 	
 	
 	
 	
 	
$ r0   c                J   t          j        |          d         pd}|                    d          r
t          d fS |                    d          r
t          d fS |                    d          r|s
t          d fS |                    d	          r
t          d
 fS t          d fS )Nr   r^  r  c                 H    t           | d         | d         dd| d         ddS )Nr  rN  r1   r  r  encrypt_typerO  )rz  mid_size)r;  r  )r  kws    r.   <lambda>z7WeixinAdapter._outbound_media_builder.<locals>.<lambda>  sG    " 022G/H#%&7#8() 
 !##4 5 
. 
. r0   r
  c                     t           | d         | d         dd| d         |                     dd          |                     dd	          d
dS )Nr  rN  r1   ra  rO  play_lengthr   rS  r*   )rz  
video_sizerh  	video_md5)r;  r  )r  r   rd  s    r.   rf  z7WeixinAdapter._outbound_media_builder.<locals>.<lambda>  si    " 022G/H#%&7#8() 
 #%%6"7#%66-#;#;!#b!9!9	 	. . r0   r  c            	         t           | d         | d         dd|                     d          |                     d          |                     d          |                     dd	          d
dS )Nr  rN  r1   ra  rQ  rS  rR  playtimer   )rz  rQ  rS  rR  rl  )r;  r  )r  r   rd  s    r.   rf  z7WeixinAdapter._outbound_media_builder.<locals>.<lambda>  s}    " 022G/H#%&7#8() 
 $&66-#8#8')vv.?'@'@#%66-#8#8 "z1 5 5
 
. . r0   r  c                 p    t           | d         | d         dd| d         t          | d                   ddS 	Nr  rN  r1   ra  r  rP  )rz  r  rP   )r;  r  r  rL   rd  s    r.   rf  z7WeixinAdapter._outbound_media_builder.<locals>.<lambda>  sV    ! 022G/H#%&7#8() 
 "$Jr"2344 - - r0   c                 p    t           | d         | d         dd| d         t          | d                   ddS rn  ro  rd  s    r.   rf  z7WeixinAdapter._outbound_media_builder.<locals>.<lambda>  sV     ,..C+D!"34$% 
  
^2./00 )
 )
 r0   )r  r  r   MEDIA_IMAGEMEDIA_VIDEOrt   rZ  
MEDIA_FILE)r   r   rB  r  s       r.   rU  z%WeixinAdapter._outbound_media_builder  s    #D))!,J0J??8$$ 	 
! 
! 
 
 ??8$$ 	 ! !   ==!! 	*? 	 ! !   ??8$$ 	        
 
 
 	
r0   c                D   K   |                     d          rdnd}|||dS )Nz	@chatroomr  r  )r  r;  r  )rt   )r   r  r  s      r.   get_chat_infozWeixinAdapter.get_chat_info  s2      &//<<FGG$	wGGGr0   c                (    |dS t          |          S )Nr*   )r  r  s     r.   r  zWeixinAdapter.format_message  s    ?2)'222r0   )rM  r   )rH   r   r'   r  r'   r(   )r'   r   )r
  r3   r'   r   )r  rL   r'   r(   )rx  r3   r  r  r  r  r'   r   )rx  r3   r'   rI   )rx  r3   r'   r  )r   rL   r8  rI   r'   r   r  rL   r'   r  )
r  rL   r  rL   r8  rI   r9  rL   r'   r   )NN)
r  rL   r  rL   r  rI   r  r   r'   r   ra   )r  rL   r  r   r'   r   )r  rL   r'   r   )r  rL   r/  rL   r0  rL   r  rI   r  r   r'   r   )NNN)r  rL   r  rL   r0  rI   r  rI   r  r   r'   r   )NNNN)r  rL   r  rL   r0  rI   r  rI   r  rI   r  r   r'   r   )r  rL   r  rL   r0  rI   r  rI   r  r   r'   r   )r  rL   r  rL   r0  rI   r  rI   r  r   r'   r   )r)  rL   r'   rL   r  )
r  rL   r   rL   r0  rL   rB  r(   r'   rL   )r   rL   rB  r(   )r  rL   r'   r3   )r  rI   r'   rL   )%r   r   r   r   r  SUPPORTS_MESSAGE_EDITINGr   staticmethodr|  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r&  r*  r.  r8  r  r  r  r
  r2  r=  rU  ru  r  __classcell__)r  s   @r.   rL  rL  f  s3       ==  %0f 0f 0f 0f 0f 0fd B B B \B) ) ) )V4 4 4 4(:- :- :- :-xK K K K:) :) :) :)x   1 1 1 1.   $       &   &` ` ` `&
 
 
 

^ ^ ^ ^H #'-1?= ?= ?= ?= ?=Bc c c c c$b b b b. #'-1    : "&"&-1
 
 
 
 
* "&#'"&-1= = = = =0 "&"&-1= = = = =* "&"&-1= = = = =6   ( ',` ` ` ` `DC
 C
 C
 C
 C
JH H H H3 3 3 3 3 3 3 3r0   rL  )r  rh  r  r   Optional[List[Tuple[str, bool]]]c                .	  K   t          |                     d          pt          j        dd                                                    }t          |                     d          pt          j        dt
                                                                                  d          }t          |                     d          pt          j        dt                                                                                  d          }t          |p)|                     d	          pt          j        d
d                                                    }|sddiS |sddiS t          t          t                                          }	|	
                    |           |	                    ||          }
t                              |          }t          |dd          }|||j        sd}|                    |          }|r/|                    ||           d{V }|j        sdd|j         iS |pg D ]}\  }}t%          |          j                                        }|dv r|                    ||           d{V }n|                    ||           d{V }|j        sdd|j         ic S ~dd||r|j        ndt1          |
          dS t3          j        dt7                                4 d{V }t9          t;          d|i t=          | pi           |||d                    }||_        ||_         ||_!        ||_"        ||_#        ||_$        |	|_%        d}|                    |          }|rA|                    ||           d{V }|j        sdd|j         icddd          d{V  S |pg D ]\  }}t%          |          j                                        }|dv r|                    ||           d{V }n|                    ||           d{V }|j        s dd|j         ic cddd          d{V  S dd||r|j        ndt1          |
          dcddd          d{V  S # 1 d{V swxY w Y   dS )z
    One-shot send helper for ``send_message`` and cron delivery.

    This bypasses the long-poll adapter lifecycle and uses the raw API directly.
    r   rO  r*   r   rQ  r   r   rR  r   rP  r7  zGWeixin token missing. Configure WEIXIN_TOKEN or platforms.weixin.token.z\Weixin account ID missing. Configure WEIXIN_ACCOUNT_ID or platforms.weixin.extra.account_id.rm  NzWeixin send failed: >   .bmpr  r  r   r  r  zWeixin media send failed: Tr   )r  platformr  r  context_token_usedr  )r   r   r   )enabledr   rh  )&rL   r   rq  rr  rO   r4  r   rR  r   r   r   r4   getattrr  r  r&  r  r7  r   r	  r-   r  r  r  r(   r>   r3  rA   rL  r   r  rm  _sessionrt  rs  ru  rv  rj  )rh  r   r  r
  r  r   r   r   resolved_tokentoken_storer8  live_adaptersend_sessionlast_resultcleanedr%  	_is_voicer  r  adapters                       r.   send_weixin_directr    s_      UYY|,,R	:Mr0R0RSSYY[[J599Z((XBI6G,X,XYY__aahhilmmHuyy00iBI>SUh4i4ijjpprryyz}~~LU%))G"4"4U	.RT8U8UVV\\^^N dbcc ywxx#C(9(9$:$:;;K
###OOJ88M!%%n55L<$??LL$<\EX$<,0--g66 	M , 1 1'7 C CCCCCCCK& M!K8I!K!KLL%0%6B 	S 	S!J	z"")//11CHHH$0$@$@*$U$UUUUUUU$0$>$>w
$S$SSSSSSS& S!Qk>O!Q!QRRRRS  4?I+00T"&}"5"5
 
 	
 $t?R?T?TUUU +
 +
 +
 +
 +
 +
 +
Y`$5;B''", ($0	  	 	 	
 
 !("'($ ,*,0((11 	M 'Wg > >>>>>>>K& M!K8I!K!KL5+
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
8 &1%6B 	S 	S!J	z"")//11CHHH$+$;$;GZ$P$PPPPPPP$+$9$9':$N$NNNNNNN& S!Qk>O!Q!QRRRG+
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
DS  4?I+00T"&}"5"5
 
K+
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
 +
s    >B/R B RR
RR)r"   r#   r$   r#   r%   r&   r'   r(   )r'   r5   rw  )rG   )rH   rI   rJ   rK   r'   rL   )rS   r3   r'   rL   )r\   )r]   r^   r_   rK   r'   r^   )rd   r^   re   r^   r'   r^   )rp   r^   re   r^   r'   r^   )rw   rK   r'   rK   )r'   rL   )r'   r3   )r   rI   r   rL   r'   r   )r   rL   r'   r   )r   rL   r   rL   r'   r   )r   rL   r   rL   r   rL   r   rL   r   rL   r'   r   )r   rL   r   rL   r'   r   )r   rL   r   rL   r'   rL   )r   rL   r   rL   r   rL   r'   rL   )r   rL   r'   r^   )r
  r3   r   rL   r'   r  )r  r  r   rL   r  rL   rS   r3   r   rI   r  rK   r'   r3   )
r  r  r   rL   r  rL   r  rK   r'   r3   )r  r  r   rL   r   rL   r.  rL   r  rK   r'   r3   )r  r  r   rL   r   rL   r7  rL   r  rL   r8  rI   r9  rL   r'   r3   )r  r  r   rL   r   rL   r  rL   rH  rL   r(  rK   r'   r   )r  r  r   rL   r   rL   r   rL   r8  rI   r'   r3   )r  r  r   rL   r   rL   r  rL   rQ  rK   r   rL   rR  rK   rS  rL   rT  rK   rU  rL   r'   r3   )r  r  rp   r^   r[  rL   r'   rL   )r  r  r)  rL   rc  r   r'   r^   )r)  rL   r'   r   )rx  r3   re   rL   r'   r3   )r  r  r   rL   r   rI   r   rI   r|  rI   rc  r   r'   r^   )r  rL   r'   rL   )r  rL   r'   r  )r  rL   r'   rL   )r  r  r'   rL   )r  rL   r'   rL   rx  )r  rL   r'   r(   )r  rL   r'   r(   )r  rL   r  rK   r'   r  r  )r  rL   r  rK   r  r(   r'   r  )T)rH   r   r  r(   r'   r(   )r@  r  r'   rL   )r  r  r  rL   r'   r   )r   rL   r   rL   r'   rL   )r   rL   r   rL   r.  rL   r'   r   )r   rL   r  rL   rc  rK   r'   r  )rh  r3   r   rI   r  rL   r
  rL   r  r|  r'   r3   )r   
__future__r   r4  r   rW  rY   loggingr  rq  r  r   r~   rH  r   r  r   pathlibr   typingr   r   r   r	   r
   urllib.parser   r   	getLoggerr   r   r>   r;   r:   cryptography.hazmat.backendsr   &cryptography.hazmat.primitives.ciphersr   r   r   rD   gateway.configr   r   gateway.platforms.helpersr   gateway.platforms.baser   r   r   r   r   r   r   hermes_constantsr   utilsr   r4  rR  r   r   r   r3  rE  rK  rO  rY  r5  r=  r  rF  rL  r6  r  r  r  r  r,   ro  r/   rq  rr  rs  rZ  r4   __annotations__rA   rD  r  r  r  r  MSG_TYPE_USERrB  rC  r)  r-  compiler  r  r  _MARKDOWN_LINK_RErF   rR   r[   rc   ro   rv   rz   r   r   r   r   r   r   r   r   r   r   r   r	  r  r+  r-  r6  rG  rM  rP  rZ  ra  rg  	frozensetro  rw  r{  r~  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  r  rJ  rL  r  rE   r0   r.   <module>r     s 	  
 
 
 # " " " " "          				 				                  3 3 3 3 3 3 3 3 3 3 3 3 3 3 ( ( ( ( ( ( ( (		8	$	$NNN   G
<<<<<<PPPPPPPPPP   OFJE 4 3 3 3 3 3 3 3 9 9 9 9 9 9                  - , , , , , # # # # # #0= 3 ')'%, *0         5 5 5 5 
!# # # # #- - - -& 	

	
 RZ011
RSSBJ+,,	BJ9:: 2 2 2 2
    J J J J- - - - -
J J J J	 	 	 	( ( ( (H H H H
0 0 0 0      < < < <      .   /m /m /m /m /m /m /m /md5 5 5 5 5 5 5 5(p p p p   R R R R8 8 8 8   &   (C C C C*" " " "J   .   *   @N N N N8 "		% 	% 	% 	% 	% 	% )2	  
) 
)  
 
 
 

 
 
 
(4 4 4 4   2K K K K5 5 5 5    M  M  M  MF% % % %<#0 #0 #0 #0L$, $, $, $,N   (C C C CK K K K   0 ;@)N )N )N )N )NX    $   :   A A A A   ; ; ; ; 	D D D D D DNl3 l3 l3 l3 l3' l3 l3 l3j 59`
 `
 `
 `
 `
 `
 `
 `
s$   1A8 8	BBB B-,B-