Q3Rcon.psm1

try {
    . (Join-Path $PSScriptRoot packet.ps1)
    . (Join-Path $PSScriptRoot base.ps1)     
}
catch {
    throw 'unable to dot source module files'
}


class Rcon {
    static [hashtable]$DefaultTimeouts = @{
        'map'          = 2000
        'map_rotate'   = 2000
        'map_restart'  = 2000
        'fast_restart' = 2000
    }

    [Object]$base
    [hashtable]$timeouts

    Rcon ([string]$hostname, [int]$port, [string]$passwd, [hashtable]$timeouts = $null) {
        $this.base = New-Base -hostname $hostname -port $port -passwd $passwd
        $this.timeouts = $timeouts ?? [Rcon]::DefaultTimeouts
    }

    [Rcon] _login() {
        $resp = $this.Send('login')
        if ($resp -in @('Bad rcon', 'Bad rconpassword.', 'Invalid password.')) {
            throw 'invalid rcon password'
        }
        $this.base.ToString() | Write-Debug
        return $this
    }

    [string] Send([string]$cmd) {
        $key = $cmd.Split()[0]
        if ($this.timeouts.ContainsKey($key)) {
            return $this.base._send($cmd, $this.timeouts[$key])
        }
        return $this.base._send($cmd)
    }

    [void] Say($msg) {
        $this.Send("say $msg")
    }

    [void] FastRestart() {
        $this.Send('fast_restart')
    }

    [void] MapRotate() {
        $this.Send('map_rotate')
    }

    [void] MapRestart() {
        $this.Send('map_restart')
    }

    [string] Map() {
        return $this.Send('mapname')
    }

    [void] SetMap($mapname) {
        $this.Send('map mp_' + $mapname.TrimStart('mp_'))
    }

    [string] Gametype() {
        return $this.Send('g_gametype')
    }

    [void] SetGametype($gametype) {
        $this.Send('g_gametype', $gametype)
    }

    [string] HostName() {
        return $this.Send('sv_hostname')
    }

    [void] SetHostName($hostname) {
        $this.Send('sv_hostname', $hostname)
    }
}

function Connect-Rcon {
    param([string]$hostname, [int]$port, [string]$passwd, [Parameter(Mandatory = $false)][hashtable]$timeouts)

    [Rcon]::new($hostname, $port, $passwd, $timeouts)._login()
}

function Disconnect-Rcon {
    param([Rcon]$rcon)

    if ($rcon -and $rcon.base) {
        $rcon.base.Dispose()
        'Disconnected from {0}:{1}' -f $rcon.base.hostname, $rcon.base.port | Write-Debug
    }
}

Export-ModuleMember -Function Connect-Rcon, Disconnect-Rcon