diff --git a/book.iml b/book.iml
index 3eac619..e8353b5 100644
--- a/book.iml
+++ b/book.iml
@@ -15,19 +15,33 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
@@ -53,7 +67,10 @@
+
+
+
\ No newline at end of file
diff --git a/project.clj b/project.clj
index 9081c7b..c6b950c 100644
--- a/project.clj
+++ b/project.clj
@@ -4,7 +4,15 @@
:license {:name "Eclipse Public License"
:url "http://www.eclipse.org/legal/epl-v10.html"}
:dependencies [[org.clojure/clojure "1.9.0"]
- [org.clojure/core.async "0.4.474"]]
+ [org.clojure/core.async "0.4.474"]
+ ;; web
+ [http-kit "2.3.0"]
+ [compojure "1.6.1"]
+ [javax.servlet/javax.servlet-api "3.1.0"]
+
+ ;;utils
+ [slingshot "0.12.2"]
+ [cheshire "5.8.0"]]
:java-source-paths ["src/java"]
:main ^:skip-aot book.core
:target-path "target/%s"
diff --git a/src/book/cli.clj b/src/book/cli.clj
new file mode 100644
index 0000000..4a2147f
--- /dev/null
+++ b/src/book/cli.clj
@@ -0,0 +1,56 @@
+(ns book.cli
+ (:require [book.match :refer [sell?]]
+ [book.util :refer :all]
+ [book.exchange :refer [empty-book process-orders create-exchange-for-security]]
+ [book.order] ;; for spec side effect
+ [slingshot.slingshot :refer [try+ throw+]]
+ [clojure.edn :as edn]
+ [clojure.core.async :refer [chan go >!! " trades-channel))
+ (go (print-chan "order > " new-book-order-channel))
+ (loop [order (read-order)]
+ (if (some? order)
+ (do
+ (let [order-with-id (add-id-to-order order)]
+ (>!! incoming-order-channel order-with-id)
+ (println "\n\norder accepted with id: " (:book.order/id order-with-id))))
+
+ (println "invalid order"))
+ (recur (read-order)))))
diff --git a/src/book/core.clj b/src/book/core.clj
index 2090939..38830ed 100644
--- a/src/book/core.clj
+++ b/src/book/core.clj
@@ -1,80 +1,10 @@
(ns book.core
- (:require [book.match :refer [sell?
- create-buy-book
- create-sell-book
- match-order-in-book]]
- [book.util :refer :all]
- [book.order] ;; for spec side effect
- [clojure.edn :as edn]
- [clojure.core.async :refer [chan go >!! !! trades-channel trades))
- (when leftover-order (>!! new-book-order-channel leftover-order))
- (recur (!! trades-channel trades))
- (when leftover-order (>!! new-book-order-channel leftover-order))
- (recur ( " trades-channel))
- (go (print-chan "order > " new-book-order-channel))
- (go (process-orders master-book incoming-order-channel trades-channel new-book-order-channel))
- (loop [order (read-order)]
- (if (some? order)
- (do
- (let [order-with-id (add-id-to-order order)]
- (>!! incoming-order-channel order-with-id)
- (println "\n\norder accepted with id: " (:book.order/id order-with-id))))
-
- (println "invalid order"))
- (recur (read-order))))
+(defn -main [& argv]
+ (case (first argv)
+ "web" (apply book.web/-main (rest argv))
+ "cli" (apply book.cli/-main (rest argv))
+ (println "First argument must be web or cli")))
diff --git a/src/book/exchange.clj b/src/book/exchange.clj
new file mode 100644
index 0000000..77dbdcb
--- /dev/null
+++ b/src/book/exchange.clj
@@ -0,0 +1,40 @@
+(ns book.exchange
+ (:require [book.match :refer [sell?
+ create-buy-book
+ create-sell-book
+ match-order-in-book]]
+ [book.util :refer :all]
+ [clojure.core.async :refer [chan go >!! !! trades-channel trade)))
+ (when leftover-order (>!! new-book-order-channel leftover-order))
+ [new-reference-book new-same-type-book]))
+
+
+(defn process-sell-order [order {sell-book :sell buy-book :buy} trades-channel new-book-order-channel]
+ (let [[new-buy-book new-sell-book] (process-abstract-sell order buy-book sell-book trades-channel new-book-order-channel)]
+ {:sell new-sell-book :buy new-buy-book}))
+
+(defn process-buy-order [order {sell-book :sell buy-book :buy} trades-channel new-book-order-channel]
+ (let [[new-sell-book new-buy-book] (process-abstract-sell order sell-book buy-book trades-channel new-book-order-channel)]
+ {:sell new-sell-book :buy new-buy-book}))
+
+(defn process-orders [master-book orders-channel trades-channel new-book-order-channel]
+ (loop [order ( 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 create-order [books]
+ (fn [{{sec-id-str :sec-id} :route-params body :body :as request}]
+ (try+
+ (let [asked-order (get-order body)
+ order (validate-order asked-order)
+ sec-id (keyword sec-id-str)
+ book (get books sec-id)]
+ (build-response request {:order order :book book}))
+ (catch [:error-type :4XX] e (build-response request e))
+ (catch [:error-type :5XX] e (build-response request e)))))
+
+
+(defn create-routes [books]
+ (routes
+ (context "/api/1" []
+ (GET "/" [] api-description)
+ (GET "/securities" [] (securities books))
+ (GET "/securities/:sec-id" [] (get-security books))
+ (POST "/securities/:sec-id" [] (create-order books)))
+ (not-found "not found")))
+
+
+(defn -main [& args]
+ (let [books {:foo empty-book :bar empty-book}
+ api-routes (create-routes books)]
+ (run-server (api api-routes) {:port 8080})))
\ No newline at end of file
diff --git a/test/book/core_test.clj b/test/book/core_test.clj
deleted file mode 100644
index 3e35b1a..0000000
--- a/test/book/core_test.clj
+++ /dev/null
@@ -1,13 +0,0 @@
-(ns book.core-test
- (:require [midje.sweet :refer :all]))
-
-(facts "big fact"
- (fact "about trivialities"
- (let [expt 3]
- (inc 2) => expt
- (inc 2) => expt))
-
- (fact "about trivialities 2"
- (let [expt 3]
- (inc 2) => expt
- (inc 2) => expt)))
diff --git a/test/book/exchange_test.clj b/test/book/exchange_test.clj
new file mode 100644
index 0000000..389620c
--- /dev/null
+++ b/test/book/exchange_test.clj
@@ -0,0 +1,28 @@
+(ns book.exchange-test
+ (:require [midje.sweet :refer :all]
+ [book.exchange :refer :all]
+ [book.match :refer [create-buy-book
+ create-sell-book]]
+ [clojure.core.async :refer [chan go >!! !! incoming-order-channel {:type :sell :quantity 10 :price 2})
+ ( {:type :sell :quantity 10 :price 2}
+ (>!! incoming-order-channel {:type :buy :quantity 20 :price 2})
+ ( #:book.order{:book-id nil
+ :order-id nil
+ :price 2
+ :quantity 10
+ :type :sell}
+ ( {:type :buy :quantity 10 :price 2})))
+
+
+
+
+
diff --git a/test/book/rest/util_test.clj b/test/book/rest/util_test.clj
new file mode 100644
index 0000000..42ace8c
--- /dev/null
+++ b/test/book/rest/util_test.clj
@@ -0,0 +1,43 @@
+(ns book.rest.util-test
+ (:require [book.rest.util :refer [build-response]]
+ [midje.sweet :refer :all]
+ [clojure.test :refer :all]))
+
+(defn expt-response [body content-type status]
+ {:body body
+ :headers {"Content-Type" content-type}
+ :status status})
+
+(facts "the building the response"
+ (fact "building the response in edn"
+ (let [content-type "application/edn"
+ request {:headers {"accept" content-type}}
+ response "foo"
+ expt (expt-response "foo" "application/edn" 200)]
+ (build-response request response) => expt))
+ (fact "building the response in edn"
+ (let [content-type "application/edn"
+ request {:headers {"accept" content-type}}
+ response {:foo [1 2 3]}
+ expt (expt-response "{:foo [1 2 3]}" "application/edn" 200)]
+ (build-response request response) => expt))
+ (fact "building the response in edn"
+ (let [content-type "application/edn,application/json"
+ request {:headers {"accept" content-type}}
+ response {:foo [1 2 3]}
+ expt (expt-response "{:foo [1 2 3]}" "application/edn" 200)]
+ (build-response request response) => expt))
+ (fact "building the response in json"
+ (let [content-type "text/html,application/xhtml+xml,application/json,application/xml;q=0.9,*/*;q=0.8"
+ request {:headers {"accept" content-type}}
+ response {:foo [1 2 3]}
+ expt (expt-response "{\"foo\":[1,2,3]}" "application/json" 200)]
+ (build-response request response) => expt))
+ (fact "My browser should receive json"
+ (let [content-type "text/html,application/xhtml+xml,application/xml;q=0.9,*/*;q=0.8"
+ request {:headers {"accept" content-type}}
+ response {:foo [1 2 3]}
+ expt (expt-response "{\"foo\":[1,2,3]}" "application/json" 200)]
+ (build-response request response) => expt)))
+
+