2020-05-09 12:03:50 +00:00
|
|
|
(ns pod.test-pod
|
|
|
|
|
(:refer-clojure :exclude [read read-string])
|
|
|
|
|
(:require [bencode.core :as bencode]
|
|
|
|
|
[cheshire.core :as cheshire]
|
|
|
|
|
[clojure.edn :as edn]
|
2020-10-15 09:27:23 +00:00
|
|
|
[clojure.java.io :as io]
|
|
|
|
|
[cognitect.transit :as transit])
|
2020-10-15 08:55:22 +00:00
|
|
|
(:import [java.io PushbackInputStream]
|
|
|
|
|
[java.net ServerSocket])
|
2020-05-09 12:03:50 +00:00
|
|
|
(:gen-class))
|
|
|
|
|
|
|
|
|
|
(def debug? false)
|
|
|
|
|
|
|
|
|
|
(defn debug [& args]
|
|
|
|
|
(when debug?
|
|
|
|
|
(binding [*out* (io/writer "/tmp/log.txt" :append true)]
|
|
|
|
|
(apply println args))))
|
|
|
|
|
|
2020-10-15 08:55:22 +00:00
|
|
|
(defn write [stream v]
|
|
|
|
|
(bencode/write-bencode stream v)
|
|
|
|
|
(flush))
|
2020-05-09 12:03:50 +00:00
|
|
|
|
|
|
|
|
(defn read-string [^"[B" v]
|
|
|
|
|
(String. v))
|
|
|
|
|
|
2020-10-15 08:55:22 +00:00
|
|
|
(defn read [stream]
|
|
|
|
|
(bencode/read-bencode stream))
|
2020-05-09 12:03:50 +00:00
|
|
|
|
2020-05-21 15:28:14 +00:00
|
|
|
(def dependents
|
|
|
|
|
(for [i (range 10)]
|
|
|
|
|
{"name" (str "x" i)
|
|
|
|
|
"code"
|
|
|
|
|
(if-not (zero? i)
|
|
|
|
|
(format "(def x%s (inc x%s))" i (dec i))
|
|
|
|
|
"(def x0 0)")}))
|
|
|
|
|
|
2020-10-15 09:27:23 +00:00
|
|
|
(defn transit-json-read [^String s]
|
|
|
|
|
(with-open [bais (java.io.ByteArrayInputStream. (.getBytes s "UTF-8"))]
|
2021-05-17 09:41:51 +00:00
|
|
|
(let [r (transit/reader bais :json {:handlers
|
2021-05-19 15:20:55 +00:00
|
|
|
{"local-date-time"
|
2021-05-17 09:41:51 +00:00
|
|
|
(transit/read-handler
|
|
|
|
|
(fn [s]
|
2021-05-19 19:19:18 +00:00
|
|
|
(java.time.LocalDateTime/parse s)))
|
|
|
|
|
"java.array"
|
|
|
|
|
(transit/read-handler
|
|
|
|
|
(fn [v]
|
|
|
|
|
(into-array v)))}})]
|
2020-10-15 09:27:23 +00:00
|
|
|
(transit/read r))))
|
|
|
|
|
|
2021-05-17 09:41:51 +00:00
|
|
|
(defn transit-json-write [s]
|
2020-10-15 09:27:23 +00:00
|
|
|
(with-open [baos (java.io.ByteArrayOutputStream. 4096)]
|
2021-05-17 09:41:51 +00:00
|
|
|
(let [w (transit/writer baos :json {:handlers
|
|
|
|
|
{java.time.LocalDateTime
|
|
|
|
|
(transit/write-handler
|
2021-05-19 15:20:55 +00:00
|
|
|
"local-date-time"
|
2021-05-19 19:19:18 +00:00
|
|
|
str)}
|
|
|
|
|
:default-handler
|
|
|
|
|
(transit/write-handler
|
|
|
|
|
(fn [x] (when (.isArray (class x)) "java.array"))
|
|
|
|
|
vec)})]
|
2020-10-15 09:27:23 +00:00
|
|
|
(transit/write w s)
|
|
|
|
|
(str baos))))
|
|
|
|
|
|
2020-05-09 12:03:50 +00:00
|
|
|
(defn run-pod [cli-args]
|
2020-10-15 09:27:23 +00:00
|
|
|
(let [format (cond (contains? cli-args "--json") :json
|
|
|
|
|
(contains? cli-args "--transit+json") :transit+json
|
|
|
|
|
:else :edn)
|
|
|
|
|
write-fn (case format
|
|
|
|
|
:edn pr-str
|
|
|
|
|
:json cheshire/generate-string
|
|
|
|
|
:transit+json transit-json-write)
|
|
|
|
|
read-fn (case format
|
|
|
|
|
:edn edn/read-string
|
|
|
|
|
:json #(cheshire/parse-string % true)
|
|
|
|
|
:transit+json transit-json-read)
|
2020-10-21 11:58:59 +00:00
|
|
|
socket (= "socket" (System/getenv "BABASHKA_POD_TRANSPORT"))
|
2020-10-15 08:55:22 +00:00
|
|
|
[in out] (if socket
|
|
|
|
|
(let [server (ServerSocket. 0)
|
|
|
|
|
port (.getLocalPort server)
|
|
|
|
|
pid (.pid (java.lang.ProcessHandle/current))
|
|
|
|
|
port-file (io/file (str ".babashka-pod-" pid ".port"))
|
|
|
|
|
_ (.addShutdownHook (Runtime/getRuntime)
|
|
|
|
|
(Thread. (fn [] (.delete port-file))))
|
|
|
|
|
_ (spit port-file
|
|
|
|
|
(str port "\n"))
|
|
|
|
|
socket (.accept server)
|
|
|
|
|
in (PushbackInputStream. (.getInputStream socket))
|
|
|
|
|
out (.getOutputStream socket)]
|
|
|
|
|
[in out])
|
|
|
|
|
[(PushbackInputStream. System/in)
|
|
|
|
|
System/out])]
|
2020-05-20 18:11:46 +00:00
|
|
|
(try
|
|
|
|
|
(loop []
|
2020-10-15 08:55:22 +00:00
|
|
|
(let [message (try (read in)
|
2020-05-20 18:11:46 +00:00
|
|
|
(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
|
2020-10-15 09:27:23 +00:00
|
|
|
(do (write out {"format" (case format
|
|
|
|
|
:edn "edn"
|
|
|
|
|
:json "json"
|
|
|
|
|
:transit+json "transit+json")
|
2020-10-15 08:55:22 +00:00
|
|
|
"readers" {"my/tag" "identity"
|
|
|
|
|
;; NOTE: this function is defined later,
|
|
|
|
|
;; which should be supported
|
|
|
|
|
"my/other-tag" "pod.test-pod/read-other-tag"}
|
|
|
|
|
"namespaces"
|
|
|
|
|
[{"name" "pod.test-pod"
|
|
|
|
|
"vars" (into [{"name" "add-sync"}
|
|
|
|
|
{"name" "range-stream"
|
|
|
|
|
"async" "true"}
|
|
|
|
|
{"name" "assoc"}
|
|
|
|
|
{"name" "error"}
|
|
|
|
|
{"name" "print"}
|
|
|
|
|
{"name" "print-err"}
|
|
|
|
|
{"name" "return-nil"}
|
|
|
|
|
{"name" "do-twice"
|
|
|
|
|
"code" "(defmacro do-twice [x] `(do ~x ~x))"}
|
|
|
|
|
{"name" "fn-call"
|
|
|
|
|
"code" "(defn fn-call [f x] (f x))"}
|
|
|
|
|
{"name" "reader-tag"}
|
|
|
|
|
;; returns thing with other tag
|
|
|
|
|
{"name" "other-tag"}
|
|
|
|
|
;; reads thing with other tag
|
|
|
|
|
{"name" "read-other-tag"
|
2021-05-17 09:41:51 +00:00
|
|
|
"code" "(defn read-other-tag [x] [x x])"}
|
|
|
|
|
{"name" "-local-date-time"}
|
2021-05-19 19:19:18 +00:00
|
|
|
{"name" "transit-stuff"
|
2021-05-17 09:41:51 +00:00
|
|
|
"code" "
|
2021-05-19 19:19:18 +00:00
|
|
|
(babashka.pods/add-transit-read-handler! \"local-date-time\"
|
2021-05-17 09:41:51 +00:00
|
|
|
(fn [s] (java.time.LocalDateTime/parse s)))
|
2021-05-19 19:19:18 +00:00
|
|
|
|
|
|
|
|
(babashka.pods/add-transit-write-handler! \"local-date-time\"
|
2021-05-17 09:41:51 +00:00
|
|
|
str #{java.time.LocalDateTime})
|
2021-05-19 19:19:18 +00:00
|
|
|
|
2021-05-17 09:41:51 +00:00
|
|
|
(defn local-date-time [x]
|
2021-05-19 19:19:18 +00:00
|
|
|
(-local-date-time x))
|
|
|
|
|
|
|
|
|
|
;; serialize Java arrays as vectors with tag java.array
|
|
|
|
|
(babashka.pods/set-transit-default-write-handler!
|
|
|
|
|
(fn [x] (when (.isArray (class x)) \"java.array\"))
|
|
|
|
|
vec)
|
|
|
|
|
|
|
|
|
|
(babashka.pods/add-transit-read-handler! \"java.array\"
|
|
|
|
|
into-array)
|
|
|
|
|
|
|
|
|
|
"}]
|
2020-10-15 08:55:22 +00:00
|
|
|
dependents)}
|
|
|
|
|
{"name" "pod.test-pod.loaded"
|
|
|
|
|
"defer" "true"}
|
|
|
|
|
{"name" "pod.test-pod.loaded2"
|
|
|
|
|
"defer" "true"}
|
|
|
|
|
{"name" "pod.test-pod.only-code"
|
|
|
|
|
"vars" [{"name" "foo"
|
|
|
|
|
"code" "(defn foo [] 1)"}]}]
|
|
|
|
|
"ops" {"shutdown" {}}})
|
2020-05-20 18:11:46 +00:00
|
|
|
(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
|
|
|
|
|
(try (let [ret (apply + args)]
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"value" (write-fn ret)
|
|
|
|
|
"id" id
|
|
|
|
|
"status" ["done"]}))
|
|
|
|
|
(catch Exception e
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"ex-data" (write-fn {:args args})
|
|
|
|
|
"ex-message" (.getMessage e)
|
|
|
|
|
"status" ["done" "error"]
|
|
|
|
|
"id" id})))
|
|
|
|
|
pod.test-pod/range-stream
|
|
|
|
|
(let [rng (apply range args)]
|
|
|
|
|
(doseq [v rng]
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"value" (write-fn v)
|
|
|
|
|
"id" id})
|
|
|
|
|
(Thread/sleep 100))
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-09 12:03:50 +00:00
|
|
|
{"status" ["done"]
|
2020-05-16 21:42:00 +00:00
|
|
|
"id" id}))
|
2020-05-20 18:11:46 +00:00
|
|
|
pod.test-pod/assoc
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"value" (write-fn (apply assoc args))
|
|
|
|
|
"status" ["done"]
|
|
|
|
|
"id" id})
|
|
|
|
|
pod.test-pod/error
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"ex-data" (write-fn {:args args})
|
|
|
|
|
"ex-message" (str "Illegal arguments")
|
|
|
|
|
"status" ["done" "error"]
|
|
|
|
|
"id" id})
|
|
|
|
|
pod.test-pod/print
|
2020-10-15 08:55:22 +00:00
|
|
|
(do (write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"out" (pr-str args)
|
|
|
|
|
"id" id})
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id}))
|
|
|
|
|
pod.test-pod/print-err
|
2020-10-15 08:55:22 +00:00
|
|
|
(do (write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"err" (pr-str args)
|
|
|
|
|
"id" id})
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id}))
|
|
|
|
|
pod.test-pod/return-nil
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-20 18:11:46 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
2020-10-15 08:35:23 +00:00
|
|
|
"value" (write-fn nil)})
|
2020-05-22 15:45:01 +00:00
|
|
|
pod.test-pod/reader-tag
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-22 15:45:01 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
|
|
|
|
"value" "#my/tag[1 2 3]"})
|
|
|
|
|
pod.test-pod/other-tag
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-22 15:45:01 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
2021-05-17 09:41:51 +00:00
|
|
|
"value" "#my/other-tag[1]"})
|
|
|
|
|
pod.test-pod/-local-date-time
|
|
|
|
|
(write out
|
|
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
|
|
|
|
"value" (write-fn (first args))}))
|
2020-05-20 18:11:46 +00:00
|
|
|
(recur))
|
2020-05-26 14:30:46 +00:00
|
|
|
:shutdown (System/exit 0)
|
|
|
|
|
:load-ns (let [ns (-> (get message "ns")
|
|
|
|
|
read-string
|
|
|
|
|
symbol)
|
|
|
|
|
id (-> (get message "id")
|
|
|
|
|
read-string)]
|
|
|
|
|
(case ns
|
|
|
|
|
pod.test-pod.loaded
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-26 14:30:46 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
|
|
|
|
"name" "pod.test-pod.loaded"
|
|
|
|
|
"vars" [{"name" "loaded"
|
|
|
|
|
"code" "(defn loaded [x] (inc x))"}]})
|
|
|
|
|
pod.test-pod.loaded2
|
2020-10-15 08:55:22 +00:00
|
|
|
(write out
|
2020-05-26 14:30:46 +00:00
|
|
|
{"status" ["done"]
|
|
|
|
|
"id" id
|
|
|
|
|
"name" "pod.test-pod.loaded2"
|
|
|
|
|
"vars" [{"name" "x"
|
|
|
|
|
"code" "(require '[pod.test-pod.loaded :as loaded])"}
|
|
|
|
|
{"name" "loaded"
|
|
|
|
|
"code" "(defn loaded [x] (loaded/loaded x))"}]}))
|
|
|
|
|
(recur)))))))
|
2020-05-20 18:11:46 +00:00
|
|
|
(catch Exception e
|
|
|
|
|
(binding [*out* *err*]
|
|
|
|
|
(prn e))))))
|
2020-05-09 12:03:50 +00:00
|
|
|
|
|
|
|
|
(defn -main [& args]
|
2020-10-15 09:27:23 +00:00
|
|
|
#_(binding [*out* *err*]
|
|
|
|
|
(prn :args args))
|
2020-05-09 17:31:25 +00:00
|
|
|
(when (= "true" (System/getenv "BABASHKA_POD"))
|
2020-05-09 15:30:20 +00:00
|
|
|
(run-pod (set args))))
|