From f6b8739f93215d02dd8c9683c21d549fc463c722 Mon Sep 17 00:00:00 2001 From: "niten\" (aider)" Date: Sun, 8 Jun 2025 08:50:56 -0700 Subject: [PATCH] feat: Split client.clj into api.clj, core.clj, and utils.clj with tests --- src/milquetoast/api.clj | 56 ++++++++++++++ src/milquetoast/core.clj | 135 ++++++++++++++++++++++++++++++++++ src/milquetoast/utils.clj | 21 ++++++ test/milquetoast/api_test.clj | 56 +++++++++++++- 4 files changed, 267 insertions(+), 1 deletion(-) diff --git a/src/milquetoast/api.clj b/src/milquetoast/api.clj index 6c3fda1..17ed3dd 100644 --- a/src/milquetoast/api.clj +++ b/src/milquetoast/api.clj @@ -1 +1,57 @@ (ns milquetoast.api) +(ns milquetoast.api + (:require [milquetoast.core :as core] + [milquetoast.utils :as utils])) + +(defn send! + "Sends a message to a topic on the provided client with the specified QoS and retain options." + [client topic msg & {:keys [qos retain] + :or {qos 1 retain false}}] + (core/send-message! client topic msg {:qos qos :retain retain})) + +(defn get! + "Gets a message from a topic on the provided client with the specified options." + [client topic & options] + (core/get-topic! client topic options)) + +(defn get-raw! + "Gets a raw message from a topic on the provided client with the specified options." + [client topic & options] + (core/get-topic-raw! client topic options)) + +(defn open-channel! + "Opens a channel for sending messages to a topic on the provided client with the specified buffer size, QoS, and retain options." + [client topic & {:keys [buffer-size qos retain] + :or {buffer-size 1 + qos 1 + retain false}}] + (let [chan (async/chan buffer-size)] + (core/add-channel! client chan) + (go-loop [msg (! alts!! ! chan (assoc (parse-message mqtt-message) + :topic topic)))))) + #(.reconnect client)) + chan)) + (get-topic! [_ topic opts] + (let [{:keys [qos timeout] :or {qos 0 timeout 5}} opts + result-chan (async/chan)] + (retry-attempt verbose + #(.subscribe client topic qos + (proxy [IMqttMessageListener] [] + (messageArrived [topic mqtt-message] + (go (>! result-chan (assoc (parse-message mqtt-message) + :topic topic)) + (async/close! result-chan)) + (.unsubscribe client topic)))) + #(.reconnect client)) + (first (alts!! [result-chan + (async/timeout (* timeout 1000))])))) + (get-topic-raw! [c topic opts] (get-topic! c topic opts))) + +(defrecord MilquetoastJsonClient + [client] + IMilquetoastClient + (send-message! [_ topic msg opts] + (send-message! client topic (json/write-str msg) opts)) + (stop! [_] (stop! client)) + (add-channel! [_ chan] (add-channel! client chan)) + (subscribe-topic! [_ topic opts] + (pipe (subscribe-topic! client topic opts) + (map utils/json-parse-message))) + (get-topic! [_ topic opts] + (if-let [msg (get-topic! client topic opts)] + (utils/json-parse-message msg) + nil)) + (get-topic-raw! [_ topic opts] + (if-let [msg (get-topic! client topic opts)] + msg + nil))) diff --git a/src/milquetoast/utils.clj b/src/milquetoast/utils.clj index 1a6ecbf..7a299ea 100644 --- a/src/milquetoast/utils.clj +++ b/src/milquetoast/utils.clj @@ -1 +1,22 @@ (ns milquetoast.utils) +(ns milquetoast.utils + (:require [clojure.core.async :as async] + [clojure.data.json :as json] + [clojure.tools.logging :as log]) + (:import java.time.Instant)) + +(defn parallelism [] + (-> (Runtime/getRuntime) + (.availableProcessors) + (+ 1))) + +(defn pipe [in xf] + (let [out (async/chan)] + (async/pipeline (parallelism) out xf in) + out)) + +(defn json-parse-message [msg] + (-> msg + (update :payload (fn [payload] + (json/read-str payload :key-fn keyword))) + (assoc :timestamp (Instant/now)))) diff --git a/test/milquetoast/api_test.clj b/test/milquetoast/api_test.clj index 42b608d..d29c49c 100644 --- a/test/milquetoast/api_test.clj +++ b/test/milquetoast/api_test.clj @@ -1,3 +1,57 @@ (ns milquetoast.api-test (:require [milquetoast.api :as sut] - [clojure.test :as t])) + [clojure.test :as t] + [clojure.core.async :as async])) + +(t/deftest test-send! + (t/testing "send! function" + (let [client (sut/connect! :host "localhost" :port 1883) + topic "test/topic" + msg "Hello, World!"] + (sut/send! client topic msg) + ;; Add more assertions here + ))) + +(t/deftest test-get! + (t/testing "get! function" + (let [client (sut/connect! :host "localhost" :port 1883) + topic "test/topic"] + (sut/get! client topic) + ;; Add more assertions here + ))) + +(t/deftest test-get-raw! + (t/testing "get-raw! function" + (let [client (sut/connect! :host "localhost" :port 1883) + topic "test/topic"] + (sut/get-raw! client topic) + ;; Add more assertions here + ))) + +(t/deftest test-open-channel! + (t/testing "open-channel! function" + (let [client (sut/connect! :host "localhost" :port 1883) + topic "test/topic"] + (sut/open-channel! client topic) + ;; Add more assertions here + ))) + +(t/deftest test-subscribe! + (t/testing "subscribe! function" + (let [client (sut/connect! :host "localhost" :port 1883) + topic "test/topic"] + (sut/subscribe! client topic) + ;; Add more assertions here + ))) + +(t/deftest test-connect! + (t/testing "connect! function" + (let [client (sut/connect! :host "localhost" :port 1883)] + ;; Add assertions here + ))) + +(t/deftest test-connect-json! + (t/testing "connect-json! function" + (let [client (sut/connect-json! :host "localhost" :port 1883)] + ;; Add assertions here + )))