diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d176978 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +*.swp +*.dump +*.beam +Mnesia.* diff --git a/.gitmodules b/.gitmodules index 2e9d3a7..4c56fac 100644 --- a/.gitmodules +++ b/.gitmodules @@ -1,6 +1,3 @@ [submodule "erlang_js"] path = erlang_js - url = https://github.com/basho/erlang_js.git -[submodule "erlv8"] - path = erlv8 - url = https://github.com/beamjs/erlv8.git + url = https://github.com/jonte/erlang_js.git diff --git a/HOWTO b/HOWTO index 035800e..2d28ea8 100644 --- a/HOWTO +++ b/HOWTO @@ -1,18 +1,21 @@ +PREREQUISITES: +python version 2.x set to default. + INSTALL 1. Cd into directory where you to have the project -2. git-clone git@github.com:jeena/GGS.git (remember to have a local key) +2. git clone git@github.com:jeena/GGS.git (remember to have a local key) 3. cd GGS/ 4. git submodule init 5. git submodule update 6. cd erlang_js 7. make -8. make test (If not all tests are passed then you are screwed!) +8. make test (Optional. It has to work though.) 10. cd ../ 11. ./build 12. USAGE 1. start a second terminal -2. telnet localhost 7000 +2. in new terminal do command: ./python_client 9000 3. back to first terminal 4. ./start diff --git a/build b/build index d468113..a9c1c79 100755 --- a/build +++ b/build @@ -3,4 +3,4 @@ for i in `find src -name "*.erl"` do erlc -o ebin $i -done +done \ No newline at end of file diff --git a/client b/client new file mode 100644 index 0000000..dff11aa --- /dev/null +++ b/client @@ -0,0 +1,17 @@ +#!/usr/bin/env ruby -wKU + +require 'socket' # Sockets are in standard library + +hostname = 'localhost' +port = 7000 + +s = TCPSocket.open(hostname, port) + + + +s.print(q.chop) + +while line = s.gets # Read lines from the socket + puts "Got Echo: " + line.chop # And print with platform line terminator +end +s.close # Close the socket when done diff --git a/ebin/ggs.app b/ebin/ggs.app index cafc9df..3315864 100644 --- a/ebin/ggs.app +++ b/ebin/ggs.app @@ -3,8 +3,7 @@ {vsn, "0.1.0"}, {modules, [ ggs_app, - ggs_sup, - ggs_server + ggs_sup ]}, {registered, [ggs_sup]}, {applications, [kernel, stdlib]}, diff --git a/erlv8 b/erlv8 deleted file mode 160000 index 688e503..0000000 --- a/erlv8 +++ /dev/null @@ -1 +0,0 @@ -Subproject commit 688e5036864eed01f7aefb6ee8b3a4c22961012f diff --git a/games/tic-tac-toe-js/index.html b/games/tic-tac-toe-js/index.html index 97d3c4f..5bdb286 100644 --- a/games/tic-tac-toe-js/index.html +++ b/games/tic-tac-toe-js/index.html @@ -12,8 +12,16 @@ function init() { GameServer.addGame(game_name, main()); - GameServer.addClient(game_name, new TicTacToeClient(frames.player1.document.getElementById("p1"), GameServer)); - GameServer.addClient(game_name, new TicTacToeClient(frames.player2.document.getElementById("p2"), GameServer)); + GameServer.addClient( + game_name, + new TicTacToeClient(frames.player1.document.getElementById("p1"), + GameServer + )); + GameServer.addClient( + game_name, + new TicTacToeClient(frames.player2.document.getElementById("p2"), + GameServer + )); } diff --git a/games/tic-tac-toe-js/proxy.rb b/games/tic-tac-toe-js/proxy.rb new file mode 100644 index 0000000..e69de29 diff --git a/python_client b/python_client index 77574e6..9a1f1a9 100755 --- a/python_client +++ b/python_client @@ -1,22 +1,78 @@ #!/usr/bin/env python -import sys - -import socket +import sys, time, socket HOST = 'localhost' # The remote host PORT = int(sys.argv[1]) # The same port as used by the server s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) s.connect((HOST, PORT)) -s.send('__hello 0') + +# Say hello + +print "Saying hello to server" +s.send( +"Command: hello\n\ +Content-Type: text\n\ +Content-Length: 0\n\ +\n\ +") fs = s.makefile() data = fs.readline() token = data.split(" ")[0] print "Token:", token +print "Data: ", ' '.join(data.split(" ")[1:]) -s.send(token+" __echo 0 msg") -data = s.recv(1024) -print data +# Define ourselves a function! + +print "Defining a function called myFun" +s.send( +"Token: %s\n\ +Command: define\n\ +Content-Type: text\n\ +Content-Length: 49\n\ +\n\ +function myFun() {return 'Hello World!' ;}" % token) +fs = s.makefile() +data = fs.readline() +print "Token:", token +print "Data: ", ' '.join(data.split(" ")[1:]) + +# Call that function! + +print "Calling myFun" +s.send( +"Token: %s\n\ +Command: call\n\ +Content-Type: text\n\ +Content-Length: 6\n\ +\n\ +myFun" % token) +fs = s.makefile() +data = fs.readline() +print "Token:", token +print "Data: ", ' '.join(data.split(" ")[1:]) s.close() +""" +HOST = 'localhost' # The remote host +PORT = int(sys.argv[1]) # The same port as used by the server +s = socket.socket(socket.AF_INET, socket.SOCK_STREAM) +s.connect((HOST, PORT)) +# Call that function! + +print "Calling myFun" +s.send( +"Token: %s\n\ +Command: call\n\ +Content-Type: text\n\ +Content-Length: 6\n\ +\n\ +myFun" % token) +fs = s.makefile() +data = fs.readline() +print "Token:", token +print "Data: ", ' '.join(data.split(" ")[1:]) + +s.close() +""" diff --git a/src/ggs_backup.erl b/src/ggs_backup.erl new file mode 100644 index 0000000..30c80a2 --- /dev/null +++ b/src/ggs_backup.erl @@ -0,0 +1,41 @@ +-module(ggs_backup). +-behaviour(gen_server). + +%% API +-export([start_link/0 ]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, + handle_info/2, terminate/2, code_change/3]). + + +-define(SERVER, ?MODULE). + +-record(state, {port, lsock, client_vm_map = []}). + +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +init([]) -> + {ok, #state{port = -1, lsock = -1, client_vm_map = -1}, 0}. + +handle_call(get_backup, _From, State) -> + BackedUpState = case State of + #state{port = -1, lsock = -1, client_vm_map = -1} -> + not_initialized; + Other -> + Other + end, + {reply, {backup_state, BackedUpState}, State}. + +handle_cast({set_backup, NewState}, _State) -> + {noreply, NewState}. + +handle_info(_Msg, State) -> + {noreply, State}. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +terminate(_Reason, _State) -> + ok. diff --git a/src/ggs_mnesia_controller_server.erl b/src/ggs_mnesia_controller_server.erl new file mode 100644 index 0000000..c1f8a10 --- /dev/null +++ b/src/ggs_mnesia_controller_server.erl @@ -0,0 +1,68 @@ +-module(ggs_mnesia_controller_server). +-behaviour(gen_server). + +%% API +-export([start_link/0, + stop/0 + ]). + +%% gen_server callbacks +-export([init/1, handle_call/3, handle_cast/2, + handle_info/2, terminate/2, code_change/3]). + + +-define(SERVER, ?MODULE). + +-record(state, {}). + +%%%==================================================== +%%% API +%%%==================================================== + +%%----------------------------------------------------- +%% @doc Starts the server +%% @end +%%----------------------------------------------------- +start_link() -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [], []). + +%%----------------------------------------------------- +%% @doc Stops the server. +%% @spec stop() -> ok +%% @end +%%----------------------------------------------------- +stop() -> + gen_server:cast(?SERVER, stop). + +%%----------------------------------------------------- +%% gen_server callbacks +%%----------------------------------------------------- + +init([]) -> + mnesia:create_schema([node()]), + mnesia:start(), + {ok, {}, 0}. + +handle_cast(a, State) -> + {noreply, State}. + +% Request a value from the Mnesia database +handle_call({getValue, _Key},_From,State) -> + {reply,value_of_key_requested_goes_here, State}; + +% Set a value in the Mnesia database +handle_call({setValue, _Key, Value},_From,State) -> + {reply,value_set_or_updated, State}. + +handle_info(timeout, State) -> + {noreply, State}. + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%----------------------------------------------------- +%% Internal functions +%%----------------------------------------------------- diff --git a/src/ggs_protocol.erl b/src/ggs_protocol.erl index c470beb..ede5115 100644 --- a/src/ggs_protocol.erl +++ b/src/ggs_protocol.erl @@ -1,36 +1,39 @@ -%% This is a parser for JSON implemented using mochijson2 -%% Don't feed it anything other than valid JSON. - -module(ggs_protocol). -export([parse/1]). parse(Data) -> - Message = string:tokens(Data, " "), - io:format(Message), - case Message of - ["__get_vms"] -> - {vms}; - [RefID, "__error", Size, Message ] -> - {ok, you_said_error}; - [_, "__boot", _ ] -> - {ok, you_said_boot}; - [RefID, "__stop", _] -> - {ok, you_said_stop}; - [RefID, "__start", _] -> - {ok, you_said_start}; - ["__hello", _] -> - {hello}; - [RefID, "__define",_, JavaScript ] -> - {ok, you_said_define}; - [RefID, "__echo", Length, Msg ] -> - {Ref, _} = string:to_integer(RefID), - {echo, Ref, Length, Msg}; - [RefID, Command, _, Parameter ] -> - {cmd, Command, Parameter}; - %% Debugging tools, not for production use - ["__crash"] -> - {crash, 0}; - %% End debugging tools - Other -> - {out_of_bounds, Other} - end. + Message =string:tokens(Data, "\n"), + % Turn "A: B" pairs into "{A, B}" tuples, for searching. + MsgKV = lists:map((fun(Str) -> + list_to_tuple(string:tokens(Str, ": ")) end + ), Message), + % Hacky way to build a tuple, filter out not_found later on + Processed = { + case lists:keysearch("Command", 1, MsgKV) of + {value,{_, "define"}} -> + define; + {value,{_, "call"}} -> + call; + {value,{_, "hello"}} -> + hello; + false -> + not_found + end, + case lists:keysearch("Token", 1, MsgKV) of + {value,{_, Value}} -> + Value; + false -> + not_found + end, + case lists:keysearch("Content-Length", 1, MsgKV) of + {value,{_, Value}} -> + {Length, _} = string:to_integer(Value), + [_|Cont] = re:split(Data, "\n\n",[{return,list}]), + Content = string:join(Cont, "\n\n"), + Payload = string:substr(Content,1,Length), + Payload; + false -> + not_found + end + }, + gen_server:cast(ggs_server, Processed). diff --git a/src/ggs_server.erl b/src/ggs_server.erl deleted file mode 100644 index 097151f..0000000 --- a/src/ggs_server.erl +++ /dev/null @@ -1,54 +0,0 @@ -%%%---------------------------------------------------- -%%% @author Jonatan Pålsson -%%% @copyright 2010 Jonatan Pålsson -%%% @end -%%%---------------------------------------------------- - --module(ggs_server). - -% import --import(ggs_network). - -%% API --export([start_link/0, start_link/1, stop/0 ]). -%-export([crash/0, vms/0, hello/0, echo/0]). --export([get_count/0]). - - -%%%==================================================== -%%% API -%%%==================================================== - -%%----------------------------------------------------- -%% @doc Starts the server -%% @end -%%----------------------------------------------------- -start_link() -> - ggs_network:start_link(). - -start_link(Port) -> - ggs_network:start_link(Port). - - -%%----------------------------------------------------- -%% @doc Fetches the number of requests made to this server -%% @spec get_count() -> {ok, Count} -%% where -%% Count = integer() -%% @end -%%----------------------------------------------------- -get_count() -> - ggs_network:get_count(get_count). - -%crash() -> gss_network:crash(). -%vms() -> gss_network:vms(). -%hello() -> gss_network:hello(). -%echo() -> gss_network:echo(). - -%%----------------------------------------------------- -%% @doc Stops the server. -%% @spec stop() -> ok -%% @end -%%----------------------------------------------------- -stop() -> - ggs_network:stop(). diff --git a/src/ggs_server_sup.erl b/src/ggs_server_sup.erl new file mode 100644 index 0000000..23d32f7 --- /dev/null +++ b/src/ggs_server_sup.erl @@ -0,0 +1,48 @@ +-module(ggs_server_sup). +-behaviour(supervisor). + +%% API +-export([start/1, start_link/1]). + +%% Supervisor callbacks +-export([init/1]). +-define(SERVER, ?MODULE). + +start(Port) -> + [FirstArg] = Port, + {IntPort, _} = string:to_integer(FirstArg), + start_link(IntPort). + +start_link(Port) -> + supervisor:start_link({local, ?SERVER}, ?MODULE, [Port]). + +init([Port]) -> + GGSServer = {ggs_server, + {ggs_server, start_link, [Port]}, + permanent, + 2000, + worker, + [ggs_server] + }, + Backup = {ggs_backup, + {ggs_backup, start_link, []}, + permanent, + 2000, + worker, + [ggs_backup] + }, + MnesiaServer = {ggs_mnesia_controller_server, + {ggs_mnesia_controller_server, start_link, []}, + permanent, + 2000, + worker, + [ggs_mnesia_controller_server] + }, + Children = [MnesiaServer, Backup, GGSServer], + + RestartStrategy = { one_for_one, % Restart only crashing child + 10, % Allow ten crashes per.. + 1 % 1 second, then crash supervisor. + }, + {ok, {RestartStrategy, Children}}. + diff --git a/src/ggs_sup.erl b/src/ggs_sup.erl index 0cc8335..ee6f8cd 100644 --- a/src/ggs_sup.erl +++ b/src/ggs_sup.erl @@ -17,12 +17,12 @@ start_link(Port) -> supervisor:start_link({local, ?SERVER}, ?MODULE, [Port]). init([Port]) -> - Server = {ggs_server, - {ggs_server, start_link, [Port]}, + Server = {ggs_server_sup, + {ggs_server_sup, start_link, [Port]}, permanent, 2000, worker, - [ggs_server] + [ggs_server_sup] }, Children = [Server], diff --git a/src/js_runner.erl b/src/js_runner.erl deleted file mode 100644 index ca866c4..0000000 --- a/src/js_runner.erl +++ /dev/null @@ -1,13 +0,0 @@ --module(js_runner). --export([define/2,call/3, boot/0]). - -boot() -> - erlang_js:start(), - {ok, Port} = js_driver:new(), - Port. - -define(Port, Data) -> - ok = js:define(Port, list_to_binary(Data)). - -call(Port, Func, Params) -> - js:call(Port, list_to_binary(Func), Params). diff --git a/src/start_ggs.erl b/src/start_ggs.erl index eabdbc5..3955715 100644 --- a/src/start_ggs.erl +++ b/src/start_ggs.erl @@ -3,4 +3,5 @@ start() -> application:start(inets), + application:start(erlang_js), application:start(ggs). diff --git a/start b/start index f3720a5..6de5737 100755 --- a/start +++ b/start @@ -1,3 +1,3 @@ #!/usr/bin/env bash -erl -boot start_sasl -pa erlang_js/ebin/ -pa ebin -pa src -s start_ggs +erl -sname ggs -mnesia -boot start_sasl -pa erlang_js/ebin/ -pa ebin -pa src -s start_ggs