Initial commit
This commit is contained in:
@@ -0,0 +1,17 @@
|
||||
# Launcher build tool
|
||||
|
||||
`install.ps1` downloads a portable Node.js 20 LTS into `node/` and runs the
|
||||
full build pipeline (`npm install --ignore-scripts`, Electron binary install,
|
||||
`electron-builder install-app-deps`, `npm run build`, `npm run pack`).
|
||||
|
||||
Use this instead of a global Node install to avoid the ClangCL / Node version
|
||||
issues documented in the repo root `BUILD.md`.
|
||||
|
||||
```powershell
|
||||
cd Tools\launcher
|
||||
.\install.ps1
|
||||
```
|
||||
|
||||
Output: `dist\OctoLauncher.exe` (portable) and `dist\OctoLauncher_Installer.exe` (NSIS).
|
||||
|
||||
The `node/` directory is gitignored — it is recreated by `install.ps1`.
|
||||
@@ -0,0 +1,71 @@
|
||||
$ErrorActionPreference = 'Stop'
|
||||
|
||||
$here = Split-Path -Parent $MyInvocation.MyCommand.Path
|
||||
$nodeDir = Join-Path $here 'node'
|
||||
$mainDir = Split-Path -Parent (Split-Path -Parent $here)
|
||||
$distDir = Join-Path $mainDir 'dist'
|
||||
|
||||
$nodeVersion = '20.18.1'
|
||||
$nodeZipName = "node-v$nodeVersion-win-x64.zip"
|
||||
$nodeUrl = "https://nodejs.org/dist/v$nodeVersion/$nodeZipName"
|
||||
$nodeExe = Join-Path $nodeDir "node-v$nodeVersion-win-x64\node.exe"
|
||||
|
||||
if (Test-Path $nodeExe) {
|
||||
Write-Host "Node.js already present at $nodeExe." -ForegroundColor Yellow
|
||||
} else {
|
||||
if (-not (Test-Path $nodeDir)) { New-Item -ItemType Directory -Path $nodeDir | Out-Null }
|
||||
$zipPath = Join-Path $nodeDir $nodeZipName
|
||||
Write-Host "Downloading Node.js $nodeVersion (~30 MB)..." -ForegroundColor Cyan
|
||||
Invoke-WebRequest -Uri $nodeUrl -OutFile $zipPath -UseBasicParsing
|
||||
Write-Host "Extracting to $nodeDir..." -ForegroundColor Cyan
|
||||
Expand-Archive -Path $zipPath -DestinationPath $nodeDir -Force
|
||||
Remove-Item $zipPath
|
||||
}
|
||||
|
||||
$nodeBinDir = Split-Path -Parent $nodeExe
|
||||
$env:PATH = "$nodeBinDir;$env:PATH"
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "node : $(& $nodeExe --version)" -ForegroundColor Green
|
||||
Write-Host "npm : $(& (Join-Path $nodeBinDir 'npm.cmd') --version)" -ForegroundColor Green
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Building Electron launcher at $mainDir..." -ForegroundColor Cyan
|
||||
Push-Location $mainDir
|
||||
try {
|
||||
if (-not (Test-Path (Join-Path $mainDir 'node_modules'))) {
|
||||
Write-Host "[npm] install --ignore-scripts (JS packages only)" -ForegroundColor Cyan
|
||||
& (Join-Path $nodeBinDir 'npm.cmd') install --ignore-scripts --no-audit --no-fund
|
||||
if ($LASTEXITCODE -ne 0) { throw "npm install failed" }
|
||||
|
||||
Write-Host "[electron] install binary" -ForegroundColor Cyan
|
||||
& $nodeExe (Join-Path $mainDir 'node_modules\electron\install.js')
|
||||
if ($LASTEXITCODE -ne 0) { throw "electron install failed" }
|
||||
|
||||
Write-Host "[electron-builder] install-app-deps (native modules)" -ForegroundColor Cyan
|
||||
& (Join-Path $mainDir 'node_modules\.bin\electron-builder.cmd') install-app-deps
|
||||
if ($LASTEXITCODE -ne 0) { throw "electron-builder install-app-deps failed" }
|
||||
} else {
|
||||
Write-Host "node_modules already exists - skipping npm install (delete it to force reinstall)." -ForegroundColor Yellow
|
||||
}
|
||||
|
||||
Write-Host "[npm] run build (electron-vite)" -ForegroundColor Cyan
|
||||
& (Join-Path $nodeBinDir 'npm.cmd') run build
|
||||
if ($LASTEXITCODE -ne 0) { throw "npm run build failed" }
|
||||
|
||||
Write-Host "[npm] run pack (electron-builder -> dist\)" -ForegroundColor Cyan
|
||||
& (Join-Path $nodeBinDir 'npm.cmd') run pack
|
||||
if ($LASTEXITCODE -ne 0) { throw "npm run pack failed" }
|
||||
} finally {
|
||||
Pop-Location
|
||||
}
|
||||
|
||||
Write-Host ""
|
||||
Write-Host "Done." -ForegroundColor Green
|
||||
if (Test-Path $distDir) {
|
||||
Get-ChildItem $distDir -Filter '*.exe' | ForEach-Object {
|
||||
$size = [math]::Round($_.Length / 1MB, 1)
|
||||
Write-Host " $($_.FullName) ($size MB)" -ForegroundColor Green
|
||||
}
|
||||
}
|
||||
Write-Host ""
|
||||
@@ -0,0 +1,66 @@
|
||||
# opentracker — OctoWow launcher torrent swarm
|
||||
|
||||
BitTorrent tracker the launcher's webtorrent clients announce to. Runs
|
||||
on your VPS alongside the companion update server. Tiny (~2 MB RSS),
|
||||
near-zero CPU, zero disk IO after boot.
|
||||
|
||||
**Why your own tracker**: public trackers (opentrackr.org, etc.) are
|
||||
reliable enough for hobby swarms but add a single-point-of-failure you
|
||||
don't control, and often rate-limit new info-hashes. The launcher also
|
||||
announces over DHT, so your tracker is redundant with DHT — but it's
|
||||
the fastest path for a fresh peer to find the swarm before DHT has
|
||||
warmed up.
|
||||
|
||||
## Deploy (VPS, Linux)
|
||||
|
||||
SSH into the VPS, clone this repo, run:
|
||||
|
||||
```
|
||||
cd Tools/launcher/tracker
|
||||
chmod +x install.sh
|
||||
./install.sh
|
||||
```
|
||||
|
||||
`install.sh` is idempotent — re-run to update. It builds opentracker
|
||||
from CVS (only distribution upstream offers), installs it under
|
||||
`/opt/opentracker/bin/`, drops a hardened systemd unit, and starts the
|
||||
service bound to `0.0.0.0:6969`.
|
||||
|
||||
**Firewall**: open `6969/tcp` + `6969/udp`. On a typical Ubuntu VPS
|
||||
with ufw: `sudo ufw allow 6969`.
|
||||
|
||||
## Verify
|
||||
|
||||
```
|
||||
sudo systemctl status opentracker
|
||||
curl http://127.0.0.1:6969/stats?mode=tpbs # shows torrents / peers / bytes
|
||||
```
|
||||
|
||||
The launcher's webtorrent client will announce to this URL the moment
|
||||
a dev runs the companion server with `TRACKER_URL` set to match.
|
||||
|
||||
## Wire the companion server to use this tracker
|
||||
|
||||
Set the `TRACKER_URL` env var when running the companion server so
|
||||
every `.torrent` it generates announces to your VPS:
|
||||
|
||||
```
|
||||
TRACKER_URL=http://<your-vps-ip>:6969/announce npm run server
|
||||
```
|
||||
|
||||
Default is `http://127.0.0.1:6969/announce` (assumes tracker + companion
|
||||
server run on the same VPS, which is the normal deployment).
|
||||
|
||||
Clients pull the `.torrent` blob from the companion server — the URL
|
||||
is already baked in by `create-torrent` at generation time, so no
|
||||
launcher-side config needed.
|
||||
|
||||
## Uninstall
|
||||
|
||||
```
|
||||
sudo systemctl stop opentracker
|
||||
sudo systemctl disable opentracker
|
||||
sudo rm /etc/systemd/system/opentracker.service
|
||||
sudo rm -rf /opt/opentracker
|
||||
sudo userdel opentracker
|
||||
```
|
||||
@@ -0,0 +1,42 @@
|
||||
set -euo pipefail
|
||||
|
||||
INSTALL_PREFIX="${INSTALL_PREFIX:-/opt/opentracker}"
|
||||
BUILD_DIR="$(mktemp -d)"
|
||||
trap "rm -rf $BUILD_DIR" EXIT
|
||||
|
||||
echo "=== Installing build deps ==="
|
||||
sudo apt-get update
|
||||
sudo apt-get install -y build-essential cvs zlib1g-dev
|
||||
|
||||
echo "=== Fetching libowfat ==="
|
||||
cd "$BUILD_DIR"
|
||||
cvs -d :pserver:cvs@cvs.fefe.de:/cvs -z9 co libowfat
|
||||
cd libowfat
|
||||
make
|
||||
|
||||
echo "=== Fetching opentracker ==="
|
||||
cd "$BUILD_DIR"
|
||||
cvs -d :pserver:anoncvs@cvs.fefe.de:/cvs -z9 co opentracker
|
||||
cd opentracker
|
||||
make FEATURES='-DWANT_V6 -DWANT_FULLSCRAPE'
|
||||
|
||||
echo "=== Installing to $INSTALL_PREFIX ==="
|
||||
sudo mkdir -p "$INSTALL_PREFIX/bin"
|
||||
sudo cp opentracker "$INSTALL_PREFIX/bin/"
|
||||
sudo cp opentracker.conf.sample "$INSTALL_PREFIX/opentracker.conf" || true
|
||||
sudo useradd --system --home "$INSTALL_PREFIX" --shell /usr/sbin/nologin opentracker 2>/dev/null || true
|
||||
sudo chown -R opentracker:opentracker "$INSTALL_PREFIX"
|
||||
|
||||
echo "=== Installing systemd unit ==="
|
||||
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
|
||||
sudo cp "$SCRIPT_DIR/opentracker.service" /etc/systemd/system/
|
||||
sudo systemctl daemon-reload
|
||||
sudo systemctl enable opentracker
|
||||
sudo systemctl start opentracker
|
||||
|
||||
echo
|
||||
echo "Done. Check status:"
|
||||
echo " sudo systemctl status opentracker"
|
||||
echo " curl http://127.0.0.1:6969/stats?mode=tpbs"
|
||||
echo
|
||||
echo "Don't forget to open port 6969/tcp + 6969/udp on your VPS firewall."
|
||||
@@ -0,0 +1,31 @@
|
||||
[Unit]
|
||||
Description=opentracker — BitTorrent tracker for OctoWow launcher swarm
|
||||
After=network.target
|
||||
|
||||
[Service]
|
||||
Type=simple
|
||||
User=opentracker
|
||||
Group=opentracker
|
||||
WorkingDirectory=/opt/opentracker
|
||||
ExecStart=/opt/opentracker/bin/opentracker -i 0.0.0.0 -p 6969 -P 6969
|
||||
Restart=on-failure
|
||||
RestartSec=5
|
||||
|
||||
# Hardening — opentracker does no filesystem IO after boot, so most of
|
||||
# the namespace can be locked down.
|
||||
NoNewPrivileges=true
|
||||
PrivateTmp=true
|
||||
ProtectSystem=strict
|
||||
ProtectHome=true
|
||||
ProtectKernelTunables=true
|
||||
ProtectKernelModules=true
|
||||
ProtectControlGroups=true
|
||||
RestrictNamespaces=true
|
||||
RestrictRealtime=true
|
||||
RestrictSUIDSGID=true
|
||||
LockPersonality=true
|
||||
MemoryDenyWriteExecute=true
|
||||
SystemCallArchitectures=native
|
||||
|
||||
[Install]
|
||||
WantedBy=multi-user.target
|
||||
Reference in New Issue
Block a user