├── rebar ├── .gitignore ├── src ├── erws.app.src ├── erws_app.erl ├── erws_sup.erl └── erws_handler.erl ├── rebar.config ├── README ├── Makefile ├── rel ├── files │ ├── vm.args │ ├── sys.config │ ├── erl │ ├── start_erl.cmd │ ├── erws.cmd │ ├── nodetool │ └── erws └── reltool.config └── priv └── index.html /rebar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/marcelog/erws/HEAD/rebar -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | deps/ 2 | ebin/ 3 | rel/erl_crash.dump 4 | rel/erws/ 5 | .rebar 6 | *.swp 7 | 8 | -------------------------------------------------------------------------------- /src/erws.app.src: -------------------------------------------------------------------------------- 1 | {application, erws, [ 2 | {description, ""}, 3 | {vsn, "1"}, 4 | {registered, []}, 5 | {applications, [kernel,stdlib,crypto,cowboy,compiler,lager,syntax_tools]}, 6 | {mod, { erws_app, []}}, 7 | {env, []} 8 | ]}. 9 | -------------------------------------------------------------------------------- /rebar.config: -------------------------------------------------------------------------------- 1 | {erl_opts, [{parse_transform, lager_transform}]}. 2 | {lib_dirs,["deps"]}. 3 | 4 | {deps, [ 5 | {'lager', ".*", { 6 | git, "git://github.com/basho/lager.git", "master"} 7 | }, 8 | {'cowboy', ".*", { 9 | git, "git://github.com/extend/cowboy.git", {tag, "0.9.0"}} 10 | } 11 | ]}. 12 | -------------------------------------------------------------------------------- /README: -------------------------------------------------------------------------------- 1 | erws 2 | ==== 3 | 4 | Example of using cowboy to handle websocket connections. This is the 5 | sourcecode for this article: http://erlang.org.ar/WebsocketsConCowboy 6 | 7 | You can find the english version here: 8 | http://marcelog.github.com/articles/erlang_websocket_server_cowboy_tutorial.html 9 | 10 | Thanks 11 | ====== 12 | McClain Looney: @mlooney for updating the code to cowboy 0.9 13 | -------------------------------------------------------------------------------- /Makefile: -------------------------------------------------------------------------------- 1 | NAME=erws 2 | 3 | all: compile release 4 | ./rebar compile 5 | 6 | compile: 7 | ./rebar compile 8 | 9 | release: 10 | cd rel && ../rebar generate && cd - 11 | 12 | node: 13 | (cd rel && ../rebar create-node nodeid=${NAME} && cd -) 14 | 15 | clean: 16 | ./rebar clean 17 | rm -rf rel/${NAME} 18 | 19 | run: 20 | rel/${NAME}/bin/${NAME} start 21 | 22 | stop: 23 | rel/${NAME}/bin/${NAME} stop 24 | 25 | runconsole: 26 | rel/${NAME}/bin/${NAME} console 27 | 28 | alldev: clean all runconsole 29 | -------------------------------------------------------------------------------- /rel/files/vm.args: -------------------------------------------------------------------------------- 1 | ## Name of the node 2 | -name erws@127.0.0.1 3 | 4 | ## Cookie for distributed erlang 5 | -setcookie erws 6 | 7 | ## Heartbeat management; auto-restarts VM if it dies or becomes unresponsive 8 | ## (Disabled by default..use with caution!) 9 | ##-heart 10 | 11 | ## Enable kernel poll and a few async threads 12 | ##+K true 13 | ##+A 5 14 | 15 | ## Increase number of concurrent ports/sockets 16 | ##-env ERL_MAX_PORTS 4096 17 | 18 | ## Tweak GC to run more often 19 | ##-env ERL_FULLSWEEP_AFTER 10 20 | -------------------------------------------------------------------------------- /rel/files/sys.config: -------------------------------------------------------------------------------- 1 | [ 2 | {sasl, [ 3 | {sasl_error_logger, {file, "log/sasl-error.log"}}, 4 | {errlog_type, error}, 5 | {error_logger_mf_dir, "log/sasl"}, % Log directory 6 | {error_logger_mf_maxbytes, 10485760}, % 10 MB max file size 7 | {error_logger_mf_maxfiles, 5} % 5 files max 8 | ]}, 9 | {lager, [ 10 | {handlers, [ 11 | {lager_console_backend, debug}, 12 | {lager_file_backend, [{file, "error.log"}, {level, error}]}, 13 | {lager_file_backend, [{file, "console.log"}, {level, info}]} 14 | ]} 15 | ]} 16 | ]. 17 | 18 | -------------------------------------------------------------------------------- /src/erws_app.erl: -------------------------------------------------------------------------------- 1 | -module(erws_app). 2 | 3 | -behaviour(application). 4 | 5 | %% Application callbacks 6 | -export([start/2, stop/1]). 7 | 8 | %% =================================================================== 9 | %% Application callbacks 10 | %% =================================================================== 11 | 12 | start(_StartType, _StartArgs) -> 13 | Dispatch = cowboy_router:compile([ 14 | {'_', [ 15 | {"/", cowboy_static, {priv_file, erws, "index.html"}}, 16 | {"/websocket", erws_handler, []} 17 | ]} 18 | ]), 19 | {ok, _} = cowboy:start_http(http, 100, [{port, 10100}], 20 | [{env, [{dispatch, Dispatch}]}]), 21 | erws_sup:start_link(). 22 | 23 | stop(_State) -> 24 | ok. 25 | -------------------------------------------------------------------------------- /src/erws_sup.erl: -------------------------------------------------------------------------------- 1 | 2 | -module(erws_sup). 3 | 4 | -behaviour(supervisor). 5 | 6 | %% API 7 | -export([start_link/0]). 8 | 9 | %% Supervisor callbacks 10 | -export([init/1]). 11 | 12 | %% Helper macro for declaring children of supervisor 13 | -define(CHILD(I, Type), {I, {I, start_link, []}, permanent, 5000, Type, [I]}). 14 | 15 | %% =================================================================== 16 | %% API functions 17 | %% =================================================================== 18 | 19 | start_link() -> 20 | supervisor:start_link({local, ?MODULE}, ?MODULE, []). 21 | 22 | %% =================================================================== 23 | %% Supervisor callbacks 24 | %% =================================================================== 25 | 26 | init([]) -> 27 | {ok, { {one_for_one, 5, 10}, []} }. 28 | 29 | -------------------------------------------------------------------------------- /priv/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 38 | 39 | 40 |
41 | Open WebSocket
42 | Send hi 43 |
44 |
45 |
46 | 47 | 48 | -------------------------------------------------------------------------------- /rel/files/erl: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | ## This script replaces the default "erl" in erts-VSN/bin. This is necessary 4 | ## as escript depends on erl and in turn, erl depends on having access to a 5 | ## bootscript (start.boot). Note that this script is ONLY invoked as a side-effect 6 | ## of running escript -- the embedded node bypasses erl and uses erlexec directly 7 | ## (as it should). 8 | ## 9 | ## Note that this script makes the assumption that there is a start_clean.boot 10 | ## file available in $ROOTDIR/release/VSN. 11 | 12 | # Determine the abspath of where this script is executing from. 13 | ERTS_BIN_DIR=$(cd ${0%/*} && pwd) 14 | 15 | # Now determine the root directory -- this script runs from erts-VSN/bin, 16 | # so we simply need to strip off two dirs from the end of the ERTS_BIN_DIR 17 | # path. 18 | ROOTDIR=${ERTS_BIN_DIR%/*/*} 19 | 20 | # Parse out release and erts info 21 | START_ERL=`cat $ROOTDIR/releases/start_erl.data` 22 | ERTS_VSN=${START_ERL% *} 23 | APP_VSN=${START_ERL#* } 24 | 25 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin 26 | EMU=beam 27 | PROGNAME=`echo $0 | sed 's/.*\\///'` 28 | CMD="$BINDIR/erlexec" 29 | export EMU 30 | export ROOTDIR 31 | export BINDIR 32 | export PROGNAME 33 | 34 | exec $CMD -boot $ROOTDIR/releases/$APP_VSN/start_clean ${1+"$@"} 35 | -------------------------------------------------------------------------------- /rel/files/start_erl.cmd: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @rem Parse arguments. erlsrv.exe prepends erl arguments prior to first ++. 4 | @rem Other args are position dependent. 5 | @set args="%*" 6 | @for /F "delims=++ tokens=1,2,3" %%I in (%args%) do @( 7 | @set erl_args=%%I 8 | @call :set_trim node_name %%J 9 | @call :set_trim node_root %%K 10 | ) 11 | 12 | @set releases_dir=%node_root%\releases 13 | 14 | @rem parse ERTS version and release version from start_erl.dat 15 | @for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @( 16 | @call :set_trim erts_version %%I 17 | @call :set_trim release_version %%J 18 | ) 19 | 20 | @set erl_exe=%node_root%\erts-%erts_version%\bin\erl.exe 21 | @set boot_file=%releases_dir%\%release_version%\%node_name% 22 | 23 | @if exist %releases_dir%\%release_version%\sys.config ( 24 | @set app_config=%releases_dir%\%release_version%\sys.config 25 | ) else ( 26 | @set app_config=%node_root%\etc\app.config 27 | ) 28 | 29 | @if exist %releases_dir%\%release_version%\vm.args ( 30 | @set vm_args=%releases_dir%\%release_version%\vm.args 31 | ) else ( 32 | @set vm_args=%node_root%\etc\vm.args 33 | ) 34 | 35 | @%erl_exe% %erl_args% -boot %boot_file% -config %app_config% -args_file %vm_args% 36 | 37 | :set_trim 38 | @set %1=%2 39 | @goto :EOF 40 | -------------------------------------------------------------------------------- /src/erws_handler.erl: -------------------------------------------------------------------------------- 1 | -module(erws_handler). 2 | -behaviour(cowboy_http_handler). 3 | -behaviour(cowboy_websocket_handler). 4 | -export([init/3, handle/2, terminate/3]). 5 | -export([ 6 | websocket_init/3, websocket_handle/3, 7 | websocket_info/3, websocket_terminate/3 8 | ]). 9 | 10 | init({tcp, http}, _Req, _Opts) -> 11 | {upgrade, protocol, cowboy_websocket}. 12 | 13 | 14 | handle(Req, State) -> 15 | lager:debug("Request not expected: ~p", [Req]), 16 | {ok, Req2} = cowboy_http_req:reply(404, [{'Content-Type', <<"text/html">>}]), 17 | {ok, Req2, State}. 18 | 19 | 20 | websocket_init(_TransportName, Req, _Opts) -> 21 | lager:debug("init websocket"), 22 | {ok, Req, undefined_state}. 23 | 24 | websocket_handle({text, Msg}, Req, State) -> 25 | lager:debug("Got Data: ~p", [Msg]), 26 | {reply, {text, << "responding to ", Msg/binary >>}, Req, State, hibernate }; 27 | 28 | 29 | websocket_handle(_Any, Req, State) -> 30 | {reply, {text, << "whut?">>}, Req, State, hibernate }. 31 | 32 | websocket_info({timeout, _Ref, Msg}, Req, State) -> 33 | {reply, {text, Msg}, Req, State}; 34 | 35 | websocket_info(_Info, Req, State) -> 36 | lager:debug("websocket info"), 37 | {ok, Req, State, hibernate}. 38 | 39 | websocket_terminate(_Reason, _Req, _State) -> 40 | ok. 41 | 42 | terminate(_Reason, _Req, _State) -> 43 | ok. 44 | -------------------------------------------------------------------------------- /rel/files/erws.cmd: -------------------------------------------------------------------------------- 1 | @setlocal 2 | 3 | @set node_name=erws 4 | 5 | @rem Get the abolute path to the parent directory, 6 | @rem which is assumed to be the node root. 7 | @for /F "delims=" %%I in ("%~dp0..") do @set node_root=%%~fI 8 | 9 | @set releases_dir=%node_root%\releases 10 | 11 | @rem Parse ERTS version and release version from start_erl.data 12 | @for /F "tokens=1,2" %%I in (%releases_dir%\start_erl.data) do @( 13 | @call :set_trim erts_version %%I 14 | @call :set_trim release_version %%J 15 | ) 16 | 17 | @set erts_bin=%node_root%\erts-%erts_version%\bin 18 | 19 | @set service_name=%node_name%_%release_version% 20 | 21 | @if "%1"=="install" @goto install 22 | @if "%1"=="uninstall" @goto uninstall 23 | @if "%1"=="start" @goto start 24 | @if "%1"=="stop" @goto stop 25 | @if "%1"=="restart" @call :stop && @goto start 26 | @if "%1"=="console" @goto console 27 | @rem TODO: attach, ping, restart and reboot 28 | 29 | :usage 30 | @echo Usage: %0 {install|uninstall|start|stop|restart|console} 31 | @goto :EOF 32 | 33 | :install 34 | @%erts_bin%\erlsrv.exe add %service_name% -c "Erlang node %node_name% in %node_root%" -sname %node_name% -w %node_root% -m %node_root%\bin\start_erl.cmd -args " ++ %node_name% ++ %node_root%" -stopaction "init:stop()." 35 | @goto :EOF 36 | 37 | :uninstall 38 | @%erts_bin%\erlsrv.exe remove %service_name% 39 | @%erts_bin%\epmd.exe -kill 40 | @goto :EOF 41 | 42 | :start 43 | @%erts_bin%\erlsrv.exe start %service_name% 44 | @goto :EOF 45 | 46 | :stop 47 | @%erts_bin%\erlsrv.exe stop %service_name% 48 | @goto :EOF 49 | 50 | :console 51 | @start %erts_bin%\werl.exe -boot %releases_dir%\%release_version%\%node_name% 52 | @goto :EOF 53 | 54 | :set_trim 55 | @set %1=%2 56 | @goto :EOF 57 | -------------------------------------------------------------------------------- /rel/reltool.config: -------------------------------------------------------------------------------- 1 | {sys, [ 2 | {lib_dirs, ["..", "../deps", "../.."]}, 3 | {erts, [{mod_cond, derived}, {app_file, strip}]}, 4 | {app_file, strip}, 5 | {rel, "erws", "1", [ 6 | kernel,stdlib,sasl,crypto,cowboy,lager,syntax_tools,erws 7 | ]}, 8 | {rel, "start_clean", "", [ 9 | kernel,stdlib,sasl,crypto,cowboy,lager,syntax_tools,erws 10 | ]}, 11 | {boot_rel, "erws"}, 12 | {profile, embedded}, 13 | {incl_cond, exclude}, 14 | {excl_archive_filters, [".*"]}, %% Do not archive built libs 15 | {excl_sys_filters, [ 16 | "^bin/.*", "^erts.*/bin/(dialyzer|typer)", 17 | "^erts.*/(doc|info|include|lib|man|src)" 18 | ]}, 19 | {excl_app_filters, ["\.gitignore"]}, 20 | {app, sasl, [{incl_cond, include}]}, 21 | {app, stdlib, [{incl_cond, include}]}, 22 | {app, crypto, [{incl_cond, include}]}, 23 | {app, kernel, [{incl_cond, include}]}, 24 | {app, goldrush, [{incl_cond, include}]}, 25 | {app, ranch, [{incl_cond, include}]}, 26 | {app, cowlib, [{incl_cond, include}]}, 27 | {app, cowboy, [{incl_cond, include}]}, 28 | {app, compiler, [{incl_cond, include}]}, 29 | {app, syntax_tools, [{incl_cond, include}]}, 30 | {app, lager, [{incl_cond, include}]}, 31 | {app, erws, [{incl_cond, include}]} 32 | ]}. 33 | 34 | {target_dir, "erws"}. 35 | 36 | {overlay, [ 37 | {mkdir, "log/sasl"}, 38 | {copy, "files/erl", "\{\{erts_vsn\}\}/bin/erl"}, 39 | {copy, "files/nodetool", "\{\{erts_vsn\}\}/bin/nodetool"}, 40 | {copy, "files/erws", "bin/erws"}, 41 | {copy, "files/sys.config", "releases/\{\{rel_vsn\}\}/sys.config"}, 42 | {copy, "files/erws.cmd", "bin/erws.cmd"}, 43 | {copy, "files/start_erl.cmd", "bin/start_erl.cmd"}, 44 | {copy, "files/vm.args", "releases/\{\{rel_vsn\}\}/vm.args"} 45 | ]}. 46 | -------------------------------------------------------------------------------- /rel/files/nodetool: -------------------------------------------------------------------------------- 1 | %% -*- mode: erlang;erlang-indent-level: 4;indent-tabs-mode: nil -*- 2 | %% ex: ft=erlang ts=4 sw=4 et 3 | %% ------------------------------------------------------------------- 4 | %% 5 | %% nodetool: Helper Script for interacting with live nodes 6 | %% 7 | %% ------------------------------------------------------------------- 8 | 9 | main(Args) -> 10 | ok = start_epmd(), 11 | %% Extract the args 12 | {RestArgs, TargetNode} = process_args(Args, [], undefined), 13 | 14 | %% See if the node is currently running -- if it's not, we'll bail 15 | case {net_kernel:hidden_connect_node(TargetNode), net_adm:ping(TargetNode)} of 16 | {true, pong} -> 17 | ok; 18 | {_, pang} -> 19 | io:format("Node ~p not responding to pings.\n", [TargetNode]), 20 | halt(1) 21 | end, 22 | 23 | case RestArgs of 24 | ["ping"] -> 25 | %% If we got this far, the node already responsed to a ping, so just dump 26 | %% a "pong" 27 | io:format("pong\n"); 28 | ["stop"] -> 29 | io:format("~p\n", [rpc:call(TargetNode, init, stop, [], 60000)]); 30 | ["restart"] -> 31 | io:format("~p\n", [rpc:call(TargetNode, init, restart, [], 60000)]); 32 | ["reboot"] -> 33 | io:format("~p\n", [rpc:call(TargetNode, init, reboot, [], 60000)]); 34 | ["rpc", Module, Function | RpcArgs] -> 35 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), 36 | [RpcArgs], 60000) of 37 | ok -> 38 | ok; 39 | {badrpc, Reason} -> 40 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), 41 | halt(1); 42 | _ -> 43 | halt(1) 44 | end; 45 | ["rpcterms", Module, Function, ArgsAsString] -> 46 | case rpc:call(TargetNode, list_to_atom(Module), list_to_atom(Function), 47 | consult(ArgsAsString), 60000) of 48 | {badrpc, Reason} -> 49 | io:format("RPC to ~p failed: ~p\n", [TargetNode, Reason]), 50 | halt(1); 51 | Other -> 52 | io:format("~p\n", [Other]) 53 | end; 54 | Other -> 55 | io:format("Other: ~p\n", [Other]), 56 | io:format("Usage: nodetool {ping|stop|restart|reboot}\n") 57 | end, 58 | net_kernel:stop(). 59 | 60 | process_args([], Acc, TargetNode) -> 61 | {lists:reverse(Acc), TargetNode}; 62 | process_args(["-setcookie", Cookie | Rest], Acc, TargetNode) -> 63 | erlang:set_cookie(node(), list_to_atom(Cookie)), 64 | process_args(Rest, Acc, TargetNode); 65 | process_args(["-name", TargetName | Rest], Acc, _) -> 66 | ThisNode = append_node_suffix(TargetName, "_maint_"), 67 | {ok, _} = net_kernel:start([ThisNode, longnames]), 68 | process_args(Rest, Acc, nodename(TargetName)); 69 | process_args(["-sname", TargetName | Rest], Acc, _) -> 70 | ThisNode = append_node_suffix(TargetName, "_maint_"), 71 | {ok, _} = net_kernel:start([ThisNode, shortnames]), 72 | process_args(Rest, Acc, nodename(TargetName)); 73 | process_args([Arg | Rest], Acc, Opts) -> 74 | process_args(Rest, [Arg | Acc], Opts). 75 | 76 | 77 | start_epmd() -> 78 | [] = os:cmd(epmd_path() ++ " -daemon"), 79 | ok. 80 | 81 | epmd_path() -> 82 | ErtsBinDir = filename:dirname(escript:script_name()), 83 | Name = "epmd", 84 | case os:find_executable(Name, ErtsBinDir) of 85 | false -> 86 | case os:find_executable(Name) of 87 | false -> 88 | io:format("Could not find epmd.~n"), 89 | halt(1); 90 | GlobalEpmd -> 91 | GlobalEpmd 92 | end; 93 | Epmd -> 94 | Epmd 95 | end. 96 | 97 | 98 | nodename(Name) -> 99 | case string:tokens(Name, "@") of 100 | [_Node, _Host] -> 101 | list_to_atom(Name); 102 | [Node] -> 103 | [_, Host] = string:tokens(atom_to_list(node()), "@"), 104 | list_to_atom(lists:concat([Node, "@", Host])) 105 | end. 106 | 107 | append_node_suffix(Name, Suffix) -> 108 | case string:tokens(Name, "@") of 109 | [Node, Host] -> 110 | list_to_atom(lists:concat([Node, Suffix, os:getpid(), "@", Host])); 111 | [Node] -> 112 | list_to_atom(lists:concat([Node, Suffix, os:getpid()])) 113 | end. 114 | 115 | 116 | %% 117 | %% Given a string or binary, parse it into a list of terms, ala file:consult/0 118 | %% 119 | consult(Str) when is_list(Str) -> 120 | consult([], Str, []); 121 | consult(Bin) when is_binary(Bin)-> 122 | consult([], binary_to_list(Bin), []). 123 | 124 | consult(Cont, Str, Acc) -> 125 | case erl_scan:tokens(Cont, Str, 0) of 126 | {done, Result, Remaining} -> 127 | case Result of 128 | {ok, Tokens, _} -> 129 | {ok, Term} = erl_parse:parse_term(Tokens), 130 | consult([], Remaining, [Term | Acc]); 131 | {eof, _Other} -> 132 | lists:reverse(Acc); 133 | {error, Info, _} -> 134 | {error, Info} 135 | end; 136 | {more, Cont1} -> 137 | consult(Cont1, eof, Acc) 138 | end. 139 | -------------------------------------------------------------------------------- /rel/files/erws: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | # -*- tab-width:4;indent-tabs-mode:nil -*- 3 | # ex: ts=4 sw=4 et 4 | 5 | RUNNER_SCRIPT_DIR=$(cd ${0%/*} && pwd) 6 | 7 | RUNNER_BASE_DIR=${RUNNER_SCRIPT_DIR%/*} 8 | RUNNER_ETC_DIR=$RUNNER_BASE_DIR/etc 9 | RUNNER_LOG_DIR=$RUNNER_BASE_DIR/log 10 | # Note the trailing slash on $PIPE_DIR/ 11 | PIPE_DIR=/tmp/$RUNNER_BASE_DIR/ 12 | RUNNER_USER= 13 | 14 | # Make sure this script is running as the appropriate user 15 | if [ ! -z "$RUNNER_USER" ] && [ `whoami` != "$RUNNER_USER" ]; then 16 | exec sudo -u $RUNNER_USER -i $0 $@ 17 | fi 18 | 19 | # Make sure CWD is set to runner base dir 20 | cd $RUNNER_BASE_DIR 21 | 22 | # Make sure log directory exists 23 | mkdir -p $RUNNER_LOG_DIR 24 | # Identify the script name 25 | SCRIPT=`basename $0` 26 | 27 | # Parse out release and erts info 28 | START_ERL=`cat $RUNNER_BASE_DIR/releases/start_erl.data` 29 | ERTS_VSN=${START_ERL% *} 30 | APP_VSN=${START_ERL#* } 31 | 32 | # Use releases/VSN/vm.args if it exists otherwise use etc/vm.args 33 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" ]; then 34 | VMARGS_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/vm.args" 35 | else 36 | VMARGS_PATH="$RUNNER_ETC_DIR/vm.args" 37 | fi 38 | 39 | # Use releases/VSN/sys.config if it exists otherwise use etc/app.config 40 | if [ -e "$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" ]; then 41 | CONFIG_PATH="$RUNNER_BASE_DIR/releases/$APP_VSN/sys.config" 42 | else 43 | CONFIG_PATH="$RUNNER_ETC_DIR/app.config" 44 | fi 45 | 46 | # Extract the target node name from node.args 47 | NAME_ARG=`egrep '^-s?name' $VMARGS_PATH` 48 | if [ -z "$NAME_ARG" ]; then 49 | echo "vm.args needs to have either -name or -sname parameter." 50 | exit 1 51 | fi 52 | 53 | # Extract the target cookie 54 | COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH` 55 | if [ -z "$COOKIE_ARG" ]; then 56 | echo "vm.args needs to have a -setcookie parameter." 57 | exit 1 58 | fi 59 | 60 | # Add ERTS bin dir to our path 61 | ERTS_PATH=$RUNNER_BASE_DIR/erts-$ERTS_VSN/bin 62 | 63 | # Setup command to control the node 64 | NODETOOL="$ERTS_PATH/escript $ERTS_PATH/nodetool $NAME_ARG $COOKIE_ARG" 65 | 66 | # Check the first argument for instructions 67 | case "$1" in 68 | start) 69 | # Make sure there is not already a node running 70 | RES=`$NODETOOL ping` 71 | if [ "$RES" = "pong" ]; then 72 | echo "Node is already running!" 73 | exit 1 74 | fi 75 | HEART_COMMAND="$RUNNER_BASE_DIR/bin/$SCRIPT start" 76 | export HEART_COMMAND 77 | mkdir -p $PIPE_DIR 78 | shift # remove $1 79 | $ERTS_PATH/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RUNNER_BASE_DIR/bin/$SCRIPT console $@" 2>&1 80 | ;; 81 | 82 | stop) 83 | # Wait for the node to completely stop... 84 | case `uname -s` in 85 | Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) 86 | # PID COMMAND 87 | PID=`ps ax -o pid= -o command=|\ 88 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` 89 | ;; 90 | SunOS) 91 | # PID COMMAND 92 | PID=`ps -ef -o pid= -o args=|\ 93 | grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $1}'` 94 | ;; 95 | CYGWIN*) 96 | # UID PID PPID TTY STIME COMMAND 97 | PID=`ps -efW|grep "$RUNNER_BASE_DIR/.*/[b]eam"|awk '{print $2}'` 98 | ;; 99 | esac 100 | $NODETOOL stop 101 | ES=$? 102 | if [ "$ES" -ne 0 ]; then 103 | exit $ES 104 | fi 105 | while `kill -0 $PID 2>/dev/null`; 106 | do 107 | sleep 1 108 | done 109 | ;; 110 | 111 | restart) 112 | ## Restart the VM without exiting the process 113 | $NODETOOL restart 114 | ES=$? 115 | if [ "$ES" -ne 0 ]; then 116 | exit $ES 117 | fi 118 | ;; 119 | 120 | reboot) 121 | ## Restart the VM completely (uses heart to restart it) 122 | $NODETOOL reboot 123 | ES=$? 124 | if [ "$ES" -ne 0 ]; then 125 | exit $ES 126 | fi 127 | ;; 128 | 129 | ping) 130 | ## See if the VM is alive 131 | $NODETOOL ping 132 | ES=$? 133 | if [ "$ES" -ne 0 ]; then 134 | exit $ES 135 | fi 136 | ;; 137 | 138 | attach) 139 | # Make sure a node IS running 140 | RES=`$NODETOOL ping` 141 | ES=$? 142 | if [ "$ES" -ne 0 ]; then 143 | echo "Node is not running!" 144 | exit $ES 145 | fi 146 | 147 | shift 148 | exec $ERTS_PATH/to_erl $PIPE_DIR 149 | ;; 150 | 151 | console|console_clean) 152 | # .boot file typically just $SCRIPT (ie, the app name) 153 | # however, for debugging, sometimes start_clean.boot is useful: 154 | case "$1" in 155 | console) BOOTFILE=$SCRIPT ;; 156 | console_clean) BOOTFILE=start_clean ;; 157 | esac 158 | # Setup beam-required vars 159 | ROOTDIR=$RUNNER_BASE_DIR 160 | BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin 161 | EMU=beam 162 | PROGNAME=`echo $0 | sed 's/.*\\///'` 163 | CMD="$BINDIR/erlexec -boot $RUNNER_BASE_DIR/releases/$APP_VSN/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH -- ${1+"$@"}" 164 | export EMU 165 | export ROOTDIR 166 | export BINDIR 167 | export PROGNAME 168 | 169 | # Dump environment info for logging purposes 170 | echo "Exec: $CMD" 171 | echo "Root: $ROOTDIR" 172 | 173 | # Log the startup 174 | logger -t "$SCRIPT[$$]" "Starting up" 175 | 176 | # Start the VM 177 | exec $CMD 178 | ;; 179 | 180 | *) 181 | echo "Usage: $SCRIPT {start|stop|restart|reboot|ping|console|console_clean|attach}" 182 | exit 1 183 | ;; 184 | esac 185 | 186 | exit 0 187 | --------------------------------------------------------------------------------