Packages

Elixir libraries and OTP behaviours for building telecom applications with SIP protocol and media handling

Current section

Files

Jump to
parrot_platform lib parrot sip handler_adapter callback_handler.ex
Raw

lib/parrot/sip/handler_adapter/callback_handler.ex

defmodule Parrot.Sip.HandlerAdapter.CallbackHandler do
@moduledoc """
Functions for calling user handler callbacks.
This module provides helper functions for calling the appropriate
handler function in a user's handler module.
"""
require Logger
@doc """
Calls the appropriate method handler in the user's handler module.
This function dynamically determines which handler function to call based on the
SIP method (e.g., INVITE, OPTIONS) and calls it with the request map and user state.
If the method handler doesn't exist in the user's module, a default 501 Not Implemented
response is returned.
## Parameters
* `handler_module` - The user's handler module
* `method_str_or_atom` - The SIP method as a string or atom (e.g., "INVITE", :invite)
* `request_map` - The request map containing the parsed SIP request
* `user_handler_state` - The user's handler state to pass to the handler
## Returns
The return value from the user's handler function, or a default 501 response if
no handler is found.
"""
def call_method_handler(handler_module, method_str_or_atom, sip_msg, user_handler_state) do
method_name_lower = String.downcase(to_string(method_str_or_atom))
handler_fun = String.to_atom("handle_#{method_name_lower}")
Logger.debug(
"HandlerAdapter: Attempting to call user handler: #{inspect(handler_module)}.#{handler_fun}/2"
)
if function_exported?(handler_module, handler_fun, 2) do
apply(handler_module, handler_fun, [sip_msg, user_handler_state])
else
Logger.warning(
"HandlerAdapter: User method handler #{handler_fun}/2 not found in #{inspect(handler_module)}. Defaulting."
)
# Default response for unhandled methods
{:respond, 501, "Not Implemented by User Handler", %{}, ""}
end
end
@doc """
Calls the appropriate transaction state handler in the user's handler module.
This function dynamically determines which transaction handler to call based on the
SIP method and transaction state (e.g., handle_transaction_invite_trying).
If the transaction handler doesn't exist, it falls back to the basic method handler.
## Parameters
* `handler_module` - The user's handler module
* `method_str_or_atom` - The SIP method as a string or atom (e.g., "INVITE")
* `trans_state_atom` - The transaction state as an atom (e.g., :trying, :proceeding)
* `request_map` - The request map containing the parsed SIP request
* `transaction_obj` - The transaction object to pass to the handler
* `user_handler_state` - The user's handler state to pass to the handler
## Returns
The return value from the user's transaction handler function, or from the fallback
method handler if no transaction handler is found.
"""
def call_transaction_handler(
handler_module,
method,
trans_state_atom,
# TODO: deprecate request_map
request_map,
transaction_obj,
user_handler_state
) do
method_name_lower = to_string(method)
trans_state_str = Atom.to_string(trans_state_atom)
handler_fun = String.to_atom("handle_transaction_#{method_name_lower}_#{trans_state_str}")
Logger.debug(
"HandlerAdapter: Attempting to call user transaction handler: #{inspect(handler_module)}.#{handler_fun}/3"
)
if function_exported?(handler_module, handler_fun, 3) do
Logger.debug("HandlerAdapter: User transaction handler #{handler_fun}/3 found. Running it.")
apply(handler_module, handler_fun, [request_map, transaction_obj, user_handler_state])
else
Logger.debug(
"HandlerAdapter: User transaction handler #{handler_fun}/3 not found. Falling back to method handler."
)
# Fall back to the basic method handler if transaction-specific one isn't found
call_method_handler(handler_module, method, request_map, user_handler_state)
end
end
@doc """
Calls the appropriate dialog state handler in the user's handler module.
This function dynamically determines which dialog handler to call based on the
dialog state (e.g., handle_dialog_early, handle_dialog_confirmed).
If the dialog handler doesn't exist, it defaults to returning :noreply.
## Parameters
* `handler_module` - The user's handler module
* `dialog_state_atom` - The dialog state as an atom (e.g., :early, :confirmed)
* `request_map` - The request map containing the parsed SIP request
* `dialog_obj` - The dialog object to pass to the handler
* `user_handler_state` - The user's handler state to pass to the handler
## Returns
The return value from the user's dialog handler function, or :noreply if
no dialog handler is found.
"""
def call_dialog_handler(
handler_module,
dialog_state_atom,
request_map,
dialog_obj,
user_handler_state
) do
dialog_state_str = Atom.to_string(dialog_state_atom)
handler_fun = String.to_atom("handle_dialog_#{dialog_state_str}")
Logger.debug(
"HandlerAdapter: Attempting to call user dialog handler: #{inspect(handler_module)}.#{handler_fun}/3"
)
if function_exported?(handler_module, handler_fun, 3) do
apply(handler_module, handler_fun, [request_map, dialog_obj, user_handler_state])
else
Logger.warning(
"HandlerAdapter: User dialog handler #{handler_fun}/3 not found. Defaulting to :noreply."
)
:noreply
end
end
end