logrotate #366; configurable pool and buffer sizes
This commit is contained in:
parent
ed85e2a284
commit
18a1bced83
106
linux.py
106
linux.py
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
import asyncio as _asyncio
|
import asyncio as _asyncio
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import subprocess
|
import subprocess
|
||||||
import sys
|
import sys
|
||||||
|
|
@ -32,6 +33,9 @@ DEFAULT_CONFIG = {
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
||||||
"verbose": False,
|
"verbose": False,
|
||||||
|
"log_max_mb": 5,
|
||||||
|
"buf_kb": 256,
|
||||||
|
"pool_size": 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -149,12 +153,17 @@ def save_config(cfg: dict):
|
||||||
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(verbose: bool = False):
|
def setup_logging(verbose: bool = False, log_max_mb: float = 5):
|
||||||
_ensure_dirs()
|
_ensure_dirs()
|
||||||
root = logging.getLogger()
|
root = logging.getLogger()
|
||||||
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
||||||
|
|
||||||
fh = logging.FileHandler(str(LOG_FILE), encoding="utf-8")
|
fh = logging.handlers.RotatingFileHandler(
|
||||||
|
str(LOG_FILE),
|
||||||
|
maxBytes=max(32 * 1024, log_max_mb * 1024 * 1024),
|
||||||
|
backupCount=0,
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
fh.setLevel(logging.DEBUG)
|
fh.setLevel(logging.DEBUG)
|
||||||
fh.setFormatter(
|
fh.setFormatter(
|
||||||
logging.Formatter(
|
logging.Formatter(
|
||||||
|
|
@ -261,6 +270,13 @@ def start_proxy():
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("Starting proxy on %s:%d ...", host, port)
|
log.info("Starting proxy on %s:%d ...", host, port)
|
||||||
|
|
||||||
|
buf_kb = cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])
|
||||||
|
pool_size = cfg.get("pool_size", DEFAULT_CONFIG["pool_size"])
|
||||||
|
tg_ws_proxy._RECV_BUF = max(4, buf_kb) * 1024
|
||||||
|
tg_ws_proxy._SEND_BUF = tg_ws_proxy._RECV_BUF
|
||||||
|
tg_ws_proxy._WS_POOL_SIZE = max(0, pool_size)
|
||||||
|
|
||||||
_proxy_thread = threading.Thread(
|
_proxy_thread = threading.Thread(
|
||||||
target=_run_proxy_thread,
|
target=_run_proxy_thread,
|
||||||
args=(port, dc_opt, verbose, host),
|
args=(port, dc_opt, verbose, host),
|
||||||
|
|
@ -363,7 +379,7 @@ def _edit_config_dialog():
|
||||||
TEXT_SECONDARY = "#707579"
|
TEXT_SECONDARY = "#707579"
|
||||||
FONT_FAMILY = "Sans"
|
FONT_FAMILY = "Sans"
|
||||||
|
|
||||||
w, h = 420, 480
|
w, h = 420, 540
|
||||||
sw = root.winfo_screenwidth()
|
sw = root.winfo_screenwidth()
|
||||||
sh = root.winfo_screenheight()
|
sh = root.winfo_screenheight()
|
||||||
root.geometry(f"{w}x{h}+{(sw - w) // 2}+{(sh - h) // 2}")
|
root.geometry(f"{w}x{h}+{(sw - w) // 2}+{(sh - h) // 2}")
|
||||||
|
|
@ -455,14 +471,29 @@ def _edit_config_dialog():
|
||||||
border_color=FIELD_BORDER,
|
border_color=FIELD_BORDER,
|
||||||
).pack(anchor="w", pady=(0, 8))
|
).pack(anchor="w", pady=(0, 8))
|
||||||
|
|
||||||
# Info label
|
# Advanced: buf_kb, pool_size, log_max_mb
|
||||||
ctk.CTkLabel(
|
adv_frame = ctk.CTkFrame(frame, fg_color="transparent")
|
||||||
frame,
|
adv_frame.pack(anchor="w", fill="x", pady=(4, 8))
|
||||||
text="Изменения вступят в силу после перезапуска прокси.",
|
|
||||||
font=(FONT_FAMILY, 11),
|
for col, (lbl, key, w_) in enumerate([
|
||||||
text_color=TEXT_SECONDARY,
|
("Буфер (KB, 256 default)", "buf_kb", 120),
|
||||||
anchor="w",
|
("WS пулов (4 default)", "pool_size", 120),
|
||||||
).pack(anchor="w", pady=(0, 16))
|
("Log size (MB, 5 def)", "log_max_mb", 120),
|
||||||
|
]):
|
||||||
|
col_frame = ctk.CTkFrame(adv_frame, fg_color="transparent")
|
||||||
|
col_frame.pack(side="left", padx=(0, 10))
|
||||||
|
ctk.CTkLabel(col_frame, text=lbl, font=(FONT_FAMILY, 11),
|
||||||
|
text_color=TEXT_SECONDARY, anchor="w").pack(anchor="w")
|
||||||
|
ctk.CTkEntry(col_frame, width=w_, height=30, font=(FONT_FAMILY, 12),
|
||||||
|
corner_radius=8, fg_color=FIELD_BG,
|
||||||
|
border_color=FIELD_BORDER, border_width=1,
|
||||||
|
text_color=TEXT_PRIMARY,
|
||||||
|
textvariable=ctk.StringVar(
|
||||||
|
value=str(cfg.get(key, DEFAULT_CONFIG[key]))
|
||||||
|
)).pack(anchor="w")
|
||||||
|
|
||||||
|
_adv_entries = list(adv_frame.winfo_children())
|
||||||
|
_adv_keys = ["buf_kb", "pool_size", "log_max_mb"]
|
||||||
|
|
||||||
def on_save():
|
def on_save():
|
||||||
import socket as _sock
|
import socket as _sock
|
||||||
|
|
@ -499,6 +530,17 @@ def _edit_config_dialog():
|
||||||
"dc_ip": lines,
|
"dc_ip": lines,
|
||||||
"verbose": verbose_var.get(),
|
"verbose": verbose_var.get(),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, key in enumerate(_adv_keys):
|
||||||
|
col_frame = _adv_entries[i]
|
||||||
|
entry = col_frame.winfo_children()[1]
|
||||||
|
try:
|
||||||
|
val = float(entry.get().strip())
|
||||||
|
if key in ("buf_kb", "pool_size"):
|
||||||
|
val = int(val)
|
||||||
|
new_cfg[key] = val
|
||||||
|
except ValueError:
|
||||||
|
new_cfg[key] = DEFAULT_CONFIG[key]
|
||||||
save_config(new_cfg)
|
save_config(new_cfg)
|
||||||
_config.update(new_cfg)
|
_config.update(new_cfg)
|
||||||
log.info("Config saved: %s", new_cfg)
|
log.info("Config saved: %s", new_cfg)
|
||||||
|
|
@ -521,33 +563,18 @@ def _edit_config_dialog():
|
||||||
root.destroy()
|
root.destroy()
|
||||||
|
|
||||||
btn_frame = ctk.CTkFrame(frame, fg_color="transparent")
|
btn_frame = ctk.CTkFrame(frame, fg_color="transparent")
|
||||||
btn_frame.pack(fill="x")
|
btn_frame.pack(fill="x", pady=(20, 0))
|
||||||
ctk.CTkButton(
|
ctk.CTkButton(btn_frame, text="Сохранить", height=38,
|
||||||
btn_frame,
|
font=(FONT_FAMILY, 14, "bold"), corner_radius=10,
|
||||||
text="Сохранить",
|
fg_color=TG_BLUE, hover_color=TG_BLUE_HOVER,
|
||||||
width=140,
|
text_color="#ffffff",
|
||||||
height=38,
|
command=on_save).pack(side="left", fill="x", expand=True, padx=(0, 8))
|
||||||
font=(FONT_FAMILY, 14, "bold"),
|
ctk.CTkButton(btn_frame, text="Отмена", height=38,
|
||||||
corner_radius=10,
|
font=(FONT_FAMILY, 14), corner_radius=10,
|
||||||
fg_color=TG_BLUE,
|
fg_color=FIELD_BG, hover_color=FIELD_BORDER,
|
||||||
hover_color=TG_BLUE_HOVER,
|
text_color=TEXT_PRIMARY, border_width=1,
|
||||||
text_color="#ffffff",
|
border_color=FIELD_BORDER,
|
||||||
command=on_save,
|
command=on_cancel).pack(side="right", fill="x", expand=True)
|
||||||
).pack(side="left", padx=(0, 10))
|
|
||||||
ctk.CTkButton(
|
|
||||||
btn_frame,
|
|
||||||
text="Отмена",
|
|
||||||
width=140,
|
|
||||||
height=38,
|
|
||||||
font=(FONT_FAMILY, 14),
|
|
||||||
corner_radius=10,
|
|
||||||
fg_color=FIELD_BG,
|
|
||||||
hover_color=FIELD_BORDER,
|
|
||||||
text_color=TEXT_PRIMARY,
|
|
||||||
border_width=1,
|
|
||||||
border_color=FIELD_BORDER,
|
|
||||||
command=on_cancel,
|
|
||||||
).pack(side="left")
|
|
||||||
|
|
||||||
root.mainloop()
|
root.mainloop()
|
||||||
|
|
||||||
|
|
@ -798,7 +825,8 @@ def run_tray():
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
setup_logging(_config.get("verbose", False))
|
setup_logging(_config.get("verbose", False),
|
||||||
|
log_max_mb=_config.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"]))
|
||||||
log.info("TG WS Proxy tray app starting")
|
log.info("TG WS Proxy tray app starting")
|
||||||
log.info("Config: %s", _config)
|
log.info("Config: %s", _config)
|
||||||
log.info("Log file: %s", LOG_FILE)
|
log.info("Log file: %s", LOG_FILE)
|
||||||
|
|
|
||||||
46
macos.py
46
macos.py
|
|
@ -2,6 +2,7 @@ from __future__ import annotations
|
||||||
|
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import psutil
|
import psutil
|
||||||
import subprocess
|
import subprocess
|
||||||
|
|
@ -43,6 +44,9 @@ DEFAULT_CONFIG = {
|
||||||
"host": "127.0.0.1",
|
"host": "127.0.0.1",
|
||||||
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
||||||
"verbose": False,
|
"verbose": False,
|
||||||
|
"log_max_mb": 5,
|
||||||
|
"buf_kb": 256,
|
||||||
|
"pool_size": 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
_proxy_thread: Optional[threading.Thread] = None
|
_proxy_thread: Optional[threading.Thread] = None
|
||||||
|
|
@ -153,12 +157,17 @@ def save_config(cfg: dict):
|
||||||
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(verbose: bool = False):
|
def setup_logging(verbose: bool = False, log_max_mb: float = 5):
|
||||||
_ensure_dirs()
|
_ensure_dirs()
|
||||||
root = logging.getLogger()
|
root = logging.getLogger()
|
||||||
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
||||||
|
|
||||||
fh = logging.FileHandler(str(LOG_FILE), encoding="utf-8")
|
fh = logging.handlers.RotatingFileHandler(
|
||||||
|
str(LOG_FILE),
|
||||||
|
maxBytes=max(32 * 1024, log_max_mb * 1024 * 1024),
|
||||||
|
backupCount=0,
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
fh.setLevel(logging.DEBUG)
|
fh.setLevel(logging.DEBUG)
|
||||||
fh.setFormatter(logging.Formatter(
|
fh.setFormatter(logging.Formatter(
|
||||||
"%(asctime)s %(levelname)-5s %(name)s %(message)s",
|
"%(asctime)s %(levelname)-5s %(name)s %(message)s",
|
||||||
|
|
@ -290,6 +299,13 @@ def start_proxy():
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("Starting proxy on %s:%d ...", host, port)
|
log.info("Starting proxy on %s:%d ...", host, port)
|
||||||
|
|
||||||
|
buf_kb = cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])
|
||||||
|
pool_size = cfg.get("pool_size", DEFAULT_CONFIG["pool_size"])
|
||||||
|
tg_ws_proxy._RECV_BUF = max(4, buf_kb) * 1024
|
||||||
|
tg_ws_proxy._SEND_BUF = tg_ws_proxy._RECV_BUF
|
||||||
|
tg_ws_proxy._WS_POOL_SIZE = max(0, pool_size)
|
||||||
|
|
||||||
_proxy_thread = threading.Thread(
|
_proxy_thread = threading.Thread(
|
||||||
target=_run_proxy_thread,
|
target=_run_proxy_thread,
|
||||||
args=(port, dc_opt, verbose, host),
|
args=(port, dc_opt, verbose, host),
|
||||||
|
|
@ -438,11 +454,34 @@ def _edit_config_dialog():
|
||||||
# Verbose
|
# Verbose
|
||||||
verbose = _ask_yes_no("Включить подробное логирование (verbose)?")
|
verbose = _ask_yes_no("Включить подробное логирование (verbose)?")
|
||||||
|
|
||||||
|
# Advanced settings
|
||||||
|
adv_str = _osascript_input(
|
||||||
|
"Расширенные настройки (буфер KB, WS пул, лог MB):\n"
|
||||||
|
"Формат: buf_kb,pool_size,log_max_mb",
|
||||||
|
f"{cfg.get('buf_kb', DEFAULT_CONFIG['buf_kb'])},"
|
||||||
|
f"{cfg.get('pool_size', DEFAULT_CONFIG['pool_size'])},"
|
||||||
|
f"{cfg.get('log_max_mb', DEFAULT_CONFIG['log_max_mb'])}")
|
||||||
|
|
||||||
|
adv = {}
|
||||||
|
if adv_str:
|
||||||
|
parts = [s.strip() for s in adv_str.split(',')]
|
||||||
|
keys = [("buf_kb", int), ("pool_size", int),
|
||||||
|
("log_max_mb", float)]
|
||||||
|
for i, (k, typ) in enumerate(keys):
|
||||||
|
if i < len(parts):
|
||||||
|
try:
|
||||||
|
adv[k] = typ(parts[i])
|
||||||
|
except ValueError:
|
||||||
|
pass
|
||||||
|
|
||||||
new_cfg = {
|
new_cfg = {
|
||||||
"host": host,
|
"host": host,
|
||||||
"port": port,
|
"port": port,
|
||||||
"dc_ip": dc_lines,
|
"dc_ip": dc_lines,
|
||||||
"verbose": verbose,
|
"verbose": verbose,
|
||||||
|
"buf_kb": adv.get("buf_kb", cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])),
|
||||||
|
"pool_size": adv.get("pool_size", cfg.get("pool_size", DEFAULT_CONFIG["pool_size"])),
|
||||||
|
"log_max_mb": adv.get("log_max_mb", cfg.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"])),
|
||||||
}
|
}
|
||||||
save_config(new_cfg)
|
save_config(new_cfg)
|
||||||
log.info("Config saved: %s", new_cfg)
|
log.info("Config saved: %s", new_cfg)
|
||||||
|
|
@ -581,7 +620,8 @@ def run_menubar():
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
setup_logging(_config.get("verbose", False))
|
setup_logging(_config.get("verbose", False),
|
||||||
|
log_max_mb=_config.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"]))
|
||||||
log.info("TG WS Proxy menubar app starting")
|
log.info("TG WS Proxy menubar app starting")
|
||||||
log.info("Config: %s", _config)
|
log.info("Config: %s", _config)
|
||||||
log.info("Log file: %s", LOG_FILE)
|
log.info("Log file: %s", LOG_FILE)
|
||||||
|
|
|
||||||
|
|
@ -4,6 +4,7 @@ import argparse
|
||||||
import asyncio
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
import logging
|
import logging
|
||||||
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import socket as _socket
|
import socket as _socket
|
||||||
import ssl
|
import ssl
|
||||||
|
|
@ -144,6 +145,7 @@ _st_I_net = struct.Struct('!I')
|
||||||
_st_Ih = struct.Struct('<Ih')
|
_st_Ih = struct.Struct('<Ih')
|
||||||
_st_I_le = struct.Struct('<I')
|
_st_I_le = struct.Struct('<I')
|
||||||
_VALID_PROTOS = frozenset((0xEFEFEFEF, 0xEEEEEEEE, 0xDDDDDDDD))
|
_VALID_PROTOS = frozenset((0xEFEFEFEF, 0xEEEEEEEE, 0xDDDDDDDD))
|
||||||
|
_WS_PING_FRAME = _st_BB4s.pack(0x80 | 0x9, 0x80 | 0, os.urandom(4))
|
||||||
|
|
||||||
|
|
||||||
class RawWebSocket:
|
class RawWebSocket:
|
||||||
|
|
@ -154,6 +156,7 @@ class RawWebSocket:
|
||||||
proxy), performs the HTTP Upgrade handshake, and provides send/recv
|
proxy), performs the HTTP Upgrade handshake, and provides send/recv
|
||||||
for binary frames with proper masking, ping/pong, and close handling.
|
for binary frames with proper masking, ping/pong, and close handling.
|
||||||
"""
|
"""
|
||||||
|
__slots__ = ('reader', 'writer', '_closed')
|
||||||
|
|
||||||
OP_CONTINUATION = 0x0
|
OP_CONTINUATION = 0x0
|
||||||
OP_TEXT = 0x1
|
OP_TEXT = 0x1
|
||||||
|
|
@ -670,8 +673,7 @@ async def _bridge_ws(reader, writer, ws: RawWebSocket, label,
|
||||||
idle = asyncio.get_event_loop().time() - last_recv_time
|
idle = asyncio.get_event_loop().time() - last_recv_time
|
||||||
if idle >= 2 and not ws._closed:
|
if idle >= 2 and not ws._closed:
|
||||||
try:
|
try:
|
||||||
ws.writer.write(
|
ws.writer.write(_WS_PING_FRAME)
|
||||||
ws._build_frame(ws.OP_PING, b'', mask=True))
|
|
||||||
await ws.writer.drain()
|
await ws.writer.drain()
|
||||||
log.debug("[%s] %s WS PING (idle %.1fs)",
|
log.debug("[%s] %s WS PING (idle %.1fs)",
|
||||||
label, dc_tag, idle)
|
label, dc_tag, idle)
|
||||||
|
|
@ -1156,6 +1158,16 @@ def main():
|
||||||
' --dc-ip 2:149.154.167.220')
|
' --dc-ip 2:149.154.167.220')
|
||||||
ap.add_argument('-v', '--verbose', action='store_true',
|
ap.add_argument('-v', '--verbose', action='store_true',
|
||||||
help='Debug logging')
|
help='Debug logging')
|
||||||
|
ap.add_argument('--log-file', type=str, default=None, metavar='PATH',
|
||||||
|
help='Log to file with rotation (default: stderr only)')
|
||||||
|
ap.add_argument('--log-max-mb', type=float, default=5, metavar='MB',
|
||||||
|
help='Max log file size in MB before rotation (default 5)')
|
||||||
|
ap.add_argument('--log-backups', type=int, default=0, metavar='N',
|
||||||
|
help='Number of rotated log files to keep (default 0)')
|
||||||
|
ap.add_argument('--buf-kb', type=int, default=256, metavar='KB',
|
||||||
|
help='Socket send/recv buffer size in KB (default 256)')
|
||||||
|
ap.add_argument('--pool-size', type=int, default=4, metavar='N',
|
||||||
|
help='WS connection pool size per DC (default 4, min 0)')
|
||||||
args = ap.parse_args()
|
args = ap.parse_args()
|
||||||
|
|
||||||
if not args.dc_ip:
|
if not args.dc_ip:
|
||||||
|
|
@ -1167,11 +1179,30 @@ def main():
|
||||||
log.error(str(e))
|
log.error(str(e))
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
|
|
||||||
logging.basicConfig(
|
log_level = logging.DEBUG if args.verbose else logging.INFO
|
||||||
level=logging.DEBUG if args.verbose else logging.INFO,
|
log_fmt = logging.Formatter('%(asctime)s %(levelname)-5s %(message)s',
|
||||||
format='%(asctime)s %(levelname)-5s %(message)s',
|
datefmt='%H:%M:%S')
|
||||||
datefmt='%H:%M:%S',
|
root = logging.getLogger()
|
||||||
)
|
root.setLevel(log_level)
|
||||||
|
|
||||||
|
console = logging.StreamHandler()
|
||||||
|
console.setFormatter(log_fmt)
|
||||||
|
root.addHandler(console)
|
||||||
|
|
||||||
|
if args.log_file:
|
||||||
|
fh = logging.handlers.RotatingFileHandler(
|
||||||
|
args.log_file,
|
||||||
|
maxBytes=max(32 * 1024, args.log_max_mb * 1024 * 1024),
|
||||||
|
backupCount=max(0, args.log_backups),
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
|
fh.setFormatter(log_fmt)
|
||||||
|
root.addHandler(fh)
|
||||||
|
|
||||||
|
global _RECV_BUF, _SEND_BUF, _WS_POOL_SIZE
|
||||||
|
_RECV_BUF = max(4, args.buf_kb) * 1024
|
||||||
|
_SEND_BUF = _RECV_BUF
|
||||||
|
_WS_POOL_SIZE = max(0, args.pool_size)
|
||||||
|
|
||||||
try:
|
try:
|
||||||
asyncio.run(_run(args.port, dc_opt, host=args.host))
|
asyncio.run(_run(args.port, dc_opt, host=args.host))
|
||||||
|
|
|
||||||
60
windows.py
60
windows.py
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
import ctypes
|
import ctypes
|
||||||
import json
|
import json
|
||||||
import logging
|
import logging
|
||||||
|
import logging.handlers
|
||||||
import os
|
import os
|
||||||
import winreg
|
import winreg
|
||||||
import psutil
|
import psutil
|
||||||
|
|
@ -38,6 +39,9 @@ DEFAULT_CONFIG = {
|
||||||
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
"dc_ip": ["2:149.154.167.220", "4:149.154.167.220"],
|
||||||
"verbose": False,
|
"verbose": False,
|
||||||
"autostart": False,
|
"autostart": False,
|
||||||
|
"log_max_mb": 5,
|
||||||
|
"buf_kb": 256,
|
||||||
|
"pool_size": 4,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
@ -148,12 +152,17 @@ def save_config(cfg: dict):
|
||||||
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
json.dump(cfg, f, indent=2, ensure_ascii=False)
|
||||||
|
|
||||||
|
|
||||||
def setup_logging(verbose: bool = False):
|
def setup_logging(verbose: bool = False, log_max_mb: float = 5):
|
||||||
_ensure_dirs()
|
_ensure_dirs()
|
||||||
root = logging.getLogger()
|
root = logging.getLogger()
|
||||||
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
root.setLevel(logging.DEBUG if verbose else logging.INFO)
|
||||||
|
|
||||||
fh = logging.FileHandler(str(LOG_FILE), encoding="utf-8")
|
fh = logging.handlers.RotatingFileHandler(
|
||||||
|
str(LOG_FILE),
|
||||||
|
maxBytes=max(32 * 1024, log_max_mb * 1024 * 1024),
|
||||||
|
backupCount=0,
|
||||||
|
encoding='utf-8',
|
||||||
|
)
|
||||||
fh.setLevel(logging.DEBUG)
|
fh.setLevel(logging.DEBUG)
|
||||||
fh.setFormatter(logging.Formatter(
|
fh.setFormatter(logging.Formatter(
|
||||||
"%(asctime)s %(levelname)-5s %(name)s %(message)s",
|
"%(asctime)s %(levelname)-5s %(name)s %(message)s",
|
||||||
|
|
@ -301,6 +310,13 @@ def start_proxy():
|
||||||
return
|
return
|
||||||
|
|
||||||
log.info("Starting proxy on %s:%d ...", host, port)
|
log.info("Starting proxy on %s:%d ...", host, port)
|
||||||
|
|
||||||
|
buf_kb = cfg.get("buf_kb", DEFAULT_CONFIG["buf_kb"])
|
||||||
|
pool_size = cfg.get("pool_size", DEFAULT_CONFIG["pool_size"])
|
||||||
|
tg_ws_proxy._RECV_BUF = max(4, buf_kb) * 1024
|
||||||
|
tg_ws_proxy._SEND_BUF = tg_ws_proxy._RECV_BUF
|
||||||
|
tg_ws_proxy._WS_POOL_SIZE = max(0, pool_size)
|
||||||
|
|
||||||
_proxy_thread = threading.Thread(
|
_proxy_thread = threading.Thread(
|
||||||
target=_run_proxy_thread,
|
target=_run_proxy_thread,
|
||||||
args=(port, dc_opt, verbose, host),
|
args=(port, dc_opt, verbose, host),
|
||||||
|
|
@ -395,7 +411,7 @@ def _edit_config_dialog():
|
||||||
TEXT_SECONDARY = "#707579"
|
TEXT_SECONDARY = "#707579"
|
||||||
FONT_FAMILY = "Segoe UI"
|
FONT_FAMILY = "Segoe UI"
|
||||||
|
|
||||||
w, h = 420, 460
|
w, h = 420, 540
|
||||||
|
|
||||||
if _supports_autostart():
|
if _supports_autostart():
|
||||||
h += 70
|
h += 70
|
||||||
|
|
@ -450,6 +466,30 @@ def _edit_config_dialog():
|
||||||
corner_radius=6, border_width=2,
|
corner_radius=6, border_width=2,
|
||||||
border_color=FIELD_BORDER).pack(anchor="w", pady=(0, 8))
|
border_color=FIELD_BORDER).pack(anchor="w", pady=(0, 8))
|
||||||
|
|
||||||
|
# Advanced: buf_kb, pool_size, log_max_mb
|
||||||
|
adv_frame = ctk.CTkFrame(frame, fg_color="transparent")
|
||||||
|
adv_frame.pack(anchor="w", fill="x", pady=(4, 8))
|
||||||
|
|
||||||
|
for col, (lbl, key, w_) in enumerate([
|
||||||
|
("Буфер (KB, 256 default)", "buf_kb", 120),
|
||||||
|
("WS пулов (4 default)", "pool_size", 120),
|
||||||
|
("Log size (MB, 5 def)", "log_max_mb", 120),
|
||||||
|
]):
|
||||||
|
col_frame = ctk.CTkFrame(adv_frame, fg_color="transparent")
|
||||||
|
col_frame.pack(side="left", padx=(0, 10))
|
||||||
|
ctk.CTkLabel(col_frame, text=lbl, font=(FONT_FAMILY, 11),
|
||||||
|
text_color=TEXT_SECONDARY, anchor="w").pack(anchor="w")
|
||||||
|
ctk.CTkEntry(col_frame, width=w_, height=30, font=(FONT_FAMILY, 12),
|
||||||
|
corner_radius=8, fg_color=FIELD_BG,
|
||||||
|
border_color=FIELD_BORDER, border_width=1,
|
||||||
|
text_color=TEXT_PRIMARY,
|
||||||
|
textvariable=ctk.StringVar(
|
||||||
|
value=str(cfg.get(key, DEFAULT_CONFIG[key]))
|
||||||
|
)).pack(anchor="w")
|
||||||
|
|
||||||
|
_adv_entries = list(adv_frame.winfo_children())
|
||||||
|
_adv_keys = ["buf_kb", "pool_size", "log_max_mb"]
|
||||||
|
|
||||||
autostart_var = None
|
autostart_var = None
|
||||||
if _supports_autostart():
|
if _supports_autostart():
|
||||||
autostart_var = ctk.BooleanVar(value=cfg["autostart"])
|
autostart_var = ctk.BooleanVar(value=cfg["autostart"])
|
||||||
|
|
@ -495,6 +535,17 @@ def _edit_config_dialog():
|
||||||
"verbose": verbose_var.get(),
|
"verbose": verbose_var.get(),
|
||||||
"autostart": (autostart_var.get() if autostart_var is not None else False),
|
"autostart": (autostart_var.get() if autostart_var is not None else False),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for i, key in enumerate(_adv_keys):
|
||||||
|
col_frame = _adv_entries[i]
|
||||||
|
entry = col_frame.winfo_children()[1]
|
||||||
|
try:
|
||||||
|
val = float(entry.get().strip())
|
||||||
|
if key in ("buf_kb", "pool_size"):
|
||||||
|
val = int(val)
|
||||||
|
new_cfg[key] = val
|
||||||
|
except ValueError:
|
||||||
|
new_cfg[key] = DEFAULT_CONFIG[key]
|
||||||
save_config(new_cfg)
|
save_config(new_cfg)
|
||||||
_config.update(new_cfg)
|
_config.update(new_cfg)
|
||||||
log.info("Config saved: %s", new_cfg)
|
log.info("Config saved: %s", new_cfg)
|
||||||
|
|
@ -740,7 +791,8 @@ def run_tray():
|
||||||
except Exception:
|
except Exception:
|
||||||
pass
|
pass
|
||||||
|
|
||||||
setup_logging(_config.get("verbose", False))
|
setup_logging(_config.get("verbose", False),
|
||||||
|
log_max_mb=_config.get("log_max_mb", DEFAULT_CONFIG["log_max_mb"]))
|
||||||
log.info("TG WS Proxy tray app starting")
|
log.info("TG WS Proxy tray app starting")
|
||||||
log.info("Config: %s", _config)
|
log.info("Config: %s", _config)
|
||||||
log.info("Log file: %s", LOG_FILE)
|
log.info("Log file: %s", LOG_FILE)
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue