import std/[os, osproc, sequtils, strformat, strutils, sugar] import cligen proc checkHost(host: seq[string]): string = case host.len: of 1: return host[0] of 0: quit "expected hostname" else: quit "expected one positinal argument" proc check(name: string): bool = (execCmd &"ssh -O check {name}") == 0 proc startSsh(name: string) = discard execCmd &"ssh -M -f -N {name}" proc activateTunnel(name: string, port: int): int = execCmd &"""ssh -fNL "{port}:localhost:{port}" {name}""" proc exitSsh(name: string):int = execCmd &"ssh -O exit {name}" proc up(port: int, host: seq[string]) = ## activate a tunnel let name = checkHost host echo "activating connection to: ", name if not check(name): startSsh(name) quit activateTunnel(name, port) proc down(host: seq[string]) = ## disable all tunnels let name = checkHost host echo "deactivating connection to: ", name quit exitSsh(name) proc show() = ## show active connections let sshDir = (getEnv "HOME") / ".ssh" let controllers = collect(for _,p in walkDir(sshDir): p) .map(extractFilename) .filterIt(it.startsWith("control")) echo &"{controllers.len} active connections" if controllers.len == 0: quit 0 echo "hosts:" echo controllers.mapIt(" " & it.split('-')[1]).join("\n") const hostUsage = "$command [flags] hostname\n${doc}Options:\n$options" usage = "$command [flags]\n${doc}Options:\n$options" dispatchMulti([up, usage=hostUsage], [down, usage=hostUsage], [show, usage=usage])