-
Notifications
You must be signed in to change notification settings - Fork 0
Quick Start
Cumulo is designed for tiny chat web apps. Maybe you want to explore by yourself:
If you want to build realtime web apps, you should probably try one of them:
Cumulo is an experimental project for build really small web apps. It's slow and immature. But you can try it in your toy app if you like.
I will suppose you have experiences on:
- ClojureScript https://github.com/clojure/clojurescript/wiki/Quick-Start
- Boot http://boot-clj.com
- WebSockets
- React.js bindings, like Om or Reagent, my Respo is also okay
My packages maintains WebSockets internally but make sure you can handle them. On the browser-side you get a store, it's learnt from React.
Read the docs below and compare it to React:
db_0 = {states: {}, users: {}, messages: {}}
# get `action` from network
db_n+1 = updater(db_n, action)
scene = renderScene(db)
store = renderStore(scene, user_id)
changes = diff(store_n, store_n+1)
# send `changes` over network
clientStore_n+1 = patch(clientStore_n, changes)
updater
is a pure function, like reducer
in Redux, or updater
in Elm.
renderScene
is merely part of renderStore
but abstracted out for performance purpose.
You should be familiar with diff
patch
already by learning React.
You need a package [cumulo/server "0.1.0"]
, here's a demo:
(ns cumulo-server.main
(:require [cumulo-server.schema :as schema]
[cumulo-server.core :refer [setup-server! reload-renderer!]]
[cumulo-server.updater.core :refer [updater]]
[cumulo-server.view :refer [render-view render-scene]]))
(defonce db-ref (atom schema/database))
(defn -main []
(setup-server! db-ref updater render-scene render-view {:port 4010}))
(set! *main-cli-fn* -main)
(defn on-jsload []
(reload-renderer! @db-ref updater render-scene render-view))
reload-renderer!
is to handle code swapping, might looks strange though.
You may be wondering about updater
, try reading this example:
(ns cumulo-server.updater.core
(:require [cumulo-server.updater.state :as state]
[cumulo-server.updater.task :as task]))
(defn updater [db op op-data state-id op-id op-time]
(case op
:state/connect (state/connect db op-data state-id op-id op-time)
:state/disconnect (state/disconnect db op-data state-id op-id op-time)
:task/add (task/add db op-data state-id op-id op-time)
:task/rm (task/rm db op-data state-id op-id op-time)
db))
I have to say states
in db
is special since Cumulo code wants to read it to decide whom to send messages. Make sure state/connect
and state/disconnect
are handled like below. My code does not give warning if your script is wrong, my bad.
(ns cumulo-server.updater.state
(:require [cumulo-server.schema :as schema]))
(defn connect [db op-data state-id op-id op-time]
(assoc-in db [:states state-id] (merge schema/state {:id state-id})))
(defn disconnect [db op-data state-id op-id op-time]
(update db :states (fn [state] (dissoc state state-id))))
render-view
returns the store you want in a browser:
(ns cumulo-server.view)
(defn render-scene [db] db-scene)
(defn render-view [state-id db-scene]
{:states (get-in db-scene [:states state-id]), :tasks (:tasks db)})
To create a server, adding updater
s and render-view
should be enough.
You will need this package on client [cumulo/client "0.1.0"]
https://github.com/Cumulo/cumulo-client/
(ns cumulo-client.main
(:require [respo-spa.core :refer [render]]
[cumulo-client.component.container :refer [comp-container]]
[cumulo-client.core :refer [send! setup-socket!]]))
(defonce store-ref (atom {}))
(defonce states-ref (atom {}))
(defn dispatch [op op-data] (send! op op-data))
(defn render-app []
(let [target (.querySelector js/document "#app")]
(render (comp-container @store-ref) target dispatch states-ref)))
(defn -main []
(render-app)
(setup-socket! store-ref {:url "ws://localhost:4010"})
(add-watch store-ref :changes render-app)
(add-watch states-ref :changes render-app))
(set! js/window.onload -main)
(defn on-jsload []
(render-app))
Now you get a store that's synced with the server. No need to maintain state by yourself. In this demo the store is rendered with Respo, which is one of my libraries. I would suggest you using Reagent instead since Respo is another piece of code to learn.
I got ideas on Cumulo less than 2 years ago. But I have to say it's still in early stage. You may witness bugs. I just believe it's simple and straight forward enough a library for you to figure out.