From 2daf20c039e5e6f58be08d0ab45f4ab4ced9658a Mon Sep 17 00:00:00 2001 From: Jeena Paradies Date: Sat, 30 Apr 2011 18:55:05 +0200 Subject: [PATCH] some bugfixes to kallfaktorns erlv8 code --- Makefile | 2 +- src/ggs_gamevm.erl | 353 ++++++-------------------------------- src/ggs_gamevm_p.erl | 2 +- src/ggs_player.erl | 14 +- src/ggs_protocol.erl | 6 +- src/ggs_protocol.erl.bk2 | 163 ------------------ src/ggs_protocol.erl.orig | 146 ---------------- src/ggs_table.erl | 8 +- 8 files changed, 66 insertions(+), 628 deletions(-) delete mode 100644 src/ggs_protocol.erl.bk2 delete mode 100644 src/ggs_protocol.erl.orig diff --git a/Makefile b/Makefile index 442fa5b..37b48b6 100644 --- a/Makefile +++ b/Makefile @@ -5,7 +5,7 @@ TESTDIR=tests LIBDIR=lib BEAMDIR=ebin -all: compile +all: compile erlv8 compile: mkdir -p $(BEAMDIR) ; diff --git a/src/ggs_gamevm.erl b/src/ggs_gamevm.erl index 5ddc553..cfbdbe9 100644 --- a/src/ggs_gamevm.erl +++ b/src/ggs_gamevm.erl @@ -8,7 +8,7 @@ %% API -export([start/0,start_link/1,stop/1]). --export([define/3, player_command/5, call_js/2]). +-export([define/2, player_command/4, call_js/2]). %% gen_server callbacks -export([init/1, handle_call/3, handle_cast/2]). @@ -31,13 +31,12 @@ start() -> %% @doc Create a new VM process. The process ID is returned and can be used %% with for example the define method of this module. start_link(Table) -> - {ok, AccessVM} = gen_server:start_link(?MODULE, [Table], []), - expose_to_js(AccessVM), - AccessVM. + {ok, GameVM} = gen_server:start_link(?MODULE, [Table], []), + GameVM. %% @doc Define some new code on the specified VM, returns the atom ok. -define(AccessVM, Key, SourceCode) -> - gen_server:cast(AccessVM, {define, Key, SourceCode}). +define(GameVM, SourceCode) -> + gen_server:cast(GameVM, {define, SourceCode}). %% @doc Execute a player command on the specified VM. This function is %% asynchronous, and returns ok. @@ -46,17 +45,17 @@ define(AccessVM, Key, SourceCode) -> %% Player = the player running the command %% Command = a game command to run %% Args = arguments for the Command parameter -player_command(accessVM, Key, Player, Command, Args) -> - gen_server:cast(accessVM, {player_command, Key, Player, Command, Args}). +player_command(GameVm, Player, Command, Args) -> + gen_server:cast(GameVm, {player_command, Player, Command, Args}). %% @private % only for tests -call_js(AccessVM, SourceCode) -> - gen_server:call(AccessVM, {eval, SourceCode}). +call_js(GameVM, SourceCode) -> + gen_server:call(GameVM, {eval, SourceCode}). % @doc stops the gamevm process -stop(AccessVM) -> - gen_server:cast(AccessVM, stop). +stop(GameVM) -> + gen_server:cast(GameVM, stop). init([Table]) -> @@ -65,192 +64,40 @@ init([Table]) -> {ok, VM} = erlv8_vm:start(), % Create a JavaScript vm Global = erlv8_vm:global(VM), % Retrieve JS global ggs_db:init(), % Initialize the database - {ok, #state { vm = VM, global = Global, table = Table }}. + NewGlobal = expose(Global, Table), + {ok, #state { vm = VM, global = NewGlobal, table = Table }}. -%% Expose to JavaScript +% @doc Exposes some GGS functions to JavaScript +expose(Global, Table) -> + Global:set_value("GGS", erlv8_object:new([ + {"localStorage", erlv8_object:new([ + {"setItem", fun(#erlv8_fun_invocation{}, [Key, Val])-> ggs_db:setItem(Table, "localStorage", Key, Val) end}, + {"removeItem", fun(#erlv8_fun_invocation{}, [Key])-> ggs_db:removeItem(Table, "localStorage", Key) end}, + {"clear", fun(#erlv8_fun_invocation{}, [])-> ggs_db:clear(Table, "localStorage") end}, + {"getItem", fun(#erlv8_fun_invocation{}, [Key])-> ggs_db:getItem(Table, "localStorage", Key) end}, + {"length", fun(#erlv8_fun_invocation{}, [])-> ggs_db:length(Table, "localStorage") end}, + {"key", fun(#erlv8_fun_invocation{}, [Position])-> ggs_db:key(Table, "localStorage", Position) end} + ])}, + {"world", erlv8_object:new([ + {"setItem", fun(#erlv8_fun_invocation{}, [Key, Val])-> ggs_db:setItem(Table, "world", Key, Val) end}, + {"removeItem", fun(#erlv8_fun_invocation{}, [Key])-> ggs_db:removeItem(Table, "world", Key) end}, + {"clear", fun(#erlv8_fun_invocation{}, [])-> ggs_db:clear(Table, "world") end}, + {"getItem", fun(#erlv8_fun_invocation{}, [Key])-> ggs_db:getItem(Table, "world", Key) end}, + {"length", fun(#erlv8_fun_invocation{}, [])-> ggs_db:length(Table, "world") end}, + {"key", fun(#erlv8_fun_invocation{}, [Position])-> ggs_db:key(Table, "world", Position) end} + ])}, + {"sendCommand", fun(#erlv8_fun_invocation{}, [Player, Command, Args])-> + erlang:display(Table), + ggs_table:send_command(Table, Player, {Command, Args}) + end}, + {"sendCommandToAll", fun(#erlv8_fun_invocation{}, [Command, Args])-> ggs_table:notify_all_players(Table, {Command, Args}) end} + %{"setTimeout", fund(#erlv8_fun_invocation{}, [Time, FunctionName])-> setTimeout(Time, FunctionName) end} + ])). -expose_to_js(AccessVM) -> - expose_localstorage_set_item(AccessVM), - expose_localstorage_get_item(AccessVM), - expose_localstorage_key(AccessVM), - expose_localstorage_length(AccessVM), - expose_localstorage_remove_item(AccessVM), - expose_localstorage_clear1(AccessVM), - expose_localstorage_clear2(AccessVM), - - expose_world_set_item(AccessVM), - expose_world_get_item(AccessVM), - expose_world_key(AccessVM), - expose_world_length(AccessVM), - expose_world_remove_item(AccessVM), - expose_world_clear1(AccessVM), - expose_world_clear2(AccessVM), - - expose_player_set_item(AccessVM), - expose_player_get_item(AccessVM), - expose_player_key(AccessVM), - expose_player_length(AccessVM), - expose_player_remove_item(AccessVM), - - expose_table_send_command(AccessVM). - - -%% Helpers - -expose_localstorage_set_item(AccessVM) -> - gen_server:cast(AccessVM, localstorage_set_item). - -expose_localstorage_remove_item(AccessVM) -> - gen_server:cast(AccessVM, localstorage_remove_item). - -expose_localstorage_clear1(AccessVM) -> - gen_server:cast(AccessVM, localstorage_clear1). - -expose_localstorage_clear2(AccessVM) -> - gen_server:cast(AccessVM, localstorage_clear2). - -expose_localstorage_get_item(AccessVM) -> - gen_server:cast(AccessVM, localstorage_get_item). - -expose_localstorage_length(AccessVM) -> - gen_server:cast(AccessVM, localstorage_length). - -expose_localstorage_key(AccessVM) -> - gen_server:cast(AccessVM, localstorage_key). - -expose_world_set_item(AccessVM) -> - gen_server:cast(AccessVM, world_set_item). - -expose_world_remove_item(AccessVM) -> - gen_server:cast(AccessVM, world_remove_item). - -expose_world_clear1(AccessVM) -> - gen_server:cast(AccessVM, world_clear1). - -expose_world_clear2(AccessVM) -> - gen_server:cast(AccessVM, world_clear2). - -expose_world_get_item(AccessVM) -> - gen_server:cast(AccessVM, world_get_item). - -expose_world_length(AccessVM) -> - gen_server:cast(AccessVM, world_length). - -expose_world_key(AccessVM) -> - gen_server:cast(AccessVM, world_key). - -expose_player_set_item(AccessVM) -> - gen_server:cast(AccessVM, player_set_item). - -expose_player_remove_item(AccessVM) -> - gen_server:cast(AccessVM, player_remove_item). - -expose_player_get_item(AccessVM) -> - gen_server:cast(AccessVM, player_get_item). - -expose_player_length(AccessVM) -> - gen_server:cast(AccessVM, player_length). - -expose_player_key(AccessVM) -> - gen_server:cast(AccessVM, player_key). - -%% Expose ggs_table - -expose_table_send_command(AccessVM) -> - gen_server:cast(AccessVM, send_command). - - -%% TODO: expose_table_send_command_to_all() - - -%% Expose helpers - -expose_fun_localstorage(Global, Name, Fun, 1) -> - Global:set_value("GGS.localStorage", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg]) -> - Fun(Arg) end}])); - -expose_fun_localstorage(Global, Name, Fun, 2) -> - Global:set_value("GGS.localStorage", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2]) -> - Fun(Arg1,Arg2) end}])); - - -expose_fun_localstorage(Global, Name, Fun, 3) -> - Global:set_value("GGS.localStorage", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3]) -> - Fun(Arg1,Arg2,Arg3) end}])); - -expose_fun_localstorage(Global, Name, Fun, 4) -> - Global:set_value("GGS.localStorage", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3,Arg4]) -> - Fun(Arg1,Arg2,Arg3,Arg4) - end}])). - - expose_fun_world(Global, Name, Fun, 1) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg]) -> - Fun(Arg) end}])); - -expose_fun_world(Global, Name, Fun, 2) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2]) -> - Fun(Arg1,Arg2) end}])); - - -expose_fun_world(Global, Name, Fun, 3) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3]) -> - Fun(Arg1,Arg2,Arg3) end}])); - -expose_fun_world(Global, Name, Fun, 4) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3,Arg4]) -> - Fun(Arg1,Arg2,Arg3,Arg4) - end}])). -expose_fun_player(Global, Name, Fun, 1) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg]) -> - Fun(Arg) end}])); - -expose_fun_player(Global, Name, Fun, 2) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2]) -> - Fun(Arg1,Arg2) end}])); - - -expose_fun_player(Global, Name, Fun, 3) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3]) -> - Fun(Arg1,Arg2,Arg3) end}])); - -expose_fun_player(Global, Name, Fun, 4) -> - Global:set_value("GGS.world", erlv8_object:new([{Name, - fun (#erlv8_fun_invocation{}, - [Arg1,Arg2,Arg3,Arg4]) -> - Fun(Arg1,Arg2,Arg3,Arg4) - end}])). - %% Retrieve a JavaScript file from hard drive and return it %read_js_file(Filename) -> % {ok, JSApp} = file:read_file(Filename), % erlang:binary_to_list(JSApp). - - -%print(Args) -> -% io:format("~s~n", [Args]). - %% private % only needed for the tests @@ -258,126 +105,24 @@ handle_call({eval, SourceCode}, _From, #state { vm = VM } = State) -> {ok, Ret} = erlv8_vm:run(VM, SourceCode), {reply, Ret, State}. -handle_cast({define, Key, SourceCode}, - #state { table = Table, global = Global } = State) -> - Global:set_value(Key, SourceCode), - ggs_table:notify_all_players(Table, {"defined", "ok"}), +handle_cast({define, SourceCode}, #state { table = Table, vm = VM } = State) -> + R = erlv8_vm:run(VM, "playerCommand"), + case R of + {throw, _} -> {ok, Ret} = erlv8_vm:run(VM, SourceCode), + ggs_table:notify_all_players(Table, {"defined", "ok"}); + _ -> ok + end {noreply, State}; - - -handle_cast({player_command, Key, Player, Command, Args}, - #state { global = Global } = State) -> - Js = "playerCommand(new Player('" ++ Player ++ "'), '" ++ - js_escape(Command) ++ "', '" ++ js_escape(Args) ++ "');", - Global:set_value(Key, Js), - erlang:display(binary_to_list(Js)), +handle_cast({player_command, Player, Command, Args}, #state { vm = VM } = State) -> + Js = "playerCommand('" ++ Player ++ "', '" ++ js_escape(Command) ++ "', '" ++ js_escape(Args) ++ "');", + {ok, _Ret} = erlv8_vm:run(VM, Js), {noreply, State}; handle_cast(stop, #state { vm = VM } = State) -> erlv8_vm:stop(VM), {stop, normal, State}; - handle_cast(localstorage_set_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key,Value) -> ggs_db:setItem(GameToken,?LOCALSTORAGE,Key,Value) end), - expose_fun_localstorage( Global, "setItem", Fun, 3), - {noreply, State}; - -handle_cast(localstorage_get_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:getItem(GameToken,?LOCALSTORAGE,Key) end), - expose_fun_localstorage( Global, "getItem", Fun, 2), - {noreply, State}; - -handle_cast(localstorage_key, #state { global = Global } = State) -> - Fun = (fun(GameToken,Position) -> ggs_db:key(GameToken,?LOCALSTORAGE,Position) end), - expose_fun_localstorage( Global, "key", Fun, 2), - {noreply, State}; - -handle_cast(localstorage_length, #state { global = Global } = State) -> - Fun = (fun(GameToken) -> ggs_db:length(GameToken,?LOCALSTORAGE) end), - expose_fun_localstorage( Global, "length", Fun, 1), - {noreply, State}; - -handle_cast(localstorage_remove_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:removeItem(GameToken,?LOCALSTORAGE,Key) end), - expose_fun_localstorage( Global, "removeItem", Fun, 2), - {noreply, State}; - -handle_cast(localstorage_clear1, #state { global = Global } = State) -> - Fun = (fun(GameToken) -> ggs_db:clear(GameToken) end), - expose_fun_localstorage( Global, "clear", Fun, 1), - {noreply, State}; - -handle_cast(localstorage_clear2, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:removeItem(GameToken,?LOCALSTORAGE,Key) end), - expose_fun_localstorage( Global, "clear", Fun, 2), - {noreply, State}; - -handle_cast(world_set_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key,Value) -> ggs_db:setItem(GameToken,?WORLD,Key,Value) end), - expose_fun_world( Global, "setItem", Fun, 3), - {noreply, State}; - -handle_cast(world_get_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:getItem(GameToken,?WORLD,Key) end), - expose_fun_world( Global, "getItem", Fun, 2), - {noreply, State}; - -handle_cast(world_key, #state { global = Global } = State) -> - Fun = (fun(GameToken,Position) -> ggs_db:key(GameToken,?WORLD,Position) end), - expose_fun_world( Global, "key", Fun, 2), - {noreply, State}; - -handle_cast(world_length, #state { global = Global } = State) -> - Fun = (fun(GameToken) -> ggs_db:length(GameToken,?WORLD) end), - expose_fun_world( Global, "length", Fun, 1), - {noreply, State}; - -handle_cast(world_remove_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:removeItem(GameToken,?WORLD,Key) end), - expose_fun_world( Global, "removeItem", Fun, 2), - {noreply, State}; - -handle_cast(world_clear1, #state { global = Global } = State) -> - Fun = (fun(GameToken) -> ggs_db:clear(GameToken) end), - expose_fun_world( Global, "clear", Fun, 1), - {noreply, State}; - -handle_cast(world_clear2, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:removeItem(GameToken,?WORLD,Key,Key) end), - expose_fun_world( Global, "clear", Fun, 2), - {noreply, State}; - -handle_cast(player_set_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key,Value) -> ggs_db:setItem(GameToken,?PLAYER,Key,Value) end), - expose_fun_player( Global, "setItem", Fun, 3), - {noreply, State}; - -handle_cast(player_get_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:getItem(GameToken,?PLAYER,Key) end), - expose_fun_player( Global, "getItem", Fun, 2), - {noreply, State}; - -handle_cast(player_key, #state { global = Global } = State) -> - Fun = (fun(GameToken,Position) -> ggs_db:key(GameToken,?PLAYER,Position) end), - expose_fun_player( Global, "key", Fun, 2), - {noreply, State}; - -handle_cast(player_length, #state { global = Global } = State) -> - Fun = (fun(GameToken) -> ggs_db:length(GameToken,?PLAYER) end), - expose_fun_player( Global, "length", Fun, 1), - {noreply, State}; - -handle_cast(player_remove_item, #state { global = Global } = State) -> - Fun = (fun(GameToken,Key) -> ggs_db:removeItem(GameToken,?PLAYER,Key) end), - expose_fun_player( Global, "removeItem", Fun, 2), - {noreply, State}; - -handle_cast(send_command, #state { global = Global } = State) -> - Fun = (fun(GameToken,PlayerToken,Message) -> ggs_table:send_command(GameToken,PlayerToken,Message) end), - expose_fun_player( Global, "sendCommand", Fun, 3), - {noreply, State}; - handle_cast(Msg, S) -> error_logger:error_report([unknown_msg, Msg]), {noreply, S}. diff --git a/src/ggs_gamevm_p.erl b/src/ggs_gamevm_p.erl index bb63eb2..7fcad8e 100644 --- a/src/ggs_gamevm_p.erl +++ b/src/ggs_gamevm_p.erl @@ -226,7 +226,7 @@ intern_start(Table, Player) -> %erlang:display("P2 ready, waiting."), ggs_table:send_command(Table, Player, {"game", "wait"}) end; - Other -> + _Other -> ok %erlang:display(Other) end. diff --git a/src/ggs_player.erl b/src/ggs_player.erl index 2e07527..c4f822e 100644 --- a/src/ggs_player.erl +++ b/src/ggs_player.erl @@ -34,12 +34,12 @@ join_table(Num) -> T; {error, no_such_table} -> case ggs_coordinator:create_table({force, integer_to_list(Num)}) of - {ok, TBToken} -> ok + {ok, _TBToken} -> ok end, case ggs_coordinator:join_table(integer_to_list(Num)) of {ok, T} -> %io:format("Creating new table: ~p~n", [T]), T; - {error, E} -> %erlang:display(E), + {error, _E} -> %erlang:display(E), join_table(Num+1) end; {error, table_full} -> @@ -93,16 +93,18 @@ stop(Player) -> handle_call(_Request, _From, St) -> {stop, unimplemented, St}. handle_cast({tcp, _Socket, Data}, #state { protocol = Protocol } = _State) -> - ggs_protocol:parse(Protocol, Data); + ggs_protocol:parse(Protocol, Data), + {noreply, State} handle_cast({tcp_closed, _Socket}, _State) -> - erlang:display("Client disconnected, but THIS IS NOT SUPPORTED YET!~n"); + erlang:display("Client disconnected, but THIS IS NOT SUPPORTED YET!~n"), + {noreply, State}; handle_cast({notify, Message}, #state { socket = Socket } = State) -> gen_tcp:send(Socket, ggs_protocol:create_message(Message)), {noreply, State}; -handle_cast({srv_cmd, "hello", _Headers, Data}, #state { token = Token } = State) -> +handle_cast({srv_cmd, "hello", _Headers, _Data}, #state { token = Token } = State) -> ggs_player:notify(self(), self(), {"hello", Token}), {noreply, State}; @@ -114,7 +116,7 @@ handle_cast({game_cmd, Command, _Headers, Data}, #state { table = Table } = Stat ggs_table:notify(Table, self(), {game, Command, Data}), {noreply, State}; -handle_cast(Request, St) -> +handle_cast(_Request, St) -> {stop, unimplemented1, St}. handle_info({tcp, _Socket, Data}, #state { protocol = Protocol } = State) -> diff --git a/src/ggs_protocol.erl b/src/ggs_protocol.erl index 39e0a6f..c79995f 100644 --- a/src/ggs_protocol.erl +++ b/src/ggs_protocol.erl @@ -74,7 +74,7 @@ expect_headers({char, $\n}, {Pid,_}, {Strings, Remains}) -> case Int of 0 -> ggs_player:notify_game(Pid, prettify(to_dictionary([SecondLast|Rest], []), [])), {reply, ok, expect_headers, {[""], 0}}; - _ -> {reply, ok, expect_data_section, {[""|Strings], Int}} + _ -> {reply, ok, expect_data_section, {[""|Strings], Int -1}} end; _Other -> ok end; @@ -92,8 +92,8 @@ expect_data_section({char, Char}, From, {Strings, Remains}) -> 0 -> [LastMsg,_|Rest] = Strings, {Pid,_} = From, - ggs_player:notify_game(Pid, prettify(to_dictionary(Rest, []), LastMsg)), - {reply, ok, expect_headers, {[[Char]], 0}}; + ggs_player:notify_game(Pid, prettify(to_dictionary(Rest, []), LastMsg ++ [Char])), + {reply, ok, expect_headers, {[""], 0}}; _Other -> [LastMsg|Rest] = Strings, NewMsg = LastMsg ++ [Char], {reply, ok, expect_data_section, {[NewMsg|Rest], Remains-1}} diff --git a/src/ggs_protocol.erl.bk2 b/src/ggs_protocol.erl.bk2 deleted file mode 100644 index db72062..0000000 --- a/src/ggs_protocol.erl.bk2 +++ /dev/null @@ -1,163 +0,0 @@ -%%% @doc This module handles TCP incomming and outcommint. - --module(ggs_protocol). --export([start_link/1,stop/1]). --behaviour(gen_server). --export([init/1, handle_call/3, handle_cast/2, handle_info/2, - terminate/2, code_change/3]). -%% Old --export([parse/1, getToken/1, create_message/4, send_command/2]). - --vsn(1.0). - --record(state, { - player, - header_string, - header_list, - body, - content_length}). - -start_link(Player) -> - gen_server:start_link(?MODULE, [Player], []). - -stop(Protocol) -> - gen_server:cast(Protocol, stop). - -send_command(Protocol, {Command, Data}) -> - gen_server:cast(Protocol, {send, Command, Data}). - -init([Player]) -> - State = #state{ - player = Player, - header_list = [], - header_string = "", - body = "", - content_length = -1 - }, - {ok, State}. - -handle_cast({tcp, _Socket, Data}, State) -> - case State#state.content_length of - -1 -> % its a header - TmpHeader = State#state.header_string ++ Data, - case string:str(TmpHeader, "\n\n") of - 0 -> % still in header - {reply, ok, State # state {header_string = TmpHeader}}; - _ -> % we left the header - {Header, Body} = parse(TmpHeader), - {_, ContentLengthString} = lists:keyfind(content_len, 1, Header), % find Content-Length - {ContentLength, []} = string:to_integer(ContentLengthString), - {reply, ok, State#state{ - header_list = Header, - header_string = "", - body = Body, - content_length = ContentLength}} - end; - Length -> % its a body - LBody = string:len(State#state.body), - LData = string:len(Data), - NewLength = LBody + LData, - if - NewLength < Length -> % not enough data - Body = State#state.body ++ Data, - {reply, ok, State#state {body = Body}}; - NewLength > Length -> % too much data - EndOfMessagePos = LBody + LData - Length, - Body = State#state.body ++ string:substr(Data, 0, EndOfMessagePos), - NextHeader = string:substr(Data, EndOfMessagePos, LData), - Message = prettify(State#state.header_list, Body), - gen_player:notify_game(State#state.player, Message), - {reply, ok, State#state { - header_string = NextHeader, - header_list = [], - body = "", - content_length = -1}}; - NewLength == Length -> % end of message - Message = prettify(State#state.header_list, State#state.body ++ Data), - gen_player:notify_game(State#state.player, Message), - {reply, ok, State#state { - header_string = "", - header_list = [], - body = "", - content_length = -1}} - end - end; - -handle_cast(_Request, St) -> {stop, unimplemented, St}. -handle_call(_Request, _From, St) -> {stop, unimplemented, St}. - -handle_info(_Info, St) -> {stop, unimplemented, St}. - - -terminate(_Reason, _St) -> ok. -code_change(_OldVsn, St, _Extra) -> {ok, St}. - - - -%% API Functions -parse(Data) -> - do_parse(Data, []). - -getToken(Parsed) -> - case lists:keyfind(token, 1, Parsed) of - {_, Value} -> - Value; - false -> - false - end. - - - -create_message(Cmd, Enc, Acc, Data) -> - Length = integer_to_list(string:len(Data)), - Msg = "Client-Command: " ++ Cmd ++ "\n" ++ - "Client-Encoding: " ++ Enc ++ "\n" ++ - "Content-Size: " ++ Length ++ "\n" ++ - "GGS-Version: 1.0\n" ++ - "Accept: " ++ Acc ++ "\n" ++ - "\n" ++ - Data, - Msg. - -%% Internal helpers -do_parse(Data, Headers) -> - NewLinePos = string:chr(Data, $\n), - Line = string:substr(Data, 1, NewLinePos-1), - Tokens = re:split(Line, ": ", [{return, list}]), - case handle(Tokens) of - {Command, more} -> - do_parse(string:substr(Data, NewLinePos+1), Headers ++ [Command]); - {separator, data_next} -> - {Headers, Data} - end. - -handle([[]]) -> - {separator, data_next}; -handle(["Server-Command", Param]) -> - {{srv_cmd, Param}, more}; -handle(["Game-Command", Param]) -> - {{game_cmd, Param}, more}; -handle(["Content-Length", Param]) -> - {{content_len, Param}, more}; -handle(["Token", Param]) -> - {{token, Param}, more}; -handle(["Content-Type", Param]) -> - {{content_type, Param}, more}. - -%handle_data(Data, Length) -> -% {data, string:substr(Data,1,Length)}. - - -prettify(Args, Data) -> - case lists:keyfind(srv_cmd, 1, Args) of - {_, Value} -> - {srv_cmd, Value, Args, Data}; - _Other -> - case lists:keyfind(game_cmd, 1, Args) of - {_, Value} -> - {game_cmd, Value, Args, Data}; - _ -> - ok - end - end. - diff --git a/src/ggs_protocol.erl.orig b/src/ggs_protocol.erl.orig deleted file mode 100644 index 61d424b..0000000 --- a/src/ggs_protocol.erl.orig +++ /dev/null @@ -1,146 +0,0 @@ -%% Parse a string formatted with the GGS protocol using -%% an FSM. Each char is put into the FSM, which incrementally -%% builds a list of strings which represent the complete -%% message. - --module(ggs_protocol). --export([parse/1, getToken/1, create_message/4, - expect_headers/2, expect_data_section/2, - expect_headers/3, expect_data_section/3]). - -%% tests --export([test/0, to_dictionary/2]). - -% gen_fsm callbacks.. --export([init/1, handle_info/2, terminate/2, code_change/3, start_link/0]). - - --define(SERVER, ?MODULE). - -%% JONTES TESTS -test() -> - start_link(), - parse("Token: %s\nServer-Command: define\nContent-Type: text\nContent-Length: 9\n\nHELLOWORLDToken: %s\nServer-Command: define\nContent-Type: text\nContent-Length: 9\n\nHELLOWORLDToken: %s\nServer-Command: define\n"), - to_dictionary(["Hello: world", "Hi: there!"], []). -%% END TESTS - - -%% API Functions -parse(Data) -> - lists:foreach(fun(X) -> - gen_fsm:sync_send_event(?SERVER, {char, X}) - end, Data). - - -start_link() -> - gen_fsm:start_link({local, ?SERVER}, ?MODULE, [], []). - -% Start state: {[""],0}, meaning: -% - Start with no strings parsed -% - Start with a data-section-lengths of 0 -init([]) -> - {ok,expect_headers,{[""], 0}}. - - - -getToken(Parsed) -> - - case lists:keyfind(token, 1, Parsed) of - {_, Value} -> - Value; - false -> - false - end. -<<<<<<< Updated upstream -======= - - -create_message(Protocol, {Command, Data}) { - create_message(Command, "text", "text", Data), -} ->>>>>>> Stashed changes - -%% Assemble a message which can b -%e used as a reply to a client -create_message(Cmd, Enc, Acc, Data) -> - Length = integer_to_list(string:len(Data)), - Msg = "Client-Command: " ++ Cmd ++ "\n" ++ - "Client-Encoding: " ++ Enc ++ "\n" ++ - "Content-Size: " ++ Length ++ "\n" ++ - "GGS-Version: 1.0\n" ++ - "Accept: " ++ Acc ++ "\n" ++ - "\n" ++ - Data, - Msg. - -%%% Transitions -expect_headers(_Event, State) -> - {next_state, expect_headers, State}. -expect_data_section(_Event, State) -> - {next_state, expect_data_section, State}. - - -%%% End transitions -expect_headers({char, $\n}, _From, {Strings, Remains}) -> - [LastMessage|_] = Strings, - case LastMessage of - "" -> % We have a data section.. Last line should thus be the content length. - [LastMessage, SecondLast | _] = Strings, - case re:split(SecondLast, ": ", [{return, list}]) of - ["Content-Length", X] -> - {Int,_} = string:to_integer(X), - {reply, ok, expect_data_section, {[""|Strings], Int}}; - Other -> ok - end; - Other -> - {reply,ok,expect_headers, {[""|Strings], Remains}} - end; - -expect_headers({char, Char}, _From, {[Current|Rest], Remains}) -> - NewCurrent = Current ++ [Char], - {reply,ok, expect_headers, {[NewCurrent|Rest], Remains}}. - - -expect_data_section({char, Char}, From, {Strings, Remains}) -> - case Remains of - 0 -> - [LastMsg,_|Rest] = Strings, - NewMsg = LastMsg ++ [Char], - Result = [NewMsg|Rest], - {Pid,_} = From, - erlang:display(From), - Pid ! (prettify(to_dictionary(Rest, []), NewMsg)), - {reply, ok, expect_headers, {[""], 0}}; - Other -> [LastMsg|Rest] = Strings, - NewMsg = LastMsg ++ [Char], - {reply, ok, expect_data_section, {[NewMsg|Rest], Remains-1}} - end. -handle_call(_Msg, _From, State) -> - {noreply, State}. -handle_info(_Msg, State) -> - {noreply, State}. -terminate(_Reason, _State) -> - ok. -code_change(_OldVsn, State, _Extra) -> - {ok, State}. - - -prettify(Args, Data) -> - case lists:keyfind("Server-Command", 1, Args) of - {_, Value} -> - {srv_cmd, Value, Args, Data}; - _Other -> - case lists:keyfind("Game-Command", 1, Args) of - {_, Value} -> - {game_cmd, Value, Args, Data}; - _ -> - ok - end - end. - -to_dictionary([], Dict) -> - Dict; -to_dictionary([S|Strings], Dict) -> - [First, Snd] = re:split(S, ": ", [{return, list}]), - to_dictionary(Strings, [{First, Snd}|Dict]). - diff --git a/src/ggs_table.erl b/src/ggs_table.erl index 60acb2a..b67afcb 100644 --- a/src/ggs_table.erl +++ b/src/ggs_table.erl @@ -74,7 +74,7 @@ send_command(TableToken, PlayerToken, Message) -> %% @private init([TableToken]) -> process_flag(trap_exit, true), - GameVM = ggs_gamevm_p:start_link(TableToken), + GameVM = ggs_gamevm:start_link(TableToken), {ok, #state { game_vm = GameVM, players = [] }}. @@ -101,9 +101,9 @@ handle_cast({notify, Player, Message}, #state { game_vm = GameVM } = State) -> PlayerToken = ggs_coordinator:player_pid_to_token(Player), case Message of {server, define, Args} -> - ggs_gamevm_p:define(GameVM, Args); + ggs_gamevm:define(GameVM, Args); {game, Command, Args} -> - ggs_gamevm_p:player_command(GameVM, PlayerToken, Command, Args) + ggs_gamevm:player_command(GameVM, PlayerToken, Command, Args) end, {noreply, State}; @@ -111,7 +111,7 @@ handle_cast({add_player, Player}, #state { players = Players } = State) -> {noreply, State#state { players = [Player | Players] }}; handle_cast({notify_game, Message, From}, #state { game_vm = GameVM } = State) -> - ggs_gamevm_p:player_command(GameVM, From, Message, ""), + ggs_gamevm:player_command(GameVM, From, Message, ""), {noreply, State}; handle_cast({notify_all_players, Message}, #state{players = Players} = State) ->