gates / gates (push) Successful in 13m1s
Spike: per-app normal levels on three boxes (19-31 days), the off-site push as a line measure (a lower bound), qBittorrent/Transmission/Plex explainers measured on 9202, a tc ceiling measured (not built). Live on 9202 with 0.342.0-rc.1: limit set; real seed explained; CPU burner and the hidden flood alarmed once each and cleared once; the household's limit left alone. Teardown: apps removed, 9202 back on 0.341.0, receiver 9471 destroyed.
48 lines
3.1 KiB
Python
48 lines
3.1 KiB
Python
# Runs INSIDE guest 9202. Transmission's own RPC numbers vs the container's exact tx bytes. Password read at use, never printed.
|
|
import json, subprocess, sys, time, urllib.request, base64
|
|
def sh(*a): return subprocess.run(a, capture_output=True, text=True).stdout.strip()
|
|
C = 'transmission'
|
|
IP = sh('docker', 'inspect', '-f', '{{range .NetworkSettings.Networks}}{{.IPAddress}} {{end}}', C).split()[0]
|
|
PID = sh('docker', 'inspect', '-f', '{{.State.Pid}}', C)
|
|
PW = sh('docker', 'exec', C, 'printenv', 'PASS')
|
|
AUTH = 'Basic ' + base64.b64encode(('admin:' + PW).encode()).decode()
|
|
SID = ''
|
|
def rpc(method, args=None):
|
|
global SID
|
|
for _ in range(2):
|
|
r = urllib.request.Request(f'http://{IP}:9091/transmission/rpc', data=json.dumps({'method': method, 'arguments': args or {}}).encode(),
|
|
headers={'Authorization': AUTH, 'Host': 'transmission:9091', 'X-Transmission-Session-Id': SID, 'Content-Type': 'application/json'}, method='POST')
|
|
try:
|
|
with urllib.request.urlopen(r, timeout=20) as resp: return json.loads(resp.read())
|
|
except urllib.error.HTTPError as e:
|
|
if e.code == 409: SID = e.headers.get('X-Transmission-Session-Id'); continue
|
|
return {'http': e.code}
|
|
def tx():
|
|
for line in open(f'/proc/{PID}/net/dev'):
|
|
if line.strip().startswith('eth0:'): return int(line.split(':', 1)[1].split()[8])
|
|
mode = sys.argv[1]
|
|
if mode == 'info':
|
|
g = rpc('session-get')['arguments']
|
|
print('version', g.get('version'), {k: g.get(k) for k in ('speed-limit-up', 'speed-limit-up-enabled', 'alt-speed-up', 'alt-speed-enabled', 'alt-speed-time-enabled', 'units')})
|
|
print('session-stats', rpc('session-stats')['arguments'])
|
|
elif mode == 'add':
|
|
meta = base64.b64encode(open('/root/uwtest.torrent', 'rb').read()).decode()
|
|
print(rpc('torrent-add', {'metainfo': meta, 'download-dir': '/mnt/felhom-drives/scratch_hdd/userdata/media/transmission', 'paused': False}))
|
|
time.sleep(5); rpc('torrent-verify', {}); time.sleep(20)
|
|
print(rpc('torrent-get', {'fields': ['name', 'status', 'percentDone', 'error', 'errorString']}))
|
|
elif mode == 'limit':
|
|
print(rpc('session-set', {'speed-limit-up': int(sys.argv[2]), 'speed-limit-up-enabled': True}))
|
|
g = rpc('session-get')['arguments']; print({k: g.get(k) for k in ('speed-limit-up', 'speed-limit-up-enabled')})
|
|
elif mode == 'reannounce':
|
|
print(rpc('torrent-reannounce', {}))
|
|
elif mode == 'sample':
|
|
dur, step = int(sys.argv[2]), int(sys.argv[3]); t0 = time.time(); prev = None
|
|
while time.time() - t0 <= dur:
|
|
st = rpc('session-stats')['arguments']; tg = rpc('torrent-get', {'fields': ['uploadedEver', 'rateUpload']})['arguments']['torrents']
|
|
row = {'t': round(time.time() - t0, 1), 'tr_upspeed': st['uploadSpeed'], 'tr_cur_up': st['current-stats']['uploadedBytes'], 'tr_tor_up': sum(x['uploadedEver'] for x in tg), 'tx': tx()}
|
|
if prev:
|
|
dt = row['t'] - prev['t']
|
|
row['rate_tr_Mbit'] = round((row['tr_cur_up'] - prev['tr_cur_up']) * 8 / dt / 1e6, 2)
|
|
row['rate_container_Mbit'] = round((row['tx'] - prev['tx']) * 8 / dt / 1e6, 2)
|
|
print(json.dumps(row), flush=True); prev = row; time.sleep(step)
|