pods/test-pod/pod/test_pod.clj

276 lines
12 KiB
Clojure
Raw Normal View History

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"))]
(let [r (transit/reader bais :json {:handlers
{"local-date-time"
(transit/read-handler
(fn [s]
(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))))
(defn transit-json-write [s]
2020-10-15 09:27:23 +00:00
(with-open [baos (java.io.ByteArrayOutputStream. 4096)]
(let [w (transit/writer baos :json {:handlers
{java.time.LocalDateTime
(transit/write-handler
"local-date-time"
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"
2021-10-15 15:43:12 +00:00
"vars" (into [{"name" "add-sync"
"meta" "{:doc \"add the arguments\"}"}
2020-10-15 08:55:22 +00:00
{"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-10-15 15:43:12 +00:00
"code" "(defn read-other-tag [x] [x x])"
"meta" "{:doc \"unread\"}"}
{"name" "-local-date-time"}
{"name" "transit-stuff"
"code" "
(babashka.pods/add-transit-read-handler! \"local-date-time\"
(fn [s] (java.time.LocalDateTime/parse s)))
2021-05-19 21:48:14 +00:00
(babashka.pods/add-transit-write-handler! #{java.time.LocalDateTime}
\"local-date-time\"
str )
(defn local-date-time [x]
(-local-date-time x))
;; serialize Java arrays as vectors with tag java.array
2021-05-19 19:31:51 +00:00
(babashka.pods/set-default-transit-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
"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))))