-module(gproxy1). -export([start/1,gateway/1,stop/1,rpc/2,change_be/2, change_code/2]). -define(TIMEOUT, 3000). %% TODO: %% - balance: gloop([S1, S2, S3]) %% - backend failover %% start the server (backend) start(Fun) -> spawn(fun() -> loop(Fun) end). %% start the proxy (frontend) gateway(Backend) -> spawn(fun() -> gloop(Backend) end). %% stop gateway or backend stop(Pid) -> Pid ! stop. %% Pid can be gateway or server rpc(Pid, Query) -> Pid ! {self(), Query}, receive {Pid, crash} -> exit(rpc); {Pid, Reply} -> Reply end. log_msg(Type, Pid, Query, Why) -> case Type of err -> io:format("[E] Server: ~p, Query: ~p, Reason: ~p~n", [Pid, Query, Why]); done -> io:format("[*] Done. Server: ~p, Query: ~p, Reply: ~p~n", [Pid, Query, Why]); timeout -> io:format("[T] Server: ~p, Timeout after: ~p~n", [Pid, Query]) end. %% change the backend %% send to the GATEWAY change_be(Gw, Backend) -> Gw ! {Backend, be_change}. %% function code change %% send to the SERVER change_code(Server, Fun1) -> Server ! {swap_code,Fun1}. %% server loop loop(Fun) -> receive stop -> void; {swap_code,Fun1} -> loop(Fun1); %% direct request {Client, Data} -> case catch Fun(Data) of {'EXIT', Why} -> log_msg(err, Client, Data, Why), Client ! {self(), crash}, loop(Fun); Reply -> Client ! {self(), Reply}, loop(Fun) end; %% request via gateway {Gw, Client, Data} -> case catch Fun(Data) of {'EXIT', Why} -> log_msg(err, Client, Data, Why), Gw ! {self(), Client, crash}, loop(Fun); Reply -> Gw ! {self(), Client, ok, Reply}, loop(Fun) end end. %% gateway loop gloop(Backend) -> receive stop -> void; {Backend1, be_change} -> gloop(Backend1); {Client, Data} -> Backend ! {self(), Client, Data}, gloop(Backend); {Server, Client, crash} -> Client ! {self(), crash}, gloop(Backend); {Server, Client, ok, Data} -> Client ! {self(), Data}, gloop(Backend) end.