(ns pod (:refer-clojure :exclude [read read-string]) (:require [babashka.pods :as pods] [bencode.core :as bencode] [cheshire.core :as cheshire] [clojure.edn :as edn] [clojure.java.io :as io]) (:import [java.io PushbackInputStream]) (:gen-class)) (def debug? false) (defn debug [& args] (when debug? (binding [*out* (io/writer "/tmp/log.txt" :append true)] (apply println args)))) (def stdin (PushbackInputStream. System/in)) (defn write [v] (bencode/write-bencode System/out v) (.flush System/out)) (defn read-string [^"[B" v] (String. v)) (defn read [] (bencode/read-bencode stdin)) (defn run-pod [cli-args] (let [format (if (contains? cli-args "--json") :json :edn) write-fn (if (identical? :json format) cheshire/generate-string pr-str) read-fn (if (identical? :json format) #(cheshire/parse-string % true) edn/read-string)] (loop [] (let [message (try (read) (catch java.io.EOFException _ ::EOF))] (when-not (identical? ::EOF message) (let [op (get message "op") op (read-string op) op (keyword op)] (case op :describe (do (write {"format" (if (= format :json) "json" "edn") "readers" {"ordered/map" "flatland.ordered.map/ordered-map"} "namespaces" [{"name" "pod.test-pod" "vars" [{"name" "add-sync"} {"name" "range-stream" "code" " (defn range-stream [val-cb done-cb & args] (babashka.pods/invoke \"pod.test-pod\" 'pod.test-pod/range-stream* args {:handlers {:success val-cb :done done-cb}}) nil)"} {"name" "assoc"} {"name" "error"} {"name" "print"} {"name" "print-err"} {"name" "ordered-map"}]}] "ops" {"shutdown" {}}}) (recur)) :invoke (let [var (-> (get message "var") read-string symbol) _ (debug "var" var) id (-> (get message "id") read-string) args (get message "args") args (read-string args) args (read-fn args)] (case var pod.test-pod/add-sync (write {"value" (write-fn (apply + args)) "id" id "status" ["done"]}) pod.test-pod/range-stream* (let [rng (apply range args)] (doseq [v rng] (write {"value" (write-fn v) "id" id}) (Thread/sleep 100)) (write {"status" ["done"] "id" id})) pod.test-pod/assoc (write {"value" (write-fn (apply assoc args)) "status" ["done"] "id" id}) pod.test-pod/error (write {"ex-data" (write-fn {:args args}) "ex-message" (str "Illegal arguments") "status" ["done" "error"] "id" id}) pod.test-pod/print (do (write {"out" (prn-str args) "id" id}) (write {"status" ["done"] "id" id})) pod.test-pod/print-err (do (write {"err" (prn-str args) "id" id}) (write {"status" ["done"] "id" id})) pod.test-pod/ordered-map (write {"value" "#ordered/map([:a 1] [:b 2])" "status" ["done"] "id" id})) (recur)) :shutdown (System/exit 0)))))))) (let [cli-args (set *command-line-args*)] (if (or (= "true" (System/getenv "BABASHKA_POD")) (contains? cli-args "--run-as-pod")) (do (debug "running pod with cli args" cli-args) (run-pod cli-args)) (let [native? (contains? cli-args "--native") windows? (contains? cli-args "--windows")] (pods/load-pod (cond native? (into ["./bb" "test-resources/pod.clj" "--run-as-pod"] cli-args) windows? (into ["cmd" "/c" "lein" "bb" "test-resources/pod.clj" "--run-as-pod"] cli-args) :else (into ["lein" "bb" "test-resources/pod.clj" "--run-as-pod"] cli-args))) (require '[pod.test-pod]) (if (contains? cli-args "--json") (do (debug "Running JSON test") (prn ((resolve 'pod.test-pod/assoc) {:a 1} :b 2))) (do (debug "Running synchronous add test") (prn ((resolve 'pod.test-pod/add-sync) 1 2 3)) (debug "Running async range test") (let [prom (promise)] ((resolve 'pod.test-pod/range-stream) prn (fn [] (deliver prom :ok)) 1 10) @prom) (debug "Running exception test") (prn (try ((resolve 'pod.test-pod/error) 1 2 3) (catch clojure.lang.ExceptionInfo e (str (ex-message e) " / " (ex-data e))))) (debug "Running print test") ((resolve 'pod.test-pod/print) "hello" "print" "this" "debugging" "message") (debug "Running print-err test") ((resolve 'pod.test-pod/print-err) "hello" "print" "this" "error") (debug "Running reader test") (require '[flatland.ordered.map :refer [ordered-map]]) (prn (= ((resolve 'flatland.ordered.map/ordered-map) :a 1 :b 2) ((resolve 'pod.test-pod/ordered-map)))))))))