Created
June 5, 2024 21:32
-
-
Save jjttjj/04675e8ca73d5052f039abe2cc6a9ad0 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
; Adapted from the clojure source code to work with babashka | |
; https://github.com/clojure/clojure/blob/c07c39cac49a91f6031fe05c2eb7a257aa089176/src/clj/clojure/core/server.clj | |
; original license info: | |
; Copyright (c) Rich Hickey. All rights reserved. | |
; The use and distribution terms for this software are covered by the | |
; Eclipse Public License 1.0 (http://opensource.org/licenses/eclipse-1.0.php) | |
; which can be found in the file epl-v10.html at the root of this distribution. | |
; By using this software in any fashion, you are agreeing to be bound by | |
; the terms of this license. | |
; You must not remove this notice, or any other, from this software. | |
(ns bb-remote-prepl | |
#_(:require [clojure.string :as str] | |
[clojure.edn :as edn] | |
[clojure.main :as m]) | |
(:import | |
[clojure.lang LineNumberingPushbackReader] | |
[java.net InetAddress Socket ServerSocket SocketException] | |
[java.io Reader Writer PrintWriter BufferedWriter BufferedReader InputStreamReader OutputStreamWriter] | |
;;[java.util Properties] | |
;;[java.util.concurrent.locks ReentrantLock] | |
)) | |
(defmacro ^:private thread | |
[^String name daemon & body] | |
`(doto (Thread. (fn [] ~@body) ~name) | |
(.setDaemon ~daemon) | |
(.start))) | |
(defn- ex->data | |
[ex phase] | |
(assoc (Throwable->map ex) :phase phase)) | |
(defn- resolve-fn [valf] | |
(if (symbol? valf) | |
(or (resolve valf) | |
(when-let [nsname (namespace valf)] | |
(require (symbol nsname)) | |
(resolve valf)) | |
(throw (Exception. (str "can't resolve: " valf)))) | |
valf)) | |
(defn remote-prepl | |
"Implements a prepl on in-reader and out-fn by forwarding to a | |
remote [io-]prepl over a socket. Messages will be read by readf, a | |
fn of a LineNumberingPushbackReader and EOF value or a symbol naming | |
same (default #(read %1 false %2)), | |
:ret and :tap vals will be processed by valf, a fn of one argument | |
or a symbol naming same (default read-string). If that function | |
throws, :val will be unprocessed. | |
Alpha, subject to change." | |
{:added "1.10"} | |
[^String host port ^Reader | |
in-reader out-fn & {:keys [valf readf] :or {valf read-string, readf #(read %1 false %2)}}] | |
(let [valf (resolve-fn valf) | |
readf (resolve-fn readf) | |
^long port (if (string? port) (Integer/valueOf ^String port) port) | |
socket (Socket. host port) | |
rd (-> socket .getInputStream InputStreamReader. BufferedReader. LineNumberingPushbackReader.) | |
wr (-> socket .getOutputStream OutputStreamWriter.) | |
EOF (Object.)] | |
(thread "clojure.core.server/remote-prepl" true | |
(try (loop [] | |
(let [{:keys [tag val] :as m} (readf rd EOF)] | |
(when-not (identical? m EOF) | |
(out-fn | |
(if (#{:ret :tap} tag) | |
(try | |
(assoc m :val (valf val)) | |
(catch Throwable ex | |
(assoc m :val (ex->data ex :read-eval-result) | |
:exception true))) | |
m)) | |
(recur)))) | |
(finally | |
(.close wr)))) | |
(let [buf (char-array 1024)] | |
(try (loop [] | |
(let [n (.read in-reader buf)] | |
(when-not (= n -1) | |
(.write wr buf 0 n) | |
(.flush wr) | |
(recur)))) | |
(finally | |
(.close rd)))))) | |
(comment | |
(remote-prepl "localhost" 6662 *in* prn)) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment