293 lines
9.0 KiB
Python
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}")
|