diff --git a/ecallmgr/src/ecallmgr_fs_nodes.erl b/ecallmgr/src/ecallmgr_fs_nodes.erl index 9565364e2ba..3ecdf6bdaf3 100644 --- a/ecallmgr/src/ecallmgr_fs_nodes.erl +++ b/ecallmgr/src/ecallmgr_fs_nodes.erl @@ -734,7 +734,8 @@ close_node(#node{node=Node}) -> close_node(Node); close_node(Node) -> catch erlang:monitor_node(Node, false), % will crash if Node is down already - _ = ecallmgr_fs_pinger_sup:remove_node(Node), + _P = ecallmgr_fs_pinger_sup:remove_node(Node), + lager:debug("stopped pinger: ~p", [_P]), ecallmgr_fs_sup:remove_node(Node). start_preconfigured_servers() -> diff --git a/ecallmgr/src/ecallmgr_fs_pinger_sup.erl b/ecallmgr/src/ecallmgr_fs_pinger_sup.erl index c47b859cfa6..523f8e1e408 100644 --- a/ecallmgr/src/ecallmgr_fs_pinger_sup.erl +++ b/ecallmgr/src/ecallmgr_fs_pinger_sup.erl @@ -46,7 +46,8 @@ add_node(Node, Options) -> -spec remove_node/1 :: (atom()) -> 'ok' | {'error', 'running' | 'not_found' | 'simple_one_for_one'}. remove_node(Node) -> - _ = supervisor:terminate_child(?SERVER, Node), + _T = supervisor:terminate_child(?SERVER, Node), + lager:debug("terminated pinger: ~p", [_T]), supervisor:delete_child(?SERVER, Node). %% =================================================================== diff --git a/ecallmgr/src/ecallmgr_fs_sup.erl b/ecallmgr/src/ecallmgr_fs_sup.erl index 0d4435a3c9d..5c5dfc0b704 100644 --- a/ecallmgr/src/ecallmgr_fs_sup.erl +++ b/ecallmgr/src/ecallmgr_fs_sup.erl @@ -38,9 +38,9 @@ start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). --spec add_node/2 :: (atom(), proplist()) -> {'error', term()} | - {'ok','undefined' | pid()} | - {'ok','undefined' | pid(), term()}. +-spec add_node/2 :: (atom(), wh_proplist()) -> {'error', term()} | + {'ok','undefined' | pid()} | + {'ok','undefined' | pid(), term()}. add_node(Node, Options) -> supervisor:start_child(?SERVER, ?NODE(Node, [Node, Options])). diff --git a/ecallmgr/src/ecallmgr_originate.erl b/ecallmgr/src/ecallmgr_originate.erl index 03470cf0a4f..e0426d08fb6 100644 --- a/ecallmgr/src/ecallmgr_originate.erl +++ b/ecallmgr/src/ecallmgr_originate.erl @@ -195,16 +195,21 @@ handle_cast({maybe_update_node, Node}, #state{node=_OldNode}=State) -> {noreply, State#state{node=Node}, hibernate}; handle_cast({create_uuid}, #state{node=Node, originate_req=JObj}=State) -> - lager:debug("creating a new uuid", []), + lager:debug("creating a new uuid"), {noreply, State#state{uuid=create_uuid(JObj, Node)}, hibernate}; -handle_cast({get_originate_action}, #state{originate_req=JObj}=State) -> +handle_cast({get_originate_action}, #state{originate_req=JObj, node=Node}=State) -> gen_listener:cast(self(), {build_originate_args}), ApplicationName = wh_json:get_value(<<"Application-Name">>, JObj), Action = get_originate_action(ApplicationName, JObj), + UseNode = maybe_update_node(JObj, Node), + lager:debug("maybe updating node from ~s to ~s", [Node, UseNode]), - {noreply, State#state{action=Action, app=ApplicationName}}; + {noreply, State#state{action=Action + ,app=ApplicationName + ,node=UseNode + }}; handle_cast({build_originate_args}, #state{uuid=undefined ,action = ?ORIGINATE_PARK @@ -272,8 +277,13 @@ handle_cast({originate_execute}, #state{tref=TRef}=State) when is_reference(TRef gen_listener:cast(self(), {originate_execute}), _ = erlang:cancel_timer(TRef), {noreply, State#state{tref=undefined}}; -handle_cast({originate_execute}, #state{dialstrings=Dialstrings, node=Node, originate_req=JObj - ,uuid=UUID, server_id=ServerId, control_pid=CtrlPid}=State) -> +handle_cast({originate_execute}, #state{dialstrings=Dialstrings + ,node=Node + ,originate_req=JObj + ,uuid=UUID + ,server_id=ServerId + ,control_pid=CtrlPid + }=State) -> case originate_execute(Node, Dialstrings) of {ok, _} when is_pid(CtrlPid) -> lager:debug("originate completed"), @@ -424,6 +434,17 @@ get_originate_action(_, _) -> lager:debug("got originate with action park"), ?ORIGINATE_PARK. +-spec maybe_update_node/2 :: (wh_json:object(), atom()) -> atom(). +maybe_update_node(JObj, Node) -> + case wh_json:get_value(<<"Existing-Call-ID">>, JObj) of + undefined -> Node; + CallId -> + case ecallmgr_fs_nodes:channel_node(CallId) of + {error, _} -> Node; + {ok, N} -> N + end + end. + get_eavesdrop_action(JObj) -> {CallId, Group} = case wh_json:get_value(<<"Eavesdrop-Group-ID">>, JObj) of undefined -> {wh_json:get_value(<<"Eavesdrop-Call-ID">>, JObj), <<>>}; @@ -450,9 +471,11 @@ build_originate_args(Action, Endpoints, JObj) -> ], JObj), list_to_binary([ecallmgr_fs_xml:get_channel_vars(J), DialStrings, " ", Action]). --spec originate_execute/2 :: (atom(), ne_binary()) -> {'ok', ne_binary()} | - {'error', ne_binary()}. +-spec originate_execute/2 :: (atom(), ne_binary()) -> + {'ok', ne_binary()} | + {'error', ne_binary()}. originate_execute(Node, Dialstrings) -> + lager:debug("executing on ~s: ~s", [Node, Dialstrings]), {ok, BGApiID} = freeswitch:bgapi(Node, 'originate', wh_util:to_list(Dialstrings)), receive diff --git a/lib/whistle-1.0.0/src/api/wapi_resource.erl b/lib/whistle-1.0.0/src/api/wapi_resource.erl index 1c566e5df8e..d13074233a1 100644 --- a/lib/whistle-1.0.0/src/api/wapi_resource.erl +++ b/lib/whistle-1.0.0/src/api/wapi_resource.erl @@ -63,6 +63,7 @@ -define(ORIGINATE_REQ_HEADERS, [<<"Endpoints">>, <<"Application-Name">>]). -define(OPTIONAL_ORIGINATE_REQ_HEADERS, [<<"Application-Data">>, <<"Custom-Channel-Vars">> ,<<"Export-Custom-Channel-Vars">>, <<"Outbound-Call-ID">> + ,<<"Existing-Call-ID">> % If set, use this node, otherwise ignore %% Eavesdrop ,<<"Eavesdrop-Call-ID">>, <<"Eavesdrop-Mode">>, <<"Eavesdrop-Group-ID">> | fun() -> diff --git a/whistle_apps/apps/acdc/src/acdc_agent.erl b/whistle_apps/apps/acdc/src/acdc_agent.erl index aeadb2e350d..341d91ef7d0 100644 --- a/whistle_apps/apps/acdc/src/acdc_agent.erl +++ b/whistle_apps/apps/acdc/src/acdc_agent.erl @@ -363,6 +363,7 @@ handle_cast({channel_hungup, CallId}, #state{call=Call ,record_calls=ShouldRecord ,is_thief=IsThief ,agent_call_id=ACallId + ,agent_id=AgentId }=State) -> CCallId = call_id(Call), case CallId of @@ -372,6 +373,7 @@ handle_cast({channel_hungup, CallId}, #state{call=Call maybe_stop_recording(Call, ShouldRecord), + put(callid, AgentId), case IsThief of false -> {noreply, State#state{call=undefined @@ -384,11 +386,11 @@ handle_cast({channel_hungup, CallId}, #state{call=Call {stop, normal, State} end; ACallId -> - lager:debug("agent channel hungup"), + lager:debug("agent channel ~s hungup", [ACallId]), acdc_util:unbind_from_call_events(ACallId), {noreply, State#state{agent_call_id=undefined}}; _CallId -> - lager:debug("~s call id for channel_hungup, ignoring", [_CallId]), + lager:debug("unknown call id ~s for channel_hungup, ignoring", [_CallId]), {noreply, State} end; @@ -447,6 +449,7 @@ handle_cast({bridge_to_member, Call, WinJObj, EPs}, #state{fsm_pid=FSM ,acct_id=AcctId ,agent_id=AgentId }=State) -> + put(callid, whapps_call:call_id(Call)), lager:debug("bridging to agent endpoints: ~p", [EPs]), RingTimeout = wh_json:get_value(<<"Ring-Timeout">>, WinJObj), @@ -482,7 +485,7 @@ handle_cast({originate_execute, JObj}, #state{my_q=Q}=State) -> ACallId = wh_json:get_value(<<"Call-ID">>, JObj), acdc_util:bind_to_call_events(ACallId), - lager:debug("execute the originate for agent callid ~s", [ACallId]), + lager:debug("execute the originate for agent call-id ~s", [ACallId]), send_originate_execute(JObj, Q), {noreply, State#state{agent_call_id=ACallId}}; @@ -736,6 +739,7 @@ maybe_connect_to_agent(FSM, EPs, Call, Timeout) -> ,{<<"Caller-ID-Number">>, whapps_call:caller_id_number(Call)} ,{<<"Outgoing-Caller-ID-Name">>, whapps_call:caller_id_name(Call)} ,{<<"Outgoing-Caller-ID-Number">>, whapps_call:caller_id_number(Call)} + ,{<<"Existing-Call-ID">>, whapps_call:call_id(Call)} | wh_api:default_headers(?APP_NAME, ?APP_VERSION) ]), diff --git a/whistle_apps/apps/acdc/src/acdc_agent_fsm.erl b/whistle_apps/apps/acdc/src/acdc_agent_fsm.erl index 9116d5d203b..21230714450 100644 --- a/whistle_apps/apps/acdc/src/acdc_agent_fsm.erl +++ b/whistle_apps/apps/acdc/src/acdc_agent_fsm.erl @@ -83,6 +83,7 @@ ,caller_exit_key = <<"#">> :: ne_binary() ,agent_call_id :: ne_binary() ,next_status :: ne_binary() + ,fsm_call_id :: ne_binary() % used when no call-ids are available ,endpoints = [] :: wh_json:objects() }). @@ -248,7 +249,8 @@ start_link(AcctId, AgentId, AgentProc, Props) -> %% @end %%-------------------------------------------------------------------- init([AcctId, AgentId, AgentProc, Props]) -> - put(callid, <<"fsm_", AcctId/binary, "_", AgentId/binary>>), + FSMCallId = <<"fsm_", AcctId/binary, "_", AgentId/binary>>, + put(callid, FSMCallId), lager:debug("started acdc agent fsm"), acdc_stats:agent_active(AcctId, AgentId), @@ -267,6 +269,7 @@ init([AcctId, AgentId, AgentProc, Props]) -> ,agent_proc=AgentProc ,agent_proc_id=acdc_util:proc_id(AgentProc) ,sync_ref=SyncRef + ,fsm_call_id=FSMCallId }}. %%-------------------------------------------------------------------- @@ -371,16 +374,20 @@ ready({sync_req, JObj}, #state{agent_proc=Srv}=State) -> ready({member_connect_win, JObj}, #state{agent_proc=Srv ,endpoints=EPs ,agent_proc_id=MyId + ,agent_id=AgentId }=State) -> Call = whapps_call:from_json(wh_json:get_value(<<"Call">>, JObj)), CallId = whapps_call:call_id(Call), + + put(callid, CallId), + WrapupTimer = wh_json:get_integer_value(<<"Wrapup-Timeout">>, JObj, 0), CallerExitKey = wh_json:get_value(<<"Caller-Exit-Key">>, JObj, <<"#">>), QueueId = wh_json:get_value(<<"Queue-ID">>, JObj), case wh_json:get_value(<<"Agent-Process-ID">>, JObj) of MyId -> - lager:debug("we won us a member: ~s", [CallId]), + lager:debug("trying to ring agent ~s to connect to caller", [AgentId]), acdc_agent:bridge_to_member(Srv, Call, JObj, EPs), @@ -392,7 +399,8 @@ ready({member_connect_win, JObj}, #state{agent_proc=Srv ,caller_exit_key=CallerExitKey }}; _OtherId -> - lager:debug("one of our counterparts won us a member: ~s", [CallId]), + lager:debug("monitoring agent ~s connecting to caller", [AgentId]), + acdc_agent:monitor_call(Srv, Call), {next_state, ringing, State#state{ @@ -425,6 +433,9 @@ ready({resume}, State) -> ready({dtmf_pressed, _}, State) -> {next_state, ready, State}; +ready({originate_failed, _E}, State) -> + {next_state, ready, State}; + ready(_Evt, State) -> lager:debug("unhandled event: ~p", [_Evt]), {next_state, ready, State}. @@ -443,14 +454,14 @@ ringing({member_connect_req, _}, State) -> {next_state, ringing, State}; ringing({member_connect_win, JObj}, #state{agent_proc=Srv}=State) -> - lager:debug("we won, but can't process this right now"), + lager:debug("agent won, but can't process this right now (already ringing)"), acdc_agent:member_connect_retry(Srv, JObj), {next_state, ringing, State}; ringing({originate_ready, JObj}, #state{agent_proc=Srv}=State) -> CallId = wh_json:get_value(<<"Call-ID">>, JObj), - lager:debug("ready to originate to the agent: ~s", [CallId]), + lager:debug("ringing agent's phone with call-id ~s", [CallId]), acdc_agent:originate_execute(Srv, JObj), {next_state, ringing, State#state{agent_call_id=CallId}}; @@ -460,7 +471,7 @@ ringing({originate_failed, _E}, #state{agent_proc=Srv ,member_call_queue_id=QueueId ,member_call_id=CallId }=State) -> - lager:debug("failed to execute originate to the agent: ~p", [_E]), + lager:debug("ringing agent failed: ~p", [_E]), acdc_agent:member_connect_retry(Srv, CallId), acdc_stats:call_missed(AcctId, QueueId, AgentId, CallId), @@ -471,7 +482,7 @@ ringing({originate_failed, _E}, #state{agent_proc=Srv ringing({channel_bridged, CallId}, #state{member_call_id=CallId ,agent_proc=Srv }=State) -> - lager:debug("agent has connected to member"), + lager:debug("agent phone has been connected to caller"), acdc_agent:member_connect_accepted(Srv), {next_state, answered, State#state{call_status_ref=start_call_status_timer() ,call_status_failures=0 @@ -484,7 +495,7 @@ ringing({channel_hungup, CallId}, #state{agent_proc=Srv ,member_call_queue_id=QueueId ,member_call_id=MCallId }=State) -> - lager:debug("agent channel was destroyed before we could connect: ~s", [CallId]), + lager:debug("agent did not answer their phone in time: ~s", [CallId]), acdc_agent:channel_hungup(Srv, CallId), acdc_agent:member_connect_retry(Srv, MCallId), @@ -501,7 +512,7 @@ ringing({channel_hungup, CallId}, #state{agent_proc=Srv ,agent_call_id=AgentCallId }=State ) -> - lager:debug("member channel (~s) has gone down, stop agent call", [CallId]), + lager:debug("caller's channel (~s) has gone down, stop agent's call", [CallId]), acdc_agent:channel_hungup(Srv, AgentCallId), acdc_stats:call_abandoned(AcctId, QueueId, CallId, ?ABANDON_HANGUP), @@ -526,14 +537,14 @@ ringing({dtmf_pressed, DTMF}, #state{caller_exit_key=DTMF ringing({channel_answered, ACallId}, #state{agent_call_id=ACallId ,agent_proc=Srv }=State) -> - lager:debug("agent channel ready: ~s", [ACallId]), + lager:debug("agent answered phone on ~s, connecting to caller", [ACallId]), acdc_agent:join_agent(Srv, ACallId), {next_state, answered, State#state{call_status_ref=start_call_status_timer() ,call_status_failures=0 }}; ringing({channel_answered, MCallId}, #state{member_call_id=MCallId}=State) -> - lager:debug("member channel answered"), + lager:debug("caller's channel answered"), {next_state, ringing, State}; ringing({sync_req, JObj}, #state{agent_proc=Srv}=State) -> @@ -560,7 +571,7 @@ ringing(current_call, _, #state{member_call=Call answered({member_connect_req, _}, State) -> {next_state, answered, State}; answered({member_connect_win, JObj}, #state{agent_proc=Srv}=State) -> - lager:debug("we won, but can't process this right now"), + lager:debug("agent won, but can't process this right now (on the phone with someone)"), acdc_agent:member_connect_retry(Srv, JObj), {next_state, answered, State}; @@ -570,7 +581,7 @@ answered({dialplan_error, _App}, #state{agent_proc=Srv ,member_call_queue_id=QueueId ,member_call_id=CallId }=State) -> - lager:debug("join failed, clearing call"), + lager:debug("connecting agent to caller failed, clearing call"), acdc_agent:member_connect_retry(Srv, CallId), acdc_stats:call_missed(AcctId, QueueId, AgentId, CallId), @@ -582,7 +593,7 @@ answered({channel_bridged, CallId}, #state{member_call_id=CallId ,acct_id=_AcctId ,member_call=_Call }=State) -> - lager:debug("member has connected to agent"), + lager:debug("agent has connected to caller"), acdc_agent:member_connect_accepted(Srv), {next_state, answered, State}; @@ -590,20 +601,20 @@ answered({channel_bridged, CallId}, #state{member_call_id=CallId answered({channel_bridged, CallId}, #state{agent_call_id=CallId ,agent_proc=Srv }=State) -> - lager:debug("agent has connected to member"), + lager:debug("agent has connected to caller"), acdc_agent:member_connect_accepted(Srv), {next_state, answered, State}; answered({channel_hungup, CallId}, #state{member_call_id=CallId}=State) -> - lager:debug("member call has hung up"), + lager:debug("caller's channel hung up"), {next_state, wrapup, State#state{wrapup_timeout=0, wrapup_ref=hangup_call(State)}}; answered({channel_hungup, CallId}, #state{agent_call_id=CallId}=State) -> - lager:debug("agent call has hung up"), + lager:debug("agent's channel has hung up"), {next_state, wrapup, State#state{wrapup_timeout=0, wrapup_ref=hangup_call(State)}}; answered({channel_hungup, CallId}, #state{agent_proc=Srv}=State) -> - lager:debug("someone(~s) hungup, who cares", [CallId]), + lager:debug("someone(~s) hungup, ignoring", [CallId]), acdc_agent:channel_hungup(Srv, CallId), {next_state, answered, State}; @@ -615,7 +626,7 @@ answered({sync_req, JObj}, #state{agent_proc=Srv {next_state, answered, State}; answered({channel_unbridged, CallId}, #state{member_call_id=CallId}=State) -> - lager:debug("member channel unbridged"), + lager:debug("caller channel unbridged"), {next_state, wrapup, State#state{wrapup_timeout=0, wrapup_ref=hangup_call(State)}}; answered({channel_unbridged, CallId}, #state{agent_call_id=CallId}=State) -> lager:debug("agent channel unbridged"), @@ -661,7 +672,7 @@ answered(current_call, _, #state{member_call=Call wrapup({member_connect_req, _}, State) -> {next_state, wrapup, State#state{wrapup_timeout=0}}; wrapup({member_connect_win, JObj}, #state{agent_proc=Srv}=State) -> - lager:debug("we won, but can't process this right now"), + lager:debug("agent won, but can't process this right now (in wrapup)"), acdc_agent:member_connect_retry(Srv, JObj), {next_state, wrapup, State#state{wrapup_timeout=0}}; @@ -754,7 +765,7 @@ paused({sync_req, JObj}, #state{agent_proc=Srv paused({member_connect_req, _}, State) -> {next_state, paused, State}; paused({member_connect_win, JObj}, #state{agent_proc=Srv}=State) -> - lager:debug("we won, but can't process this right now"), + lager:debug("agent won, but can't process this right now"), acdc_agent:member_connect_retry(Srv, JObj), {next_state, paused, State}; paused(_Evt, State) -> @@ -929,7 +940,8 @@ time_left(Ref) when is_reference(Ref) -> time_left(false) -> undefined; time_left(Ms) when is_integer(Ms) -> Ms div 1000. -clear_call(State) -> +clear_call(#state{fsm_call_id=FSMCallId}=State) -> + put(callid, FSMCallId), State#state{wrapup_timeout = 0 ,wrapup_ref = undefined ,member_call = undefined diff --git a/whistle_apps/apps/callflow/src/module/cf_menu.erl b/whistle_apps/apps/callflow/src/module/cf_menu.erl index 30cbfc862a2..286bf09e5a3 100644 --- a/whistle_apps/apps/callflow/src/module/cf_menu.erl +++ b/whistle_apps/apps/callflow/src/module/cf_menu.erl @@ -355,15 +355,8 @@ get_new_attachment_url(AttachmentName, MediaId, Call) -> {error, _} -> ok end, - Rev = case couch_mgr:lookup_doc_rev(AccountDb, MediaId) of - {ok, R} -> <<"?rev=", R/binary>>; - _ -> <<>> - end, - <<(couch_mgr:get_url())/binary - ,AccountDb/binary - ,$/, MediaId/binary - ,$/, AttachmentName/binary - ,Rev/binary>>. + {ok, URL} = wh_media_url:store(AccountDb, MediaId, AttachmentName), + URL. %%-------------------------------------------------------------------- %% @private diff --git a/whistle_apps/apps/callflow/src/module/cf_record_call.erl b/whistle_apps/apps/callflow/src/module/cf_record_call.erl index bcc557aa5df..1a084999ed5 100644 --- a/whistle_apps/apps/callflow/src/module/cf_record_call.erl +++ b/whistle_apps/apps/callflow/src/module/cf_record_call.erl @@ -138,10 +138,5 @@ store_url(Call, JObj) -> AccountDb = whapps_call:account_db(Call), MediaId = wh_json:get_value(<<"_id">>, JObj), MediaName = wh_json:get_value(<<"name">>, JObj), - - Rev = wh_json:get_value(<<"_rev">>, JObj), - list_to_binary([couch_mgr:get_url(), AccountDb - ,"/", MediaId - ,"/", MediaName - ,"?rev=", Rev - ]). + {ok, URL} = wh_media_url:store(AccountDb, MediaId, MediaName), + URL. diff --git a/whistle_apps/apps/callflow/src/module/cf_voicemail.erl b/whistle_apps/apps/callflow/src/module/cf_voicemail.erl index 9c6829eac05..75d5a60c8e4 100644 --- a/whistle_apps/apps/callflow/src/module/cf_voicemail.erl +++ b/whistle_apps/apps/callflow/src/module/cf_voicemail.erl @@ -1105,12 +1105,8 @@ get_new_attachment_url(AttachmentName, MediaId, Call) -> end; {error, _} -> ok end, - Rev = case couch_mgr:lookup_doc_rev(AccountDb, MediaId) of - {ok, R} -> <<"?rev=", R/binary>>; - _ -> <<>> - end, - - list_to_binary([couch_mgr:get_url(), AccountDb, <<"/">>, MediaId, <<"/">>, AttachmentName, Rev]). + {ok, URL} = wh_media_url:store(AccountDb, MediaId, AttachmentName), + URL. %%-------------------------------------------------------------------- %% @private diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_cache_sup.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_cache_sup.erl index afb5611737c..aa304c01bb8 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_cache_sup.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_cache_sup.erl @@ -11,17 +11,20 @@ -behaviour(supervisor). %% API --export([start_link/0 - ,find_file_server/3, find_file_server/4 - ,find_tts_server/1, find_tts_server/2 - ]). +-export([start_link/0]). +-export([find_file_server/3]). +-export([start_file_server/3]). +-export([find_tts_server/1]). +-export([find_tts_server/2]). %% Supervisor callbacks -export([init/1]). +-include("whistle_media.hrl"). + -define(SERVER, ?MODULE). --define(CHILD(Name, Id, Doc, Attachment, Meta), {Name, {wh_media_file_cache, start_link, [Id, Doc, Attachment, Meta]}, temporary, 5000, worker, [wh_media_file_cache]}). +-define(CHILD(Name, Id, Doc, Attachment), {Name, {wh_media_file_cache, start_link, [Id, Doc, Attachment]}, temporary, 5000, worker, [wh_media_file_cache]}). -define(CHILD(Name, Text, JObj), {Name, {wh_media_tts_cache, start_link, [Text, JObj]}, temporary, 5000, worker, [wh_media_tts_cache]}). %%%=================================================================== @@ -38,23 +41,27 @@ start_link() -> supervisor:start_link({local, ?SERVER}, ?MODULE, []). +-spec find_file_server/3 :: (ne_binary(), ne_binary(), ne_binary()) -> {'ok', pid()} | + {'error', 'no_file_server'}. find_file_server(Id, Doc, Attachment) -> - Name = [Id,Doc,Attachment], + Name = [Id, Doc, Attachment], case [P||{N,P,_,_} <- supervisor:which_children(?MODULE), N =:= Name, is_pid(P)] of [] -> {error, no_file_server}; [P] -> {ok, P} end. -find_file_server(Id, Doc, Attachment, Meta) -> - Name = [Id,Doc,Attachment], - find_file_server(Id, Doc, Attachment, Meta, Name). -find_file_server(Id, Doc, Attachment, Meta, Name) -> - case supervisor:start_child(?MODULE, ?CHILD(Name, Id, Doc, Attachment, Meta)) of +-spec start_file_server/3 :: (ne_binary(), ne_binary(), ne_binary()) -> {'ok', pid()} | + {'error', _}. +start_file_server(Id, Doc, Attachment) -> + Name = [Id, Doc, Attachment], + start_file_server(Id, Doc, Attachment, Name). +start_file_server(Id, Doc, Attachment, Name) -> + case supervisor:start_child(?MODULE, ?CHILD(Name, Id, Doc, Attachment)) of {ok, _Pid}=OK -> OK; {error, {already_started, Pid}} -> {ok, Pid}; {error, already_present} -> _ = supervisor:delete_child(?MODULE, Name), - find_file_server(Id, Doc, Attachment, Meta, Name); + start_file_server(Id, Doc, Attachment, Name); {error, _}=E -> E end. diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_continuous_proxy.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_continuous_proxy.erl index a6d81cb59f3..7b928c88ea8 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_continuous_proxy.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_continuous_proxy.erl @@ -18,19 +18,20 @@ init({_Transport, _Proto}, Req0, _Opts) -> put(callid, wh_util:rand_hex_binary(16)), - case cowboy_http_req:path_info(Req0) of {[<<"tts">>, Id], Req1} -> init_from_tts(Id, Req1); - {[Id, Doc, Attachment], Req1} -> - init_from_doc(Id, Doc, Attachment, Req1) + {[?MEDIA_DB = Db, Id, Attachment], Req1} -> + init_from_doc(Db, Id, Attachment, Req1); + {[Db, Id, Attachment], Req1} -> + AccountDb = wh_util:format_account_id(Db, encoded), + init_from_doc(AccountDb, Id, Attachment, Req1) end. init_from_tts(Id, Req) -> lager:debug("fetching tts/~s", [Id]), case wh_media_cache_sup:find_tts_server(Id) of {ok, Pid} -> - %%TODO: James should this not be continuous? -Karl {ok, Req, wh_media_file_cache:single(Pid)}; {error, _} -> lager:debug("missing tts server"), @@ -38,10 +39,9 @@ init_from_tts(Id, Req) -> {shutdown, Req1, ok} end. -init_from_doc(Id, Doc, Attachment, Req) -> - lager:debug("fetching ~s/~s/~s", [Id, Doc, Attachment]), - - case wh_media_cache_sup:find_file_server(Id, Doc, Attachment) of +init_from_doc(Db, Id, Attachment, Req) -> + lager:debug("fetching ~s/~s/~s", [Db, Id, Attachment]), + case wh_media_cache_sup:find_file_server(Db, Id, Attachment) of {ok, Pid} -> {ok, Req, wh_media_file_cache:single(Pid)}; {error, _} -> diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file.erl index 5559b4d3b62..d83faa2b250 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file.erl @@ -13,10 +13,10 @@ -include("whistle_media.hrl"). --spec get_uri/2 :: ([ne_binary(),...] | ne_binary(), wh_json:object()) -> {'error', 'not_found'} | +-spec get_uri/2 :: ([ne_binary(),...] | ne_binary(), wh_json:object()) -> {'ok', ne_binary()} | + {'error', 'not_found'} | {'error', 'no_data'} | - {'error', 'no_stream_strategy'}| - {'ok', ne_binary()}. + {'error', 'no_stream_strategy'}. get_uri(Media, JObj) when is_binary(Media) -> Paths = [Path || Path <- binary:split(Media, <<"/">>, [global, trim]) @@ -26,66 +26,78 @@ get_uri(Media, JObj) when is_binary(Media) -> get_uri(Paths, JObj) -> case find_attachment(Paths) of {error, _}=E -> E; - {Db, Id, Attachment, _} -> - DbName = wh_util:format_account_id(Db, raw), - maybe_local_haproxy_uri(JObj, DbName, Id, Attachment) + {ok, {Db, Id, Attachment}} -> + maybe_local_haproxy_uri(JObj, Db, Id, Attachment) end. - + +-spec maybe_prepare_proxy/1 :: (ne_binary()) -> 'ok' | 'error'. maybe_prepare_proxy(URI) -> case wh_util:to_binary(props:get_value(path, uri_parser:parse(wh_util:to_list(URI), []), <<>>)) of - <<"/single/", Rest/binary>> -> prepary_proxy(binary:split(Rest, <<"/">>, [global, trim])); - <<"/continuous/", Rest/binary>> -> prepary_proxy(binary:split(Rest, <<"/">>, [global, trim])); + <<"/single/", Rest/binary>> -> prepare_proxy(binary:split(Rest, <<"/">>, [global, trim])); + <<"/continuous/", Rest/binary>> -> prepare_proxy(binary:split(Rest, <<"/">>, [global, trim])); _Else -> ok end. -prepary_proxy([Db, Id, Attachment]=Tokens) -> - case wh_media_cache_sup:find_file_server(Db, Id, Attachment) =:= {error, no_file_server} - andalso find_attachment(Tokens) - of - {_, _, _, _}=Media -> - start_media_file_cache(Media); - false -> - lager:debug("existing file server for ~s/~s/~s", [Db, Id, Attachment]); - _R -> - lager:debug("unable to prepare file server for ~s/~s/~s: ~p", [Db, Id, Attachment, _R]), - error - end. - -start_media_file_cache({Db, Id, Attachment, MetaData}) -> - DbName = wh_util:format_account_id(Db, raw), - {ok, _FileServer} = wh_media_cache_sup:find_file_server(DbName, Id, Attachment, MetaData), +-spec prepare_proxy/1 :: ([ne_binary(),...]) -> 'ok' | 'error'. +prepare_proxy([Db, Id, Attachment]) -> + case wh_media_cache_sup:find_file_server(Db, Id, Attachment) =:= {error, no_file_server} of + true -> start_media_file_cache(Db, Id, Attachment); + false -> lager:debug("existing file server for ~s/~s/~s", [Db, Id, Attachment]) + end. + +-spec start_media_file_cache/3 :: (ne_binary(), ne_binary(), ne_binary()) -> 'ok'. +start_media_file_cache(Db, Id, Attachment) -> + {ok, _FileServer} = wh_media_cache_sup:start_file_server(Db, Id, Attachment), lager:debug("file server at ~p for ~s/~s/~s", [_FileServer, Db, Id, Attachment]). +-spec find_attachment/1 :: ([ne_binary(),...] | ne_binary()) -> {'ok', {ne_binary(), ne_binary(), ne_binary()}} | + {'error', 'not_found'}. find_attachment([Id]) -> find_attachment([?MEDIA_DB, Id]); -find_attachment([DbName, Id]) -> - find_attachment([DbName, Id, first]); -find_attachment([DbName, Id, Attachment]) -> - Db = case DbName =/= ?MEDIA_DB of - false-> DbName; - true -> wh_util:format_account_id(DbName, encoded) - end, - case couch_mgr:open_doc(Db, Id) of - {ok, JObj} -> maybe_find_attachment(JObj, Db, Id, Attachment); - _ -> {error, not_found} - end; +find_attachment([Db, Id]) -> + find_attachment([Db, Id, first]); +find_attachment([Db, Id, first]) -> + maybe_find_attachment(Db, Id); +find_attachment([Db = ?MEDIA_DB, Id, Attachment]) -> + {ok, {Db, Id, Attachment}}; +find_attachment([Db, Id, Attachment]) -> + AccountDb = wh_util:format_account_id(Db, encoded), + {ok, {AccountDb, Id, Attachment}}; find_attachment(Id) when not is_list(Id) -> find_attachment([Id]). -maybe_find_attachment(JObj, Db, Id, first) -> +-spec maybe_find_attachment/2 :: (ne_binary(), ne_binary()) -> {'ok', {ne_binary(), ne_binary(), ne_binary()}} | + {'error', 'not_found'}. +-spec maybe_find_attachment/3 :: (wh_json:object(), ne_binary(), ne_binary()) -> {'ok', {ne_binary(), ne_binary(), ne_binary()}} | + {'error', 'not_found'} | + {'error', 'no_data'}. + +maybe_find_attachment(?MEDIA_DB = Db, Id) -> + {ok, {Db, Id, <>}}; +maybe_find_attachment(Db, Id) -> + AccountDb = wh_util:format_account_id(Db, encoded), + case couch_mgr:open_doc(AccountDb, Id) of + {error, _R} -> + lager:debug("unable to open media doc ~s in ~s: ~p", [Id, Db, _R]), + {error, not_found}; + {ok, JObj} -> + maybe_find_attachment(JObj, AccountDb, Id) + end. + +maybe_find_attachment(JObj, Db, Id) -> lager:debug("trying to find first attachment on doc ~s in db ~s", [Id, Db]), case wh_json:get_value(<<"_attachments">>, JObj, []) of - [] -> {error, no_data}; + [] -> + lager:debug("media doc ~s in ~s has no attachments", [Id, Db]), + {error, no_data}; Attachments -> - {Attachment, MetaData} = hd(wh_json:to_proplist(Attachments)), - {Db, Id, Attachment, MetaData} - end; -maybe_find_attachment(JObj, Db, Id, Attachment) -> - case wh_json:get_value([<<"_attachments">>, Attachment], JObj, false) of - undefined -> {error, no_data}; - MetaData -> {Db, Id, Attachment, MetaData} + {Attachment, _} = hd(wh_json:to_proplist(Attachments)), + lager:debug("found first attachment ~s on ~s in ~s", [Attachment, Id, Db]), + {ok, {Db, Id, Attachment}} end. +-spec maybe_local_haproxy_uri/4 :: (wh_json:object(), ne_binary(), ne_binary(), ne_binary()) -> {'ok', ne_binary()} | + {'error', 'no_stream_strategy'}. maybe_local_haproxy_uri(JObj, Db, Id, Attachment) -> case whapps_config:get_is_true(?CONFIG_CAT, <<"use_bigcouch_direct">>, false) of false -> maybe_media_manager_proxy_uri(JObj, Db, Id, Attachment); @@ -102,10 +114,12 @@ maybe_local_haproxy_uri(JObj, Db, Id, Attachment) -> true -> direct_store; false -> direct_playback end, - {ok, <<(wh_media_util:base_url(Host, Port, Permissions))/binary, Db/binary - ,"/", Id/binary, "/", Attachment/binary>>} + {ok, <<(wh_media_util:base_url(Host, Port, Permissions))/binary + ,Db/binary, "/", Id/binary, "/", Attachment/binary>>} end. +-spec maybe_media_manager_proxy_uri/4 :: (wh_json:object(), ne_binary(), ne_binary(), ne_binary()) -> {'ok', ne_binary()} | + {'error', 'no_stream_strategy'}. maybe_media_manager_proxy_uri(JObj, Db, Id, Attachment) -> case whapps_config:get_is_true(?CONFIG_CAT, <<"use_media_proxy">>, true) of false -> @@ -119,6 +133,6 @@ maybe_media_manager_proxy_uri(JObj, Db, Id, Attachment) -> true -> proxy_store; false -> proxy_playback end, - {ok, <<(wh_media_util:base_url(Host, Port, Permissions))/binary, StreamType/binary, "/" - ,Db/binary, "/", Id/binary, "/", Attachment/binary>>} + {ok, <<(wh_media_util:base_url(Host, Port, Permissions))/binary, StreamType/binary + ,"/", Db/binary, "/", Id/binary, "/", Attachment/binary>>} end. diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file_cache.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file_cache.erl index 02cfd4fbd89..bc5b048a150 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file_cache.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_file_cache.erl @@ -11,7 +11,7 @@ -behaviour(gen_server). %% API --export([start_link/4 +-export([start_link/3 ,single/1 ,continuous/1 ]). @@ -53,14 +53,15 @@ %% @spec start_link() -> {ok, Pid} | ignore | {error, Error} %% @end %%-------------------------------------------------------------------- --spec start_link/4 :: (ne_binary(), ne_binary(), ne_binary(), wh_json:json_object()) -> - startlink_ret(). -start_link(Id, Doc, Attach, Meta) -> - gen_server:start_link(?MODULE, [Id, Doc, Attach, Meta, get(callid)], []). +-spec start_link/3 :: (ne_binary(), ne_binary(), ne_binary()) -> startlink_ret(). +start_link(Db, Id, Attachment) -> + gen_server:start_link(?MODULE, [Db, Id, Attachment, get(callid)], []). +-spec single/1 :: (pid()) -> {wh_json:object(), binary()}. single(Srv) -> gen_server:call(Srv, single). +-spec continuous/1 :: (pid()) -> {wh_json:object(), binary()}. continuous(Srv) -> gen_server:call(Srv, continuous). @@ -79,33 +80,33 @@ continuous(Srv) -> %% {stop, Reason} %% @end %%-------------------------------------------------------------------- -init([<<"system_media">>|Rest]) -> - init(<<"system_media">>, Rest); -init([Id|Rest]) -> - init(wh_util:format_account_id(Id, encoded), Rest). - -init(Db, [Doc, Attach, Meta, CallId]) -> +init([Db, Id, Attachment, CallId]) -> case wh_util:is_empty(CallId) of true -> put(callid, ?LOG_SYSTEM_ID); false -> put(callid, CallId) end, - - lager:debug("streaming ~s/~s/~s", [Db, Doc, Attach]), - {ok, Ref} = couch_mgr:stream_attachment(Db, Doc, Attach), - - {ok - ,#state{ - db=Db - ,doc=Doc - ,attach=Attach - ,meta=Meta - ,stream_ref=Ref - ,status=streaming - ,contents = <<>> - ,reqs = [] %% buffer requests until file has completed streaming - ,timer_ref=start_timer() - } - }. + maybe_start_file_cache(Db, Id, Attachment). + +maybe_start_file_cache(Db, Id, Attachment) -> + case couch_mgr:open_doc(Db, Id) of + {error, Reason} -> + lager:debug("unable get metadata for ~s on ~s in ~s: ~p", [Attachment, Id, Db, Reason]), + {stop, Reason}; + {ok, JObj} -> + lager:debug("starting cache for ~s on ~s in ~s", [Attachment, Id, Db]), + Meta = wh_json:get_value([<<"_attachments">>, Attachment], JObj, wh_json:new()), + {ok, Ref} = couch_mgr:stream_attachment(Db, Id, Attachment), + {ok, #state{db=Db + ,doc=Id + ,attach=Attachment + ,meta=Meta + ,stream_ref=Ref + ,status=streaming + ,contents = <<>> + ,reqs = [] %% buffer requests until file has completed streaming + ,timer_ref=start_timer() + }} + end. %%-------------------------------------------------------------------- %% @private diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_proxy.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_proxy.erl index ec41621b6c9..ae1624dcf2c 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_proxy.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_proxy.erl @@ -12,6 +12,7 @@ -include("whistle_media.hrl"). +-spec start_link/0 :: () -> 'ignore'. start_link() -> put(callid, ?LOG_SYSTEM_ID), Dispatch = [ diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_single_proxy.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_single_proxy.erl index 370166fbd77..1a63564b08b 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_single_proxy.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_single_proxy.erl @@ -21,8 +21,11 @@ init({_Transport, _Proto}, Req0, _Opts) -> case cowboy_http_req:path_info(Req0) of {[<<"tts">>, Id], Req1} -> init_from_tts(Id, Req1); - {[Id, Doc, Attachment], Req1} -> - init_from_doc(Id, Doc, Attachment, Req1) + {[?MEDIA_DB = Db, Id, Attachment], Req1} -> + init_from_doc(Db, Id, Attachment, Req1); + {[Db, Id, Attachment], Req1} -> + AccountDb = wh_util:format_account_id(Db, encoded), + init_from_doc(AccountDb, Id, Attachment, Req1) end. init_from_tts(Id, Req) -> @@ -36,9 +39,9 @@ init_from_tts(Id, Req) -> {shutdown, Req1, ok} end. -init_from_doc(Id, Doc, Attachment, Req) -> - lager:debug("fetching ~s/~s/~s", [Id, Doc, Attachment]), - case wh_media_cache_sup:find_file_server(Id, Doc, Attachment) of +init_from_doc(Db, Id, Attachment, Req) -> + lager:debug("fetching ~s/~s/~s", [Db, Id, Attachment]), + case wh_media_cache_sup:find_file_server(Db, Id, Attachment) of {ok, Pid} -> {ok, Req, wh_media_file_cache:single(Pid)}; {error, _} -> @@ -131,8 +134,7 @@ the_header({K, H}) -> set_resp_headers(Req, ContentType) -> lists:foldl(fun({K,V}, {ok, Req0Acc}) -> cowboy_http_req:set_resp_header(K, V, Req0Acc) - end, {ok, Req}, [ - {<<"Server">>, list_to_binary([?APP_NAME, "/", ?APP_VERSION])} + end, {ok, Req}, [{<<"Server">>, list_to_binary([?APP_NAME, "/", ?APP_VERSION])} ,{<<"Content-Type">>, ContentType} ] ). @@ -141,8 +143,7 @@ set_resp_headers(Req, ContentType) -> set_resp_headers(Req, ChunkSize, ContentType, MediaName, Url) -> lists:foldl(fun({K,V}, {ok, Req0Acc}) -> cowboy_http_req:set_resp_header(K, V, Req0Acc) - end, {ok, Req}, [ - {<<"Server">>, list_to_binary([?APP_NAME, "/", ?APP_VERSION])} + end, {ok, Req}, [{<<"Server">>, list_to_binary([?APP_NAME, "/", ?APP_VERSION])} ,{<<"Content-Type">>, ContentType} ,{<<"icy-notice1">>, <<"MediaMgr">>} ,{<<"icy-name">>, MediaName} diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_store_proxy.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_store_proxy.erl index f781c6eb590..805312a52fa 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_store_proxy.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_store_proxy.erl @@ -15,6 +15,8 @@ -include("whistle_media.hrl"). +-spec init/3 :: ({_, _}, #http_req{}, proplist()) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. init({_Transport, _Proto}, Req0, _Opts) -> put(callid, wh_util:rand_hex_binary(16)), case cowboy_http_req:path_info(Req0) of @@ -25,6 +27,8 @@ init({_Transport, _Proto}, Req0, _Opts) -> {shutdown, Req2, ok} end. +-spec is_authentic/2 :: ([ne_binary(),...], #http_req{}) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. is_authentic(PathTokens, Req0) -> case whapps_config:get_is_true(?CONFIG_CAT, <<"proxy_store_authenticate">>, true) of false -> @@ -34,6 +38,8 @@ is_authentic(PathTokens, Req0) -> maybe_basic_authentication(PathTokens, Req0) end. +-spec maybe_basic_authentication/2 :: ([ne_binary(),...], #http_req{}) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. maybe_basic_authentication(PathTokens, Req0) -> case credentials(Req0) of {undefined, undefined, Req1} -> @@ -43,9 +49,11 @@ maybe_basic_authentication(PathTokens, Req0) -> maybe_basic_authentication(Username, Password, PathTokens, Req1) end. +-spec maybe_basic_authentication/4 :: (ne_binary(), ne_binary(), [ne_binary(),...], #http_req{}) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. maybe_basic_authentication(Username, Password, PathTokens, Req1) -> - AuthUsername = whapps_config:get_binary(?CONFIG_CAT, <<"proxy_store_username">>, <<>>), - AuthPassword = whapps_config:get_binary(?CONFIG_CAT, <<"proxy_store_password">>, <<>>), + AuthUsername = whapps_config:get_binary(?CONFIG_CAT, <<"proxy_username">>, <<>>), + AuthPassword = whapps_config:get_binary(?CONFIG_CAT, <<"proxy_password">>, <<>>), case (not wh_util:is_empty(AuthUsername)) andalso (not wh_util:is_empty(AuthPassword)) andalso Username =:= AuthUsername andalso Password =:= AuthPassword of @@ -55,12 +63,16 @@ maybe_basic_authentication(Username, Password, PathTokens, Req1) -> {shutdown, unauthorized(Req1), ok} end. +-spec maybe_acl_authentication/2 :: ([ne_binary(),...], #http_req{}) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. maybe_acl_authentication(PathTokens, Req0) -> ACLs = whapps_config:get(?CONFIG_CAT, <<"proxy_store_acls">>, [<<"127.0.0.0/24">>]), {IpTuple, Req1} = cowboy_http_req:peer_addr(Req0), Ip = wh_network_utils:iptuple_to_binary(IpTuple), maybe_acl_authentication(ACLs, Ip, PathTokens, Req1). +-spec maybe_acl_authentication/4 :: ([ne_binary(),...] | [], ne_binary(), [ne_binary(),...], #http_req{}) -> {'ok', #http_req{}, [ne_binary(),...]} | + {'shutdown', #http_req{}, 'ok'}. maybe_acl_authentication([], Ip, _, Req0) -> lager:debug("ip address ~s can not be authenticated via ACLs", [Ip]), {shutdown, unauthorized(Req0), ok}; @@ -73,6 +85,7 @@ maybe_acl_authentication([ACL|ACLs], Ip, PathTokens, Req0) -> maybe_acl_authentication(ACLs, Ip, PathTokens, Req0) end. +-spec credentials/1 :: (#http_req{}) -> {api_binary(), api_binary(), #http_req{}}. credentials(Req0) -> case cowboy_http_req:header('Authorization', Req0) of {undefined, Req1} -> @@ -82,6 +95,7 @@ credentials(Req0) -> {Username, Password, Req1} end. +-spec credentials_from_header/1 :: (ne_binary()) -> {api_binary(), api_binary()}. credentials_from_header(AuthorizationHeader) -> case binary:split(AuthorizationHeader, <<$ >>) of [<<"Basic">>, EncodedCredentials] -> @@ -90,6 +104,7 @@ credentials_from_header(AuthorizationHeader) -> {undefined, undefined} end. +-spec decoded_credentials/1 :: (ne_binary()) -> {api_binary(), api_binary()}. decoded_credentials(EncodedCredentials) -> DecodedCredentials = base64:decode(EncodedCredentials), case binary:split(DecodedCredentials, <<$:>>) of @@ -99,12 +114,14 @@ decoded_credentials(EncodedCredentials) -> {undefined, undefined} end. +-spec unauthorized/1 :: (#http_req{}) -> #http_req{}. unauthorized(Req0) -> {ok, Req1} = cowboy_http_req:set_resp_header(<<"Www-Authenticate">>, <<"Basic realm=\"Kazoo Media Storage Proxy\"">>, Req0), {ok, Req2} = cowboy_http_req:set_resp_body(unauthorized_body(), Req1), {ok, Req3} = cowboy_http_req:reply(401, Req2), Req3. +-spec unauthorized_body/0 :: () -> ne_binary(). unauthorized_body() -> <<" ">>. +-spec handle/2 :: (#http_req{}, [ne_binary(),...]) -> {'ok', #http_req{}, 'ok'}. handle(Req0, [Db, Id, Attachment]) -> is_appropriate_content_type(Db, Id, Attachment, Req0). +-spec is_appropriate_content_type/4 :: (ne_binary(), ne_binary(), ne_binary(), #http_req{}) -> {'ok', #http_req{}, 'ok'}. is_appropriate_content_type(Db, Id, Attachment, Req0) -> case cowboy_http_req:header('Content-Type', Req0) of {<<"audio/", _/binary>> = CT, Req1}-> @@ -130,7 +149,8 @@ is_appropriate_content_type(Db, Id, Attachment, Req0) -> lager:debug("inappropriate content-type via headers: ~s", [_CT]), is_appropriate_extension(Db, Id, Attachment, Req1) end. - + +-spec is_appropriate_extension/4 :: (ne_binary(), ne_binary(), ne_binary(), #http_req{}) -> {'ok', #http_req{}, 'ok'}. is_appropriate_extension(Db, Id, Attachment, Req0) -> Extension = filename:extension(Attachment), case wh_mime_types:from_extension(Extension) of @@ -143,6 +163,7 @@ is_appropriate_extension(Db, Id, Attachment, Req0) -> {ok, Req1, ok} end. +-spec ensure_extension_present/5 :: (ne_binary(), ne_binary(), ne_binary(), ne_binary(), #http_req{}) -> {'ok', #http_req{}, 'ok'}. ensure_extension_present(Db, Id, Attachment, CT, Req0) -> case wh_util:is_empty(filename:extension(Attachment)) andalso wh_mime_types:to_extension(CT) @@ -157,24 +178,38 @@ ensure_extension_present(Db, Id, Attachment, CT, Req0) -> {ok, Req1, ok} end. +-spec try_to_store/5 :: (ne_binary(), ne_binary(), ne_binary(), ne_binary(), #http_req{}) -> {'ok', #http_req{}, 'ok'}. try_to_store(Db, Id, Attachment, CT, Req0) -> Conflicts = case get(conflicts) of undefined -> 0; Count -> Count end, DbName = wh_util:format_account_id(Db, encoded), {ok, Contents, Req1} = cowboy_http_req:body(Req0), Options = [{content_type, wh_util:to_list(CT)}], case couch_mgr:put_attachment(DbName, Id, Attachment, Contents, Options) of - {ok, _} -> + {ok, JObj} -> lager:debug("successfully stored(~p) ~p ~p ~p", [CT, DbName, Id, Attachment]), - {ok, Req2} = cowboy_http_req:reply(200, Req1), - {ok, Req2, ok}; + {ok, success(JObj, Req1), ok}; {error, conflict} when Conflicts < 2 -> put(conflicts, Conflicts + 1), try_to_store(Db, Id, Attachment, CT, Req1); - {error, _R} -> - lager:debug("unable to store file: ~p", [_R]), - {ok, Req2} = cowboy_http_req:reply(500, Req1), - {ok, Req2, ok} + {error, Reason} -> + lager:debug("unable to store file: ~p", [Reason]), + {ok, failure(Reason, Req1), ok} end. +-spec success/2 :: (wh_json:object(), #http_req{}) -> #http_req{}. +success(JObj, Req0) -> + Body = io_lib:format("~s~n", [wh_json:encode(wh_json:set_value(<<"ok">>, true, JObj))]), + {ok, Req1} = cowboy_http_req:set_resp_body(Body, Req0), + {ok, Req2} = cowboy_http_req:reply(200, Req1), + Req2. + +-spec failure/2 :: (term(), #http_req{}) -> #http_req{}. +failure(Reason, Req0) -> + Body = io_lib:format("~p~n", [Reason]), + {ok, Req1} = cowboy_http_req:set_resp_body(Body, Req0), + {ok, Req2} = cowboy_http_req:reply(500, Req1), + Req2. + +-spec terminate/2 :: (#http_req{}, _) -> 'ok'. terminate(_Req, _State) -> ok. diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_url.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_url.erl index 5a6d9b8888b..a3399ab3d26 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_url.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_url.erl @@ -13,6 +13,8 @@ -include("whistle_media.hrl"). +-spec playback/2 :: (api_binary(), wh_json:object()) -> {'ok', ne_binary()} | + {'error', _}. playback(undefined, _) -> {error, invalid_media_name}; playback(<<"tts://", _/binary>> = TTS, Options) -> @@ -27,6 +29,16 @@ playback(Media, Options) -> Ok end. +-spec store/3 :: (ne_binary(), ne_binary(), ne_binary()) -> {'ok', ne_binary()} | + {'error', _}. store(Db, Id, Attachment) -> Options = wh_json:from_list([{<<"Stream-Type">>, <<"store">>}]), - wh_media_file:get_uri([Db, Id, Attachment], Options). + Rev = case couch_mgr:lookup_doc_rev(Db, Id) of + {ok, R} -> <<"?rev=", R/binary>>; + _ -> <<>> + end, + case wh_media_file:get_uri([Db, Id, Attachment], Options) of + {error, _}=E -> E; + {ok, URI} -> + {ok, <>} + end. diff --git a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_util.erl b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_util.erl index ede8543df7b..c4c4a4852c7 100644 --- a/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_util.erl +++ b/whistle_apps/lib/whistle_media-1.0.0/src/wh_media_util.erl @@ -20,27 +20,35 @@ base_url(Host, Port) -> base_url(Host, Port, proxy_playback). base_url(Host, Port, direct_playback) -> - case whapps_config:get_is_true(?CONFIG_CAT, <<"bigcouch_authenticated_playback">>, false) of + case whapps_config:get_is_true(?CONFIG_CAT, <<"authenticated_playback">>, false) of false -> build_url(Host, Port, [], []); true -> {Username, Password} = couch_mgr:get_creds(), build_url(Host, Port, Username, Password) end; base_url(Host, Port, proxy_playback) -> - Username = whapps_config:get_string(?CONFIG_CAT, <<"proxy_store_username">>, <<>>), - Password = whapps_config:get_string(?CONFIG_CAT, <<"proxy_store_password">>, <<>>), - build_url(Host, Port, Username, Password); + case whapps_config:get_is_true(?CONFIG_CAT, <<"authenticated_playback">>, false) of + false -> build_url(Host, Port, [], []); + true -> + Username = whapps_config:get_string(?CONFIG_CAT, <<"proxy_username">>, wh_util:rand_hex_binary(8)), + Password = whapps_config:get_string(?CONFIG_CAT, <<"proxy_password">>, wh_util:rand_hex_binary(8)), + build_url(Host, Port, Username, Password) + end; base_url(Host, Port, direct_store) -> - case whapps_config:get_is_true(?CONFIG_CAT, <<"bigcouch_authenticated_store">>, true) of + case whapps_config:get_is_true(?CONFIG_CAT, <<"authenticated_store">>, true) of false -> build_url(Host, Port, [], []); true -> {Username, Password} = couch_mgr:get_creds(), build_url(Host, Port, Username, Password) end; -base_url(Host, Port, proxy_store) -> - Username = whapps_config:get_string(?CONFIG_CAT, <<"proxy_store_username">>, <<>>), - Password = whapps_config:get_string(?CONFIG_CAT, <<"proxy_store_password">>, <<>>), - build_url(Host, Port, Username, Password). +base_url(Host, Port, proxy_store) -> + case whapps_config:get_is_true(?CONFIG_CAT, <<"authenticated_store">>, true) of + false -> build_url(Host, Port, [], []); + true -> + Username = whapps_config:get_string(?CONFIG_CAT, <<"proxy_username">>, wh_util:rand_hex_binary(8)), + Password = whapps_config:get_string(?CONFIG_CAT, <<"proxy_password">>, wh_util:rand_hex_binary(8)), + build_url(Host, Port, Username, Password) + end. build_url(H, P, [], []) -> Scheme = case whapps_config:get_is_true(?CONFIG_CAT, <<"use_https">>, false) of