(ns ird.tunnels
"HTTPS tunnels on your own domain, reverse-tunneled to your device over
SSH. Hourly billing while the tunnel exists. Mutations are subject to the
client's domain gate on the hostname. Every function returns a channel
(see ird.async)."
(:require [ird.async :refer [go-try <?]]
[ird.gate :as gate]
[ird.transport :as transport]))
(defn list-tunnels
"GET /tunnels — List your tunnels."
[client]
(transport/request client :get "/tunnels"))
(defn create-tunnel
"POST /tunnels — Create a tunnel.
BODY keys include :hostname, :transport, :ssh_key_id, :ssh_public_key,
:settings, :totp_code. Subject to the client's domain gate on :hostname."
[client body]
(gate/request client "POST /tunnels" {:domain (:hostname body)}
:post "/tunnels" {:body body}))
(defn get-tunnel
"GET /tunnels/{id} — Tunnel detail."
[client id]
(transport/request client :get ["tunnels" id]))
(defn- tunnel-target
"Gate target for a tunnel: its hostname via `get-tunnel`. Called only when
the client has a gate."
[client id]
(go-try {:domain (get-in (<? (get-tunnel client id)) [:tunnel :hostname])}))
(defn delete-tunnel
"DELETE /tunnels/{id} — Delete a tunnel (billing stops).
Optional BODY carries :totp_code. Subject to the client's domain gate on
the tunnel's hostname (resolved via `get-tunnel` when a gate is set)."
([client id] (delete-tunnel client id nil))
([client id body]
(gate/request client "DELETE /tunnels/{id}" #(tunnel-target client id)
:delete ["tunnels" id] (when body {:body body}))))
(defn update-tunnel
"PATCH /tunnels/{id} — Update tunnel settings.
BODY carries :settings and optional :totp_code. Subject to the client's
domain gate on the tunnel's hostname (resolved via `get-tunnel` when a
gate is set)."
[client id body]
(gate/request client "PATCH /tunnels/{id}" #(tunnel-target client id)
:patch ["tunnels" id] {:body body}))
(defn verify-dns
"POST /tunnels/{id}/verify-dns — Re-check DNS."
[client id]
(transport/request client :post ["tunnels" id "verify-dns"]))