-
-
Save fishcakez/5805105 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| -module(pecypc_session). | |
| -author('Vladimir Dronnikov <[email protected]>'). | |
| %% ----------------------------------------------------------------------------- | |
| %% API exports | |
| %% ----------------------------------------------------------------------------- | |
| -export([ | |
| add/1, | |
| add/2, | |
| kill/0, | |
| kill/1, | |
| remove/1, | |
| start_link/1, | |
| where/1 | |
| ]). | |
| -export([ | |
| call/1, | |
| call/2, | |
| read/0, | |
| read/1, | |
| touch/0, | |
| touch/1, | |
| write/2 | |
| ]). | |
| -export([ | |
| init/2, | |
| handle/2 | |
| ]). | |
| %% ----------------------------------------------------------------------------- | |
| %% gen_server exports | |
| %% ----------------------------------------------------------------------------- | |
| -behaviour(gen_server). | |
| -export([ | |
| init/1, terminate/2, code_change/3, | |
| handle_call/3, handle_cast/2, handle_info/2 | |
| ]). | |
| %% ----------------------------------------------------------------------------- | |
| %% API functions | |
| %% ----------------------------------------------------------------------------- | |
| start_link({Id, _Data} = Arg) -> | |
| gen_server:start_link({via, gproc, {n, l, {?MODULE, Id}}}, ?MODULE, Arg, []). | |
| % call(Id, Msg) -> | |
| % case gproc:where({n, l, {?MODULE, Id}}) of | |
| % undefined -> {error, badarg}; | |
| % Pid -> gen_server:call(Pid, Msg) | |
| % end. | |
| % send(Prop, Msg) -> | |
| % gproc:send({p, l, {?MODULE, Prop}}, Msg). | |
| add(Data) -> | |
| add(base64url:encode(crypto:rand_bytes(16)), Data). | |
| add(Id, Data) -> | |
| case supervisor:start_child(pecypc_session_sup, [{Id, Data}]) of | |
| {ok, _Pid} -> | |
| {ok, Id}; | |
| {error, {already_started, _Pid}} -> | |
| {ok, Id} | |
| end. | |
| remove(Id) -> | |
| gen_server:cast(where(Id), stop). | |
| where(Id) -> | |
| gproc:where({n, l, {?MODULE, Id}}). | |
| %% @todo: get all ids? | |
| all() -> | |
| gproc:lookup_pids({p, l, ?MODULE}). | |
| call(Cmd) -> | |
| [gen_server:call(P, {command, Cmd}) || P <- all()]. | |
| call(Id, Cmd) -> | |
| gen_server:call(where(Id), {command, Cmd}). | |
| read() -> | |
| [gen_server:call(P, get) || P <- all()]. | |
| read(Id) -> | |
| gen_server:call(where(Id), get). | |
| write(Id, Data) -> | |
| gen_server:cast(where(Id), {set, Data}). | |
| touch() -> | |
| [gen_server:cast(P, touch) || P <- all()], | |
| ok. | |
| touch(Id) -> | |
| gen_server:cast(where(Id), touch). | |
| kill() -> | |
| kill(normal). | |
| kill(Reason) -> | |
| [exit(P, Reason) || P <- all()], | |
| ok. | |
| %% ----------------------------------------------------------------------------- | |
| %% gen_server behaviour | |
| %% ----------------------------------------------------------------------------- | |
| -record(state, { | |
| expires, | |
| handler, | |
| state | |
| }). | |
| init({Id, Opts}) -> | |
| pecypc_log:info({init_pecypc_session, Id, Opts}), | |
| {_, Handler} = {handler, pecypc_session}, % @todo: configurable | |
| true = gproc:reg({p, l, ?MODULE}), | |
| % true = gproc:mreg(p, l, [{{?MODULE, Key}, Value} || {Key, Value} <- Props]), | |
| {MegaSecs, Secs, _} = os:timestamp(), | |
| State = #state{ | |
| expires = MegaSecs * 1000000 + Secs, | |
| handler = Handler, | |
| state = Handler:init(Id, Opts) | |
| }, | |
| {ok, prolong(State)}. | |
| terminate(Reason, State) -> | |
| pecypc_log:info({terminate_pecypc_session, Reason, State}), | |
| ok. | |
| code_change(_OldVsn, State, _Extra) -> | |
| {ok, State}. | |
| handle_call(get, _From, State = #state{state = S}) -> | |
| {reply, S, prolong(State)}; | |
| handle_call({command, Cmd}, _From, State = #state{handler = H, state = S}) -> | |
| % pecypc_log:info({call_pecypc_session_command, Cmd, State}), | |
| {Reply, S2} = H:handle(Cmd, S), | |
| {reply, Reply, prolong(State#state{state = S2})}; | |
| handle_call(_Request, _From, State) -> | |
| % pecypc_log:info({call_pecypc_session, Request, From, State}), | |
| {reply, {error, badarg}, State}. | |
| handle_cast({set, S}, State) -> | |
| {noreply, prolong(State#state{state = S})}; | |
| handle_cast(touch, State) -> | |
| {noreply, prolong(State)}; | |
| handle_cast(stop, State = #state{handler = H, state = S}) -> | |
| H:handle(stop, S), | |
| {stop, normal, State}; | |
| handle_cast(Msg, State = #state{handler = H, state = S}) -> | |
| % pecypc_log:info({cast_pecypc_session, Msg, State}), | |
| {ok, S2} = H:handle(Msg, S), | |
| {noreply, prolong(State#state{state = S2})}. | |
| handle_info({'EXIT', _, Reason}, State) -> | |
| terminate(Reason, State), | |
| {noreply, State}; | |
| handle_info(info, State) -> | |
| pecypc_log:info({info_pecypc_session, info, State}), | |
| {noreply, State}. | |
| %% ----------------------------------------------------------------------------- | |
| %% Private functions | |
| %% ----------------------------------------------------------------------------- | |
| prolong(State = #state{expires = Expires}) -> | |
| Expires2 = Expires + 120, | |
| State#state{expires = Expires2}. | |
| %% ----------------------------------------------------------------------------- | |
| %% Handler functions | |
| %% ----------------------------------------------------------------------------- | |
| init(_Id, Opts) -> | |
| Opts. | |
| handle(stop, State) -> | |
| {ok, State}; | |
| handle({command, Cmd}, State) -> | |
| pecypc_log:info({pecypc_session_handle, Cmd, State}), | |
| {ok, State}. |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment