implemented so many things...

This commit is contained in:
didier amyot committed 2018-09-09 12:20:12 -04:00
1 parent fd843a5425
commit bce64fc8f6
24 files changed
+734 -59

No files matched your search

+1 -1
View File
@@ -9,7 +9,7 @@
(defn -main [config exchange-apis]
(let [bookkeeper-config (:api-bookkeeper config)
api-routes (create-routes-for-bookkeeper exchange-apis config)]
(println "Running server with bellow config")
(println "Running skirmish.bookkeeper.core server with bellow config\n" bookkeeper-config)
(println bookkeeper-config)
(run-server
(-> api-routes api (wrap-cors :access-control-allow-origin #"http://localhost:3449"
+5
View File
@@ -1,4 +1,9 @@
(ns skirmish.broker.core)
(def portfolio {:dapm {:amount 10}
:foo {:amount 5 :long-exposure 10 :short-exposure 7}
:bar {:amount 100 :long-exposure 10 :short-exposure 7}})
(defn -main [config exchange-apis])
+3 -1
View File
@@ -5,6 +5,7 @@
[skirmish.wui.server]
[skirmish.bookkeeper.core]
[skirmish.exchange-gateway.core]
[skirmish.ledger.core]
[skirmish.middleware.core :refer [create-exchange-apis-for]]
[aero.core :refer (read-config)]
[orchestra.spec.test :as st]
@@ -16,11 +17,12 @@
{:api-server skirmish.exchange-gateway.core/-main
:exchange-core skirmish.exchange.core/-main ;; should be skirmish.exchange.core/api-main
:api-bookkeeper skirmish.bookkeeper.core/-main
:ledger skirmish.ledger.core/-main
:wui skirmish.wui.server/-main})
(defn run-all-targets-in-separate-threads [target-fns config exchange-apis]
(println "running multiple targets. This is okay in dev but horrible in production")
(println target-fns)
(println (clojure.string/join "\n" target-fns))
(let [threads (map #(async/thread (% config exchange-apis)) target-fns)
finished-threads (async/merge threads)]
(loop [finished-thread (async/<!! finished-threads)]
+1 -2
View File
@@ -10,8 +10,7 @@
(defn -main [config exchange-apis]
(let [webserver-config (:api-server config)
api-routes (create-routes-for-exchange exchange-apis)]
(println "Running server with bellow config")
(println webserver-config)
(println "Running skirmish.exchange-gateway.core server with bellow config\n" webserver-config)
(run-server (api api-routes) webserver-config)))
@@ -5,12 +5,11 @@
[compojure.handler :refer [api]]
[compojure.core :refer :all]
[skirmish.order] ;; for spec side effect
[skirmish.rest.util :refer [build-response build-response-body]]
[skirmish.rest.util :refer [build-response build-response-body get-body]]
[clojure.spec.alpha :as s]
[kinsky.client]
[slingshot.slingshot :refer [try+ throw+]]
[clojure.core.async :refer [chan go go-loop close! <! >!! sub]]
[clojure.edn :as edn]))
[clojure.core.async :refer [chan go go-loop close! <! >!! sub]]))
(def order-id (atom -1))
@@ -28,13 +27,6 @@
:book.order/entry-timestamp now})))
(defn get-body [body]
(try+
(-> body clojure.java.io/reader slurp edn/read-string)
(catch Exception e
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid body format. Body must be edn format."}}))))
(defn get-exchange-api [sec-id exchange-apis]
(if (contains? exchange-apis sec-id)
(get exchange-apis sec-id)
+93 -1
View File
@@ -1 +1,93 @@
(ns skirmish.ledger.accounts)
(ns skirmish.ledger.accounts
(:require [datomic.api :as d]
[slingshot.slingshot :refer [throw+]]))
(def db-uri "datomic:free://localhost:4334/skirmish")
(def create-securities
[
{:db/ident :skirmish.ledger/create-security
:db/doc "Create a security in the system."
:db/fn (d/function {:lang "clojure"
:requires ['[slingshot.slingshot]]
:params '[db sec-id interest-rate]
:code '(let [security (d/pull db '[:db/id] [:skirmish.security/sec-id sec-id])]
(when (-> security :db/id some?)
(slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "The security already exists."}}))
[#:skirmish.security{:sec-id sec-id :interest-rate interest-rate}])})}])
(def print-securities
[
{:db/ident :skirmish.ledger/emit-securities
:db/doc "Print securities fresh from the press."
:db/fn (d/function {:lang "clojure"
:requires ['[slingshot.slingshot]]
:params '[db sec-id amount account-public-key]
:code '(let [security (d/pull db '[:db/id] [:skirmish.security/sec-id sec-id])
account (d/pull db '[:skirmish.ledger/amount :skirmish.security/sec] [:skirmish.ledger/owner-public-key account-public-key])
base-amount (get account :skirmish.ledger/amount 0)
entity (:db/id account "new-account")]
(when (-> security :db/id nil?)
(slingshot.slingshot/throw+ {:error-type :4XX :status 404 :body {:error "No security with such id."}}))
(when (and (not= (:skirmish.security/sec account) (:db/id security)) (some? (:db/id account)))
(slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "The security emitted does not match the account security."}}))
[[:db/add entity :skirmish.ledger/amount (+ base-amount amount)]
[:db/add entity :skirmish.ledger/owner-public-key account-public-key]
[:db/add entity :skirmish.ledger/sec (:db/id security)]])})}])
;; there are different types of securities...
;; 1. currencies, which pays interest rates in their one sec-id.
;; 2. equities, which do not pay interest rates.
;; 3. bonds, which pays interest rates in another currency.
(def schema-securities
[
{
:db/ident :skirmish.security/sec-id
:db/valueType :db.type/keyword
:db/cardinality :db.cardinality/one
:db/unique :db.unique/identity
:db/doc "The sec id."}
{
:db/ident :skirmish.security/interest-rate
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one
:db/doc "The interest-rate payed by the security as a multiple of 0.01% (100 is 1% interest rate)."}])
(def ledger-schema
[
{
:db/ident :skirmish.ledger/owner-public-key
:db/unique :db.unique/identity
:db/valueType :db.type/string
:db/cardinality :db.cardinality/one
:db/doc "The public key of the owner"}
{
:db/ident :skirmish.ledger/amount
:db/index false
:db/valueType :db.type/long
:db/cardinality :db.cardinality/one
:db/doc "The quantity of currency owned by this account."}
{
:db/ident :skirmish.ledger/sec
:db/index false
:db/valueType :db.type/ref
:db/cardinality :db.cardinality/one
:db/doc "The sec kept in this account."}])
(def schema (-> []
(concat schema-securities)
(concat ledger-schema)
(concat create-securities)
(concat print-securities)))
(defn create-connection [uri]
(let [new-db? (d/create-database uri)
conn (d/connect uri)]
(when new-db?
@(d/transact conn schema))
conn))
+174 -1
View File
@@ -1 +1,174 @@
(ns skirmish.ledger.core)
(ns skirmish.ledger.core
(:require [org.httpkit.server :refer [run-server]]
[compojure.handler :refer [api]]
[skirmish.util :refer [block-thread]]
[slingshot.slingshot :refer [try+ throw+]]
[compojure.route :refer [not-found]]
[skirmish.middleware.core :refer [create-exchange-apis-for]]
[skirmish.exchange-gateway.exchange-gateway :refer [create-routes-for-exchange]]
[skirmish.rest.util :refer [build-response get-body]]
[skirmish.ledger.accounts]
[datomic.api :as d]
[compojure.core :refer :all]
[clojure.spec.alpha :as s]
[ring.middleware.cors :refer [wrap-cors]]))
;; the ledger is the central
;; an :account-id is the public key of a
;; an :account-secret is an :acount-id private key
(defn get-account-body [request account sec]
(if (nil? sec)
(build-response request {:status 404})
(let [sec-url (str "/api/1/securities/" (-> sec :skirmish.security/sec-id name))
beautify-account { :amount (:skirmish.ledger/amount account)
:sec-id (:skirmish.security/sec-id sec)
:account-public-key (:skirmish.ledger/owner-public-key account)}
ret {:account beautify-account :sec-url sec-url}]
(build-response request ret))))
(defn get-account [conn]
"Returns the value of an account."
(fn [{{account-id :account-id} :route-params :as request}]
(let [db (d/db conn)
account (d/pull db '[*] [:skirmish.ledger/owner-public-key account-id])
sec-eid (-> account :skirmish.ledger/sec :db/id)
sec (d/entity db sec-eid)]
(get-account-body request account sec))))
(s/def ::transaction (s/cat :type #{:create}
:sec-id keyword?
:amount int?
:account-id string?))
(defn get-transaction [raw-transact]
(if (s/valid? ::transaction raw-transact)
(s/conform ::transaction raw-transact)
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid transaction format."}})))
(s/def ::security (s/cat :sec-id keyword?
:interest-rate nat-int?))
(defn get-new-security [raw-securities]
(if (s/valid? ::security raw-securities)
raw-securities
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid security format."}})))
(defn get-security-from-db [conn sec-id]
(let [e (d/pull (d/db conn) '[*] [:skirmish.security/sec-id sec-id])
{interest-rate :skirmish.security/interest-rate id :db/id} e
ret {:sec-id sec-id :interest-rate interest-rate}]
(if (nil? id)
(throw+ {:error-type :4XX :status 404 :body {:error "Security not found."}})
ret)))
(defn create-security [conn]
"Create a fresh new security."
(fn [{body :body :as request}]
(try+
(let [[sec-id interest-rate] (-> body get-body get-new-security)]
@(d/transact conn [[:skirmish.ledger/create-security sec-id interest-rate]])
(build-response request {:body {:success true}
:headers {"location" (str "/api/1" "/ledger/securities/" (name sec-id))}}))
(catch [:error-type :4XX] e (build-response request e))
(catch [:error-type :5XX] e (build-response request e))
(catch Object _
(println (:throwable &throw-context) "unexpected error")))))
(defn get-security [conn]
"Returns the security."
(fn [{{sec-id-str :sec-id} :route-params :as request}]
(try+
(let [sec-id (keyword sec-id-str)]
(build-response request (get-security-from-db conn sec-id)))
(catch [:error-type :4XX] e (build-response request e))
(catch [:error-type :5XX] e (build-response request e)))))
(defn update-security [conn]
"Update a security with new features."
(fn [request]
(try+
(catch [:error-type :4XX] e (build-response request e))
(catch [:error-type :5XX] e (build-response request e)))))
(defn get-available-securities-body [securities]
(let [sec-id->url #(str "/api/1/ledger/securities/" (name %))
to-security-description #(hash-map :sec-id % :url (sec-id->url %))
xf (comp cat (map to-security-description))
securities-info (sequence xf securities)];;
{:securities securities-info}))
(defn get-available-securities [conn]
(fn [request]
(let [securities (d/q '[:find ?s :where [?e :skirmish.security/sec-id ?s]] (d/db conn))]
(build-response request (get-available-securities-body securities)))))
(s/def ::emit-securities (s/cat :sec-id keyword?
:amount nat-int?
:account string?))
(defn get-emit-securities-request [[amount account] sec-id]
(if (s/valid? ::emit-securities [sec-id amount account])
[:skirmish.ledger/emit-securities sec-id amount account]
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid emit request."}})))
(defn emit-securities [conn]
(fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
(try+
(let [emit-request (-> body get-body (get-emit-securities-request (keyword sec-id-str)))]
@(d/transact conn [emit-request])
(build-response request {}))
(catch [:error-type :4XX] e (build-response request e))
(catch [:error-type :5XX] e (build-response request e)))))
(defn get-available-accounts-body [accounts]
(let [sec-id->url #(str "/api/1/ledger/accounts/" (name %))
to-security-description #(hash-map :account-public-key % :url (sec-id->url %))
xf (comp cat (map to-security-description))
securities-info (sequence xf accounts)];;
{:accounts securities-info}))
(defn get-available-accounts [conn]
(fn [request]
(let [securities (d/q '[:find ?pk :where [?e :skirmish.ledger/owner-public-key ?pk]] (d/db conn))]
(build-response request (get-available-accounts-body securities)))))
(defn get-api-description [request]
(let [body [{:url "ledger/accounts" :name "accounts"}
{:url "ledger/securities" :name "securities"}]]
(build-response request body)))
(defn create-routes-for-ledger [securities conn]
(routes
(context "/api/1" []
(GET "/" get-api-description)
(GET "/ledger/accounts" [] (get-available-accounts conn))
(GET "/ledger/accounts/:account-id" [] (get-account conn))
(GET "/ledger/securities" [] (get-available-securities conn)) ;; done
(POST "/ledger/securities" [] (create-security conn)) ;; done
(GET "/ledger/securities/:sec-id" [] (get-security conn)) ;; done
(PUT "/ledger/securities/:sec-id" [] (update-security conn)) ;; not done
(POST "/ledger/securities/:sec-id" [] (emit-securities conn))) ;; done
(not-found "not found")))
(defn -main [config exchange-apis]
(let [ledger-config (:ledger-server config)
conn (skirmish.ledger.accounts/create-connection (-> config :datomic :transactor-url))
api-routes (create-routes-for-ledger (:securities config) conn)]
(println "Running skirmish.ledger.core server with bellow config\n" ledger-config)
(run-server (api api-routes) ledger-config)))
+22 -4
View File
@@ -1,5 +1,7 @@
(ns skirmish.rest.util
(:require [cheshire.core :refer [generate-string]]
[slingshot.slingshot :refer [try+ throw+]]
[clojure.edn :as edn]
[clojure.string :refer [split starts-with? ends-with?]]))
;; Access-Control-Allow-Origin
@@ -40,8 +42,24 @@
(let [[_ serializer] (get-best-serializer request)]
(serializer body)))
(defn build-response [request {status :status body :body :as response}]
(let [[content-type serializer] (get-best-serializer request)]
(defn build-response [request {status :status body :body headers :headers :as response}]
(let [[content-type serializer] (get-best-serializer request)
ret-headers (if (some? headers) headers {})]
{:body (serializer (if (nil? body) response body))
:headers {"Content-Type" content-type}
:status (get-status status request)}))
:headers (into {"Content-Type" content-type} ret-headers)
:status (get-status status request)}))
(defn get-body [body]
(try+
(-> body clojure.java.io/reader slurp edn/read-string)
(catch Exception e
(throw+ {:error-type :4XX :status 400 :body {:error "Invalid body format. Body must be edn format."}}))))
(defn string->stream
([s] (string->stream s "UTF-8"))
([s encoding]
(-> s
(.getBytes encoding)
(java.io.ByteArrayInputStream.))))
(def edn->stream (comp string->stream str))
+18 -1
View File
@@ -10,4 +10,21 @@
(defn block-thread []
"Block the current thread until chuck norris gets weaker."
(async/<!! (async/chan)))
(async/<!! (async/chan)))
(defn- get-overlapping-for-specific-event [event sorted-events]
(let [event-end (:calendar.event/end event)]
(take-while #(< (:calendar.event/start %) event-end) sorted-events)))
(defn get-overlapping-events [events]
(let [sorted-events (sort-by :calendar.event/start events)]
(loop [events sorted-events ret []]
(if (seq events)
(let [first-event (first events)
rest-events (rest events)
overlapping-events (get-overlapping-for-specific-event first-event rest-events)
overlapping-pairs (map vector (repeat first-event) overlapping-events)
new-ret (if (seq overlapping-pairs) (into ret overlapping-pairs) ret)]
(recur rest-events new-ret))
ret))))
@@ -1,4 +1,50 @@
(ns skirmish.wui.components.create-order-page)
(ns skirmish.wui.components.create-order-page
(:require [reagent.core :refer [atom]]))
(defn set-value-in-atom [atm key evt]
(swap! atm #(assoc % key (-> evt .-target .-value))))
(defn select-type [order]
[:div.control
[:div.select
[:select {:on-change (partial set-value-in-atom order :type)}
[:option {:value :buy} "Buy"]
[:option {:value :sell} "Sell"]]]])
(defn select-securities [order]
[:div.control
[:div.select
[:select {:on-change (partial set-value-in-atom order :sec-id)}
[:option {:value :nype} ":nype"]
[:option {:value :osko} ":osko"]
[:option {:value :oops} ":oops"]]]])
(defn select-quantities [order]
[:div.control
[:input.input {:type "number"
:on-change (partial set-value-in-atom order :quantity)}]])
(def action-button
[:div.control
[:button.button.is-primary "Submit"]])
(defn page []
[:h1 "create order page"])
(let [order (atom {})]
(fn []
[:div
[:div.columns
[:div.column.content
[:div.columns.is-centered
[:column
[:div.field.has-addons
(select-type order)
(select-securities order)
(select-quantities order)
action-button]]]]]
[:div.columns
[:div.column.content
[:pre (str @order)]]]])))
@@ -1,4 +1,16 @@
(ns skirmish.wui.components.home-page)
(ns skirmish.wui.components.home-page
(:require [reagent.core :refer [atom]]))
(def lorem-ipsum ["Lorem ipsum dolor amet pickled bushwick next level adaptogen ugh franzen salvia hoodie man bun organic kinfolk. Hammock pickled banjo, artisan single-origin coffee brunch 90's occupy taxidermy. Put a bird on it gentrify offal tilde. Authentic put a bird on it prism semiotics, roof party banh mi typewriter. XOXO schlitz sriracha godard."
"Succulents shoreditch twee, VHS hammock hot chicken distillery. Edison bulb aesthetic pork belly meggings. 3 wolf moon artisan keytar blue bottle. Actually pok pok asymmetrical, banh mi before they sold out PBR&B portland tumblr."
"Gentrify palo santo enamel pin, tumeric jianbing thundercats shaman green juice chambray yr. Kale chips synth meditation chambray thundercats helvetica, cornhole whatever kickstarter ennui pop-up lo-fi godard. Austin unicorn brunch woke hammock. Coloring book kombucha occupy tofu wayfarers."])
(defn page [state]
[:h1 "Hello world sdjjksd dsklsd"])
[:div
[:section.section
[:div.container
[:h1.title "lorem ipsum"]
(for [sentence lorem-ipsum]
[:p sentence])]]])
@@ -1,4 +1,21 @@
(ns skirmish.wui.components.portfolio-page)
(ns skirmish.wui.components.portfolio-page
(:require [reagent.core :refer [atom]]
[skirmish.wui.components.secunit :refer [secunit]]))
(defn make-portfolio-summary-table [portfolio]
[:table
[:thead
[:tr [:th "Security"] [:th "Amount"] [:th "Face Value"]]]
[:tbody
(for [sec-summary portfolio]
[:tr
[:td (:sec-id sec-summary)]
[:td [secunit (:sec-id sec-summary) (:amount sec-summary)]]
[:td [secunit :dapm (:face-value sec-summary)]]])]])
(defn page []
[:h1 "portfolio page"])
(let [porfolio [{:sec-id :foo :amount 100 :face-value 1265}
{:sec-id :toto :amount 100 :face-value 1265}
{:sec-id :foo :amount 100 :face-value 1265}]]
[:div.content
(make-portfolio-summary-table porfolio)]))
@@ -0,0 +1,5 @@
(ns skirmish.wui.components.secunit)
(defn secunit [sec-id amount]
(let [href (str "/securities/" sec-id)]
[:a {:href href} (str amount)]))