Skip to content

Commit

Permalink
Merge pull request #20 from liquidz/dev
Browse files Browse the repository at this point in the history
Next release
  • Loading branch information
liquidz authored Jan 4, 2025
2 parents 086ae96 + 4b8c0ed commit 4c728e0
Show file tree
Hide file tree
Showing 12 changed files with 174 additions and 77 deletions.
29 changes: 20 additions & 9 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -44,21 +44,32 @@ jobs:
git config --global user.name "github-actions"
git add CHANGELOG.adoc
git commit -m "Update CHANGELOG" || exit 0
git push
git push origin main
git fetch origin dev
git switch dev
git rebase main
git push origin dev
create_pull_request:
needs: [changelog]
runs-on: ubuntu-latest
permissions:
contents: write
pull-requests: write
steps:
- uses: actions/checkout@v4
- name: Create Pull Request
uses: peter-evans/create-pull-request@v7
- name: Create a pull request
uses: actions/github-script@v7
with:
title: Next release
branch: dev
base: main
labels: release
draft: true
github-token: ${{ secrets.GITHUB_TOKEN }}
script: |
const headRef = '${{ steps.pull_request_head.outputs.ref }}'
const createParams = {
owner: context.repo.owner,
repo: context.repo.repo,
base: 'main',
head: 'dev',
title: 'Next release'
}
const { data } = await github.rest.pulls.create(createParams)
return data
2 changes: 1 addition & 1 deletion bb.edn
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
:__elin_internal__
{:command {:deps {nrepl/nrepl {:mvn/version "1.3.1"}
refactor-nrepl/refactor-nrepl {:mvn/version "3.10.0"}
cider/cider-nrepl {:mvn/version "0.51.0"}}
cider/cider-nrepl {:mvn/version "0.51.1"}}
:middlewares [cider.nrepl/cider-middleware
refactor-nrepl.middleware/wrap-refactor]}}

Expand Down
2 changes: 1 addition & 1 deletion dev/analysis.edn

Large diffs are not rendered by default.

2 changes: 2 additions & 0 deletions dev/elin/task/doc.clj
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,8 @@
e.c.interceptor/debug "Executed on debugging."
e.c.interceptor/modify-code "Executed on modifying code."
e.c.interceptor/tap "Executed on tapping some values."
e.c.interceptor/http-route "Executed on creating http routes."
e.c.interceptor/http-request "Executed on handling requests for HTTP server."
nil))

(defn- generate-interceptor-document
Expand Down
2 changes: 1 addition & 1 deletion doc/pages/getting_started/index.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ Alternatively, you can also start the REPL within the Elin server using the <<El

[source,shell]
----
$ clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.3.1"} cider/cider-nrepl {:mvn/version "0.51.0"}}}' -M -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]" --interactive
$ clj -Sdeps '{:deps {nrepl/nrepl {:mvn/version "1.3.1"} cider/cider-nrepl {:mvn/version "0.51.1"}}}' -M -m nrepl.cmdline --middleware "[cider.nrepl/cider-middleware]" --interactive
----

Once the REPL is running, connect to the REPL using the <<ElinConnect>> command.
1 change: 1 addition & 0 deletions resources/config.edn
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@
elin.interceptor.debug/initialize-debugger {}
elin.interceptor.debug/process-debugger {}
elin.interceptor.handler/handling-error {}
elin.interceptor.http/api-route {}
elin.interceptor.nrepl/nrepl-output {}
elin.interceptor.nrepl/eval-ns {}
elin.interceptor.nrepl/normalize-path {}
Expand Down
111 changes: 48 additions & 63 deletions src/elin/component/server/http.clj
Original file line number Diff line number Diff line change
@@ -1,85 +1,70 @@
(ns elin.component.server.http
(:require
[cheshire.core :as json]
[clojure.java.io :as io]
[com.stuartsierra.component :as component]
[elin.protocol.host.rpc :as e.p.h.rpc]
[elin.constant.interceptor :as e.c.interceptor]
[elin.protocol.interceptor :as e.p.interceptor]
[elin.util.http :as e.u.http]
[org.httpkit.server :as h.server])
(:import
(java.net URLDecoder)))

(defn- valid-request?
[{:keys [request-method headers]}]
(and (= :post request-method)
(= "application/json" (get headers "content-type"))))

(defprotocol IHttpHandler
(new-message [this request params])
(handle [this request]))

(defrecord ApiMessage
[host message method params]
e.p.h.rpc/IRpcMessage
(request? [_] true)
(response? [_] false)
(parse-message [_]
{:id -1
:method method
:params params}))

(defn- ok
[resp]
{:body resp})

(defn- bad-request
[& [m]]
(merge {:status 400 :body "Bad request"}
m))

(defn- not-found
[& [m]]
(merge {:status 404 :body "Not found"}
m))

(defrecord HttpServer
[handler host port stop-server]
[handler server-host port
;; Parameters set at start
stop-server
context
routes]
component/Lifecycle
(start [this]
(assoc this :stop-server (h.server/run-server
#(handle this %)
{:port port})))
(let [context {;; Other components
:component/nrepl (:nrepl handler)
:component/interceptor (:interceptor handler)
:component/host (:lazy-host handler)
:component/handler handler
:component/session-storage (:session-storage handler)
:component/clj-kondo (:clj-kondo handler)
;; This component parameters
:server-host server-host
:port port}
routes (:routes (e.p.interceptor/execute
(:interceptor handler)
e.c.interceptor/http-route
(assoc context :routes {})
identity))
this' (assoc this
:context context
:routes routes)]
(assoc this' :stop-server (h.server/run-server
#(handle this' %)
{:port port}))))
(stop [this]
(stop-server)
(dissoc this :stop-server))
(dissoc this :stop-server :context))

IHttpHandler
(new-message [_ method params]
(map->ApiMessage {:host host
:message []
:method (keyword method)
:params (or params [])}))

(handle [this {:as req :keys [uri body]}]
(let [uri (URLDecoder/decode uri)]
(condp = uri
"/api/v1"
(if-not (valid-request? req)
(not-found)
(let [handler' (:handler handler)
{:keys [method params]} (json/parse-stream (io/reader body) keyword)]
(if (not method)
(bad-request)
(-> (new-message this
(keyword method)
(or params []))
(handler')
(json/generate-string)
(ok)))))

(not-found)))))
(handle [_ request]
(let [context' (assoc context
:routes routes
:request request)]
(:response
(e.p.interceptor/execute
(:interceptor handler)
e.c.interceptor/http-request
context'
(fn [{:as ctx :keys [routes request]}]
(let [uri (URLDecoder/decode (:uri request))
route-fn (get routes uri)]
(assoc ctx :response
(if (and route-fn
(fn? route-fn))
(route-fn ctx)
(e.u.http/not-found))))))))))

(defn new-http-server
[config]
(-> (or (:http-server config) {})
(merge {:host (get-in config [:server :host])})
(merge {:server-host (get-in config [:server :host])})
(map->HttpServer)))
2 changes: 2 additions & 0 deletions src/elin/constant/interceptor.clj
Original file line number Diff line number Diff line change
Expand Up @@ -17,3 +17,5 @@
(def debug ::debug)
(def modify-code ::modify-code)
(def tap ::tap)
(def http-route ::http-route)
(def http-request ::http-request)
4 changes: 3 additions & 1 deletion src/elin/interceptor/debug.clj
Original file line number Diff line number Diff line change
Expand Up @@ -47,7 +47,9 @@
e.c.interceptor/test-result e.s.interceptor/?TestResultContext
e.c.interceptor/quickfix e.s.interceptor/?QuickfixContext
e.c.interceptor/modify-code e.s.interceptor/?ModifyCodeContext
e.c.interceptor/tap e.s.interceptor/?TapContext})
e.c.interceptor/tap e.s.interceptor/?TapContext
e.c.interceptor/http-route e.s.interceptor/?HttpRouteContext
e.c.interceptor/http-request e.s.interceptor/?HttpRequestContext})

(def interceptor-context-checking
{:kind e.c.interceptor/all
Expand Down
55 changes: 55 additions & 0 deletions src/elin/interceptor/http.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
(ns elin.interceptor.http
(:require
[cheshire.core :as json]
[clojure.java.io :as io]
[elin.constant.interceptor :as e.c.interceptor]
[elin.protocol.host.rpc :as e.p.h.rpc]
[elin.util.http :as e.u.http]))

(defrecord ApiMessage
[host message method params]
e.p.h.rpc/IRpcMessage
(request? [_] true)
(response? [_] false)
(parse-message [_]
{:id -1
:method method
:params params}))

(defn- api-request?
[{:keys [request-method headers]}]
(and (= :post request-method)
(= "application/json" (get headers "content-type"))))

(defn- new-message
[server-host method params]
(map->ApiMessage {:host server-host
:message []
:method (keyword method)
:params (or params [])}))

(defn- handle-api
[{:component/keys [handler] :keys [server-host request]}]
(if-not (api-request? request)
(e.u.http/bad-request)
(let [handler' (:handler handler)
{:keys [body]} request
{:keys [method params]} (json/parse-stream (io/reader body) keyword)]
(if (not method)
(e.u.http/bad-request)
(-> (new-message server-host
(keyword method)
(or params []))
(handler')
(e.u.http/json))))))

(def api-route
"Add http route as `/api/v1` for API request.
.e.g.
[source,shell]
----
curl -XPOST -H \"Content-Type: application/json\" -d '{\"method\": \"elin.handler.complete/complete\", \"params\": [\"ma\"]}' http://localhost:12345/api/v1
----"
{:kind e.c.interceptor/http-route
:enter #(assoc-in % [:routes "/api/v1"] handle-api)})
18 changes: 17 additions & 1 deletion src/elin/schema/interceptor.clj
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,9 @@
e.c.interceptor/test-result
e.c.interceptor/quickfix
e.c.interceptor/modify-code
e.c.interceptor/tap])
e.c.interceptor/tap
e.c.interceptor/http-route
e.c.interceptor/http-request])

(def ?Interceptor
[:map
Expand Down Expand Up @@ -128,3 +130,17 @@
;; LEAVE
[:value-str {:optional true} string?]]
(m.util/merge e.s.handler/?Components)))

(def ?HttpRouteContext
(-> [:map
[:routes map?]]
(m.util/merge e.s.handler/?Components)))

(def ?HttpRequestContext
(-> [:map
;; ENTER
[:routes map?]
[:request any?]
;; LEAVE
[:response {:optional true} any?]]
(m.util/merge e.s.handler/?Components)))
23 changes: 23 additions & 0 deletions src/elin/util/http.clj
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
(ns elin.util.http
(:require
[cheshire.core :as json]))

(defn ok
[resp]
{:body resp})

(defn bad-request
[& [m]]
(merge {:status 400 :body "Bad request"}
m))

(defn not-found
[& [m]]
(merge {:status 404 :body "Not found"}
m))

(defn json
[value]
(-> value
(json/generate-string)
(ok)))

0 comments on commit 4c728e0

Please sign in to comment.