Merge branch fix/provider-session-dispatch
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import hashlib
|
||||
import json
|
||||
import logging
|
||||
import socket
|
||||
import tempfile
|
||||
import unittest
|
||||
from pathlib import Path
|
||||
@@ -16,6 +17,7 @@ from unideskcprovider import (
|
||||
ProviderConfig,
|
||||
UiBus,
|
||||
UpdateManager,
|
||||
configure_tcp_keepalive,
|
||||
default_data_endpoint,
|
||||
encode_data_frame,
|
||||
parse_bridge_powershell_command,
|
||||
@@ -137,6 +139,11 @@ class ProtocolHelpersTest(unittest.TestCase):
|
||||
self.assertIn(b'"length":3', header)
|
||||
self.assertEqual(frame[-3:], b"abc")
|
||||
|
||||
def test_data_channel_enables_tcp_keepalive(self):
|
||||
value = MagicMock()
|
||||
configure_tcp_keepalive(value)
|
||||
value.setsockopt.assert_any_call(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
|
||||
def test_recycles_only_the_oldest_expired_idle_channel(self):
|
||||
manager = ProviderManager.__new__(ProviderManager)
|
||||
manager.state_lock = provider.threading.RLock()
|
||||
|
||||
@@ -48,7 +48,7 @@ else:
|
||||
|
||||
|
||||
APP_NAME = "UniDesk Windows Provider"
|
||||
APP_VERSION = "0.3.1"
|
||||
APP_VERSION = "0.3.2"
|
||||
CONFIG_DIR = Path.home() / ".unidesk"
|
||||
CONFIG_PATH = CONFIG_DIR / "provider.yaml"
|
||||
LOG_DIR = CONFIG_DIR / "logs"
|
||||
@@ -62,6 +62,9 @@ MAX_HEADER_BYTES = 64 * 1024
|
||||
MAX_PAYLOAD_BYTES = 16 * 1024 * 1024
|
||||
HEARTBEAT_SECONDS = 15
|
||||
DATA_CHANNEL_MAX_IDLE_SECONDS = 10 * 60
|
||||
TCP_KEEPALIVE_IDLE_SECONDS = 30
|
||||
TCP_KEEPALIVE_INTERVAL_SECONDS = 10
|
||||
TCP_KEEPALIVE_PROBES = 3
|
||||
DEFAULT_UPDATE_METADATA_URL = (
|
||||
"https://apps.hwpod.com/v1/unideskcprovider/update.json"
|
||||
)
|
||||
@@ -121,6 +124,24 @@ def default_data_endpoint(server: urllib.parse.ParseResult) -> tuple[str, int]:
|
||||
return server.hostname or "", port
|
||||
|
||||
|
||||
def configure_tcp_keepalive(value: socket.socket) -> None:
|
||||
value.setsockopt(socket.SOL_SOCKET, socket.SO_KEEPALIVE, 1)
|
||||
if os.name == "nt" and hasattr(socket, "SIO_KEEPALIVE_VALS"):
|
||||
value.ioctl(
|
||||
socket.SIO_KEEPALIVE_VALS,
|
||||
(1, TCP_KEEPALIVE_IDLE_SECONDS * 1000, TCP_KEEPALIVE_INTERVAL_SECONDS * 1000),
|
||||
)
|
||||
return
|
||||
for option_name, option_value in (
|
||||
("TCP_KEEPIDLE", TCP_KEEPALIVE_IDLE_SECONDS),
|
||||
("TCP_KEEPINTVL", TCP_KEEPALIVE_INTERVAL_SECONDS),
|
||||
("TCP_KEEPCNT", TCP_KEEPALIVE_PROBES),
|
||||
):
|
||||
option = getattr(socket, option_name, None)
|
||||
if option is not None:
|
||||
value.setsockopt(socket.IPPROTO_TCP, option, option_value)
|
||||
|
||||
|
||||
def version_key(value: str) -> tuple[int, ...]:
|
||||
if not isinstance(value, str) or not VERSION_PATTERN.fullmatch(value):
|
||||
raise ValueError(f"invalid update version: {value!r}")
|
||||
@@ -681,6 +702,7 @@ class DataChannel:
|
||||
reason = "data channel closed"
|
||||
try:
|
||||
self.socket = socket.create_connection((self.manager.config.data_host, self.manager.config.data_port), timeout=5)
|
||||
configure_tcp_keepalive(self.socket)
|
||||
self.socket.settimeout(1)
|
||||
self.write(
|
||||
{
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
{
|
||||
"schemaVersion": 1,
|
||||
"channel": "stable",
|
||||
"latestVersion": "0.3.1",
|
||||
"latestVersion": "0.3.2",
|
||||
"downloadUrl": "unideskcprovider.py",
|
||||
"bytes": 72278,
|
||||
"sha256": "075a41d81d551b5ef2b75aa7958a7cf38da3c2865bc999e79cc440c1b3b4195d",
|
||||
"releaseNotes": "主动轮换长期空闲 TCP 通道,修复托盘退出期间的日志控件异常,并保持 32 条 warm pool。"
|
||||
"bytes": 73147,
|
||||
"sha256": "5b98d5f18bed0c1b3efd736bc3f9464681d8610cee3ebca64f844abc402900bf",
|
||||
"releaseNotes": "为 32 条 warm pool 启用 Windows TCP keepalive,避免旧空闲通道在并发传输时被网络设备重置。"
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user