(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)))))