107 lines
3.0 KiB
Clojure
107 lines
3.0 KiB
Clojure
(ns examples.http
|
|
"HTTP request example - demonstrates async commands.
|
|
Mirrors bubbletea's http example."
|
|
(:require [tui.core :as tui]
|
|
[tui.events :as ev]
|
|
[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"})
|
|
|
|
;; === Update ===
|
|
(defn update-fn [{:keys [model event]}]
|
|
(let [{:keys [url]} model]
|
|
(cond
|
|
;; Quit
|
|
(or (ev/key= event \q)
|
|
(ev/key= event \c #{:ctrl}))
|
|
{:model model :events [(ev/quit)]}
|
|
|
|
;; Enter - start request
|
|
(and (= (:state model) :idle)
|
|
(ev/key= event :enter))
|
|
{:model (assoc model :state :loading)
|
|
:events [(ev/shell ["curl" "-s" "-o" "/dev/null" "-w" "%{http_code}" url]
|
|
{:type :http-result})]}
|
|
|
|
;; r - retry/reset
|
|
(ev/key= event \r)
|
|
{:model (assoc model :state :idle :status nil :error nil)}
|
|
|
|
;; HTTP result
|
|
(= (:type event) :http-result)
|
|
(let [{:keys [success out err]} (:result event)]
|
|
(if success
|
|
{:model (assoc model :state :success :status (parse-long out))}
|
|
{:model (assoc model :state :error :error err)}))
|
|
|
|
:else
|
|
{:model model})))
|
|
|
|
;; === View ===
|
|
(defn view [{:keys [state status error url]} _size]
|
|
[: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-fn
|
|
:view view})]
|
|
(when (= (:state final) :success)
|
|
(println "Request completed with status:" (:status final)))))
|