mirror of
https://github.com/Flowseal/tg-ws-proxy.git
synced 2026-07-04 12:21:07 +03:00
Compare commits
6 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| e9b74d7d7d | |||
| 050dcbce44 | |||
| 4f9edf3072 | |||
| 9ff95d1222 | |||
| 4c19a6cce4 | |||
| bb900e0c9e |
@@ -12,6 +12,31 @@ on:
|
||||
description: "Release version tag (e.g. v1.0.0)"
|
||||
required: false
|
||||
default: "v1.0.0"
|
||||
build_windows_x64:
|
||||
description: 'Build Windows x64?'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_windows_arm64:
|
||||
description: 'Build Windows ARM64?'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_win7:
|
||||
description: 'Build Windows 7 (x64 + x86)?'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_macos:
|
||||
description: 'Build macOS universal?'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
build_linux:
|
||||
description: 'Build Linux (amd64/.deb/.rpm)?'
|
||||
type: boolean
|
||||
required: false
|
||||
default: true
|
||||
|
||||
permissions:
|
||||
contents: write
|
||||
@@ -19,6 +44,7 @@ permissions:
|
||||
jobs:
|
||||
build-windows-x64:
|
||||
runs-on: windows-latest
|
||||
if: ${{ github.event.inputs.build_windows_x64 == 'true' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -78,6 +104,7 @@ jobs:
|
||||
|
||||
build-windows-arm64:
|
||||
runs-on: windows-11-arm
|
||||
if: ${{ github.event.inputs.build_windows_arm64 == 'true' }}
|
||||
env:
|
||||
CRYPTOGRAPHY_VERSION: "46.0.5"
|
||||
ARM64_WHEELHOUSE: wheelhouse-arm64
|
||||
@@ -154,6 +181,7 @@ jobs:
|
||||
|
||||
build-win7:
|
||||
runs-on: windows-latest
|
||||
if: ${{ github.event.inputs.build_win7 == 'true' }}
|
||||
strategy:
|
||||
matrix:
|
||||
include:
|
||||
@@ -207,6 +235,7 @@ jobs:
|
||||
|
||||
build-macos:
|
||||
runs-on: macos-latest
|
||||
if: ${{ github.event.inputs.build_macos == 'true' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -345,6 +374,7 @@ jobs:
|
||||
|
||||
build-linux:
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.build_linux == 'true' }}
|
||||
steps:
|
||||
- name: Checkout
|
||||
uses: actions/checkout@v6
|
||||
@@ -511,7 +541,13 @@ jobs:
|
||||
release:
|
||||
needs: [build-windows-x64, build-windows-arm64, build-win7, build-macos, build-linux]
|
||||
runs-on: ubuntu-latest
|
||||
if: ${{ github.event.inputs.make_release == 'true' }}
|
||||
if: >-
|
||||
${{ github.event.inputs.make_release == 'true'
|
||||
&& github.event.inputs.build_windows_x64 == 'true'
|
||||
&& github.event.inputs.build_windows_arm64 == 'true'
|
||||
&& github.event.inputs.build_win7 == 'true'
|
||||
&& github.event.inputs.build_macos == 'true'
|
||||
&& github.event.inputs.build_linux == 'true' }}
|
||||
steps:
|
||||
- uses: actions/download-artifact@v8
|
||||
with:
|
||||
@@ -525,7 +561,7 @@ jobs:
|
||||
tag_name: ${{ github.event.inputs.version }}
|
||||
name: "TG WS Proxy ${{ github.event.inputs.version }}"
|
||||
body: |
|
||||
##
|
||||
---
|
||||
### [❤️ Поддержать развитие проекта](https://github.com/Flowseal/tg-ws-proxy/blob/main/docs/Funding.md)
|
||||
|
||||
> [!TIP]
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
# http://msdn.microsoft.com/en-us/library/ms646997.aspx
|
||||
VSVersionInfo(
|
||||
ffi=FixedFileInfo(
|
||||
filevers=(1, 8, 0, 0),
|
||||
prodvers=(1, 8, 0, 0),
|
||||
filevers=(1, 8, 1, 0),
|
||||
prodvers=(1, 8, 1, 0),
|
||||
mask=0x3f,
|
||||
flags=0x0,
|
||||
OS=0x40004,
|
||||
@@ -21,12 +21,12 @@ VSVersionInfo(
|
||||
[
|
||||
StringStruct(u'CompanyName', u'Flowseal'),
|
||||
StringStruct(u'FileDescription', u'Telegram Desktop WebSocket Bridge Proxy'),
|
||||
StringStruct(u'FileVersion', u'1.8.0.0'),
|
||||
StringStruct(u'FileVersion', u'1.8.1.0'),
|
||||
StringStruct(u'InternalName', u'TgWsProxy'),
|
||||
StringStruct(u'LegalCopyright', u'Copyright (c) Flowseal. MIT License.'),
|
||||
StringStruct(u'OriginalFilename', u'TgWsProxy.exe'),
|
||||
StringStruct(u'ProductName', u'TG WS Proxy'),
|
||||
StringStruct(u'ProductVersion', u'1.8.0.0'),
|
||||
StringStruct(u'ProductVersion', u'1.8.1.0'),
|
||||
]
|
||||
)
|
||||
]
|
||||
|
||||
+1
-1
@@ -1,6 +1,6 @@
|
||||
from .config import parse_dc_ip_list, proxy_config, coerce_domain_list
|
||||
from .utils import get_link_host, build_github_opener
|
||||
|
||||
__version__ = "1.8.0"
|
||||
__version__ = "1.8.1"
|
||||
|
||||
__all__ = ["__version__", "get_link_host", "proxy_config", "parse_dc_ip_list", "build_github_opener", "coerce_domain_list"]
|
||||
+24
-12
@@ -33,13 +33,15 @@ from ._aes import Cipher, algorithms, modes
|
||||
|
||||
log = logging.getLogger('tg-mtproto-proxy')
|
||||
|
||||
DC_FAIL_COOLDOWN = 30.0
|
||||
IP_FAIL_COOLDOWN = 3600.0
|
||||
DC_FAIL_COOLDOWN = 60.0
|
||||
WS_FAIL_TIMEOUT = 2.0
|
||||
FRONTING_COOLDOWN = 1800.0
|
||||
LISTENER_CHECK_INTERVAL = 5.0
|
||||
LISTENER_RESTART_DELAY = 1.0
|
||||
ws_blacklist: Set[str] = set()
|
||||
dc_fail_until: Dict[str, float] = {}
|
||||
ip_fail_until: Dict[str, float] = {}
|
||||
fronting_until: float = 0.0
|
||||
|
||||
|
||||
@@ -295,15 +297,24 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
|
||||
dc_key = f'{dc}{"m" if is_media else ""}'
|
||||
media_tag = " media" if is_media else ""
|
||||
now = time.monotonic()
|
||||
target = proxy_config.dc_redirects.get(dc)
|
||||
is_any_cf_fallback = proxy_config.fallback_cfproxy or proxy_config.cfproxy_worker_domains
|
||||
|
||||
# Fallback if DC not in config, if WS blacklisted for this DC/is_media or if connect to ip is timed out
|
||||
if (dc not in proxy_config.dc_redirects
|
||||
or dc_key in ws_blacklist
|
||||
or now < ip_fail_until.get(target, 0) and is_any_cf_fallback):
|
||||
|
||||
# Fallback if DC not in config or WS blacklisted for this DC/is_media
|
||||
if dc not in proxy_config.dc_redirects or dc_key in ws_blacklist:
|
||||
if dc not in proxy_config.dc_redirects:
|
||||
log.info("[%s] DC%d not in config -> fallback",
|
||||
label, dc)
|
||||
else:
|
||||
elif dc_key in ws_blacklist:
|
||||
log.info("[%s] DC%d%s WS blacklisted -> fallback",
|
||||
label, dc, media_tag)
|
||||
else:
|
||||
log.info("[%s] DC%d%s WS connect to %s was timed out -> fallback",
|
||||
label, dc, media_tag, target)
|
||||
splitter = None
|
||||
try:
|
||||
splitter = MsgSplitter(relay_init, proto_int)
|
||||
@@ -318,13 +329,10 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
label, dc, media_tag)
|
||||
return
|
||||
|
||||
now = time.monotonic()
|
||||
fail_until = dc_fail_until.get(dc_key, 0)
|
||||
ws_timeout = WS_FAIL_TIMEOUT if now < fail_until else 10.0
|
||||
ws_timeout = WS_FAIL_TIMEOUT if now < dc_fail_until.get(dc_key, 0) else 5.0
|
||||
fronting_active = now < fronting_until
|
||||
|
||||
domains = ws_domains(dc, is_media)
|
||||
target = proxy_config.dc_redirects[dc]
|
||||
ws = None
|
||||
ws_failed_redirect = False
|
||||
ws_timed_out = False
|
||||
@@ -340,7 +348,7 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
label, dc, media_tag, domains[0])
|
||||
try:
|
||||
ws = await RawWebSocket.connect(target, domains[0],
|
||||
timeout=10.0,
|
||||
timeout=5.0,
|
||||
sni="sprinthost.ru")
|
||||
except Exception as exc:
|
||||
stats.ws_errors += 1
|
||||
@@ -381,6 +389,7 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
ws_timed_out = True
|
||||
log.warning("[%s] DC%d%s WS connect timed out via %s",
|
||||
label, dc, media_tag, domain)
|
||||
break
|
||||
except Exception as exc:
|
||||
stats.ws_errors += 1
|
||||
all_redirects = False
|
||||
@@ -395,7 +404,7 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
label, dc, media_tag, domains[0])
|
||||
try:
|
||||
ws = await RawWebSocket.connect(target, domains[0],
|
||||
timeout=10.0,
|
||||
timeout=5.0,
|
||||
sni="sprinthost.ru")
|
||||
except Exception as exc:
|
||||
stats.ws_errors += 1
|
||||
@@ -410,6 +419,9 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
|
||||
# WS failed -> fallback
|
||||
if ws is None:
|
||||
if ws_timed_out:
|
||||
ip_fail_until[target] = now + IP_FAIL_COOLDOWN
|
||||
|
||||
if ws_failed_redirect and all_redirects:
|
||||
ws_blacklist.add(dc_key)
|
||||
log.warning("[%s] DC%d%s blacklisted for WS (all 302)",
|
||||
@@ -418,8 +430,6 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
dc_fail_until[dc_key] = now + DC_FAIL_COOLDOWN
|
||||
else:
|
||||
dc_fail_until[dc_key] = now + DC_FAIL_COOLDOWN
|
||||
# TODO: may be don't try regular WS connection and do fallback instanstly
|
||||
# instead of waiting for WS_FAIL_TIMEOUT and then fallback
|
||||
log.info("[%s] DC%d%s WS cooldown for %ds",
|
||||
label, dc, media_tag, int(DC_FAIL_COOLDOWN))
|
||||
|
||||
@@ -438,6 +448,7 @@ async def _handle_client(reader, writer, secret: bytes):
|
||||
return
|
||||
|
||||
dc_fail_until.pop(dc_key, None)
|
||||
ip_fail_until.pop(target, None)
|
||||
stats.connections_ws += 1
|
||||
|
||||
splitter = None
|
||||
@@ -491,6 +502,7 @@ async def _run(stop_event: Optional[asyncio.Event] = None):
|
||||
cf_worker_pool.reset()
|
||||
ws_blacklist.clear()
|
||||
dc_fail_until.clear()
|
||||
ip_fail_until.clear()
|
||||
_client_tasks.clear()
|
||||
fronting_until = 0.0
|
||||
|
||||
|
||||
+4
-1
@@ -25,7 +25,10 @@ class LocaleEnum(str, Enum):
|
||||
return _DEFAULT_LOCALE
|
||||
|
||||
|
||||
_LOCALES_DIR = Path(__file__).resolve().parent
|
||||
try:
|
||||
_LOCALES_DIR = Path(__file__).resolve(strict=False).parent
|
||||
except OSError:
|
||||
_LOCALES_DIR = Path(os.path.realpath(__file__)).parent
|
||||
_DEFAULT_LOCALE = LocaleEnum.english
|
||||
|
||||
_translations: Dict[str, str] = {}
|
||||
|
||||
@@ -41,7 +41,10 @@ def _exe_dir() -> Optional[Path]:
|
||||
return None
|
||||
if not base:
|
||||
return None
|
||||
p = Path(base).resolve()
|
||||
try:
|
||||
p = Path(base).resolve(strict=False)
|
||||
except OSError:
|
||||
p = Path(os.path.realpath(base))
|
||||
return p.parent if p.is_file() else p
|
||||
|
||||
|
||||
|
||||
Reference in New Issue
Block a user