From 9d30e52d4fd7c921683fd8a55c818ff7fd3ef7fe Mon Sep 17 00:00:00 2001 From: eltrac Date: Mon, 14 Sep 2026 18:12:39 +0800 Subject: httpclient, webhook, verifier: add weepinbell.http.client to wrap org.httpkit.client comment --- src/weepinbell/http/client.clj | 69 ++++++++++++++++++++++++++++++++++++++++++ src/weepinbell/utils.clj | 7 ++--- src/weepinbell/verifier.clj | 6 ++-- src/weepinbell/webhook.clj | 8 ++--- 4 files changed, 79 insertions(+), 11 deletions(-) create mode 100644 src/weepinbell/http/client.clj diff --git a/src/weepinbell/http/client.clj b/src/weepinbell/http/client.clj new file mode 100644 index 0000000..34cd458 --- /dev/null +++ b/src/weepinbell/http/client.clj @@ -0,0 +1,69 @@ +(ns weepinbell.http.client + "HTTP client adapter. Only this adapter depends directly on external HTTP client library. + The rest of the codebase uses this adapter to make HTTP requests. + All HTTP client related changeability and complexity is containend within here, + for instance, all Exceptions are caught inside and returned as normal value." + (:refer-clojure :exclude [get]) + (:require [org.httpkit.client :as hk])) + +(def default-options + {:user-agent "WebmentionBot" + :timeout 15000}) + +(defn- wrap-response [response] + (assoc response :content-length (or (get-in response [:headers "Content-Length"]) + (get-in response [:headers "content-length"])))) + +(defn- wrap-promise [promised-response] + (future (wrap-response @promised-response))) + +(defn post + "Sends POST request asynchronously. Returns a promise/future." + ([url] + (post url nil)) + ([url options] + (post url options nil)) + ([url options callbacks] + (-> url + (hk/post (merge default-options options) callbacks) + wrap-promise))) + +(defn get + "Sends GET request asynchronously. Returns a promise/future." + ([url] + (get url nil)) + ([url options] + (get url options nil)) + ([url options callbacks] + (-> url + (hk/get (merge default-options options) callbacks) + wrap-promise))) + +(defn get! + "Sends GET request synchronously. Returns response." + ([url] + @(get url nil)) + ([url options] + @(get url options nil)) + ([url options callbacks] + @(get url options callbacks))) + +(defn head + "Sends HEAD request asynchronously. Returns a promise/future." + ([url] + (head url nil)) + ([url options] + (head url options nil)) + ([url options callbacks] + (-> url + (hk/head (merge default-options options) callbacks) + wrap-promise))) + +(defn head! + "Sends HEAD request synchronously. Returns a response." + ([url] + @(head url nil)) + ([url options] + @(head url options nil)) + ([url options callbacks] + @(head url options callbacks))) diff --git a/src/weepinbell/utils.clj b/src/weepinbell/utils.clj index 9c279b7..a2e0cd9 100644 --- a/src/weepinbell/utils.clj +++ b/src/weepinbell/utils.clj @@ -1,5 +1,5 @@ (ns weepinbell.utils - (:require [org.httpkit.client :as hk] + (:require [weepinbell.http.client :as client] [clojure.string :as string] [clojure.walk :as walk] [clojure.java.io :as io] @@ -16,9 +16,8 @@ parent-dir (.getParentFile file)] (when (and parent-dir (not (.exists parent-dir))) (.mkdirs parent-dir)) - (let [response (hk/get url {:as :stream - :timeout 30000}) - content-length (get-in @response [:headers "content-length"])] + (let [response (client/get! url {:as :stream}) + content-length (get-in response [:headers "content-length"])] (timbre/info "Downloading [" url "] -> [" dest-path "]") (when content-length (timbre/info "File size:" content-length "bytes")) diff --git a/src/weepinbell/verifier.clj b/src/weepinbell/verifier.clj index 2b28e3f..c79c539 100644 --- a/src/weepinbell/verifier.clj +++ b/src/weepinbell/verifier.clj @@ -5,7 +5,7 @@ 2) source respond with 2** status code. 3) source's Content-Type is either HTML or plain text." (:require [clojure.string :refer [includes? trim lower-case split]] - [org.httpkit.client :as hk] + [weepinbell.http.client :as client] [weepinbell.utils.digest :refer [digest-short]] [taoensso.timbre :as timbre])) @@ -23,8 +23,8 @@ [source target] (try ;; get first 1MB of source URL and verify - (let [{:keys [status body headers]} @(hk/get source {:headers {"Range" "bytes=0-1048575"}}) - target-headers (:headers @(hk/head target)) + (let [{:keys [status body headers]} (client/get! source {:headers {"Range" "bytes=0-1048575"}}) + target-headers (:headers (client/head! target)) id (digest-short (str source target))] (timbre/info "verifying webmention" id (str "(" "source: " source ", target: " target ")")) diff --git a/src/weepinbell/webhook.clj b/src/weepinbell/webhook.clj index e1283d1..c084f47 100644 --- a/src/weepinbell/webhook.clj +++ b/src/weepinbell/webhook.clj @@ -1,10 +1,10 @@ (ns weepinbell.webhook - (:require [org.httpkit.client :as hk] - [taoensso.timbre :as timbre] - [weepinbell.utils.url :refer [valid-http-url?]])) + (:require [taoensso.timbre :as timbre] + [weepinbell.utils.url :refer [valid-http-url?]] + [weepinbell.http.client :as client])) (defn- send-webhook [url] - (hk/post url + (client/post url {:timeout 15000} (fn async-callback [{:keys [status _ _ error]}] (cond -- cgit v1.2.3