Metadata-Version: 2.4
Name: s-xray-gate
Version: 0.2.1
Summary: Единый VLESS/Trojan-шлюз (xray-core): не-RU egress со smart-routing для проброса прокси в любой проект/сервис; обход гео-блокировок и РКН-DPI. Импорт подписки (multi-UA), авто-обновление, пинг/выбор лучших нод, пул именованных инстансов (PIN/BAL) с разметкой по подписке, self-heal, autostart; фасад Gateway + адаптеры httpx/requests/playwright/telethon.
Author: Dmitry
License: MIT
License-File: LICENSE
Keywords: egress,geo-bypass,proxy,reality,socks5,subscription,vless,xray
Classifier: Environment :: Console
Classifier: License :: OSI Approved :: MIT License
Classifier: Operating System :: OS Independent
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Programming Language :: Python :: 3.13
Classifier: Topic :: Internet :: Proxy Servers
Classifier: Topic :: System :: Networking
Requires-Python: >=3.11
Requires-Dist: s-clikit>=0.1.0
Requires-Dist: s-librarykit>=0.1.8
Provides-Extra: adapters
Requires-Dist: httpx[socks]>=0.27; extra == 'adapters'
Requires-Dist: requests[socks]>=2.31; extra == 'adapters'
Provides-Extra: dev
Requires-Dist: pytest>=8; extra == 'dev'
Provides-Extra: socks
Requires-Dist: httpx[socks]>=0.27; extra == 'socks'
Requires-Dist: pysocks>=1.7; extra == 'socks'
Description-Content-Type: text/markdown

# sh-xray — единый VPN-шлюз (skill-hub xray) для всех AI-навыков

Один общий SOCKS5-прокси (xray-core) с НЕ-российской нодой и smart-routing
(РУ/CN → напрямую, остальное → за рубеж). Пишет общий указатель
**`~/.sh-xray.json`**, который читают ВСЕ навыки (паттерн `open_client._apply_proxy`).
Системный трафик НЕ трогает (только opt-in инструменты через `ALL_PROXY`) — РУ-сервисы не ломаются.

## Команды
CLI `xray-gate` — на [clikit](https://gitlab.com/S-kits/clikit) (даёт `--json`/`--help`/`--version`):
```
xray-gate install            # xray binary + geoip/geosite (качает с GitHub-релиза XTLS/Xray-core)
xray-gate test               # выбрать рабочую НЕ-RU ноду (проверка реального выхода через ipinfo.io)
xray-gate start [--port N]   # поднять + записать ~/.sh-xray.json (порт по умолч. 10810)
xray-gate status             # alive + live exit country
xray-gate stop
xray-gate ensure             # self-heal: поднять, если процесс умер (после reboot/краша)
xray-gate autostart          # Windows Task Scheduler: ensure каждые 10 мин (переживает reboot)
xray-gate autostart --remove
xray-gate add-sub <url>      # своя VLESS-подписка (vless/base64; авто-обновление по интервалу подписки)
```
Без установки китов (свежая машина, handoff-бандл) — тот же набор через **dep-free ядро**:
`python xray_gate/_core.py <команда>` (чистый stdlib, никаких зависимостей). Именно его
дёргает watchdog (`ensure` каждые 10 мин), чтобы self-heal не зависел от китов.

## Построен на Китах (S-kits)
sh-xray — НЕ кит, а супернавык/сервис, который *строится* на [китах](https://gitlab.com/S-kits):
**clikit** даёт человеческий CLI (`xray_gate/cli.py`), **librarykit.config_util** — атомарную
запись общих указателей (`~/.sh-xray.json`, `~/.sh-gateway.json`). Ядро-движок
(`xray_gate/_core.py`, бывший top-level `gateway.py`) намеренно остаётся на чистом stdlib —
у обоих kit-обращений есть stdlib-фолбэк, поэтому self-heal работает даже без китов.
gateway-роутер потребляет egress sh-xray через свой `ProxyProvider` (читает `~/.sh-xray.json`).

## Переживает перезагрузку
`autostart` ставит задачу планировщика (`ensure` каждые 10 мин, `StartWhenAvailable`). После reboot
старый pid мёртв → `ensure` поднимает xray заново (при старте/в течение ~10 мин). `~/.sh-xray.json`
обновляется новым pid, все навыки снова ходят через прокси. Без `autostart` — поднимать вручную `start`.

## Общий указатель `~/.xray-gate/state.json`
```json
{"http_proxy": "http://127.0.0.1:10811", "all_proxy": "socks5h://127.0.0.1:10810", "node": "...", "backend": "xray-gate"}
```
Потребители читают его и ходят через ОДИН egress (важно: один IP для логина И API, иначе Google убивает сессию).
Всё хозяйство рантайма — под `~/.xray-gate/` (state.json/routing.json/byedpi/zapret/бинарь).

## Потребление в проектах (egress «из коробки»)
xray-gate — **источник пути** (его знает он, не нейтральный librarykit-корень). Потребитель ставит
его как egress-расширение и берёт прокси у его адаптеров. Установка (на PyPI НЕТ — из git):
```bash
uv add --optional egress "s-xray-gate @ git+https://gitlab.com/s-skills/s-xray-gate.git"  # запишет в pyproject+lock
uv sync --extra egress                                   # или: pip install git+https://gitlab.com/s-skills/s-xray-gate.git
```
4 способа взять прокси (нет указателя/шлюз не поднят → `None` → проект идёт напрямую):
```python
import xray_gate.adapters as eg
httpx.Client(proxy=eg.httpx_proxy())                       # socks5h://127.0.0.1:10810
sess = eg.requests_session()                                # requests.Session с прокси
browser.launch(proxy=eg.playwright_proxy())                 # {"server":"socks5://..."}
TelegramClient(s, api_id, api_hash, proxy=eg.telethon_proxy())

# через нейтральный librarykit-транспорт (проект на китах):
from librarykit import HttpClient, HttpxTransport
HttpClient(HttpxTransport(proxy=eg.httpx_proxy()), auth, errmap)

# env-wide (subprocess/curl/любой ALL_PROXY-клиент):
from xray_gate import apply_to_env; apply_to_env("notebooklm")   # по карте ~/.xray-gate/routing.json

# zero-dep (без установки пакета — просто JSON):
import json, pathlib
proxy = json.loads((pathlib.Path.home()/".xray-gate"/"state.json").read_text())["all_proxy"]
```
Реальный пример-потребитель — bublictr (`adapters/_common/browser.py`): `BUBLICTR_BROWSER_PROXY=shxray`
→ `xray_gate.adapters.playwright_proxy()`.

## Портативность / другие устройства
`install` качает xray-core сам. `add-sub <url>` + `test` подберёт не-RU ноду. Так работает на любой машине/агенте.

## Замечание по нодам
Качество зависит от подписки. Нестабильная нода → таймауты (xray ретраит, но лучше иметь несколько не-RU нод).
`status` показывает live exit; `test` перевыбирает рабочую.
