Files
clojure-tui/examples/http.clj
2026-01-21 01:21:05 -05:00

112 lines
2.9 KiB
Clojure

(ns examples.http
"HTTP request example - demonstrates async commands.
Mirrors bubbletea's http example."
(:require [tui.core :as tui]
[clojure.java.io :as io])
(:import [java.net URL HttpURLConnection]))
;; === HTTP Helpers ===
(defn http-get
"Simple HTTP GET request. Returns {:status code :body string} or {:error msg}"
[url-str]
(try
(let [url (URL. url-str)
conn ^HttpURLConnection (.openConnection url)]
(.setRequestMethod conn "GET")
(.setConnectTimeout conn 5000)
(.setReadTimeout conn 5000)
(let [status (.getResponseCode conn)
body (with-open [r (io/reader (.getInputStream conn))]
(slurp r))]
{:status status :body body}))
(catch Exception e
{:error (.getMessage e)})))
;; === Model ===
(def initial-model
{:state :idle ; :idle, :loading, :success, :error
:status nil
:error nil
:url "https://httpstat.us/200"})
;; === Commands ===
(defn fetch-url [url]
(fn []
(let [result (http-get url)]
(if (:error result)
[:http-error (:error result)]
[:http-success (:status result)]))))
;; === Update ===
(defn update-model [{:keys [url] :as model} msg]
(cond
;; Quit
(or (tui/key= msg "q")
(tui/key= msg [:ctrl \c]))
[model tui/quit]
;; Enter - start request
(and (= (:state model) :idle)
(tui/key= msg :enter))
[(assoc model :state :loading) (fetch-url url)]
;; r - retry/reset
(tui/key= msg "r")
[(assoc model :state :idle :status nil :error nil) nil]
;; HTTP success
(= (first msg) :http-success)
[(assoc model :state :success :status (second msg)) nil]
;; HTTP error
(= (first msg) :http-error)
[(assoc model :state :error :error (second msg)) nil]
:else
[model nil]))
;; === View ===
(defn view [{:keys [state status error url]}]
[:col {:gap 1}
[:box {:border :rounded :padding [1 2]}
[:col {:gap 1}
[:text {:bold true} "HTTP Request Demo"]
[:text ""]
[:row {:gap 1}
[:text {:fg :gray} "URL:"]
[:text {:fg :cyan} url]]
[:text ""]
(case state
:idle
[:text {:fg :gray} "Press enter to fetch..."]
:loading
[:row {:gap 1}
[:text {:fg :yellow} "⠋"]
[:text "Fetching..."]]
:success
[:row {:gap 1}
[:text {:fg :green} "✓"]
[:text (str "Status: " status)]]
:error
[:col
[:row {:gap 1}
[:text {:fg :red} "✗"]
[:text {:fg :red} "Error:"]]
[:text {:fg :red} error]])]]
[:text {:fg :gray}
(if (= state :idle)
"enter: fetch q: quit"
"r: retry q: quit")]])
;; === Main ===
(defn -main [& _args]
(println "Starting HTTP demo...")
(let [final (tui/run {:init initial-model
:update update-model
:view view})]
(when (= (:state final) :success)
(println "Request completed with status:" (:status final)))))