Created
December 4, 2018 14:58
-
-
Save kaffein/94e7bffab0e59ed585753ac58953c26c to your computer and use it in GitHub Desktop.
Yetibot's Scala command refactoring
This file contains 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
(ns yetibot.commands.scala | |
(:require | |
[taoensso.timbre :refer [info warn error]] | |
[yetibot.core.hooks :refer [cmd-hook]] | |
[clj-http.client :as client] | |
[clojure.string :as s] | |
[cheshire.core :as json] | |
[kvlt.core :as kvlt] | |
[clojure.core.async :as async])) | |
(def endpoint "https://scastie.scala-lang.org/api/") | |
(def sbt-config-extra "scalacOptions ++= Seq(\"-deprecation\", \"-encoding\", \"UTF-8\", \"-feature\", \"-unchecked\")") | |
(def scala-version "2.12.6") | |
(def platform "Jvm") | |
(defn make-body | |
[scala-str] | |
(json/generate-string {:_isWorksheetMode true | |
:code scala-str | |
:target {:scalaVersion scala-version | |
:$type platform} | |
:libraries [] | |
:librariesFromList [] | |
:sbtConfigExtra sbt-config-extra | |
:sbtPluginsConfigExtra "" | |
:isShowingInUserProfile false})) | |
(defn try-scala | |
"Submits the Scala expression to the evaluation API and returns a | |
Server-Sent Events core.async channel for retrieving the result." | |
[expr] | |
(info "scala:" expr) | |
(as-> (str endpoint "run") v | |
(client/post v {:content-type :json | |
:accept :json | |
:body (make-body expr)}) | |
(:body v) | |
(json/parse-string v true) | |
(:base64UUID v) | |
(str endpoint "progress-sse/" v) | |
(kvlt/event-source! v))) | |
(defn extract-success | |
"Extracts success evaluation info from the SSE-message data." | |
[{user-output :userOutput instrumentations :instrumentations}] | |
(cond | |
(seq user-output) (get-in user-output [:line]) | |
(seq instrumentations) (->> instrumentations | |
(map (fn [{{v :v className :className} :render}] | |
(format "%s: %s" v className))) | |
(s/join "\n")))) | |
(defmulti format-result | |
"Returns a dispatch-value based on the SSE data received from the evaluation API." | |
(fn [{:keys [compilationInfos isTimeout]}] | |
(cond | |
(true? isTimeout) :eval-timeout | |
(seq compilationInfos) :eval-runtime-error | |
:else :eval-success))) | |
(defmethod format-result :eval-timeout | |
[_] | |
(str "The expression timed out")) | |
(defmethod format-result :eval-runtime-error | |
[data] | |
(->> data | |
:compilationInfos | |
(map :message) | |
(s/join "\n"))) | |
(defmethod format-result :eval-success | |
[data] | |
(extract-success data)) | |
(defn extract-result | |
"Extracts the Scala evaluation result from the core.async channel provided | |
as argument." | |
[chan] | |
(let [out-chan (async/chan)] | |
(async/go-loop [] | |
(when-let [v (async/<! chan)] | |
(let [data (json/parse-string (:data v) true)] | |
(when-let [result (format-result data)] | |
(async/>! out-chan result))) | |
(recur))) | |
out-chan)) | |
(defn scala-cmd | |
"scala <expression> # evaluate a scala expression" | |
{:yb/cat #{:repl}} | |
[{expr :match}] | |
(let [out-chan (-> expr | |
try-scala | |
extract-result) | |
result (async/<!! out-chan)] | |
(async/close! out-chan) | |
result)) | |
(cmd-hook #"scala" | |
#".*" scala-cmd) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment