trqsh 0.1.1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- trqsh/__init__.py +8 -0
- trqsh/__main__.py +22 -0
- trqsh/_runtime.py +132 -0
- trqsh-0.1.1.dist-info/METADATA +55 -0
- trqsh-0.1.1.dist-info/RECORD +7 -0
- trqsh-0.1.1.dist-info/WHEEL +4 -0
- trqsh-0.1.1.dist-info/entry_points.txt +2 -0
trqsh/__init__.py
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
"""trqsh — expose localhost to the internet.
|
|
2
|
+
|
|
3
|
+
This PyPI package is a thin wrapper that fetches the prebuilt ``trqsh`` CLI
|
|
4
|
+
binary for your platform (from the GitHub release) and execs it. The real
|
|
5
|
+
program is the Go binary; see https://trqsh.uz.
|
|
6
|
+
"""
|
|
7
|
+
|
|
8
|
+
__version__ = "0.1.1"
|
trqsh/__main__.py
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"""Console entry point: exec the real trqsh binary with the caller's arguments."""
|
|
2
|
+
|
|
3
|
+
from __future__ import annotations
|
|
4
|
+
|
|
5
|
+
import os
|
|
6
|
+
import subprocess
|
|
7
|
+
import sys
|
|
8
|
+
|
|
9
|
+
from ._runtime import ensure_binary
|
|
10
|
+
|
|
11
|
+
|
|
12
|
+
def main() -> None:
|
|
13
|
+
binary = str(ensure_binary())
|
|
14
|
+
args = [binary, *sys.argv[1:]]
|
|
15
|
+
if os.name == "nt":
|
|
16
|
+
# os.execv on Windows doesn't preserve the console cleanly; use subprocess.
|
|
17
|
+
sys.exit(subprocess.run(args).returncode)
|
|
18
|
+
os.execv(binary, args)
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
if __name__ == "__main__":
|
|
22
|
+
main()
|
trqsh/_runtime.py
ADDED
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
"""Locate (or download) the prebuilt trqsh binary for the current platform.
|
|
2
|
+
|
|
3
|
+
The archive names mirror the goreleaser template
|
|
4
|
+
``trqsh_<version>_<os>_<arch>.<ext>`` (.zip on Windows, .tar.gz elsewhere),
|
|
5
|
+
downloaded from the GitHub release and verified against ``checksums.txt``. Only
|
|
6
|
+
the Python standard library is used.
|
|
7
|
+
"""
|
|
8
|
+
|
|
9
|
+
from __future__ import annotations
|
|
10
|
+
|
|
11
|
+
import hashlib
|
|
12
|
+
import os
|
|
13
|
+
import platform
|
|
14
|
+
import stat
|
|
15
|
+
import sys
|
|
16
|
+
import tarfile
|
|
17
|
+
import tempfile
|
|
18
|
+
import urllib.request
|
|
19
|
+
import zipfile
|
|
20
|
+
from pathlib import Path
|
|
21
|
+
|
|
22
|
+
from . import __version__
|
|
23
|
+
|
|
24
|
+
REPO = os.environ.get("TRQSH_REPO", "trqsh-uz/downloads")
|
|
25
|
+
VERSION = os.environ.get("TRQSH_VERSION", __version__)
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def _target() -> tuple[str, str, str]:
|
|
29
|
+
goos = {"darwin": "darwin", "linux": "linux", "windows": "windows"}.get(
|
|
30
|
+
platform.system().lower()
|
|
31
|
+
)
|
|
32
|
+
goarch = {
|
|
33
|
+
"x86_64": "amd64",
|
|
34
|
+
"amd64": "amd64",
|
|
35
|
+
"arm64": "arm64",
|
|
36
|
+
"aarch64": "arm64",
|
|
37
|
+
}.get(platform.machine().lower())
|
|
38
|
+
if not goos or not goarch:
|
|
39
|
+
raise SystemExit(
|
|
40
|
+
f"trqsh: unsupported platform {platform.system()}/{platform.machine()}. "
|
|
41
|
+
f"Download manually from https://github.com/{REPO}/releases"
|
|
42
|
+
)
|
|
43
|
+
ext = "zip" if goos == "windows" else "tar.gz"
|
|
44
|
+
return goos, goarch, ext
|
|
45
|
+
|
|
46
|
+
|
|
47
|
+
def _bin_name() -> str:
|
|
48
|
+
return "trqsh.exe" if platform.system() == "Windows" else "trqsh"
|
|
49
|
+
|
|
50
|
+
|
|
51
|
+
def _cache_dir() -> Path:
|
|
52
|
+
base = os.environ.get("XDG_CACHE_HOME") or (Path.home() / ".cache")
|
|
53
|
+
d = Path(base) / "trqsh" / VERSION
|
|
54
|
+
d.mkdir(parents=True, exist_ok=True)
|
|
55
|
+
return d
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def bin_path() -> Path:
|
|
59
|
+
return _cache_dir() / _bin_name()
|
|
60
|
+
|
|
61
|
+
|
|
62
|
+
def _download(url: str) -> bytes:
|
|
63
|
+
req = urllib.request.Request(url, headers={"User-Agent": "trqsh-pypi-installer"})
|
|
64
|
+
with urllib.request.urlopen(req) as resp: # noqa: S310 (trusted GitHub host)
|
|
65
|
+
return resp.read()
|
|
66
|
+
|
|
67
|
+
|
|
68
|
+
def _verify(data: bytes, archive: str, base: str) -> None:
|
|
69
|
+
if os.environ.get("TRQSH_SKIP_CHECKSUM") == "1":
|
|
70
|
+
return
|
|
71
|
+
try:
|
|
72
|
+
sums = _download(f"{base}/checksums.txt").decode()
|
|
73
|
+
except Exception as exc: # noqa: BLE001
|
|
74
|
+
print(f"trqsh: warning — could not fetch checksums.txt ({exc}); skipping verify", file=sys.stderr)
|
|
75
|
+
return
|
|
76
|
+
want = None
|
|
77
|
+
for line in sums.splitlines():
|
|
78
|
+
parts = line.split()
|
|
79
|
+
if len(parts) == 2 and parts[1].lstrip("*") == archive:
|
|
80
|
+
want = parts[0].lower()
|
|
81
|
+
break
|
|
82
|
+
if not want:
|
|
83
|
+
print(f"trqsh: warning — {archive} absent from checksums.txt; skipping verify", file=sys.stderr)
|
|
84
|
+
return
|
|
85
|
+
got = hashlib.sha256(data).hexdigest()
|
|
86
|
+
if got != want:
|
|
87
|
+
raise SystemExit(f"trqsh: checksum mismatch for {archive}\n expected {want}\n got {got}")
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
def _extract(archive_path: Path, ext: str, dest: Path) -> None:
|
|
91
|
+
if ext == "zip":
|
|
92
|
+
with zipfile.ZipFile(archive_path) as zf:
|
|
93
|
+
zf.extractall(dest)
|
|
94
|
+
else:
|
|
95
|
+
with tarfile.open(archive_path) as tf:
|
|
96
|
+
try:
|
|
97
|
+
tf.extractall(dest, filter="data") # py3.12+ safe extraction
|
|
98
|
+
except TypeError:
|
|
99
|
+
tf.extractall(dest)
|
|
100
|
+
|
|
101
|
+
|
|
102
|
+
def ensure_binary() -> Path:
|
|
103
|
+
"""Return the path to the trqsh binary, downloading it once if needed."""
|
|
104
|
+
target = bin_path()
|
|
105
|
+
if target.exists():
|
|
106
|
+
return target
|
|
107
|
+
|
|
108
|
+
goos, goarch, ext = _target()
|
|
109
|
+
archive = f"trqsh_{VERSION}_{goos}_{goarch}.{ext}"
|
|
110
|
+
# Overridable (TRQSH_DOWNLOAD_BASE) for mirrors, air-gapped installs, or tests.
|
|
111
|
+
base = os.environ.get("TRQSH_DOWNLOAD_BASE") or f"https://github.com/{REPO}/releases/download/v{VERSION}"
|
|
112
|
+
|
|
113
|
+
print(f"trqsh: downloading {archive} (v{VERSION})...", file=sys.stderr)
|
|
114
|
+
data = _download(f"{base}/{archive}")
|
|
115
|
+
_verify(data, archive, base)
|
|
116
|
+
|
|
117
|
+
tmp = Path(tempfile.mkdtemp())
|
|
118
|
+
archive_path = tmp / archive
|
|
119
|
+
archive_path.write_bytes(data)
|
|
120
|
+
_extract(archive_path, ext, _cache_dir())
|
|
121
|
+
|
|
122
|
+
if not target.exists():
|
|
123
|
+
for found in _cache_dir().rglob(target.name):
|
|
124
|
+
found.replace(target)
|
|
125
|
+
break
|
|
126
|
+
if not target.exists():
|
|
127
|
+
raise SystemExit("trqsh: binary not found after extraction")
|
|
128
|
+
|
|
129
|
+
if os.name != "nt":
|
|
130
|
+
target.chmod(target.stat().st_mode | stat.S_IEXEC | stat.S_IXGRP | stat.S_IXOTH)
|
|
131
|
+
print("trqsh: installed ✓", file=sys.stderr)
|
|
132
|
+
return target
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: trqsh
|
|
3
|
+
Version: 0.1.1
|
|
4
|
+
Summary: Expose localhost to the internet — fast QUIC tunnels with a desktop app. Installs the trqsh CLI binary for your platform.
|
|
5
|
+
Project-URL: Homepage, https://trqsh.uz
|
|
6
|
+
Project-URL: Documentation, https://trqsh.uz/docs
|
|
7
|
+
Project-URL: Source, https://github.com/trqsh/trqsh
|
|
8
|
+
Project-URL: Issues, https://github.com/trqsh/trqsh/issues
|
|
9
|
+
Author-email: trqsh <ops@trqsh.uz>
|
|
10
|
+
License-Expression: Apache-2.0
|
|
11
|
+
Keywords: http3,localhost,ngrok-alternative,quic,trqsh,tunnel,webhook
|
|
12
|
+
Classifier: Development Status :: 4 - Beta
|
|
13
|
+
Classifier: Environment :: Console
|
|
14
|
+
Classifier: Intended Audience :: Developers
|
|
15
|
+
Classifier: Operating System :: MacOS
|
|
16
|
+
Classifier: Operating System :: Microsoft :: Windows
|
|
17
|
+
Classifier: Operating System :: POSIX :: Linux
|
|
18
|
+
Classifier: Programming Language :: Python :: 3
|
|
19
|
+
Classifier: Topic :: Internet :: Proxy Servers
|
|
20
|
+
Classifier: Topic :: Software Development :: Testing
|
|
21
|
+
Requires-Python: >=3.8
|
|
22
|
+
Description-Content-Type: text/markdown
|
|
23
|
+
|
|
24
|
+
# trqsh (PyPI)
|
|
25
|
+
|
|
26
|
+
Install the [trqsh](https://trqsh.uz) CLI with pip. This package fetches the
|
|
27
|
+
signed, prebuilt binary for your platform from the GitHub release on first run.
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
pip install trqsh
|
|
31
|
+
# or, isolated:
|
|
32
|
+
pipx install trqsh
|
|
33
|
+
|
|
34
|
+
trqsh http 3000 # expose localhost:3000 over a public HTTPS URL
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
## How it works
|
|
38
|
+
|
|
39
|
+
The console script `trqsh` calls `trqsh.ensure_binary()`, which detects your OS
|
|
40
|
+
(`darwin`/`linux`/`windows`) and CPU (`amd64`/`arm64`), downloads
|
|
41
|
+
`trqsh_<version>_<os>_<arch>.<ext>` from
|
|
42
|
+
`https://github.com/trqsh/trqsh/releases`, verifies its SHA-256 against
|
|
43
|
+
`checksums.txt`, caches the binary under `~/.cache/trqsh/<version>/`, and execs
|
|
44
|
+
it. Pure standard library — no runtime dependencies.
|
|
45
|
+
|
|
46
|
+
## Environment overrides
|
|
47
|
+
|
|
48
|
+
| Variable | Purpose |
|
|
49
|
+
|---|---|
|
|
50
|
+
| `TRQSH_VERSION` | Pin a specific release (defaults to the package version). |
|
|
51
|
+
| `TRQSH_REPO` | Alternate `owner/repo` for the release download. |
|
|
52
|
+
| `TRQSH_DOWNLOAD_BASE` | Full base URL of a mirror serving the release assets (for air-gapped/internal mirrors). |
|
|
53
|
+
| `TRQSH_SKIP_CHECKSUM=1` | Skip SHA-256 verification (not recommended). |
|
|
54
|
+
|
|
55
|
+
Licensed Apache-2.0.
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
trqsh/__init__.py,sha256=0ndFNaVarZZrW22AVBXDa3YG7Tx1Aj16U54ya_iuifk,273
|
|
2
|
+
trqsh/__main__.py,sha256=6NLkSrBSCZ29-5CwE1E3MDhPaoAYtSO9NxPkC838gMA,512
|
|
3
|
+
trqsh/_runtime.py,sha256=XOhMlJfW5BLgFgfq1U4WLZl4cgVN-GSCvwFmle4-wFo,4304
|
|
4
|
+
trqsh-0.1.1.dist-info/METADATA,sha256=TgvQ7mM3zwCI_-Qze__ZwTRcKCXGs0xPQRy6epv_I-o,2135
|
|
5
|
+
trqsh-0.1.1.dist-info/WHEEL,sha256=lCkmxWfQsSc9CfIClYeavTdQeEX2toPqufh9gI35EQA,87
|
|
6
|
+
trqsh-0.1.1.dist-info/entry_points.txt,sha256=8Qs_xqNviQgcpJt29tpQYRJqM18qyw3nqSOd0IyeW4I,46
|
|
7
|
+
trqsh-0.1.1.dist-info/RECORD,,
|