Current section
Files
Jump to
Current section
Files
src/osc_client_mgr.erl
-module(osc_client_mgr).
-behaviour(gen_server).
%% gen_server callback exports
-export([init/1,
handle_call/3,
handle_cast/2,
handle_info/2,
code_change/3,
terminate/2
]).
%% API exports
-export([start/3,
start_link/3
]).
%% Constants, etc.
-define(SERVER, ?MODULE).
-define(GEN_SERV_OPTS, []).
-define(UDP_TIMEOUT, 2000).
-record(state, {
host,
port,
socket,
opts
}).
%% API
start(Host, Port, UdpOpts) ->
start_link(Host, Port, UdpOpts).
start_link(Host, Port, UdpOpts) ->
process_flag(trap_exit, true),
gen_server:start_link({global, ?SERVER}, ?MODULE, [Host, Port, UdpOpts], ?GEN_SERV_OPTS).
%% Callbacks
init([]) ->
{ok, #state{}};
init([Host, Port, UdpOpts]) ->
{ok, Socket} = gen_udp:open(0, UdpOpts),
{ok, #state{host=Host, port=Port, socket=Socket, opts=UdpOpts}}.
handle_call(ping, _From, State) ->
{reply, pong, State};
handle_call(socket, _From, State) ->
{reply, State#state.socket, State};
handle_call(reconnect, _From, State) ->
gen_udp:close(State#state.socket),
{ok, Socket} = gen_udp:open(0, State#state.opts),
{reply, ok, State#state{socket=Socket}};
handle_call({Type, Address}, _From, State) ->
Data = encode(Type, Address),
Result = call_udp(State, Data, ?UDP_TIMEOUT),
{reply, Result, State};
handle_call({Type, Address, Args}, _From, State) ->
Data = encode(Type, Address, Args),
Result = call_udp(State, Data, ?UDP_TIMEOUT),
{reply, Result, State};
handle_call(_Msg, _From, State) ->
{reply, unknown_cmd, State}.
handle_cast({Type, Address}, State) ->
Data = encode(Type, Address),
cast_udp(State, Data),
{noreply, State};
handle_cast({Type, Address, Args}, State) ->
Data = encode(Type, Address, Args),
cast_udp(State, Data),
{noreply, State};
handle_cast(_Msg, State) ->
{noreply, State}.
handle_info({'EXIT', _From, normal}, State) ->
error_logger:error_msg("The OSC client manager is exiting (normal)."),
{noreply, State};
handle_info({'EXIT', _From, shutdown}, State) ->
error_logger:error_msg("The OSC client manager is exiting (shutdown)."),
{noreply, State};
handle_info({'EXIT', From, Reason}, State) ->
io:format("OSC client manager process: ~p exited with reason: ~p~n",
[From, Reason]),
{noreply, State};
handle_info(_Info, State) ->
{noreply, State}.
code_change(_OldVsn, State, _Extra) ->
{ok, State}.
terminate(_Reason, State) ->
gen_udp:close(State#state.socket),
ok.
%% Private / support functions
encode(Type, Address) ->
encode(Type, Address, []).
encode(Type, Address, Args) ->
osc_lib:encode({Type, Address, Args}).
%% Pass the state and the data for comms with a reply
call_udp(#state{host=Host, port=Port, socket=Socket}, Data, Timeout) ->
ok = gen_udp:send(Socket, Host, Port, Data),
receive
{udp, Socket, _, _, Bin} ->
osc_lib:decode(Bin)
after Timeout ->
{error, timeout}
end.
%% Pass the state and the data for comms with no reply
cast_udp(#state{host=Host, port=Port, socket=Socket}, Data) ->
ok = gen_udp:send(Socket, Host, Port, Data).