mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-18 19:12:54 +00:00
- Add TelecomSDK GenServer module with start_link initialization and Config struct - Add subscriber management: get_subscriber, list_subscribers with pagination/status filter, create_subscriber, update_subscriber - Add subscriber lifecycle: suspend_subscriber, activate_subscriber, terminate_subscriber - Add usage tracking: get_usage_stats with date range, list_usage_events with filtering, get_real_time_usage
382 lines
11 KiB
Elixir
382 lines
11 KiB
Elixir
defmodule TelecomSDK do
|
|
@moduledoc """
|
|
Telecom Platform Elixir SDK
|
|
|
|
Provides GenServer-based async access to the Telecom Platform API with full Elixir pattern matching.
|
|
"""
|
|
|
|
use GenServer
|
|
require Logger
|
|
|
|
# Client API
|
|
|
|
@doc """
|
|
Start the Telecom SDK GenServer
|
|
"""
|
|
def start_link(opts \\ []) do
|
|
config = struct(Config, opts)
|
|
GenServer.start_link(__MODULE__, config, name: __MODULE__)
|
|
end
|
|
|
|
@doc """
|
|
Get subscriber by ID
|
|
"""
|
|
def get_subscriber(id) do
|
|
GenServer.call(__MODULE__, {:get_subscriber, id})
|
|
end
|
|
|
|
@doc """
|
|
List subscribers with pagination
|
|
"""
|
|
def list_subscribers(page \\ 1, page_size \\ 50, status \\ nil) do
|
|
GenServer.call(__MODULE__, {:list_subscribers, page, page_size, status})
|
|
end
|
|
|
|
@doc """
|
|
Create a new subscriber
|
|
"""
|
|
def create_subscriber(request) do
|
|
GenServer.call(__MODULE__, {:create_subscriber, request})
|
|
end
|
|
|
|
@doc """
|
|
Update an existing subscriber
|
|
"""
|
|
def update_subscriber(id, request) do
|
|
GenServer.call(__MODULE__, {:update_subscriber, id, request})
|
|
end
|
|
|
|
@doc """
|
|
Suspend a subscriber
|
|
"""
|
|
def suspend_subscriber(id) do
|
|
GenServer.call(__MODULE__, {:suspend_subscriber, id})
|
|
end
|
|
|
|
@doc """
|
|
Activate a suspended subscriber
|
|
"""
|
|
def activate_subscriber(id) do
|
|
GenServer.call(__MODULE__, {:activate_subscriber, id})
|
|
end
|
|
|
|
@doc """
|
|
Terminate a subscriber
|
|
"""
|
|
def terminate_subscriber(id) do
|
|
GenServer.call(__MODULE__, {:terminate_subscriber, id})
|
|
end
|
|
|
|
@doc """
|
|
Get usage statistics for a subscriber
|
|
"""
|
|
def get_usage_stats(subscriber_id, start_date, end_date) do
|
|
GenServer.call(__MODULE__, {:get_usage_stats, subscriber_id, start_date, end_date})
|
|
end
|
|
|
|
@doc """
|
|
List usage events with filtering
|
|
"""
|
|
def list_usage_events(opts \\ []) do
|
|
GenServer.call(__MODULE__, {:list_usage_events, opts})
|
|
end
|
|
|
|
@doc """
|
|
Get real-time usage for a subscriber
|
|
"""
|
|
def get_real_time_usage(subscriber_id) do
|
|
GenServer.call(__MODULE__, {:get_real_time_usage, subscriber_id})
|
|
end
|
|
|
|
@doc """
|
|
Create a payment transaction
|
|
"""
|
|
def create_payment_transaction(request) do
|
|
GenServer.call(__MODULE__, {:create_payment_transaction, request})
|
|
end
|
|
|
|
@doc """
|
|
Get payment transaction by ID
|
|
"""
|
|
def get_payment_transaction(transaction_id) do
|
|
GenServer.call(__MODULE__, {:get_payment_transaction, transaction_id})
|
|
end
|
|
|
|
@doc """
|
|
List payment transactions with filtering
|
|
"""
|
|
def list_payment_transactions(opts \\ []) do
|
|
GenServer.call(__MODULE__, {:list_payment_transactions, opts})
|
|
end
|
|
|
|
@doc """
|
|
List all available rating plans
|
|
"""
|
|
def list_rating_plans do
|
|
GenServer.call(__MODULE__, :list_rating_plans)
|
|
end
|
|
|
|
@doc """
|
|
Get rating plan by ID
|
|
"""
|
|
def get_rating_plan(plan_id) do
|
|
GenServer.call(__MODULE__, {:get_rating_plan, plan_id})
|
|
end
|
|
|
|
@doc """
|
|
Get system statistics
|
|
"""
|
|
def get_system_stats do
|
|
GenServer.call(__MODULE__, :get_system_stats)
|
|
end
|
|
|
|
@doc """
|
|
Get system health status
|
|
"""
|
|
def get_health_status do
|
|
GenServer.call(__MODULE__, :get_health_status)
|
|
end
|
|
|
|
@doc """
|
|
Execute a GraphQL query
|
|
"""
|
|
def execute_graphql_query(query, variables \\ %{}) do
|
|
GenServer.call(__MODULE__, {:execute_graphql_query, query, variables})
|
|
end
|
|
|
|
@doc """
|
|
Connect to WebSocket for real-time updates
|
|
"""
|
|
def connect_websocket(message_handler \\ nil) do
|
|
GenServer.call(__MODULE__, {:connect_websocket, message_handler})
|
|
end
|
|
|
|
# GenServer Callbacks
|
|
|
|
@impl true
|
|
def init(config) do
|
|
Finch.start_link(name: MyFinch)
|
|
{:ok, %{config: config, finch: MyFinch}}
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:get_subscriber, id}, _from, state) do
|
|
case make_request(:get, "/v1/subscribers/#{id}", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, Subscriber.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:list_subscribers, page, page_size, status}, _from, state) do
|
|
params = %{page: page, page_size: page_size}
|
|
params = if status, do: Map.put(params, :status, status), else: params
|
|
|
|
case make_request(:get, "/v1/subscribers", params, state) do
|
|
{:ok, response} -> {:reply, {:ok, SubscriberList.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:create_subscriber, request}, _from, state) do
|
|
case make_request(:post, "/v1/subscribers", request.to_map(), state) do
|
|
{:ok, response} -> {:reply, {:ok, Subscriber.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:update_subscriber, id, request}, _from, state) do
|
|
case make_request(:put, "/v1/subscribers/#{id}", request.to_map(), state) do
|
|
{:ok, response} -> {:reply, {:ok, Subscriber.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:suspend_subscriber, id}, _from, state) do
|
|
case make_request(:post, "/v1/subscribers/#{id}/suspend", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, Subscriber.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:activate_subscriber, id}, _from, state) do
|
|
case make_request(:post, "/v1/subscribers/#{id}/activate", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, Subscriber.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:terminate_subscriber, id}, _from, state) do
|
|
case make_request(:delete, "/v1/subscribers/#{id}", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, response["success"]}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:get_usage_stats, subscriber_id, start_date, end_date}, _from, state) do
|
|
params = %{
|
|
start_date: DateTime.to_iso8601(start_date),
|
|
end_date: DateTime.to_iso8601(end_date)
|
|
}
|
|
|
|
case make_request(:get, "/v1/subscribers/#{subscriber_id}/usage", params, state) do
|
|
{:ok, response} -> {:reply, {:ok, UsageStats.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:list_usage_events, opts}, _from, state) do
|
|
params = build_params(opts, [:subscriber_id, :usage_type, :start_date, :end_date, :page, :page_size])
|
|
|
|
case make_request(:get, "/v1/usage/events", params, state) do
|
|
{:ok, response} -> {:reply, {:ok, UsageEventList.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:get_real_time_usage, subscriber_id}, _from, state) do
|
|
case make_request(:get, "/v1/subscribers/#{subscriber_id}/realtime", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, RealTimeUsage.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:create_payment_transaction, request}, _from, state) do
|
|
case make_request(:post, "/v1/payments/transactions", request.to_map(), state) do
|
|
{:ok, response} -> {:reply, {:ok, PaymentTransaction.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:get_payment_transaction, transaction_id}, _from, state) do
|
|
case make_request(:get, "/v1/payments/transactions/#{transaction_id}", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, PaymentTransaction.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:list_payment_transactions, opts}, _from, state) do
|
|
params = build_params(opts, [:subscriber_id, :status, :page, :page_size])
|
|
|
|
case make_request(:get, "/v1/payments/transactions", params, state) do
|
|
{:ok, response} -> {:reply, {:ok, PaymentTransactionList.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(:list_rating_plans, _from, state) do
|
|
case make_request(:get, "/v1/rating-plans", nil, state) do
|
|
{:ok, response} ->
|
|
plans = Enum.map(response, &RatingPlan.from_map/1)
|
|
{:reply, {:ok, plans}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:get_rating_plan, plan_id}, _from, state) do
|
|
case make_request(:get, "/v1/rating-plans/#{plan_id}", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, RatingPlan.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(:get_system_stats, _from, state) do
|
|
case make_request(:get, "/v1/system/stats", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, SystemStats.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call(:get_health_status, _from, state) do
|
|
case make_request(:get, "/v1/health", nil, state) do
|
|
{:ok, response} -> {:reply, {:ok, HealthStatus.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:execute_graphql_query, query, variables}, _from, state) do
|
|
request = %{query: query, variables: variables}
|
|
|
|
case make_request(:post, "/graphql", request, state) do
|
|
{:ok, response} -> {:reply, {:ok, GraphQLResponse.from_map(response)}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
@impl true
|
|
def handle_call({:connect_websocket, message_handler}, _from, state) do
|
|
ws_url = String.replace(state.config.api_url, "http://", "ws://") <> "/ws"
|
|
|
|
case WebSockex.start_link(ws_url, WebSocketHandler, %{message_handler: message_handler}) do
|
|
{:ok, pid} -> {:reply, {:ok, pid}, state}
|
|
{:error, error} -> {:reply, {:error, error}, state}
|
|
end
|
|
end
|
|
|
|
# Private functions
|
|
|
|
defp make_request(method, path, params, state) do
|
|
url = state.config.api_url <> path
|
|
|
|
headers = [
|
|
{"user-agent", "Telecom-Elixir-SDK/1.0.0"},
|
|
{"content-type", "application/json"}
|
|
]
|
|
|
|
headers = if state.config.api_key do
|
|
[{"authorization", "Bearer #{state.config.api_key}"} | headers]
|
|
else
|
|
headers
|
|
end
|
|
|
|
request = Finch.build(method, url, headers, Jason.encode!(params || %{}))
|
|
|
|
case Finch.request(request, state.finch) do
|
|
{:ok, response} ->
|
|
case response.status do
|
|
200 ->
|
|
body = response.body |> Jason.decode!()
|
|
{:ok, body}
|
|
401 ->
|
|
{:error, :authentication_error}
|
|
429 ->
|
|
{:error, :rate_limit_error}
|
|
status when status in 400..499 ->
|
|
body = response.body |> Jason.decode!()
|
|
{:error, {:api_error, body["error"] || "Bad request"}}
|
|
status when status in 500..599 ->
|
|
{:error, {:server_error, status}}
|
|
_ ->
|
|
{:error, :unknown_error}
|
|
end
|
|
{:error, reason} ->
|
|
{:error, {:network_error, reason}}
|
|
end
|
|
end
|
|
|
|
defp build_params(opts, keys) do
|
|
Enum.reduce(keys, %{}, fn key, acc ->
|
|
case Map.get(opts, key) do
|
|
nil -> acc
|
|
value -> Map.put(acc, key, value)
|
|
end
|
|
end)
|
|
end
|
|
end
|