Files
Escape-penacony-standalone/app/src/main/python/run_ppsr.py
T

293 lines
9.0 KiB
Python

import sys
import os
import builtins
import time
import _thread
import gc
import socket
import struct
import warnings
# === GLOBAL WARNING SUPPRESSION & METADATA SHIM (very early) ===
try:
import importlib.metadata
_orig_metadata_version = importlib.metadata.version
_orig_metadata_distribution = importlib.metadata.distribution
_KNOWN_VERSIONS = {
"werkzeug": "3.1.9",
"flask": "3.1.3",
"marshmallow": "3.20.0",
"requests": "2.34.2",
"urllib3": "2.8.0",
"protobuf": "7.36.2",
"click": "8.5.0",
"jinja2": "3.1.6",
"itsdangerous": "2.2.0",
"blinker": "1.9.0",
"markupsafe": "3.0.4",
"dataclasses-json": "0.6.7",
"dataclasses_json": "0.6.7",
"packaging": "26.3"
}
class _ShimedDistribution:
def __init__(self, name, version):
self.name = name
self.version = version
self.metadata = {"Name": name, "Version": version}
def _safe_metadata_version(name):
try:
return _orig_metadata_version(name)
except Exception:
clean = name.lower().replace("-", "_")
return _KNOWN_VERSIONS.get(name.lower(), _KNOWN_VERSIONS.get(clean, "1.0.0"))
def _safe_metadata_distribution(name):
try:
return _orig_metadata_distribution(name)
except Exception:
ver = _safe_metadata_version(name)
return _ShimedDistribution(name, ver)
importlib.metadata.version = _safe_metadata_version
importlib.metadata.distribution = _safe_metadata_distribution
except Exception:
pass
warnings.filterwarnings("ignore", message=".*default.*deprecated.*")
warnings.filterwarnings("ignore", message=".*metadata.*deprecated.*")
warnings.filterwarnings("ignore", module="marshmallow.*")
warnings.filterwarnings("ignore", module="dataclasses_json.*")
try:
from marshmallow.warnings import RemovedInMarshmallow4Warning
warnings.filterwarnings("ignore", category=RemovedInMarshmallow4Warning)
warnings.simplefilter("ignore", category=RemovedInMarshmallow4Warning)
print("[Shim] Global warning suppression activated")
except Exception:
pass
_active_server_instance = None
# --- 1. Stream Redirector for Android UI ---
class AndroidLogStream:
def __init__(self, activity_context, original_stream):
self.activity_context = activity_context
self.original_stream = original_stream
self.buffer = ""
self._in_write = False
def write(self, message):
if self._in_write:
if self.original_stream:
try:
self.original_stream.write(message)
except Exception:
pass
return
self._in_write = True
try:
if self.original_stream:
try:
self.original_stream.write(message)
except Exception:
pass
self.buffer += message
while "\n" in self.buffer:
line, self.buffer = self.buffer.split("\n", 1)
clean_line = line.strip()
if clean_line and self.activity_context:
try:
self.activity_context.onServerLog(clean_line)
except Exception:
pass
finally:
self._in_write = False
def flush(self):
if self.original_stream:
try:
self.original_stream.flush()
except Exception:
pass
if self.buffer.strip() and self.activity_context:
try:
self.activity_context.onServerLog(self.buffer.strip())
self.buffer = ""
except Exception:
pass
# --- 2. Headless Input Mock ---
def _mock_input(prompt=""):
if prompt:
print(f"[CLI]: {prompt}")
time.sleep(2)
return ""
builtins.input = _mock_input
# --- 3. Minimal Marshmallow Info ---
try:
import marshmallow
print(f"[Shim] marshmallow {marshmallow.__version__}")
except Exception:
print("[Shim] marshmallow not available")
# --- 4. Shutdown Logic ---
def kill_server_process():
global _active_server_instance
print("[Shutdown]: Force-stopping server execution...")
if _active_server_instance is not None:
try:
if hasattr(_active_server_instance, 'shutdown'):
_active_server_instance.shutdown()
if hasattr(_active_server_instance, 'server_close'):
_active_server_instance.server_close()
except Exception:
pass
try:
sock = getattr(_active_server_instance, 'socket', None)
if sock:
sock.setsockopt(socket.SOL_SOCKET, socket.SO_LINGER, struct.pack('ii', 1, 0))
sock.close()
except Exception:
pass
_active_server_instance = None
try:
for obj in gc.get_objects():
if isinstance(obj, socket.socket):
try:
obj.shutdown(socket.SHUT_RDWR)
obj.close()
except Exception:
pass
except Exception:
pass
try:
s = socket.socket(socket.AF_INET, socket.SOCK_STREAM)
s.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
s.close()
except Exception:
pass
time.sleep(1.2)
for _ in range(5):
try:
_thread.interrupt_main()
time.sleep(0.2)
except Exception:
pass
# --- 5. Main Execution Entrypoint ---
def run_server(ppsr_path, activity_context=None):
if activity_context is not None:
sys.stdout = AndroidLogStream(activity_context, sys.__stdout__)
sys.stderr = AndroidLogStream(activity_context, sys.__stderr__)
# Extra safety - re-apply on every start
try:
warnings.filterwarnings("ignore", category=RemovedInMarshmallow4Warning)
except Exception:
pass
ppsr_dir = os.path.dirname(os.path.abspath(ppsr_path))
misc_dir = os.path.join(ppsr_dir, "misc")
pkg_zip = os.path.join(ppsr_dir, "packages.zip")
if os.path.exists(ppsr_dir):
os.chdir(ppsr_dir)
print(f"Working directory locked: {os.getcwd()}")
for path in [ppsr_dir, misc_dir, pkg_zip]:
if os.path.exists(path) and path not in sys.path:
sys.path.insert(0, path)
warnings.filterwarnings("ignore", message=".*default.*deprecated.*")
warnings.filterwarnings("ignore", message=".*metadata.*deprecated.*")
warnings.filterwarnings("ignore", module="marshmallow.*")
warnings.filterwarnings("ignore", module="dataclasses_json.*")
# Verify and auto-recover critical packages if needed
for pkg_name in ["requests", "werkzeug", "flask"]:
try:
__import__(pkg_name)
except ImportError:
print(f"[Shim] Package '{pkg_name}' missing, attempting auto-install...")
try:
import package_fetcher
package_fetcher.install_package(pkg_name, ppsr_dir)
except Exception as ex:
print(f"[Shim Warning] Fallback failed for {pkg_name}: {ex}")
# --- Werkzeug Patch ---
try:
import werkzeug.serving
if hasattr(werkzeug.serving, "ThreadedWSGIServer"):
try:
werkzeug.serving.ThreadedWSGIServer._server_version = "Werkzeug/3.1.9"
except Exception:
pass
_orig_make_server = werkzeug.serving.make_server
def _patched_make_server(*args, **kwargs):
global _active_server_instance
kwargs.pop('options', None)
server = _orig_make_server(*args, **kwargs)
try:
server._server_version = "Werkzeug/3.1.9"
except Exception:
pass
try:
if hasattr(server, 'socket') and server.socket:
server.socket.setsockopt(socket.SOL_SOCKET, socket.SO_REUSEADDR, 1)
except Exception:
pass
_active_server_instance = server
print("[Server] Server instance patched and ready")
return server
werkzeug.serving.make_server = _patched_make_server
print("[Patch] Werkzeug make_server patched successfully")
except Exception as e:
print(f"[Patch Warning] Werkzeug patch: {e}")
print(f"Loading bytecode target: {ppsr_path}...")
with open(ppsr_path, "rb") as f:
code_bytes = f.read()
try:
import marshal
code_obj = marshal.loads(code_bytes[16:])
except Exception:
code_obj = compile(code_bytes, ppsr_path, "exec")
main_globals = {
"__name__": "__main__",
"__file__": ppsr_path,
"__doc__": None,
"sys": sys,
"os": os,
"input": _mock_input
}
try:
exec(code_obj, main_globals)
except KeyboardInterrupt:
print("[System]: Server loop interrupted cleanly.")
except Exception as e:
print(f"[System]: Server terminated: {e}")