diff --git a/README.md b/README.md index d2cf33f..5421a74 100644 --- a/README.md +++ b/README.md @@ -39,6 +39,7 @@ file should be self documented. * [clojure](https://clojure.org/) for programming language * [kafka](http://kafka.apache.org/) for message broker/database * [datomic-free](https://www.datomic.com/) for transaction needs +* [clickhouse](https://clickhouse.yandex) to store the market data #### In the browser * [clojure script](https://clojurescript.org/) for programming language diff --git a/docker-compose.yml b/docker-compose.yml index 01e4935..be70280 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -159,6 +159,14 @@ services: - "4335:4335" - "4336:4336" + clickhouse: + image: "yandex/clickhouse-server:18.14" + restart: "unless-stopped" + ports: + - "8123:8123" + - "9000:9000" + + # skirmish itself diff --git a/env/dev/clj/skirmish/wui/middleware.clj b/env/dev/clj/skirmish/wui/middleware.clj index 753b1a6..b9714a3 100644 --- a/env/dev/clj/skirmish/wui/middleware.clj +++ b/env/dev/clj/skirmish/wui/middleware.clj @@ -1,7 +1,6 @@ (ns skirmish.wui.middleware (:require [ring.middleware.defaults :refer [site-defaults wrap-defaults]] - [prone.middleware :refer [wrap-exceptions]] - [ring.middleware.reload :refer [wrap-reload]])) + [prone.middleware :refer [wrap-exceptions]])) (defn custom-dev-middleware [handler] (fn [request] @@ -12,5 +11,4 @@ (-> handler (wrap-defaults site-defaults) custom-dev-middleware - wrap-exceptions - wrap-reload)) + wrap-exceptions)) diff --git a/package-lock.json b/package-lock.json index 42637fa..077f9f5 100644 --- a/package-lock.json +++ b/package-lock.json @@ -5,9 +5,9 @@ "requires": true, "dependencies": { "bulma": { - "version": "0.7.1", - "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.1.tgz", - "integrity": "sha512-wRSO2LXB+qI9Pyz2id+uZr4quz5aftSN7Ay1ysr1+krzVp3utD+Ci4CeKuZdrYGc800t65b7heXBL6qw2Wo/lQ==" + "version": "0.7.2", + "resolved": "https://registry.npmjs.org/bulma/-/bulma-0.7.2.tgz", + "integrity": "sha512-6JHEu8U/1xsyOst/El5ImLcZIiE2JFXgvrz8GGWbnDLwTNRPJzdAM0aoUM1Ns0avALcVb6KZz9NhzmU53dGDcQ==" }, "font-awesome": { "version": "4.7.0", diff --git a/project.clj b/project.clj index 8575deb..00cee7d 100644 --- a/project.clj +++ b/project.clj @@ -56,7 +56,7 @@ :java-source-paths ["src/java"] - :npm {:dependencies [[bulma "0.7.1"] + :npm {:dependencies [[bulma "0.7.2"] [font-awesome "4.7.0"]]} :ring {:handler skirmish.wui.handler/app diff --git a/resources/config.edn b/resources/config.edn index 1a48ce0..b00e21e 100644 --- a/resources/config.edn +++ b/resources/config.edn @@ -38,14 +38,10 @@ :ip "0.0.0.0" :max-body 524288 ;; 512kb, small but enough :max-ws 524288 + :default-sec-id :dapm :datomic {:transactor-url "datomic:free://localhost:4334/skirmish.broker"}} :wui - {:port #long #or [#env WUI_PORT 3000]} - - ;; stupid parameters about benchmarking tools - :benchmark { - :number-of-requests-per-securities 30}} - + {:port #long #or [#env WUI_PORT 3000]}} diff --git a/resources/public/css/site.css b/resources/public/css/site.css index a39965c..532912a 100644 --- a/resources/public/css/site.css +++ b/resources/public/css/site.css @@ -14,7 +14,7 @@ -ms-user-select: none; user-select: none; } -.select:not(.is-multiple):not(.is-loading)::after, .navbar-link::after { +.select:not(.is-multiple):not(.is-loading)::after, .navbar-link:not(.is-arrowless)::after { border: 3px solid transparent; border-radius: 2px; border-right: 0; @@ -31,7 +31,7 @@ width: 0.625em; } .box:not(:last-child), .content:not(:last-child), .notification:not(:last-child), .progress:not(:last-child), .table:not(:last-child), .table-container:not(:last-child), .title:not(:last-child), -.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .message:not(:last-child), .tabs:not(:last-child) { +.subtitle:not(:last-child), .block:not(:last-child), .highlight:not(:last-child), .breadcrumb:not(:last-child), .level:not(:last-child), .list:not(:last-child), .message:not(:last-child), .tabs:not(:last-child) { margin-bottom: 1.5rem; } .delete, .modal-close { @@ -41,6 +41,7 @@ border: none; border-radius: 290486px; cursor: pointer; + pointer-events: auto; display: inline-block; flex-grow: 0; flex-shrink: 0; @@ -993,6 +994,16 @@ a.has-text-danger:hover, a.has-text-danger:focus { .is-hidden { display: none !important; } +.is-sr-only { + border: none !important; + clip: rect(0, 0, 0, 0) !important; + height: 0.01em !important; + overflow: hidden !important; + padding: 0 !important; + position: absolute !important; + white-space: nowrap !important; + width: 0.01em !important; } + @media screen and (max-width: 768px) { .is-hidden-mobile { display: none !important; } } @@ -1081,10 +1092,10 @@ a.has-text-danger:hover, a.has-text-danger:focus { box-shadow: none !important; } .box { - background-color: white; + background-color: #7a7a7a; border-radius: 6px; - box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); - color: whitesmoke; + box-shadow: 0 2px 3px #b5b5b5, 0 0 0 1px #b5b5b5; + color: white; display: block; padding: 1.25rem; } @@ -1788,7 +1799,7 @@ a.box:active { justify-content: flex-start; } .buttons .button { margin-bottom: 0.5rem; } - .buttons .button:not(:last-child) { + .buttons .button:not(:last-child):not(.is-fullwidth) { margin-right: 0.5rem; } .buttons:last-child { margin-bottom: -0.5rem; } @@ -1903,9 +1914,19 @@ a.box:active { padding: 1.25em 1.5em; } .content ol { - list-style: decimal outside; + list-style-position: outside; margin-left: 2em; margin-top: 1em; } + .content ol:not([type]) { + list-style-type: decimal; } + .content ol:not([type]).is-lower-alpha { + list-style-type: lower-alpha; } + .content ol:not([type]).is-lower-roman { + list-style-type: lower-roman; } + .content ol:not([type]).is-upper-alpha { + list-style-type: upper-alpha; } + .content ol:not([type]).is-upper-roman { + list-style-type: upper-roman; } .content ul { list-style: disc outside; @@ -2239,7 +2260,7 @@ a.box:active { .select select:not([multiple]) { padding-right: 2.5em; } .select select[multiple] { - height: initial; + height: auto; padding: 0; } .select select[multiple] option { padding: 0.5em 1em; } @@ -2595,12 +2616,13 @@ a.box:active { border-color: #cfcfcf; } .file-input { - height: 0.01em; + height: 100%; left: 0; + opacity: 0; outline: none; position: absolute; top: 0; - width: 0.01em; } + width: 100%; } .file-cta, .file-name { @@ -2696,31 +2718,31 @@ a.box:active { .field.has-addons .control:last-child .select select { border-bottom-left-radius: 0; border-top-left-radius: 0; } - .field.has-addons .control .button:hover, .field.has-addons .control .button.is-hovered, - .field.has-addons .control .input:hover, - .field.has-addons .control .input.is-hovered, - .field.has-addons .control .select select:hover, - .field.has-addons .control .select select.is-hovered { + .field.has-addons .control .button:not([disabled]):hover, .field.has-addons .control .button:not([disabled]).is-hovered, + .field.has-addons .control .input:not([disabled]):hover, + .field.has-addons .control .input:not([disabled]).is-hovered, + .field.has-addons .control .select select:not([disabled]):hover, + .field.has-addons .control .select select:not([disabled]).is-hovered { z-index: 2; } - .field.has-addons .control .button:focus, .field.has-addons .control .button.is-focused, .field.has-addons .control .button:active, .field.has-addons .control .button.is-active, - .field.has-addons .control .input:focus, - .field.has-addons .control .input.is-focused, - .field.has-addons .control .input:active, - .field.has-addons .control .input.is-active, - .field.has-addons .control .select select:focus, - .field.has-addons .control .select select.is-focused, - .field.has-addons .control .select select:active, - .field.has-addons .control .select select.is-active { + .field.has-addons .control .button:not([disabled]):focus, .field.has-addons .control .button:not([disabled]).is-focused, .field.has-addons .control .button:not([disabled]):active, .field.has-addons .control .button:not([disabled]).is-active, + .field.has-addons .control .input:not([disabled]):focus, + .field.has-addons .control .input:not([disabled]).is-focused, + .field.has-addons .control .input:not([disabled]):active, + .field.has-addons .control .input:not([disabled]).is-active, + .field.has-addons .control .select select:not([disabled]):focus, + .field.has-addons .control .select select:not([disabled]).is-focused, + .field.has-addons .control .select select:not([disabled]):active, + .field.has-addons .control .select select:not([disabled]).is-active { z-index: 3; } - .field.has-addons .control .button:focus:hover, .field.has-addons .control .button.is-focused:hover, .field.has-addons .control .button:active:hover, .field.has-addons .control .button.is-active:hover, - .field.has-addons .control .input:focus:hover, - .field.has-addons .control .input.is-focused:hover, - .field.has-addons .control .input:active:hover, - .field.has-addons .control .input.is-active:hover, - .field.has-addons .control .select select:focus:hover, - .field.has-addons .control .select select.is-focused:hover, - .field.has-addons .control .select select:active:hover, - .field.has-addons .control .select select.is-active:hover { + .field.has-addons .control .button:not([disabled]):focus:hover, .field.has-addons .control .button:not([disabled]).is-focused:hover, .field.has-addons .control .button:not([disabled]):active:hover, .field.has-addons .control .button:not([disabled]).is-active:hover, + .field.has-addons .control .input:not([disabled]):focus:hover, + .field.has-addons .control .input:not([disabled]).is-focused:hover, + .field.has-addons .control .input:not([disabled]):active:hover, + .field.has-addons .control .input:not([disabled]).is-active:hover, + .field.has-addons .control .select select:not([disabled]):focus:hover, + .field.has-addons .control .select select:not([disabled]).is-focused:hover, + .field.has-addons .control .select select:not([disabled]):active:hover, + .field.has-addons .control .select select:not([disabled]).is-active:hover { z-index: 4; } .field.has-addons .control.is-expanded { flex-grow: 1; } @@ -2805,6 +2827,7 @@ a.box:active { margin-right: 0.75rem; } } .control { + clear: both; font-size: 1rem; position: relative; text-align: left; } @@ -2963,7 +2986,7 @@ a.box:active { border-radius: 4px; padding: 1.25rem 2.5rem 1.25rem 1.5rem; position: relative; } - .notification a:not(.button) { + .notification a:not(.button):not(.dropdown-item) { color: currentColor; text-decoration: underline; } .notification strong { @@ -3205,7 +3228,9 @@ a.box:active { .table.is-hoverable tbody tr:not(.is-selected):hover { background-color: #242424; } .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover { - background-color: whitesmoke; } + background-color: #242424; } + .table.is-hoverable.is-striped tbody tr:not(.is-selected):hover:nth-child(even) { + background-color: whitesmoke; } .table.is-narrow td, .table.is-narrow th { padding: 0.25em 0.5em; } @@ -3502,7 +3527,7 @@ a.tag:hover { position: relative; } .card-header { - background-color: none; + background-color: transparent; align-items: stretch; box-shadow: 0 1px 2px rgba(10, 10, 10, 0.1); display: flex; } @@ -3529,11 +3554,11 @@ a.tag:hover { position: relative; } .card-content { - background-color: none; + background-color: transparent; padding: 1.5rem; } .card-footer { - background-color: none; + background-color: transparent; border-top: 1px solid #dbdbdb; align-items: stretch; display: flex; } @@ -3591,13 +3616,18 @@ a.tag:hover { padding: 0.375rem 1rem; position: relative; } -a.dropdown-item { +a.dropdown-item, +button.dropdown-item { padding-right: 3rem; - white-space: nowrap; } - a.dropdown-item:hover { + text-align: left; + white-space: nowrap; + width: 100%; } + a.dropdown-item:hover, + button.dropdown-item:hover { background-color: #0a0a0a; color: #0a0a0a; } - a.dropdown-item.is-active { + a.dropdown-item.is-active, + button.dropdown-item.is-active { background-color: #00d1b2; color: #fff; } @@ -3623,12 +3653,11 @@ a.dropdown-item { display: flex; } .level.is-mobile .level-left + .level-right { margin-top: 0; } - .level.is-mobile .level-item { + .level.is-mobile .level-item:not(:last-child) { + margin-bottom: 0; margin-right: 0.75rem; } - .level.is-mobile .level-item:not(:last-child) { - margin-bottom: 0; } - .level.is-mobile .level-item:not(.is-narrow) { - flex-grow: 1; } + .level.is-mobile .level-item:not(.is-narrow) { + flex-grow: 1; } @media screen and (min-width: 769px), print { .level { display: flex; } @@ -3679,6 +3708,32 @@ a.dropdown-item { .level-right { display: flex; } } +.list { + background-color: white; + border-radius: 4px; + box-shadow: 0 2px 3px rgba(10, 10, 10, 0.1), 0 0 0 1px rgba(10, 10, 10, 0.1); } + +.list-item { + display: block; + padding: 0.5em 1em; } + .list-item:not(a) { + color: whitesmoke; } + .list-item:first-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; } + .list-item:last-child { + border-top-left-radius: 4px; + border-top-right-radius: 4px; } + .list-item:not(:last-child) { + border-bottom: 1px solid #dbdbdb; } + .list-item.is-active { + background-color: #00d1b2; + color: #fff; } + +a.list-item { + background-color: #0a0a0a; + cursor: pointer; } + .media { align-items: flex-start; display: flex; @@ -3722,6 +3777,10 @@ a.dropdown-item { flex-shrink: 1; text-align: left; } +@media screen and (max-width: 768px) { + .media-content { + overflow-x: auto; } } + .menu { font-size: 1rem; } .menu.is-small { @@ -3891,6 +3950,7 @@ a.dropdown-item { .modal { align-items: center; display: none; + flex-direction: column; justify-content: center; overflow: hidden; position: fixed; @@ -3927,7 +3987,8 @@ a.dropdown-item { display: flex; flex-direction: column; max-height: calc(100vh - 40px); - overflow: hidden; } + overflow: hidden; + -ms-overflow-y: visible; } .modal-card-head, .modal-card-foot { @@ -3984,6 +4045,8 @@ a.dropdown-item { color: #0a0a0a; } .navbar.is-white .navbar-brand .navbar-link::after { border-color: #0a0a0a; } + .navbar.is-white .navbar-burger { + color: #0a0a0a; } @media screen and (min-width: 1088px) { .navbar.is-white .navbar-start > .navbar-item, .navbar.is-white .navbar-start .navbar-link, @@ -4022,6 +4085,8 @@ a.dropdown-item { color: white; } .navbar.is-black .navbar-brand .navbar-link::after { border-color: white; } + .navbar.is-black .navbar-burger { + color: white; } @media screen and (min-width: 1088px) { .navbar.is-black .navbar-start > .navbar-item, .navbar.is-black .navbar-start .navbar-link, @@ -4060,6 +4125,8 @@ a.dropdown-item { color: #363636; } .navbar.is-light .navbar-brand .navbar-link::after { border-color: #363636; } + .navbar.is-light .navbar-burger { + color: #363636; } @media screen and (min-width: 1088px) { .navbar.is-light .navbar-start > .navbar-item, .navbar.is-light .navbar-start .navbar-link, @@ -4098,6 +4165,8 @@ a.dropdown-item { color: whitesmoke; } .navbar.is-dark .navbar-brand .navbar-link::after { border-color: whitesmoke; } + .navbar.is-dark .navbar-burger { + color: whitesmoke; } @media screen and (min-width: 1088px) { .navbar.is-dark .navbar-start > .navbar-item, .navbar.is-dark .navbar-start .navbar-link, @@ -4136,6 +4205,8 @@ a.dropdown-item { color: #fff; } .navbar.is-primary .navbar-brand .navbar-link::after { border-color: #fff; } + .navbar.is-primary .navbar-burger { + color: #fff; } @media screen and (min-width: 1088px) { .navbar.is-primary .navbar-start > .navbar-item, .navbar.is-primary .navbar-start .navbar-link, @@ -4174,6 +4245,8 @@ a.dropdown-item { color: #fff; } .navbar.is-link .navbar-brand .navbar-link::after { border-color: #fff; } + .navbar.is-link .navbar-burger { + color: #fff; } @media screen and (min-width: 1088px) { .navbar.is-link .navbar-start > .navbar-item, .navbar.is-link .navbar-start .navbar-link, @@ -4212,6 +4285,8 @@ a.dropdown-item { color: #fff; } .navbar.is-info .navbar-brand .navbar-link::after { border-color: #fff; } + .navbar.is-info .navbar-burger { + color: #fff; } @media screen and (min-width: 1088px) { .navbar.is-info .navbar-start > .navbar-item, .navbar.is-info .navbar-start .navbar-link, @@ -4250,6 +4325,8 @@ a.dropdown-item { color: #fff; } .navbar.is-success .navbar-brand .navbar-link::after { border-color: #fff; } + .navbar.is-success .navbar-burger { + color: #fff; } @media screen and (min-width: 1088px) { .navbar.is-success .navbar-start > .navbar-item, .navbar.is-success .navbar-start .navbar-link, @@ -4288,6 +4365,8 @@ a.dropdown-item { color: rgba(0, 0, 0, 0.7); } .navbar.is-warning .navbar-brand .navbar-link::after { border-color: rgba(0, 0, 0, 0.7); } + .navbar.is-warning .navbar-burger { + color: rgba(0, 0, 0, 0.7); } @media screen and (min-width: 1088px) { .navbar.is-warning .navbar-start > .navbar-item, .navbar.is-warning .navbar-start .navbar-link, @@ -4326,6 +4405,8 @@ a.dropdown-item { color: #fff; } .navbar.is-danger .navbar-brand .navbar-link::after { border-color: #fff; } + .navbar.is-danger .navbar-burger { + color: #fff; } @media screen and (min-width: 1088px) { .navbar.is-danger .navbar-start > .navbar-item, .navbar.is-danger .navbar-start .navbar-link, @@ -4395,6 +4476,7 @@ body.has-navbar-fixed-bottom { overflow-y: hidden; } .navbar-burger { + color: #4a4a4a; cursor: pointer; display: block; height: 3.25rem; @@ -4481,9 +4563,9 @@ a.navbar-item, flex-grow: 1; flex-shrink: 1; } -.navbar-link { +.navbar-link:not(.is-arrowless) { padding-right: 2.5em; } - .navbar-link::after { + .navbar-link:not(.is-arrowless)::after { border-color: #00d1b2; margin-top: -0.375em; right: 1.125em; } @@ -4645,10 +4727,10 @@ a.navbar-item, display: block; } .navbar > .container .navbar-brand, .container > .navbar .navbar-brand { - margin-left: -1rem; } + margin-left: -.75rem; } .navbar > .container .navbar-menu, .container > .navbar .navbar-menu { - margin-right: -1rem; } + margin-right: -.75rem; } .navbar.is-fixed-bottom-desktop, .navbar.is-fixed-top-desktop { left: 0; position: fixed; @@ -5816,22 +5898,265 @@ label.panel-block { padding-right: var(--columnGap); } .columns.is-variable.is-0 { --columnGap: 0rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-0-mobile { + --columnGap: 0rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-0-tablet { + --columnGap: 0rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-0-tablet-only { + --columnGap: 0rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-0-touch { + --columnGap: 0rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-0-desktop { + --columnGap: 0rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-0-desktop-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-0-widescreen { + --columnGap: 0rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-0-widescreen-only { + --columnGap: 0rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-0-fullhd { + --columnGap: 0rem; } } .columns.is-variable.is-1 { --columnGap: 0.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-1-mobile { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-1-tablet { + --columnGap: 0.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-1-tablet-only { + --columnGap: 0.25rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-1-touch { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-1-desktop { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-1-desktop-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-1-widescreen { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-1-widescreen-only { + --columnGap: 0.25rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-1-fullhd { + --columnGap: 0.25rem; } } .columns.is-variable.is-2 { --columnGap: 0.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-2-mobile { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-2-tablet { + --columnGap: 0.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-2-tablet-only { + --columnGap: 0.5rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-2-touch { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-2-desktop { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-2-desktop-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-2-widescreen { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-2-widescreen-only { + --columnGap: 0.5rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-2-fullhd { + --columnGap: 0.5rem; } } .columns.is-variable.is-3 { --columnGap: 0.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-3-mobile { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-3-tablet { + --columnGap: 0.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-3-tablet-only { + --columnGap: 0.75rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-3-touch { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-3-desktop { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-3-desktop-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-3-widescreen { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-3-widescreen-only { + --columnGap: 0.75rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-3-fullhd { + --columnGap: 0.75rem; } } .columns.is-variable.is-4 { --columnGap: 1rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-4-mobile { + --columnGap: 1rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-4-tablet { + --columnGap: 1rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-4-tablet-only { + --columnGap: 1rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-4-touch { + --columnGap: 1rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-4-desktop { + --columnGap: 1rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-4-desktop-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-4-widescreen { + --columnGap: 1rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-4-widescreen-only { + --columnGap: 1rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-4-fullhd { + --columnGap: 1rem; } } .columns.is-variable.is-5 { --columnGap: 1.25rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-5-mobile { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-5-tablet { + --columnGap: 1.25rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-5-tablet-only { + --columnGap: 1.25rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-5-touch { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-5-desktop { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-5-desktop-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-5-widescreen { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-5-widescreen-only { + --columnGap: 1.25rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-5-fullhd { + --columnGap: 1.25rem; } } .columns.is-variable.is-6 { --columnGap: 1.5rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-6-mobile { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-6-tablet { + --columnGap: 1.5rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-6-tablet-only { + --columnGap: 1.5rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-6-touch { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-6-desktop { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-6-desktop-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-6-widescreen { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-6-widescreen-only { + --columnGap: 1.5rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-6-fullhd { + --columnGap: 1.5rem; } } .columns.is-variable.is-7 { --columnGap: 1.75rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-7-mobile { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-7-tablet { + --columnGap: 1.75rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-7-tablet-only { + --columnGap: 1.75rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-7-touch { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-7-desktop { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-7-desktop-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-7-widescreen { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-7-widescreen-only { + --columnGap: 1.75rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-7-fullhd { + --columnGap: 1.75rem; } } .columns.is-variable.is-8 { --columnGap: 2rem; } + @media screen and (max-width: 768px) { + .columns.is-variable.is-8-mobile { + --columnGap: 2rem; } } + @media screen and (min-width: 769px), print { + .columns.is-variable.is-8-tablet { + --columnGap: 2rem; } } + @media screen and (min-width: 769px) and (max-width: 1087px) { + .columns.is-variable.is-8-tablet-only { + --columnGap: 2rem; } } + @media screen and (max-width: 1087px) { + .columns.is-variable.is-8-touch { + --columnGap: 2rem; } } + @media screen and (min-width: 1088px) { + .columns.is-variable.is-8-desktop { + --columnGap: 2rem; } } + @media screen and (min-width: 1088px) and (max-width: 1279px) { + .columns.is-variable.is-8-desktop-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1280px) { + .columns.is-variable.is-8-widescreen { + --columnGap: 2rem; } } + @media screen and (min-width: 1280px) and (max-width: 1471px) { + .columns.is-variable.is-8-widescreen-only { + --columnGap: 2rem; } } + @media screen and (min-width: 1472px) { + .columns.is-variable.is-8-fullhd { + --columnGap: 2rem; } } .tile { align-items: stretch; @@ -6356,16 +6681,18 @@ label.panel-block { .hero.is-large .hero-body { padding-bottom: 18rem; padding-top: 18rem; } } - .hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body { + .hero.is-halfheight .hero-body, .hero.is-fullheight .hero-body, .hero.is-fullheight-with-navbar .hero-body { align-items: center; display: flex; } - .hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container { + .hero.is-halfheight .hero-body > .container, .hero.is-fullheight .hero-body > .container, .hero.is-fullheight-with-navbar .hero-body > .container { flex-grow: 1; flex-shrink: 1; } .hero.is-halfheight { min-height: 50vh; } .hero.is-fullheight { min-height: 100vh; } + .hero.is-fullheight-with-navbar { + min-height: calc(100vh - 3.25rem); } .hero-video { overflow: hidden; } diff --git a/src/clj/skirmish/bookkeeper/core.clj b/src/clj/skirmish/bookkeeper/core.clj index 297688d..294ea6c 100644 --- a/src/clj/skirmish/bookkeeper/core.clj +++ b/src/clj/skirmish/bookkeeper/core.clj @@ -1,3 +1,7 @@ +; This is the service that broadcast market data to the +; world. The users need to expect websocket and REST api. + + (ns skirmish.bookkeeper.core (:require [org.httpkit.server :refer [run-server]] [compojure.handler :refer [api]] diff --git a/src/clj/skirmish/broker/broker.clj b/src/clj/skirmish/broker/broker.clj index f6aae79..c637e6e 100644 --- a/src/clj/skirmish/broker/broker.clj +++ b/src/clj/skirmish/broker/broker.clj @@ -4,15 +4,50 @@ [datomic.api :as d] [slingshot.slingshot :refer [try+ throw+]] [skirmish.rest.util :refer [build-response not-found-resp get-body]] - [taoensso.timbre :as timbre])) + [taoensso.timbre :as timbre] + [skirmish.routes.core :as routes] + [clj-http.client :as http-client])) -(defn create-user [conn] +(defn generate-amount-for-new-user [seed] + (let [random (new java.util.Random seed) + random-fn #(. random nextInt 20000)] + (* 100 (reduce + (take 100 (repeatedly random-fn)))))) + + +(defn create-account [account-id sec-id] + #:skirmish.broker.account{:id account-id + :sec-id sec-id + :private-key (str account-id)}) + + +(defn create-user-account [seed default-sec-id] + (let [url (routes/get-path-for :ledger/security {:sec-id (name default-sec-id)}) + account-id (java.util.UUID/randomUUID) + amount (generate-amount-for-new-user seed) + payload [amount (str account-id)]] + (timbre/info "Creating new account " account-id " with ammount " amount " of " default-sec-id) + (timbre/info url) + (http-client/post url {:body (str payload)}) + (create-account account-id default-sec-id))) + +(defn create-user-seed-from-email [email] + (let [hasher (java.security.MessageDigest/getInstance "SHA-256") + salt (. "this should be private and set in config" getBytes "utf-8") + msg (. email getBytes "utf-8") + _ (doto hasher (.update salt) (.update msg)) + hash (. hasher digest)] + (int (mod (new BigInteger 1 hash) (biginteger Integer/MAX_VALUE))))) + + +(defn create-user [conn default-sec-id] (fn [{body :body :as request}] (try+ - (let [email (-> body get-body :email)] - (timbre/info "Creating new user" email) - @(d/transact conn [[:skirmish.broker.user/create-user email]]) + (let [email (-> body get-body :email) + _ (timbre/info "Creating new user" email) + seed (create-user-seed-from-email email) + account (create-user-account seed default-sec-id)] + @(d/transact conn [[:skirmish.broker.user/create-user email [account]]]) (build-response request {:status 201 :headers {"location" (str "/api/1/users/" email)}})) (catch [:error-type :4XX] e (build-response request e)) (catch [:error-type :5XX] e (build-response request e))))) @@ -24,6 +59,7 @@ ret (map #(assoc % :skirmish.broker.account/url (url %)) accounts)] (assoc user :skirmish.broker.user/accounts ret))) + (defn get-user [conn] (fn [{{email :email} :route-params :as request}] (try+ @@ -54,14 +90,15 @@ (catch [:error-type :4XX] e (build-response request e)) (catch [:error-type :5XX] e (build-response request e))))) + (defn get-account [conn] (fn [email account])) -(defn create-routes [conn] +(defn create-routes [conn config] (routes (context "/api/1" [] - (POST "/users" [] (create-user conn)) + (POST "/users" [] (create-user conn (:default-sec-id config))) (GET "/users" [] (get-all-users conn)) (GET "/users/:email" [email] (get-user conn)) (GET "/users/:email/accounts/:account" [email account] (get-account conn))) diff --git a/src/clj/skirmish/broker/core.clj b/src/clj/skirmish/broker/core.clj index befd11b..1335f46 100644 --- a/src/clj/skirmish/broker/core.clj +++ b/src/clj/skirmish/broker/core.clj @@ -1,3 +1,5 @@ +; The backend of the skirmish web user interface. + (ns skirmish.broker.core (:require [org.httpkit.server :refer [run-server]] [compojure.handler :refer [api]] @@ -11,7 +13,7 @@ (defn -main [config securities-api exchange-apis] (let [webserver-config (:api-broker config) conn (create-connection (-> webserver-config :datomic :transactor-url)) - api-routes (create-routes conn)] + api-routes (create-routes conn webserver-config)] (timbre/info "Running skirmish.broker.core server with config: " webserver-config) (run-server (-> api-routes api cors-middleware) diff --git a/src/clj/skirmish/broker/db.clj b/src/clj/skirmish/broker/db.clj index aee683c..04cbf40 100644 --- a/src/clj/skirmish/broker/db.clj +++ b/src/clj/skirmish/broker/db.clj @@ -8,12 +8,11 @@ :db/doc "Create a new user in the system." :db/fn (d/function {:lang "clojure" :requires ['[slingshot.slingshot]] - :params '[db email] + :params '[db email accounts] :code '(let [existing-user (d/pull db '[:db/id] [:skirmish.broker.user/email email])] - ;:skirmish.broker.user/accounts []])] (when (-> existing-user :db/id some?) (slingshot.slingshot/throw+ {:error-type :4XX :status 400 :body {:error "A user with this email already exists."}})) - [#:skirmish.broker.user{:email email}])})}]) + [#:skirmish.broker.user{:email email :accounts accounts}])})}]) (def accounts-schema [ diff --git a/src/clj/skirmish/cli/benchmark.clj b/src/clj/skirmish/cli/benchmark.clj deleted file mode 100644 index 882e7b0..0000000 --- a/src/clj/skirmish/cli/benchmark.clj +++ /dev/null @@ -1,104 +0,0 @@ -(ns skirmish.cli.benchmark - (:require [clojure.math.combinatorics :refer [cartesian-product]] - [clojure.core.async :refer [go chan ! close! to-chan close!] :as async] - [gniazdo.core :as ws] - [clj-http.client :as client] - [com.stuartsierra.frequencies :as freq] - [clojure.edn :as edn])) - - -(def ids (atom 0)) - - -(defn web-socket-to-channel [url output-ch] - (let [on-receive #(go (>! output-ch %)) - headers {"accept" "application/edn"}] - (ws/connect url :headers headers :on-receive on-receive))) - - -(defn create-orders-channel [securities] - (let [output (chan 1 (map edn/read-string)) - url #(format "ws://localhost:%s/api/1/securities/%s/orders" 8080 %) - xf (comp (map :sec-id) - (map name) - (map url) - (map #(web-socket-to-channel % output)))] - (doall (sequence xf securities)) - (async/pub output :book.order/id))) - - - -(defn create-requests-payload-for-security [i security id] - (let [rd (new java.util.Random i) - rand-bool (= (mod (. rd nextInt) 2) 0) ;; java random number generator REALLY sucks - type (if rand-bool :sell :buy) - price (+ (* 3 (. rd nextGaussian)) 30) - int-price (int (* price 100)) - quantity (reduce + 1 (map #(. rd nextInt (inc %)) (range 100)))] - - {:type type :quantity quantity :price int-price :security security :benchmark/id id})) - - -(defn create-requests-for-security [[i security]] - (let [req-id (swap! ids inc) - payload (create-requests-payload-for-security i (str (:sec-id security)) req-id) - sec-id-str (-> security :sec-id name) - params {:throw-exceptions false :content-type :edn :headers {"accept" "application/edn"}} - url (format "http://localhost:%s/api/1/securities/%s" 8080 sec-id-str)] - (fn [] - (let [now (System/nanoTime)] - (client/post url (assoc params :form-params (assoc payload :benchmark/request-time now))))))) - - -(defn make-requests [n securities] - (map create-requests-for-security (cartesian-product (range n) securities))) - - -(defn no-more-then-n-simultaneously [f input-chan n] - (let [buffer (chan)] - (go (async/pipeline n buffer (map f) input-chan)) - buffer)) - -(defn decode-response [response] - (let [now (System/nanoTime) - ret {} - ret (assoc ret :status (:status response)) - ret (assoc ret :order (edn/read-string (:body response))) - ret (assoc ret :duration (/ (- now (get-in ret [:order :benchmark/request-time])) (Math/pow 10 9)))] - ret)) - - -(defn benchmark [requests orders] - (let [decoded-responses (chan 1 (map decode-response)) - responses (no-more-then-n-simultaneously #(%) (to-chan requests) 10)] - (go (async/pipe responses decoded-responses)) - decoded-responses)) - - -(defn compute-result [results new-result] - (let [status-code (:status new-result) - duration (:duration new-result) - old-status-code-count (get-in results [:status status-code] 0) - ret results - ret (assoc-in ret [:status status-code] (inc old-status-code-count)) - ret (assoc ret :durations (conj (:durations ret) duration))] - ret)) - -(defn pp-durations [durations] - (let [freq-map (frequencies durations)] - (print (freq/stats freq-map)))) - -(defn display-results [results] - (println results) - (println "number of request: " (:n results)) - (println "status map: " (:status results)) - (pp-durations (:durations results))) - -(defn -main [config exchange-apis] - (let [benchmark-config (:benchmark config) - requests (-> benchmark-config :number-of-requests-per-securities (make-requests (:securities config))) - orders (create-orders-channel (:securities config)) - results (benchmark requests orders)] - (display-results (async/!! " 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/clj/skirmish/core.clj b/src/clj/skirmish/core.clj index 74ab4b2..58801d7 100644 --- a/src/clj/skirmish/core.clj +++ b/src/clj/skirmish/core.clj @@ -1,7 +1,5 @@ (ns skirmish.core - (:require [skirmish.cli.core] - [skirmish.cli.benchmark] - [skirmish.exchange.core] + (:require [skirmish.exchange.core] [skirmish.wui.server] [skirmish.bookkeeper.core] [skirmish.exchange-gateway.core] diff --git a/src/clj/skirmish/exchange/exchange.clj b/src/clj/skirmish/exchange/exchange.clj index 5b692bc..173364a 100644 --- a/src/clj/skirmish/exchange/exchange.clj +++ b/src/clj/skirmish/exchange/exchange.clj @@ -106,6 +106,3 @@ ( body get-body (get-emit-securities-request (keyword sec-id-str)))] @@ -184,7 +189,6 @@ (defn create-routes-for-ledger [conn] (compojure/routes - ;; (routes/get-context :ledger) (routes/context :ledger [] (routes/GET :ledger/home [] get-api-description) (routes/GET :ledger/accounts [] (get-available-accounts conn)) diff --git a/src/clj/skirmish/wui/handler.clj b/src/clj/skirmish/wui/handler.clj index 30cc9b2..f943150 100644 --- a/src/clj/skirmish/wui/handler.clj +++ b/src/clj/skirmish/wui/handler.clj @@ -26,7 +26,8 @@ (head) [:body.body-container mount-target - (include-js "/js/app.js")])) + (include-js "/js/app.js") + (include-js "https://sidecar.gitter.im/dist/sidecar.v1.js")])) (defn loading-page [] (html5 diff --git a/src/cljs/skirmish/wui/components/home_page.cljs b/src/cljs/skirmish/wui/components/home_page.cljs index 2aff50d..8fdc27e 100644 --- a/src/cljs/skirmish/wui/components/home_page.cljs +++ b/src/cljs/skirmish/wui/components/home_page.cljs @@ -1,14 +1,10 @@ (ns skirmish.wui.components.home-page (:require [cljs-http.client :as http] [reagent.core :refer [atom]] + [skirmish.wui.util :refer [email?]] [cljs.core.async :refer [> s str (re-matches email-pattern) some?))) - - (defn create-user [email] (go (let [url "http://localhost:1605/api/1/users" diff --git a/src/cljs/skirmish/wui/components/otc_page.cljs b/src/cljs/skirmish/wui/components/otc_page.cljs new file mode 100644 index 0000000..302cf0c --- /dev/null +++ b/src/cljs/skirmish/wui/components/otc_page.cljs @@ -0,0 +1,69 @@ +(ns skirmish.wui.components.otc-page + (:require [reagent.core :refer [atom]] + [skirmish.wui.util :refer [email?]])) + + +(defn set-amount [state event] + (let [inserted-value (-> event .-target .-value) + new-value (first (re-find #"^\d+(\.\d*)?" inserted-value))] + (swap! state #(assoc % :value new-value)))) + +(defn set-email [state event] + (let [new-email (-> event .-target .-value)] + (swap! state #(assoc % :email new-email)))) + +(defn set-sec-id [state event] + (let [sec-id (-> event .-target .-value)] + (swap! state #(assoc % :sec-id sec-id)))) + + + +(defn ready-to-transfer? [state] + (and (-> state :value js/parseInt pos?) + (-> state :email email?))) + +(defn direct-send-confirmation [] + [:div.model + [:div.modal-background] + [:div.modal-content + [:div.modal-card + [:header.modal-card-head + [:p.modal-card-title "Modal title"] + [:button.delete]]]] + [:a.button.modal-close.is-large {:aria-label "close"} "dslkds"]]) + +(defn direct-send [] + (let [state (atom {})] + (fn [] + [:div + [:div.content + [:p "Send securities to another person."] + [:pre (str @state)]] + [:form.form + [:div.field.has-addons.has-addons-centered + [:div.control + [:span.select + [:select {:value (:sec-id @state) + :on-change (partial set-sec-id state)} + [:option {:value :foo :selected true} "damp"] + [:option {:value :bar } "blah blah blah"]]]] + [:div.control + [:input.input {:type "text" + :value (:value @state) + :on-change (partial set-amount state) + :placeholder "110.90"}]] + [:div.control + [:input.input {:type "text" + :value (:email @state) + :on-change (partial set-email state) + :placeholder "boris.johnson@redneck.co.uk"}]] + [:a.button.is-primary {:style {:marginLeft "1em"} + :disabled (-> @state ready-to-transfer? not)} "transfer"]]]]))) + +(defn page [state] + [:div + ;[direct-send-confirmation] + [:div.content + [:h5 "Do transaction without passing by the exchange."]] + + [direct-send]]) diff --git a/src/cljs/skirmish/wui/components/portfolio_page.cljs b/src/cljs/skirmish/wui/components/portfolio_page.cljs index d4ad55d..0413e6a 100644 --- a/src/cljs/skirmish/wui/components/portfolio_page.cljs +++ b/src/cljs/skirmish/wui/components/portfolio_page.cljs @@ -23,8 +23,9 @@ accounts (map :body (> s str (re-matches email-pattern) some?))) + diff --git a/src/sass/site.scss b/src/sass/site.scss index c3de32b..85d1c97 100644 --- a/src/sass/site.scss +++ b/src/sass/site.scss @@ -25,6 +25,10 @@ $table-background-color: $grey-dark; $table-cell-heading-color: $grey-darker; $table-row-hover-background-color: $black-ter; +// box +$box-background-color: $grey; +$box-color: $white; +$box-shadow: 0 2px 3px $grey-light, 0 0 0 1px $grey-light;// $red; @import "../../node_modules/bulma/sass/base/_all"; diff --git a/test/clj/skirmish/broker/broker_test.clj b/test/clj/skirmish/broker/broker_test.clj index 0bf4d58..273b40a 100644 --- a/test/clj/skirmish/broker/broker_test.clj +++ b/test/clj/skirmish/broker/broker_test.clj @@ -1,7 +1,9 @@ (ns skirmish.broker.broker-test (:require [midje.sweet :refer :all] [orchestra.spec.test :as st] - [skirmish.broker.broker :refer [add-account-urls]])) + [skirmish.broker.broker :refer [add-account-urls + create-user-seed-from-email + generate-amount-for-new-user]])) (st/instrument) @@ -13,3 +15,19 @@ :skirmish.broker.account/url "http://localhost:1604/api/1/ledger/accounts/foo"}]}] (add-account-urls user) => ret))) +(facts "about the new users" + (fact "we should add some random amount of damp in their account" + (let [random-values (map generate-amount-for-new-user (range 10000)) + sum (reduce + random-values) + mean (/ sum (count random-values)) + min-data (apply min random-values) + max-data (apply max random-values)] + (int mean) => 100027427 + min-data => 78422400 + max-data => 120128000)) + + (fact "we should generate the random seed by the email" + (create-user-seed-from-email "foo@gmail.com") => 399122929 + (create-user-seed-from-email "boo@gmail.com") => 1433675645)) + + diff --git a/test/clj/skirmish/broker/db_test.clj b/test/clj/skirmish/broker/db_test.clj index 9ada989..8d22543 100644 --- a/test/clj/skirmish/broker/db_test.clj +++ b/test/clj/skirmish/broker/db_test.clj @@ -2,7 +2,8 @@ (:require [midje.sweet :refer :all] [orchestra.spec.test :as st] [datomic.api :as d] - [skirmish.broker.db :refer [create-connection]])) + [skirmish.broker.db :refer [create-connection]] + [skirmish.broker.broker :refer [create-account]])) (st/instrument) @@ -15,7 +16,10 @@ (fact "should be able to create new users" (let [conn (create-conn) email "foo@gmail.com" - _ @(d/transact conn [[:skirmish.broker.user/create-user email]]) + account-id #uuid"dc0d1123-e659-4e8a-b38b-ece520f4c4d0" + account (create-account account-id :dapm) + _ @(d/transact conn [[:skirmish.broker.user/create-user email account]]) db (d/db conn) - user (d/pull db '[*] [:skirmish.broker.user/email email])] - (:skirmish.broker.user/email user) => email))); \ No newline at end of file + user (d/pull db '[* {:skirmish.broker.user/accounts [*]}] [:skirmish.broker.user/email email])] + (:skirmish.broker.user/email user) => email + (-> user :skirmish.broker.user/accounts first :skirmish.broker.account/id) => account-id))) \ No newline at end of file diff --git a/test/clj/skirmish/cli/benchmark_test.clj b/test/clj/skirmish/cli/benchmark_test.clj deleted file mode 100644 index 0a86ba2..0000000 --- a/test/clj/skirmish/cli/benchmark_test.clj +++ /dev/null @@ -1,30 +0,0 @@ -(ns skirmish.cli.benchmark-test - (:require [skirmish.cli.benchmark :refer :all] - [midje.sweet :refer :all] - [clojure.core.async :as async])) - -(facts "creating simple orders" - (fact "buy order" - (let [buy-order (create-requests-payload-for-security 666 (str :equity/ibm) 1) - expt {:benchmark/id 1 :price 2922 :quantity 2476 :security ":equity/ibm" :type :buy}] - buy-order => expt));; - (fact "sell order" - (let [buy-order (create-requests-payload-for-security 667 (str :equity/ibm) 2) - expt {:benchmark/id 2 :price 2740 :quantity 2516 :security ":equity/ibm" :type :sell}] - buy-order => expt))) - -(facts "the utility functions" - (fact "no-more-then-n-simultaneously" - (let [simultatious (atom []) - input-chan (async/to-chan (range 10)) - sleep-time #(+ (mod (+ (* 5142 %) 8765) 200) 50) - f (fn [i] - (swap! simultatious #(conj % {:id i :status :start :value 1})) - (Thread/sleep (sleep-time i)) - (swap! simultatious #(conj % {:id i :status :end :value -1})) - i) - res (async/ 3 - (first simultatious-over-time) => 0 - (last simultatious-over-time) => 0)))