Files
kefu/deploy/loading-performance-20260917/protocol_performance_patch.py
T
2026-09-21 10:34:06 +08:00

138 lines
7.6 KiB
Python

from pathlib import Path
import shutil
root=Path('C:/wechat_rpa')
backup=root/'backups/loading-performance-20260917'
backup.mkdir(parents=True,exist_ok=True)
def edit(name, replacements):
path=root/name
text=path.read_text(encoding='utf-8')
for old,new in replacements:
assert text.count(old)==1,(name,old[:90],text.count(old))
text=text.replace(old,new)
compile(text,str(path),'exec')
assert not (backup/name).exists(),f'Backup exists: {name}'
shutil.copy2(path,backup/name)
path.write_text(text,encoding='utf-8')
edit('wecom_native_sender.py',[
('from contextlib import contextmanager','from contextlib import contextmanager\nfrom contextvars import ContextVar'),
("class NativeClient:\n",'''_readonly_build_validation = ContextVar('wecom_readonly_build_validation', default=None)
@contextmanager
def readonly_build_validation_scope():
"""Reuse only file hashes within one probe, never live account/send readiness."""
state={'entries':{},'hashedFiles':0,'reusedFiles':0,'bytesHashed':0}
token=_readonly_build_validation.set(state)
try:yield state
finally:_readonly_build_validation.reset(token)
def _file_identity(info):
return (info.st_dev,info.st_ino,info.st_size,info.st_mtime_ns,info.st_ctime_ns)
def _hash_client_file(path):
"""Bound memory and reject a replacement/change during the complete hash."""
with Path(path).open('rb') as handle:
before=_file_identity(os.fstat(handle.fileno()))
digest=hashlib.sha256()
while chunk:=handle.read(1024*1024):digest.update(chunk)
after=_file_identity(os.fstat(handle.fileno()))
if before!=after or before!=_file_identity(Path(path).stat()):
raise NativeUnavailable('企业微信文件在校验期间发生变化,请重新检测')
return digest.hexdigest(),before
def _process_creation_id(pid,kernel32):
"""PID reuse must not reuse the earlier process's build validation."""
handle=kernel32.OpenProcess(0x1000,False,int(pid))
if not handle:return None
try:
created=w.FILETIME();exited=w.FILETIME();system=w.FILETIME();user=w.FILETIME()
if not kernel32.GetProcessTimes(handle,c.byref(created),c.byref(exited),c.byref(system),c.byref(user)):
return None
return (created.dwHighDateTime<<32)|created.dwLowDateTime
finally:kernel32.CloseHandle(handle)
def _client_file_digest(path,pid,kernel32,*,readonly):
state=_readonly_build_validation.get() if readonly else None
if state is None:
return _hash_client_file(path)[0]
created=_process_creation_id(pid,kernel32)
before=_file_identity(Path(path).stat())
identity=(int(pid),created,os.path.normcase(os.path.abspath(path)),before)
if created is not None and identity in state['entries']:
state['reusedFiles']+=1
return state['entries'][identity]
digest,verified=_hash_client_file(path)
state['hashedFiles']+=1
state['bytesHashed']+=verified[2]
if before!=verified:
raise NativeUnavailable('企业微信文件在校验期间发生变化,请重新检测')
if created is not None:state['entries'][identity]=digest
return digest
class NativeClient:
'''),
("('GetExitCodeThread',w.BOOL,[w.HANDLE,c.POINTER(w.DWORD)])]", "('GetExitCodeThread',w.BOOL,[w.HANDLE,c.POINTER(w.DWORD)]),\n ('GetProcessTimes',w.BOOL,[w.HANDLE,c.POINTER(w.FILETIME),c.POINTER(w.FILETIME),c.POINTER(w.FILETIME),c.POINTER(w.FILETIME)])]"),
("self.profile=build_for_hash(hashlib.sha256(self.path.read_bytes()).hexdigest())", "self.profile=build_for_hash(_client_file_digest(self.path,self.pid,self.k,readonly=not write))"),
])
edit('wxwork_protocol_probe.py',[
('import argparse','import argparse\nfrom contextlib import contextmanager'),
(' result = []\n for pid in find_wxwork_pids', ' result = []\n binary_metadata = {}\n for pid in find_wxwork_pids'),
(' entry.update(pe_header(path))\n entry["version"] = file_version(path)', ''' identity = os.path.normcase(os.path.abspath(path))
metadata = binary_metadata.get(identity)
if metadata is None:
metadata = {**pe_header(path), "version": file_version(path), "size": Path(path).stat().st_size}
binary_metadata[identity] = metadata
entry.update(metadata)'''),
('def probe_installed_client(*, deep=False, initialize_database=False):', '''@contextmanager
def _probe_phase(timings, name):
started=time.perf_counter()
try:yield
finally:timings[name]=round((time.perf_counter()-started)*1000,3)
def probe_installed_client(*, deep=False, initialize_database=False):
"""Run fresh identity checks; static build hashes live for this call only."""
from wecom_native_sender import readonly_build_validation_scope
started=time.perf_counter()
timings={}
with readonly_build_validation_scope() as builds:
result=_probe_installed_client(deep=deep,initialize_database=initialize_database,timings=timings)
timings['total']=round((time.perf_counter()-started)*1000,3)
result['timingsMs']=timings
result['buildValidation']={key:builds[key] for key in ('hashedFiles','reusedFiles','bytesHashed')}
return result
def _probe_installed_client(*, deep=False, initialize_database=False, timings):'''),
(' result["clients"] = running_clients()', ' with _probe_phase(timings,"processes"):\n result["clients"] = running_clients()'),
(' result["binaries"].append(inspect_binary(target, deep=deep))', ''' metadata=next((item for item in result['clients'] if item.get('path')==str(target)),{})
if not deep and all(key in metadata for key in ('size','architecture','machine','sections','buildTimestamp','isDll','version')):
result['binaries'].append({'name':target.name,'path':str(target),**{
key:metadata[key] for key in ('size','architecture','machine','sections','buildTimestamp','isDll','version')}})
else:
result["binaries"].append(inspect_binary(target, deep=deep))'''),
(' live = discover(result["clients"])', ' with _probe_phase(timings,"clientValidation"):\n live = discover(result["clients"])'),
(' database = protocol_database_status(live["accountId"], initialize=initialize_database)', ' with _probe_phase(timings,"databaseValidation"):\n database = protocol_database_status(live["accountId"], initialize=initialize_database)'),
(' current = discover()', ' with _probe_phase(timings,"identityRecheck"):\n current = discover()'),
])
edit('reply_database.py',[
(' def _open_database(*, account="", initialize=True):', ' def _open_database(*, account="", initialize=True, source_directory=None):'),
(' source = detect_wxwork_dir(account=account) if account else detect_wxwork_dir()', ' # The protocol probe already located this account; reuse only that path,\n # never a readiness result. health_check below still verifies the account.\n source = source_directory if source_directory is not None else (detect_wxwork_dir(account=account) if account else detect_wxwork_dir())'),
])
edit('wecom_environment.py',[
(' if not detect_wxwork_dir(account=account):', ' source=detect_wxwork_dir(account=account)\n if not source:'),
(' database = LiveReplyDatabase._open_database(account=account, initialize=initialize)', ' database = LiveReplyDatabase._open_database(account=account, initialize=initialize, source_directory=source)'),
])
print('Patched bounded same-probe hashes, phase timings, metadata reuse and one-time data-directory lookup.')