mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-11-04 19:02:19 +00:00
feat: Refactor CLI API client by splitting billing, carrier, and charging modules into separate files
- Extract Invoice, Payment, Subscriber types and GetInvoices, GetPayments, GenerateInvoice methods to billing.go - Extract CarrierInfo, ConnectivityStatus, ProfileInfo types and carrier connector methods to carrier.go - Extract CreditCheckRequest/Response, CreditBalanceResponse types and charging engine methods to charging.go - Add PacketStats, CreditInfo types and GetPacketStats, GetCreditInfo
This commit is contained in:
@@ -0,0 +1,155 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"encoding/json"
|
||||||
|
"fmt"
|
||||||
|
"io"
|
||||||
|
"net/http"
|
||||||
|
"time"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Invoice represents an invoice from the API
|
||||||
|
type Invoice struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
SubscriberID string `json:"subscriber_id"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
DueDate time.Time `json:"due_date"`
|
||||||
|
PaidAt *time.Time `json:"paid_at,omitempty"`
|
||||||
|
Subscriber Subscriber `json:"subscriber"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// Payment represents a payment from the API
|
||||||
|
type Payment struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
InvoiceID string `json:"invoice_id"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
Method string `json:"method"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
ProcessedAt *time.Time `json:"processed_at,omitempty"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateInvoiceRequest represents a request to generate an invoice
|
||||||
|
type GenerateInvoiceRequest struct {
|
||||||
|
SubscriberID string `json:"subscriber_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateInvoiceResponse represents a response from generating an invoice
|
||||||
|
type GenerateInvoiceResponse struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Amount float64 `json:"amount"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
CreatedAt time.Time `json:"created_at"`
|
||||||
|
DueDate time.Time `json:"due_date"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetInvoices retrieves invoices from the API
|
||||||
|
func (c *Client) GetInvoices() ([]Invoice, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/invoices", c.baseURL)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to make request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Data []Invoice `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPayments retrieves payments from the API
|
||||||
|
func (c *Client) GetPayments() ([]Payment, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/payments", c.baseURL)
|
||||||
|
|
||||||
|
req, err := http.NewRequest("GET", url, nil)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to make request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusOK {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var response struct {
|
||||||
|
Data []Payment `json:"data"`
|
||||||
|
}
|
||||||
|
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return response.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GenerateInvoice generates a new invoice for a subscriber
|
||||||
|
func (c *Client) GenerateInvoice(subscriberID string) (*GenerateInvoiceResponse, error) {
|
||||||
|
url := fmt.Sprintf("%s/api/v1/invoices/generate", c.baseURL)
|
||||||
|
|
||||||
|
request := GenerateInvoiceRequest{
|
||||||
|
SubscriberID: subscriberID,
|
||||||
|
}
|
||||||
|
|
||||||
|
jsonData, err := json.Marshal(request)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to create request: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||||
|
req.Header.Set("Content-Type", "application/json")
|
||||||
|
|
||||||
|
resp, err := c.httpClient.Do(req)
|
||||||
|
if err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to make request: %w", err)
|
||||||
|
}
|
||||||
|
defer resp.Body.Close()
|
||||||
|
|
||||||
|
if resp.StatusCode != http.StatusCreated {
|
||||||
|
body, _ := io.ReadAll(resp.Body)
|
||||||
|
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
||||||
|
}
|
||||||
|
|
||||||
|
var response GenerateInvoiceResponse
|
||||||
|
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
||||||
|
return nil, fmt.Errorf("failed to decode response: %w", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return &response, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,70 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Carrier Connector Integration
|
||||||
|
type CarrierInfo struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Country string `json:"country"`
|
||||||
|
NetworkType string `json:"network_type"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ConnectivityStatus struct {
|
||||||
|
Connected bool `json:"connected"`
|
||||||
|
Latency string `json:"latency"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type ProfileInfo struct {
|
||||||
|
ProfileID string `json:"profile_id"`
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
ActivationCode string `json:"activation_code"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type OrderProfileRequest struct {
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
ProfileID string `json:"profile_id"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetCarrierInfo retrieves carrier information
|
||||||
|
func (c *Client) GetCarrierInfo() (*CarrierInfo, error) {
|
||||||
|
var info CarrierInfo
|
||||||
|
if err := c.doGetJSON("/api/v1/carrier/info", &info); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &info, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckConnectivity checks carrier connectivity
|
||||||
|
func (c *Client) CheckConnectivity() (*ConnectivityStatus, error) {
|
||||||
|
var status ConnectivityStatus
|
||||||
|
if err := c.doGetJSON("/api/v1/carrier/connectivity", &status); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &status, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListProfiles lists eSIM profiles
|
||||||
|
func (c *Client) ListProfiles() ([]ProfileInfo, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []ProfileInfo `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/esim/profiles", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// OrderProfile orders a new eSIM profile
|
||||||
|
func (c *Client) OrderProfile(req *OrderProfileRequest) (*ProfileInfo, error) {
|
||||||
|
var profile ProfileInfo
|
||||||
|
if err := c.doPostJSON("/api/v1/esim/profiles", req, &profile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &profile, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteProfile deletes an eSIM profile
|
||||||
|
func (c *Client) DeleteProfile(profileID string) error {
|
||||||
|
return c.doDelete("/api/v1/esim/profiles/" + profileID)
|
||||||
|
}
|
||||||
@@ -0,0 +1,64 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Charging Engine Integration
|
||||||
|
type CreditCheckRequest struct {
|
||||||
|
BytesRequested uint64 `json:"bytes_requested"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreditCheckResponse struct {
|
||||||
|
Allowed bool `json:"allowed"`
|
||||||
|
Available uint64 `json:"available"`
|
||||||
|
Requested uint64 `json:"requested"`
|
||||||
|
Remaining uint64 `json:"remaining"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreditBalanceResponse struct {
|
||||||
|
Balance uint64 `json:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreditAddRequest struct {
|
||||||
|
BytesToAdd uint64 `json:"bytes_to_add"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type CreditDeductRequest struct {
|
||||||
|
BytesUsed uint64 `json:"bytes_used"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// CheckCredit checks if a subscriber has enough credit
|
||||||
|
func (c *Client) CheckCredit(ip string, bytesRequested uint64) (*CreditCheckResponse, error) {
|
||||||
|
var resp CreditCheckResponse
|
||||||
|
req := CreditCheckRequest{BytesRequested: bytesRequested}
|
||||||
|
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/check", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetBalance gets the current credit balance for a subscriber
|
||||||
|
func (c *Client) GetBalance(ip string) (*CreditBalanceResponse, error) {
|
||||||
|
var resp CreditBalanceResponse
|
||||||
|
if err := c.doGetJSON("/v1/charging/credit/"+ip+"/balance", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// AddCredit adds credit to a subscriber
|
||||||
|
func (c *Client) AddCredit(ip string, bytesToAdd uint64) (*CreditBalanceResponse, error) {
|
||||||
|
var resp CreditBalanceResponse
|
||||||
|
req := CreditAddRequest{BytesToAdd: bytesToAdd}
|
||||||
|
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/add", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeductCredit deducts credit from a subscriber
|
||||||
|
func (c *Client) DeductCredit(ip string, bytesUsed uint64) (*CreditBalanceResponse, error) {
|
||||||
|
var resp CreditBalanceResponse
|
||||||
|
req := CreditDeductRequest{BytesUsed: bytesUsed}
|
||||||
|
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/deduct", req, &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &resp, nil
|
||||||
|
}
|
||||||
@@ -115,289 +115,6 @@ func (c *Client) doDelete(path string) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// SubscriberAccount holds account info
|
|
||||||
type SubscriberAccount struct {
|
|
||||||
IMSI string `json:"imsi"`
|
|
||||||
Name string `json:"name"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Balance float64 `json:"balance"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListSubscribers retrieves subscribers
|
|
||||||
func (c *Client) ListSubscribers() ([]SubscriberAccount, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []SubscriberAccount `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/subscribers", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSubscriber retrieves a single subscriber
|
|
||||||
func (c *Client) GetSubscriber(imsi string) (*SubscriberAccount, error) {
|
|
||||||
var sub SubscriberAccount
|
|
||||||
if err := c.doGetJSON("/api/v1/subscribers/"+imsi, &sub); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &sub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CreateSubscriber creates a subscriber
|
|
||||||
func (c *Client) CreateSubscriber(imsi, name string) (*SubscriberAccount, error) {
|
|
||||||
var sub SubscriberAccount
|
|
||||||
body := map[string]string{"imsi": imsi, "name": name}
|
|
||||||
if err := c.doPostJSON("/api/v1/subscribers", body, &sub); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &sub, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteSubscriber deletes a subscriber
|
|
||||||
func (c *Client) DeleteSubscriber(imsi string) error {
|
|
||||||
return c.doDelete("/api/v1/subscribers/" + imsi)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Service describes a platform service
|
|
||||||
type Service struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Version string `json:"version"`
|
|
||||||
Uptime string `json:"uptime"`
|
|
||||||
CPU float64 `json:"cpu"`
|
|
||||||
Memory string `json:"memory"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// PostRestart requests the API to restart the named service.
|
|
||||||
func (c *Client) PostRestart(name string) error {
|
|
||||||
return c.doPostJSON("/api/v1/services/"+name+"/restart", nil, nil)
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListServices returns platform services
|
|
||||||
func (c *Client) ListServices() ([]Service, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []Service `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/services", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Alert represents a monitoring alert
|
|
||||||
type Alert struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Severity string `json:"severity"`
|
|
||||||
Service string `json:"service"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
Time time.Time `json:"time"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListAlerts returns alerts
|
|
||||||
func (c *Client) ListAlerts() ([]Alert, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []Alert `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/alerts", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// SystemStats represents system health/metrics
|
|
||||||
type SystemStats struct {
|
|
||||||
ActiveSessions int `json:"active_sessions"`
|
|
||||||
TotalAccounts int `json:"total_accounts"`
|
|
||||||
BlockedUsers int `json:"blocked_users"`
|
|
||||||
LowBalanceAlerts int `json:"low_balance_alerts"`
|
|
||||||
CPUUsage float64 `json:"cpu_usage"`
|
|
||||||
MemoryUsage float64 `json:"memory_usage"`
|
|
||||||
Uptime string `json:"uptime"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetSystemStats retrieves system stats
|
|
||||||
func (c *Client) GetSystemStats() (*SystemStats, error) {
|
|
||||||
var stats SystemStats
|
|
||||||
if err := c.doGetJSON("/api/v1/system/stats", &stats); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &stats, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// HealthStatus represents a health check result
|
|
||||||
type HealthStatus struct {
|
|
||||||
Service string `json:"service"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
Uptime string `json:"uptime"`
|
|
||||||
LastCheck time.Time `json:"last_check"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetHealth returns per-service health
|
|
||||||
func (c *Client) GetHealth() ([]HealthStatus, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []HealthStatus `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/health", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Invoice represents an invoice from the API
|
|
||||||
type Invoice struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
SubscriberID string `json:"subscriber_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
DueDate time.Time `json:"due_date"`
|
|
||||||
PaidAt *time.Time `json:"paid_at,omitempty"`
|
|
||||||
Subscriber Subscriber `json:"subscriber"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Payment represents a payment from the API
|
|
||||||
type Payment struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
InvoiceID string `json:"invoice_id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Method string `json:"method"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
ProcessedAt *time.Time `json:"processed_at,omitempty"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// Subscriber represents a subscriber from the API
|
|
||||||
type Subscriber struct {
|
|
||||||
ID uint `json:"id"`
|
|
||||||
IMSI string `json:"imsi"`
|
|
||||||
FirstName string `json:"first_name"`
|
|
||||||
LastName string `json:"last_name"`
|
|
||||||
Email string `json:"email"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetInvoices retrieves invoices from the API
|
|
||||||
func (c *Client) GetInvoices() ([]Invoice, error) {
|
|
||||||
url := fmt.Sprintf("%s/api/v1/invoices", c.baseURL)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to make request: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
var response struct {
|
|
||||||
Data []Invoice `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPayments retrieves payments from the API
|
|
||||||
func (c *Client) GetPayments() ([]Payment, error) {
|
|
||||||
url := fmt.Sprintf("%s/api/v1/payments", c.baseURL)
|
|
||||||
|
|
||||||
req, err := http.NewRequest("GET", url, nil)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to make request: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusOK {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
var response struct {
|
|
||||||
Data []Payment `json:"data"`
|
|
||||||
}
|
|
||||||
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return response.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateInvoiceRequest represents a request to generate an invoice
|
|
||||||
type GenerateInvoiceRequest struct {
|
|
||||||
SubscriberID string `json:"subscriber_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateInvoiceResponse represents a response from generating an invoice
|
|
||||||
type GenerateInvoiceResponse struct {
|
|
||||||
ID string `json:"id"`
|
|
||||||
Amount float64 `json:"amount"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
CreatedAt time.Time `json:"created_at"`
|
|
||||||
DueDate time.Time `json:"due_date"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GenerateInvoice generates a new invoice for a subscriber
|
|
||||||
func (c *Client) GenerateInvoice(subscriberID string) (*GenerateInvoiceResponse, error) {
|
|
||||||
url := fmt.Sprintf("%s/api/v1/invoices/generate", c.baseURL)
|
|
||||||
|
|
||||||
request := GenerateInvoiceRequest{
|
|
||||||
SubscriberID: subscriberID,
|
|
||||||
}
|
|
||||||
|
|
||||||
jsonData, err := json.Marshal(request)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to marshal request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req, err := http.NewRequest("POST", url, bytes.NewBuffer(jsonData))
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to create request: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
|
||||||
req.Header.Set("Content-Type", "application/json")
|
|
||||||
|
|
||||||
resp, err := c.httpClient.Do(req)
|
|
||||||
if err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to make request: %w", err)
|
|
||||||
}
|
|
||||||
defer resp.Body.Close()
|
|
||||||
|
|
||||||
if resp.StatusCode != http.StatusCreated {
|
|
||||||
body, _ := io.ReadAll(resp.Body)
|
|
||||||
return nil, fmt.Errorf("API request failed with status %d: %s", resp.StatusCode, string(body))
|
|
||||||
}
|
|
||||||
|
|
||||||
var response GenerateInvoiceResponse
|
|
||||||
if err := json.NewDecoder(resp.Body).Decode(&response); err != nil {
|
|
||||||
return nil, fmt.Errorf("failed to decode response: %w", err)
|
|
||||||
}
|
|
||||||
|
|
||||||
return &response, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// IsConnected checks if the API server is reachable
|
// IsConnected checks if the API server is reachable
|
||||||
func (c *Client) IsConnected() bool {
|
func (c *Client) IsConnected() bool {
|
||||||
url := fmt.Sprintf("%s/health", c.baseURL)
|
url := fmt.Sprintf("%s/health", c.baseURL)
|
||||||
@@ -417,168 +134,3 @@ func (c *Client) IsConnected() bool {
|
|||||||
|
|
||||||
return resp.StatusCode == http.StatusOK
|
return resp.StatusCode == http.StatusOK
|
||||||
}
|
}
|
||||||
|
|
||||||
// Charging Engine Integration
|
|
||||||
type CreditCheckRequest struct {
|
|
||||||
BytesRequested uint64 `json:"bytes_requested"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreditCheckResponse struct {
|
|
||||||
Allowed bool `json:"allowed"`
|
|
||||||
Available uint64 `json:"available"`
|
|
||||||
Requested uint64 `json:"requested"`
|
|
||||||
Remaining uint64 `json:"remaining"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreditBalanceResponse struct {
|
|
||||||
Balance uint64 `json:"balance"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreditAddRequest struct {
|
|
||||||
BytesToAdd uint64 `json:"bytes_to_add"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreditDeductRequest struct {
|
|
||||||
BytesUsed uint64 `json:"bytes_used"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckCredit checks if a subscriber has enough credit
|
|
||||||
func (c *Client) CheckCredit(ip string, bytesRequested uint64) (*CreditCheckResponse, error) {
|
|
||||||
var resp CreditCheckResponse
|
|
||||||
req := CreditCheckRequest{BytesRequested: bytesRequested}
|
|
||||||
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/check", req, &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetBalance gets the current credit balance for a subscriber
|
|
||||||
func (c *Client) GetBalance(ip string) (*CreditBalanceResponse, error) {
|
|
||||||
var resp CreditBalanceResponse
|
|
||||||
if err := c.doGetJSON("/v1/charging/credit/"+ip+"/balance", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// AddCredit adds credit to a subscriber
|
|
||||||
func (c *Client) AddCredit(ip string, bytesToAdd uint64) (*CreditBalanceResponse, error) {
|
|
||||||
var resp CreditBalanceResponse
|
|
||||||
req := CreditAddRequest{BytesToAdd: bytesToAdd}
|
|
||||||
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/add", req, &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeductCredit deducts credit from a subscriber
|
|
||||||
func (c *Client) DeductCredit(ip string, bytesUsed uint64) (*CreditBalanceResponse, error) {
|
|
||||||
var resp CreditBalanceResponse
|
|
||||||
req := CreditDeductRequest{BytesUsed: bytesUsed}
|
|
||||||
if err := c.doPostJSON("/v1/charging/credit/"+ip+"/deduct", req, &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &resp, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// Carrier Connector Integration
|
|
||||||
type CarrierInfo struct {
|
|
||||||
Name string `json:"name"`
|
|
||||||
Country string `json:"country"`
|
|
||||||
NetworkType string `json:"network_type"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ConnectivityStatus struct {
|
|
||||||
Connected bool `json:"connected"`
|
|
||||||
Latency string `json:"latency"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type ProfileInfo struct {
|
|
||||||
ProfileID string `json:"profile_id"`
|
|
||||||
IMSI string `json:"imsi"`
|
|
||||||
Status string `json:"status"`
|
|
||||||
ActivationCode string `json:"activation_code"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type OrderProfileRequest struct {
|
|
||||||
IMSI string `json:"imsi"`
|
|
||||||
ProfileID string `json:"profile_id"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCarrierInfo retrieves carrier information
|
|
||||||
func (c *Client) GetCarrierInfo() (*CarrierInfo, error) {
|
|
||||||
var info CarrierInfo
|
|
||||||
if err := c.doGetJSON("/api/v1/carrier/info", &info); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &info, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// CheckConnectivity checks carrier connectivity
|
|
||||||
func (c *Client) CheckConnectivity() (*ConnectivityStatus, error) {
|
|
||||||
var status ConnectivityStatus
|
|
||||||
if err := c.doGetJSON("/api/v1/carrier/connectivity", &status); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &status, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// ListProfiles lists eSIM profiles
|
|
||||||
func (c *Client) ListProfiles() ([]ProfileInfo, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []ProfileInfo `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/esim/profiles", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// OrderProfile orders a new eSIM profile
|
|
||||||
func (c *Client) OrderProfile(req *OrderProfileRequest) (*ProfileInfo, error) {
|
|
||||||
var profile ProfileInfo
|
|
||||||
if err := c.doPostJSON("/api/v1/esim/profiles", req, &profile); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return &profile, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// DeleteProfile deletes an eSIM profile
|
|
||||||
func (c *Client) DeleteProfile(profileID string) error {
|
|
||||||
return c.doDelete("/api/v1/esim/profiles/" + profileID)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Packet Gateway Integration
|
|
||||||
type PacketStats struct {
|
|
||||||
IP uint64 `json:"ip"`
|
|
||||||
Bytes uint64 `json:"bytes"`
|
|
||||||
}
|
|
||||||
|
|
||||||
type CreditInfo struct {
|
|
||||||
IP uint64 `json:"ip"`
|
|
||||||
Credit int64 `json:"credit"`
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetPacketStats retrieves packet statistics
|
|
||||||
func (c *Client) GetPacketStats() ([]PacketStats, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []PacketStats `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/packet-gateway/stats", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|
||||||
// GetCreditInfo retrieves credit information from packet gateway
|
|
||||||
func (c *Client) GetCreditInfo() ([]CreditInfo, error) {
|
|
||||||
var resp struct {
|
|
||||||
Data []CreditInfo `json:"data"`
|
|
||||||
}
|
|
||||||
if err := c.doGetJSON("/api/v1/packet-gateway/credits", &resp); err != nil {
|
|
||||||
return nil, err
|
|
||||||
}
|
|
||||||
return resp.Data, nil
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
import "time"
|
||||||
|
|
||||||
|
// Alert represents a monitoring alert
|
||||||
|
type Alert struct {
|
||||||
|
ID string `json:"id"`
|
||||||
|
Severity string `json:"severity"`
|
||||||
|
Service string `json:"service"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
Time time.Time `json:"time"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListAlerts returns alerts
|
||||||
|
func (c *Client) ListAlerts() ([]Alert, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []Alert `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/alerts", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SystemStats represents system health/metrics
|
||||||
|
type SystemStats struct {
|
||||||
|
ActiveSessions int `json:"active_sessions"`
|
||||||
|
TotalAccounts int `json:"total_accounts"`
|
||||||
|
BlockedUsers int `json:"blocked_users"`
|
||||||
|
LowBalanceAlerts int `json:"low_balance_alerts"`
|
||||||
|
CPUUsage float64 `json:"cpu_usage"`
|
||||||
|
MemoryUsage float64 `json:"memory_usage"`
|
||||||
|
Uptime string `json:"uptime"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSystemStats retrieves system stats
|
||||||
|
func (c *Client) GetSystemStats() (*SystemStats, error) {
|
||||||
|
var stats SystemStats
|
||||||
|
if err := c.doGetJSON("/api/v1/system/stats", &stats); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &stats, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// HealthStatus represents a health check result
|
||||||
|
type HealthStatus struct {
|
||||||
|
Service string `json:"service"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Uptime string `json:"uptime"`
|
||||||
|
LastCheck time.Time `json:"last_check"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetHealth returns per-service health
|
||||||
|
func (c *Client) GetHealth() ([]HealthStatus, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []HealthStatus `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/health", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,34 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Packet Gateway Integration
|
||||||
|
type PacketStats struct {
|
||||||
|
IP uint64 `json:"ip"`
|
||||||
|
Bytes uint64 `json:"bytes"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type PacketCreditInfo struct {
|
||||||
|
IP uint64 `json:"ip"`
|
||||||
|
Credit int64 `json:"credit"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPacketStats retrieves packet statistics
|
||||||
|
func (c *Client) GetPacketStats() ([]PacketStats, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []PacketStats `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/packet-gateway/stats", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetPacketCreditInfo retrieves credit information from packet gateway
|
||||||
|
func (c *Client) GetPacketCreditInfo() ([]PacketCreditInfo, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []PacketCreditInfo `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/packet-gateway/credits", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,27 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Service describes a platform service
|
||||||
|
type Service struct {
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Version string `json:"version"`
|
||||||
|
Uptime string `json:"uptime"`
|
||||||
|
CPU float64 `json:"cpu"`
|
||||||
|
Memory string `json:"memory"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// PostRestart requests the API to restart the named service.
|
||||||
|
func (c *Client) PostRestart(name string) error {
|
||||||
|
return c.doPostJSON("/api/v1/services/"+name+"/restart", nil, nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListServices returns platform services
|
||||||
|
func (c *Client) ListServices() ([]Service, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []Service `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/services", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
@@ -0,0 +1,54 @@
|
|||||||
|
package api
|
||||||
|
|
||||||
|
// Subscriber represents a subscriber from the API
|
||||||
|
type Subscriber struct {
|
||||||
|
ID uint `json:"id"`
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
FirstName string `json:"first_name"`
|
||||||
|
LastName string `json:"last_name"`
|
||||||
|
Email string `json:"email"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// SubscriberAccount holds account info
|
||||||
|
type SubscriberAccount struct {
|
||||||
|
IMSI string `json:"imsi"`
|
||||||
|
Name string `json:"name"`
|
||||||
|
Status string `json:"status"`
|
||||||
|
Balance float64 `json:"balance"`
|
||||||
|
}
|
||||||
|
|
||||||
|
// ListSubscribers retrieves subscribers
|
||||||
|
func (c *Client) ListSubscribers() ([]SubscriberAccount, error) {
|
||||||
|
var resp struct {
|
||||||
|
Data []SubscriberAccount `json:"data"`
|
||||||
|
}
|
||||||
|
if err := c.doGetJSON("/api/v1/subscribers", &resp); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return resp.Data, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// GetSubscriber retrieves a single subscriber
|
||||||
|
func (c *Client) GetSubscriber(imsi string) (*SubscriberAccount, error) {
|
||||||
|
var sub SubscriberAccount
|
||||||
|
if err := c.doGetJSON("/api/v1/subscribers/"+imsi, &sub); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &sub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// CreateSubscriber creates a subscriber
|
||||||
|
func (c *Client) CreateSubscriber(imsi, name string) (*SubscriberAccount, error) {
|
||||||
|
var sub SubscriberAccount
|
||||||
|
body := map[string]string{"imsi": imsi, "name": name}
|
||||||
|
if err := c.doPostJSON("/api/v1/subscribers", body, &sub); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &sub, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// DeleteSubscriber deletes a subscriber
|
||||||
|
func (c *Client) DeleteSubscriber(imsi string) error {
|
||||||
|
return c.doDelete("/api/v1/subscribers/" + imsi)
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user