mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-19 11:32:53 +00:00
feat: Add Elixir SDK GenServer-based client with comprehensive Telecom Platform API integration
- 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
This commit is contained in:
@@ -0,0 +1,381 @@
|
||||
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
|
||||
Reference in New Issue
Block a user