#!/usr/bin/env python3
"""Server console from the terminal (the RCON password never leaves this machine).
  ./rcon status            one command
  ./rcon                   interactive prompt (Ctrl+D or 'exit' to quit)
Reads the port from .env and the password from secrets/rcon-password.txt."""
import os, socket, sys

D = os.path.dirname(os.path.abspath(__file__))
env = {}
for line in open(os.path.join(D, ".env"), encoding="utf-8"):
    k, _, v = line.strip().partition("=")
    env[k] = v
PW = open(os.path.join(D, "secrets", "rcon-password.txt")).read().strip()
ADDR = ("127.0.0.1", int(env.get("CS_PORT") or 27015))
H = b"\xff\xff\xff\xff"


def rcon(cmd):
    s = socket.socket(socket.AF_INET, socket.SOCK_DGRAM)
    s.settimeout(3)
    try:
        s.sendto(H + b"challenge rcon\n", ADDR)
        ch = s.recvfrom(4096)[0].split()[2]
    except (OSError, IndexError):
        return "(no answer: server down or changing map?)"
    s.sendto(H + b"rcon " + ch + b' "' + PW.encode() + b'" ' + cmd.encode(), ADDR)
    out = []
    while True:  # long replies (status, cvarlist) come in several packets
        try:
            data = s.recvfrom(65535)[0]
        except OSError:
            break
        out.append(data[5:].decode(errors="replace") if data[:4] == H else data.decode(errors="replace"))
        s.settimeout(0.4)
    text = "".join(out)
    # never show passwords (a map change prints the whole cvar list)
    return "\n".join(l for l in text.splitlines()
                     if "rcon_password" not in l and "sv_password" not in l) or "(ok, no output)"


if __name__ == "__main__":
    if len(sys.argv) > 1:
        print(rcon(" ".join(sys.argv[1:])))
        sys.exit()
    print("CS 1.6 console: status, changelevel de_nuke, yb_quota 6, esef_mode gg, say hi. Ctrl+D to quit.")
    while True:
        try:
            line = input("cs16> ").strip()
        except (EOFError, KeyboardInterrupt):
            print()
            break
        if line in ("exit", "quit"):
            break
        if line:
            print(rcon(line))
