Skip to content

Instantly share code, notes, and snippets.

@chinnurtb
Forked from kachayev/01.hotdo.terminal
Created August 22, 2013 09:06
Show Gist options
  • Select an option

  • Save chinnurtb/6304839 to your computer and use it in GitHub Desktop.

Select an option

Save chinnurtb/6304839 to your computer and use it in GitHub Desktop.
$ mkdir p1
$ cd p1/
$ rebar create-app appid=hotdo
$ ls
$ mkdir deps
$ touch rebar.config
$ # feeling rebar config file
$ wget -O rebar.config https://gist.github.com/kachayev/5657307/raw/fb9b0cd0d62e053efe54774bf2033e6e651c6622/hotdo.rebar.config
$ rebar get-deps
$ tree -L 2
$ rebar compile
$ tree -L 2
$ touch src/hotdo.erl # define application API
$ erl -pa ebin deps/*/ebin -s hotdo # show how it works
$ # static content serving with cowboy
$ mkdir priv
$ echo "hello" > priv/hello.txt
$ rebar compile && erl -pa ebin deps/*/ebin -s hotdo
$ # show how it works
$ # copy knockoutjs code
$ mkdir todojs
$ cd todojs/
$ git clone https://github.com/tastejs/todomvc.git
$ cd ..
$ cp -r todojs/todomvc/architecture-examples/knockoutjs/* p1/priv/
$ # show it in browser
$ # create websocket handler with echo functionality
$ touch src/hotdo_ws.erl
$ rebar compile && erl -pa ebin deps/*/ebin -s hotdo
$ # 1. show how it works with JS console
$ # 2. register each process and resend message to all processes
$ # 3. WS.do and WS.on/trigger functionality
$ # 4. sync for add / delete / edit functionality
$ # 5. folsom to calculate number of active users: init / terminate
$ # 6. send notification on each changes
$ # share access to all users
$ ipconfig getifaddr en1
$ # list of todos
$ # links to get more information
{lib_dirs, ["deps"]}.
{deps, [
{gproc, ".*", {git, "git://github.com/uwiger/gproc.git"}},
{cowboy, ".*", {git, "git://github.com/extend/cowboy.git"}},
{jiffy, ".*", {git, "git://github.com/davisp/jiffy.git"}},
{mimetypes, ".*", {git, "git://github.com/spawngrid/mimetypes.git", "master"}},
{folsom, ".*", {git, "git://github.com/boundary/folsom.git"}}
]}.
%% show that application is running in console
start(_StartType, _StartArgs) ->
io:format("App is starting"),
hotdo_sup:start_link().
%% show how to start with -s hotdo
-module(hotdo).
-export([start/0]).
start() ->
lists:foreach(fun(App) ->
ok = application:start(App)
end,
[crypto, ranch, cowboy, gproc, folsom, hotdo]).
%% create text file and show it in browser
Static = {"/[...]", cowboy_static, [
{directory, {priv_dir, hotdo, []}},
{mimetypes, {fun mimetypes:path_to_mimes/2, default}}
]},
Ws = {"/websocket", hotdo_ws, []},
Dispatch = cowboy_router:compile([
{'_', [Ws, Static]}
]),
{ok, _} = cowboy:start_http(http, 100,
[{port, 7070}],
[{env, [{dispatch, Dispatch}]}]),
%% webocket echo server
-module(hotdo_ws).
-behavior(cowboy_websocket_handler).
-export([init/3,
websocket_init/3,
websocket_handle/3,
websocket_info/3,
websocket_terminate/3]).
init(_, _, _) ->
{upgrade, protocol, cowboy_websocket}.
websocket_init(_Transport, Req, _Opt) ->
{ok, Req, undefined}.
websocket_handle({text, Msg}, Req, State) ->
{reply, {text, Msg}, State}.
websocket_info(_, Req, State) ->
{ok, Req, State}.
websocket_terminate(_Reason, _Req, _State) ->
ok.
// websocket connection
var ws = new WebSocket("ws://" + window.location.host + "/websocket");
ws.onopen = function(event) { console.log(event) };
ws.onmessage = function(event) { console.log(event) };
window.ws = ws;
// distribute events with server
ws.do = function(action, args) {
ws.send(JSON.stringify([action, args]));
}
// add a new todo, when enter key is pressed
self.add = function () {
var current = self.current().trim();
if (current) {
// self.todos.push(new Todo(current));
ws.do("add", [current]);
self.current('');
}
};
// should fail with error
// add callback function
ws.add = function(cur) {
self.todos.unshift(new Todo(cur));
}
%% send to all users
websocket_init(_Transport, Req, _Opt) ->
gproc:reg({p, l, hotdo}),
{ok, Req, undefined}.
websocket_handle({text, Msg}, Req, State) ->
gproc:send({p, l, hotdo}, {text, Msg}),
{ok, Req, State}.
websocket_info({text, Msg}, Req, State) ->
{reply, {text, Msg}, Req, State};
websocket_info(_, Req, State) ->
{ok, Req, State}.
<h1>todos (<span data-bind="text: totalUsers">0</span>)</h1>
// count active users
self.totalUsers = ko.observable(0);
ws.counter = function(num) {
self.totalUsers(num);
}
%% create empty counter
start(_StartType, _StartArgs) ->
%% ... starting cowboy
folsom_metrics:new_counter(hotdo_users),
hotdo_sup:start_link().
%% send notifications about changes
update_counter(Op) ->
folsom_metrics:notify({hotdo_users, {Op, 1}}),
gproc:send({p, l, hotdo},
{counter, folsom_metrics:get_metric_value(hotdo_users)}).
websocket_init(_Transport, Req, _Opt) ->
gproc:reg({p, l, hotdo}),
update_counter(inc),
{ok, Req, undefined}.
websocket_info({text, Msg}, Req, State) ->
{reply, {text, Msg}, Req, State};
websocket_info({counter, Num}, Req, State) ->
{reply, {text, jiffy:encode([<<"counter">>, [Num]])}, Req, State};
websocket_info(_, Req, State) ->
{ok, Req, State}.
websocket_terminate(_Reason, _Req, _State) ->
update_counter(dec),
ok.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment