mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-10-23 05:02:17 +00:00
feat: Add comprehensive CLI documentation with commands reference, configuration, and plugin system
- Add README.md with installation instructions (source, go install, binary release) - Add quick start guide with initial setup and interactive dashboard - Add global options table with help, version, verbose, no-color, format, and profile flags - Add configuration commands reference with set/get/profiles operations and options table - Add subscribers commands reference with list/show/create/update/delete operations and
This commit is contained in:
+246
-42
@@ -8,7 +8,7 @@ import (
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"github.com/nutcas3/telecom-platform/apps/cli/internal/config"
|
||||
"github.com/nutcas3/telecom-platform/apps/cli/internal/types"
|
||||
)
|
||||
|
||||
// Client represents the API client for the telecom platform
|
||||
@@ -18,8 +18,11 @@ type Client struct {
|
||||
httpClient *http.Client
|
||||
}
|
||||
|
||||
// NewClient creates a new API client
|
||||
func NewClient(cfg *config.Config) *Client {
|
||||
// NewClient creates a new API client from CLI config
|
||||
func NewClient(cfg *types.CLIConfig) *Client {
|
||||
if cfg == nil {
|
||||
cfg = &types.CLIConfig{APIEndpoint: "http://localhost:8000"}
|
||||
}
|
||||
return &Client{
|
||||
baseURL: cfg.APIEndpoint,
|
||||
apiKey: cfg.APIToken,
|
||||
@@ -29,27 +32,228 @@ func NewClient(cfg *config.Config) *Client {
|
||||
}
|
||||
}
|
||||
|
||||
// doGetJSON performs a GET request and decodes JSON into out
|
||||
func (c *Client) doGetJSON(path string, out any) error {
|
||||
req, err := http.NewRequest("GET", c.baseURL+path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.apiKey != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(body))
|
||||
}
|
||||
return json.NewDecoder(resp.Body).Decode(out)
|
||||
}
|
||||
|
||||
// doPostJSON performs a POST request with JSON body and decodes response
|
||||
func (c *Client) doPostJSON(path string, body any, out any) error {
|
||||
var buf *bytes.Buffer
|
||||
if body != nil {
|
||||
b, err := json.Marshal(body)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
buf = bytes.NewBuffer(b)
|
||||
} else {
|
||||
buf = bytes.NewBuffer(nil)
|
||||
}
|
||||
req, err := http.NewRequest("POST", c.baseURL+path, buf)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.apiKey != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||
}
|
||||
req.Header.Set("Content-Type", "application/json")
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
rb, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(rb))
|
||||
}
|
||||
if out == nil {
|
||||
return nil
|
||||
}
|
||||
return json.NewDecoder(resp.Body).Decode(out)
|
||||
}
|
||||
|
||||
// doDelete performs a DELETE request
|
||||
func (c *Client) doDelete(path string) error {
|
||||
req, err := http.NewRequest("DELETE", c.baseURL+path, nil)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if c.apiKey != "" {
|
||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||
}
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
if resp.StatusCode >= 400 {
|
||||
body, _ := io.ReadAll(resp.Body)
|
||||
return fmt.Errorf("API %s %d: %s", path, resp.StatusCode, string(body))
|
||||
}
|
||||
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"`
|
||||
}
|
||||
|
||||
// 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"`
|
||||
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"`
|
||||
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
|
||||
@@ -65,68 +269,68 @@ type Subscriber struct {
|
||||
// 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
|
||||
}
|
||||
|
||||
@@ -147,59 +351,59 @@ type GenerateInvoiceResponse struct {
|
||||
// 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)
|
||||
|
||||
|
||||
req, err := http.NewRequest("GET", url, nil)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
|
||||
|
||||
req.Header.Set("Authorization", "Bearer "+c.apiKey)
|
||||
|
||||
|
||||
resp, err := c.httpClient.Do(req)
|
||||
if err != nil {
|
||||
return false
|
||||
}
|
||||
defer resp.Body.Close()
|
||||
|
||||
|
||||
return resp.StatusCode == http.StatusOK
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user