diff --git a/src/ggs_server.erl b/src/ggs_server.erl new file mode 100644 index 0000000..aae268e --- /dev/null +++ b/src/ggs_server.erl @@ -0,0 +1,156 @@ +%%%---------------------------------------------------- +%%% @author Jonatan Pålsson +%%% @copyright 2010 Jonatan Pålsson +%%% @doc RPC over TCP server +%%% @end +%%%---------------------------------------------------- + +-module(ggs_server). +-behaviour(gen_server). + +%% API +-export([start_link/1, + 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). +-define(DEFAULT_PORT, 1055). + +-record(state, {port, lsock, client_vm_map = []}). + +%%%==================================================== +%%% API +%%%==================================================== + +%%----------------------------------------------------- +%% @doc Starts the server +%% @end +%%----------------------------------------------------- +start_link(Port) -> + gen_server:start_link({local, ?SERVER}, ?MODULE, [Port], []). + +start_link() -> + start_link(?DEFAULT_PORT). + +%%----------------------------------------------------- +%% @doc Stops the server. +%% @spec stop() -> ok +%% @end +%%----------------------------------------------------- +stop() -> + gen_server:cast(?SERVER, stop). + +%%----------------------------------------------------- +%% gen_server callbacks +%%----------------------------------------------------- + +init([Port]) -> + case gen_server:call(ggs_backup, get_backup) of + {backup_state, not_initialized} -> + {ok, LSock} = gen_tcp:listen(Port, [{active, true}, + {reuseaddr, true}]), + {ok, #state{port = Port, lsock = LSock}, 0}; + {backup_state, State} -> + {ok, LSock} = gen_tcp:listen(Port, [{active, true}, + {reuseaddr, true}]), + {ok, State#state{lsock = LSock}, 0} + end. + +handle_call({backup_state, OldState}, _From, State) -> + io:format("Received old state from backup~n"), + {noreply, OldState}. + + +handle_info({tcp, Socket, RawData}, State) -> + ggs_protocol:parse(RawData), + {noreply, State#state{lsock = Socket}}; + +handle_info({tcp_closed, Socket}, State) -> + gen_tcp:close(Socket), + {stop, "Client closed socket", State}; + +handle_info(timeout, #state{lsock = LSock} = State) -> + {ok, _Sock} = gen_tcp:accept(LSock), + {noreply, State}; + +handle_info(Other, State) -> + erlang:display(Other). + +terminate(_Reason, _State) -> + ok. + +code_change(_OldVsn, State, _Extra) -> + {ok, State}. + +%%----------------------------------------------------- +%% Internal functions +%%----------------------------------------------------- +handle_cast(stop, State) -> + {stop, normal, State}; + +% Handle javascript defines +handle_cast({define, Token, Payload}, State) -> + JSVM = getJSVM(Token, State), + %js_runner:define(JSVM, Payload), + JSVM!{define,self(),Payload}, + send(State#state.lsock, Token, "Okay, defined that for you!"), + {noreply, State}; + +% Handle javascript calls +handle_cast({call, Token, Payload}, State) -> + io:format("test1~n"), + io:format("Got call request: ~p~n", [Payload]), + io:format("test2~n"), + JSVM = getJSVM(Token, State), + JSVM!{get_port, self()}, + receive + {ok, Port} -> erlang:display(erlang:port_info(Port)), + io:format("test1~n") + end, + %erlang:display(erlang:port_info(Port)), + %{ok, Ret} = js_runner:call(JSVM, Payload, []), + JSVM!{call, self(), Payload, []}, + receive + {ok, Ret} -> + send(State#state.lsock, Token, "JS says:", binary_to_list(Ret)), + {noreply, State} + end; +% Set the new state to the reference generated, and JSVM associated +handle_cast({hello, _, _}, State) -> + JSVM = js_runner:boot(), + Client = getRef(), + send(State#state.lsock, Client, "This is your refID"), + OldMap = State#state.client_vm_map, + JSVM!{get_port, self()}, + receive + {ok, Port} -> NewState = State#state{client_vm_map = OldMap ++ [{Client, Port}]}, + gen_server:cast(ggs_backup, {set_backup, NewState}), + {noreply, NewState} + end. +%%----------------------------------------------------- +%% Helpers +%%----------------------------------------------------- +getRef() -> + %{A1,A2,A3} = now(), + %#random:seed(A1, A2, A3), + %random:uniform(1000). + string:strip(os:cmd("uuidgen"), right, $\n ). + +getJSVM(RefID, State) -> + VMs = State#state.client_vm_map, + erlang:display(RefID), + erlang:display(VMs), + {value, {_,VM}} = lists:keysearch(RefID, 1, VMs), + VM. + +send(Socket, RefID, String) -> + gen_tcp:send(Socket, string:join([RefID,String,"\n"], " ")). + +send(Socket, RefID, String1, String2) -> + gen_tcp:send(Socket, string:join([RefID,String1, String2,"\n"], " ")). diff --git a/src/js_runner.erl b/src/js_runner.erl new file mode 100644 index 0000000..65511e9 --- /dev/null +++ b/src/js_runner.erl @@ -0,0 +1,33 @@ +-module(js_runner). +-export([boot/0]). + +%Mattias +boot() -> + erlang_js:start(), + {ok, Port} = js_driver:new(), + PortPid = spawn(fun() -> port_process(Port) end ), + PortPid. + + +port_process(Port) -> +receive + {get_port, From} -> + From!{ok,Port}, + port_process(Port); + {define, From, Data} -> + ok = js:define(From, list_to_binary(Data)), + From!{ok}, + port_process(Port); + {call, From, Func, Params} -> + {ok,Ret} = js:call(From, list_to_binary(Func), Params), %Port unsure + From!{ok,Ret}, + port_process(Port) +end. + +%These two babies will be ambigiuous +%define(Port, Data) -> +% port_pid!{define,self(),Port,Data}. + + +%call(Port, Func, Params) -> +% port_pid!{call, self(), Port, Func, Params}.