From bd3226edf042c3e70cf567cfdffd7073d7cbd649 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Sat, 25 Apr 2026 05:33:41 +0300 Subject: [PATCH] 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 --- apps/cli/internal/api/billing.go | 155 +++++++++ apps/cli/internal/api/carrier.go | 70 +++++ apps/cli/internal/api/charging.go | 64 ++++ apps/cli/internal/api/client.go | 448 --------------------------- apps/cli/internal/api/monitoring.go | 62 ++++ apps/cli/internal/api/packet.go | 34 ++ apps/cli/internal/api/services.go | 27 ++ apps/cli/internal/api/subscribers.go | 54 ++++ 8 files changed, 466 insertions(+), 448 deletions(-) create mode 100644 apps/cli/internal/api/billing.go create mode 100644 apps/cli/internal/api/carrier.go create mode 100644 apps/cli/internal/api/charging.go create mode 100644 apps/cli/internal/api/monitoring.go create mode 100644 apps/cli/internal/api/packet.go create mode 100644 apps/cli/internal/api/services.go create mode 100644 apps/cli/internal/api/subscribers.go diff --git a/apps/cli/internal/api/billing.go b/apps/cli/internal/api/billing.go new file mode 100644 index 0000000..ec9ab20 --- /dev/null +++ b/apps/cli/internal/api/billing.go @@ -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 +} diff --git a/apps/cli/internal/api/carrier.go b/apps/cli/internal/api/carrier.go new file mode 100644 index 0000000..83445a5 --- /dev/null +++ b/apps/cli/internal/api/carrier.go @@ -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) +} diff --git a/apps/cli/internal/api/charging.go b/apps/cli/internal/api/charging.go new file mode 100644 index 0000000..45e53f5 --- /dev/null +++ b/apps/cli/internal/api/charging.go @@ -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 +} diff --git a/apps/cli/internal/api/client.go b/apps/cli/internal/api/client.go index 1c6832d..35bfc89 100644 --- a/apps/cli/internal/api/client.go +++ b/apps/cli/internal/api/client.go @@ -115,289 +115,6 @@ func (c *Client) doDelete(path string) error { 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 func (c *Client) IsConnected() bool { url := fmt.Sprintf("%s/health", c.baseURL) @@ -417,168 +134,3 @@ func (c *Client) IsConnected() bool { 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 -} diff --git a/apps/cli/internal/api/monitoring.go b/apps/cli/internal/api/monitoring.go new file mode 100644 index 0000000..472dead --- /dev/null +++ b/apps/cli/internal/api/monitoring.go @@ -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 +} diff --git a/apps/cli/internal/api/packet.go b/apps/cli/internal/api/packet.go new file mode 100644 index 0000000..35ef1e1 --- /dev/null +++ b/apps/cli/internal/api/packet.go @@ -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 +} diff --git a/apps/cli/internal/api/services.go b/apps/cli/internal/api/services.go new file mode 100644 index 0000000..3c26ab4 --- /dev/null +++ b/apps/cli/internal/api/services.go @@ -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 +} diff --git a/apps/cli/internal/api/subscribers.go b/apps/cli/internal/api/subscribers.go new file mode 100644 index 0000000..487e29e --- /dev/null +++ b/apps/cli/internal/api/subscribers.go @@ -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) +}