docs: Add Go SDK README with comprehensive API documentation and implement modular architecture with authentication provider

- Add README.md with installation instructions, architecture overview, and API examples for all SDK modules
- Add AuthProvider class with API key and JWT token support (GenerateJWTToken, ValidateJWTToken, GetHeaders, ClearTokenCache methods)
- Add HTTPClient base class with retry logic, error handling, and timeout management
- Add GraphQLAPI, PaymentsAPI, RatingPlansAPI
This commit is contained in:
nutcas3
2026-04-25 04:56:33 +03:00
parent cfdbe92477
commit d846c304a4
11 changed files with 682 additions and 244 deletions
+59 -13
View File
@@ -1,9 +1,10 @@
# Telecom Platform Go SDK
Go SDK for the Telecom Platform with both HTTP and gRPC support.
Go SDK for the Telecom Platform with modular architecture for HTTP and gRPC support.
## Features
- **Modular Architecture**: Separate modules for authentication, HTTP client, and API services
- **Dual Protocol Support**: Both HTTP REST and gRPC APIs
- **Type Safety**: Strong typing with Go structs
- **Context Support**: Full context.Context support
@@ -11,6 +12,20 @@ Go SDK for the Telecom Platform with both HTTP and gRPC support.
- **Retry Logic**: Built-in retry mechanism
- **Async Operations**: Non-blocking operations
## Architecture
The SDK is organized into modular components:
- `auth.go` - Authentication provider handling API keys and JWT tokens
- `client.go` - HTTP client with retry logic and authentication
- `subscribers_api.go` - Subscriber management API
- `usage_api.go` - Usage tracking API
- `payments_api.go` - Payment processing API
- `rating_plans_api.go` - Rating plan management API
- `system_api.go` - System monitoring API
- `graphql_api.go` - GraphQL query execution
- `telecom.go` - Main client integrating all modules
## Installation
```bash
@@ -45,7 +60,7 @@ func main() {
ctx := context.Background()
// Get subscriber
subscriber, err := client.GetSubscriber(ctx, 1)
subscriber, err := client.Subscribers.Get(ctx, 1)
if err != nil {
panic(err)
}
@@ -53,7 +68,7 @@ func main() {
fmt.Printf("Subscriber: %s %s\n", subscriber.FirstName, subscriber.LastName)
// List subscribers
list, err := client.ListSubscribers(ctx, 1, 50)
list, err := client.Subscribers.List(ctx, 1, 50)
if err != nil {
panic(err)
}
@@ -119,10 +134,10 @@ config := &telecom.Config{
```go
// Get subscriber
subscriber, err := client.GetSubscriber(ctx, 1)
subscriber, err := client.Subscribers.Get(ctx, 1)
// List subscribers
list, err := client.ListSubscribers(ctx, 1, 50)
list, err := client.Subscribers.List(ctx, 1, 50, "")
// Create subscriber
req := &telecom.CreateSubscriberRequest{
@@ -133,51 +148,82 @@ req := &telecom.CreateSubscriberRequest{
Email: "[email protected]",
PlanID: 1,
}
subscriber, err := client.CreateSubscriber(ctx, req)
subscriber, err := client.Subscribers.Create(ctx, req)
// Update subscriber
updateReq := &telecom.UpdateSubscriberRequest{
FirstName: stringPtr("Jane"),
}
subscriber, err := client.UpdateSubscriber(ctx, 1, updateReq)
subscriber, err := client.Subscribers.Update(ctx, 1, updateReq)
// Delete subscriber
err := client.DeleteSubscriber(ctx, 1)
err := client.Subscribers.Delete(ctx, 1)
// Suspend subscriber
subscriber, err := client.Subscribers.Suspend(ctx, 1)
// Activate subscriber
subscriber, err := client.Subscribers.Activate(ctx, 1)
```
### Usage Management
```go
// Get usage stats
stats, err := client.GetUsageStats(ctx, 1, time.Now().AddDate(0, -1, 0), time.Now())
stats, err := client.Usage.GetStats(ctx, 1, time.Now().AddDate(0, -1, 0), time.Now())
fmt.Printf("Data usage: %d bytes\n", stats.DataUp + stats.DataDown)
// List usage events
events, err := client.Usage.ListEvents(ctx, 1, "", 1, 50)
// Get real-time usage
realtime, err := client.Usage.GetRealTime(ctx, 1)
```
### Payment Management
```go
// Create payment
// Create payment transaction
req := &telecom.CreatePaymentRequest{
SubscriberID: "1",
Amount: 25.00,
Currency: "USD",
Gateway: "stripe",
}
transaction, err := client.CreatePaymentTransaction(ctx, req)
transaction, err := client.Payments.CreateTransaction(ctx, req)
// Get transaction
transaction, err := client.Payments.GetTransaction(ctx, "txn-123")
// List transactions
transactions, err := client.Payments.ListTransactions(ctx, 1, "", 1, 50)
```
### Rating Plans
```go
// List rating plans
plans, err := client.RatingPlans.List(ctx)
// Get specific plan
plan, err := client.RatingPlans.Get(ctx, "plan-123")
```
### System Management
```go
// Get system stats
stats, err := client.GetSystemStats(ctx)
stats, err := client.System.GetStats(ctx)
fmt.Printf("Active sessions: %d\n", stats.ActiveSessions)
// Get health status
health, err := client.System.GetHealth(ctx)
```
## Error Handling
```go
subscriber, err := client.GetSubscriber(ctx, 1)
subscriber, err := client.Subscribers.Get(ctx, 1)
if err != nil {
switch {
case strings.Contains(err.Error(), "HTTP error: 401"):
+151
View File
@@ -0,0 +1,151 @@
package telecom
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"time"
)
// AuthProvider handles authentication for the Telecom SDK
type AuthProvider struct {
apiKey string
jwtSecret string
tokenCache string
tokenExpiry time.Time
}
// NewAuthProvider creates a new authentication provider
func NewAuthProvider(apiKey, jwtSecret string) *AuthProvider {
return &AuthProvider{
apiKey: apiKey,
jwtSecret: jwtSecret,
}
}
// GetHeaders returns authentication headers for API requests
func (a *AuthProvider) GetHeaders() map[string]string {
headers := map[string]string{
"Content-Type": "application/json",
"User-Agent": "Telecom-Go-SDK/1.0.0",
}
if a.apiKey != "" {
headers["X-API-Key"] = a.apiKey
}
if a.tokenCache != "" && a.isTokenValid() {
headers["Authorization"] = "Bearer " + a.tokenCache
}
return headers
}
// GenerateJWTToken generates a JWT token for authentication
func (a *AuthProvider) GenerateJWTToken(userID string, expiryHours int, additionalClaims map[string]interface{}) (string, error) {
if a.jwtSecret == "" {
return "", fmt.Errorf("JWT secret not configured")
}
now := time.Now().Unix()
claims := map[string]interface{}{
"sub": userID,
"exp": now + int64(expiryHours*3600),
"iat": now,
}
for k, v := range additionalClaims {
claims[k] = v
}
header := map[string]interface{}{
"alg": "HS256",
"typ": "JWT",
}
encodedHeader := a.base64URLEncode(header)
encodedPayload := a.base64URLEncode(claims)
signature := a.sign(encodedHeader + "." + encodedPayload)
token := encodedHeader + "." + encodedPayload + "." + signature
a.tokenCache = token
a.tokenExpiry = time.Unix(claims["exp"].(int64), 0)
return token, nil
}
// ValidateJWTToken validates a JWT token
func (a *AuthProvider) ValidateJWTToken(token string) (map[string]interface{}, error) {
if a.jwtSecret == "" {
return nil, fmt.Errorf("JWT secret not configured")
}
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid token format")
}
encodedHeader, encodedPayload, signature := parts[0], parts[1], parts[2]
expectedSignature := a.sign(encodedHeader + "." + encodedPayload)
if signature != expectedSignature {
return nil, fmt.Errorf("invalid token signature")
}
payloadBytes, err := a.base64URLDecode(encodedPayload)
if err != nil {
return nil, fmt.Errorf("failed to decode payload: %w", err)
}
var payload map[string]interface{}
if err := json.Unmarshal(payloadBytes, &payload); err != nil {
return nil, fmt.Errorf("failed to unmarshal payload: %w", err)
}
if exp, ok := payload["exp"].(float64); ok {
if float64(time.Now().Unix()) > exp {
return nil, fmt.Errorf("token has expired")
}
}
return payload, nil
}
// ClearTokenCache clears the cached JWT token
func (a *AuthProvider) ClearTokenCache() {
a.tokenCache = ""
a.tokenExpiry = time.Time{}
}
// isTokenValid checks if the cached token is still valid
func (a *AuthProvider) isTokenValid() bool {
if a.tokenCache == "" || a.tokenExpiry.IsZero() {
return false
}
return time.Now().Before(a.tokenExpiry)
}
// base64URLEncode encodes data to base64 URL-safe format
func (a *AuthProvider) base64URLEncode(data interface{}) string {
jsonBytes, _ := json.Marshal(data)
return strings.TrimRight(base64.URLEncoding.EncodeToString(jsonBytes), "=")
}
// base64URLDecode decodes base64 URL-safe format
func (a *AuthProvider) base64URLDecode(data string) ([]byte, error) {
// Add padding if needed
for len(data)%4 != 0 {
data += "="
}
return base64.URLEncoding.DecodeString(data)
}
// sign creates a HMAC-SHA256 signature
func (a *AuthProvider) sign(data string) string {
h := hmac.New(sha256.New, []byte(a.jwtSecret))
h.Write([]byte(data))
return a.base64URLEncode(h.Sum(nil))
}
+134
View File
@@ -0,0 +1,134 @@
package telecom
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// HTTPClient handles HTTP requests with authentication
type HTTPClient struct {
client *http.Client
authProvider *AuthProvider
baseURL string
timeout time.Duration
maxRetries int
retryDelay time.Duration
enableLogging bool
}
// NewHTTPClient creates a new HTTP client
func NewHTTPClient(baseURL string, authProvider *AuthProvider, timeout time.Duration, maxRetries int, retryDelay time.Duration, enableLogging bool) *HTTPClient {
return &HTTPClient{
client: &http.Client{
Timeout: timeout,
},
authProvider: authProvider,
baseURL: baseURL,
timeout: timeout,
maxRetries: maxRetries,
retryDelay: retryDelay,
enableLogging: enableLogging,
}
}
// Get makes an HTTP GET request
func (h *HTTPClient) Get(ctx context.Context, path string, result interface{}, params ...map[string]string) error {
return h.request(ctx, "GET", path, nil, result, params...)
}
// Post makes an HTTP POST request
func (h *HTTPClient) Post(ctx context.Context, path string, body, result interface{}) error {
return h.request(ctx, "POST", path, body, result)
}
// Put makes an HTTP PUT request
func (h *HTTPClient) Put(ctx context.Context, path string, body, result interface{}) error {
return h.request(ctx, "PUT", path, body, result)
}
// Delete makes an HTTP DELETE request
func (h *HTTPClient) Delete(ctx context.Context, path string) error {
return h.request(ctx, "DELETE", path, nil, nil)
}
// request makes an HTTP request with retry logic
func (h *HTTPClient) request(ctx context.Context, method, path string, body, result interface{}, params ...map[string]string) error {
var lastErr error
for attempt := 0; attempt <= h.maxRetries; attempt++ {
var bodyBytes []byte
var err error
if body != nil {
bodyBytes, err = json.Marshal(body)
if err != nil {
return fmt.Errorf("failed to marshal body: %w", err)
}
}
req, err := http.NewRequestWithContext(ctx, method, h.baseURL+path, bytes.NewReader(bodyBytes))
if err != nil {
return fmt.Errorf("failed to create request: %w", err)
}
// Set headers
headers := h.authProvider.GetHeaders()
for k, v := range headers {
req.Header.Set(k, v)
}
// Add query parameters
if len(params) > 0 {
q := req.URL.Query()
for k, v := range params[0] {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := h.client.Do(req)
if err != nil {
lastErr = err
if attempt == h.maxRetries {
return fmt.Errorf("request failed after %d retries: %w", h.maxRetries, err)
}
time.Sleep(h.retryDelay * time.Duration(1<<uint(attempt)))
continue
}
defer resp.Body.Close()
if resp.StatusCode == http.StatusUnauthorized {
return fmt.Errorf("authentication failed")
}
if resp.StatusCode == http.StatusTooManyRequests {
return fmt.Errorf("rate limit exceeded")
}
if resp.StatusCode >= 400 && resp.StatusCode < 500 {
var errorResp map[string]interface{}
json.NewDecoder(resp.Body).Decode(&errorResp)
return fmt.Errorf("API error: %v", errorResp)
}
if resp.StatusCode >= 500 {
return fmt.Errorf("server error: %d", resp.StatusCode)
}
if result != nil {
if err := json.NewDecoder(resp.Body).Decode(result); err != nil {
return fmt.Errorf("failed to decode response: %w", err)
}
}
return nil
}
return lastErr
}
// Close closes the HTTP client
func (h *HTTPClient) Close() error {
return nil
}
+29
View File
@@ -0,0 +1,29 @@
package telecom
import (
"context"
)
// GraphQLAPI handles GraphQL API calls
type GraphQLAPI struct {
client *HTTPClient
}
// NewGraphQLAPI creates a new GraphQLAPI
func NewGraphQLAPI(client *HTTPClient) *GraphQLAPI {
return &GraphQLAPI{client: client}
}
// Execute executes a GraphQL query
func (g *GraphQLAPI) Execute(ctx context.Context, query string, variables map[string]interface{}) (map[string]interface{}, error) {
data := map[string]interface{}{
"query": query,
}
if variables != nil {
data["variables"] = variables
}
var result map[string]interface{}
err := g.client.Post(ctx, "/graphql", data, &result)
return result, err
}
+49
View File
@@ -0,0 +1,49 @@
package telecom
import (
"context"
"fmt"
)
// PaymentAPI handles payment-related API calls
type PaymentAPI struct {
client *HTTPClient
}
// NewPaymentAPI creates a new PaymentAPI
func NewPaymentAPI(client *HTTPClient) *PaymentAPI {
return &PaymentAPI{client: client}
}
// CreateTransaction creates a new payment transaction
func (p *PaymentAPI) CreateTransaction(ctx context.Context, req *CreatePaymentRequest) (*PaymentTransaction, error) {
var transaction PaymentTransaction
err := p.client.Post(ctx, "/v1/payments/transactions", req, &transaction)
return &transaction, err
}
// GetTransaction retrieves a payment transaction by ID
func (p *PaymentAPI) GetTransaction(ctx context.Context, transactionID string) (*PaymentTransaction, error) {
var transaction PaymentTransaction
err := p.client.Get(ctx, fmt.Sprintf("/v1/payments/transactions/%s", transactionID), &transaction)
return &transaction, err
}
// ListTransactions retrieves a list of payment transactions
func (p *PaymentAPI) ListTransactions(ctx context.Context, subscriberID int64, status string, page, pageSize int32) (*SubscriberList, error) {
params := map[string]string{
"page": fmt.Sprintf("%d", page),
"page_size": fmt.Sprintf("%d", pageSize),
}
if subscriberID > 0 {
params["subscriber_id"] = fmt.Sprintf("%d", subscriberID)
}
if status != "" {
params["status"] = status
}
var list SubscriberList
err := p.client.Get(ctx, "/v1/payments/transactions", &list, params)
return &list, err
}
+30
View File
@@ -0,0 +1,30 @@
package telecom
import (
"context"
"fmt"
)
// RatingPlanAPI handles rating plan-related API calls
type RatingPlanAPI struct {
client *HTTPClient
}
// NewRatingPlanAPI creates a new RatingPlanAPI
func NewRatingPlanAPI(client *HTTPClient) *RatingPlanAPI {
return &RatingPlanAPI{client: client}
}
// List retrieves all available rating plans
func (r *RatingPlanAPI) List(ctx context.Context) ([]RatingPlan, error) {
var plans []RatingPlan
err := r.client.Get(ctx, "/v1/rating-plans", &plans)
return plans, err
}
// Get retrieves a rating plan by ID
func (r *RatingPlanAPI) Get(ctx context.Context, planID string) (*RatingPlan, error) {
var plan RatingPlan
err := r.client.Get(ctx, fmt.Sprintf("/v1/rating-plans/%s", planID), &plan)
return &plan, err
}
+71
View File
@@ -0,0 +1,71 @@
package telecom
import (
"context"
"fmt"
)
// SubscriberAPI handles subscriber-related API calls
type SubscriberAPI struct {
client *HTTPClient
}
// NewSubscriberAPI creates a new SubscriberAPI
func NewSubscriberAPI(client *HTTPClient) *SubscriberAPI {
return &SubscriberAPI{client: client}
}
// Get retrieves a subscriber by ID
func (s *SubscriberAPI) Get(ctx context.Context, id int64) (*Subscriber, error) {
var subscriber Subscriber
err := s.client.Get(ctx, fmt.Sprintf("/v1/subscribers/%d", id), &subscriber)
return &subscriber, err
}
// List retrieves a list of subscribers
func (s *SubscriberAPI) List(ctx context.Context, page, pageSize int32, status string) (*SubscriberList, error) {
params := map[string]string{
"page": fmt.Sprintf("%d", page),
"page_size": fmt.Sprintf("%d", pageSize),
}
if status != "" {
params["status"] = status
}
var list SubscriberList
err := s.client.Get(ctx, "/v1/subscribers", &list, params)
return &list, err
}
// Create creates a new subscriber
func (s *SubscriberAPI) Create(ctx context.Context, req *CreateSubscriberRequest) (*Subscriber, error) {
var subscriber Subscriber
err := s.client.Post(ctx, "/v1/subscribers", req, &subscriber)
return &subscriber, err
}
// Update updates an existing subscriber
func (s *SubscriberAPI) Update(ctx context.Context, id int64, req *UpdateSubscriberRequest) (*Subscriber, error) {
var subscriber Subscriber
err := s.client.Put(ctx, fmt.Sprintf("/v1/subscribers/%d", id), req, &subscriber)
return &subscriber, err
}
// Delete deletes a subscriber
func (s *SubscriberAPI) Delete(ctx context.Context, id int64) error {
return s.client.Delete(ctx, fmt.Sprintf("/v1/subscribers/%d", id))
}
// Suspend suspends a subscriber
func (s *SubscriberAPI) Suspend(ctx context.Context, id int64) (*Subscriber, error) {
var subscriber Subscriber
err := s.client.Post(ctx, fmt.Sprintf("/v1/subscribers/%d/suspend", id), nil, &subscriber)
return &subscriber, err
}
// Activate activates a suspended subscriber
func (s *SubscriberAPI) Activate(ctx context.Context, id int64) (*Subscriber, error) {
var subscriber Subscriber
err := s.client.Post(ctx, fmt.Sprintf("/v1/subscribers/%d/activate", id), nil, &subscriber)
return &subscriber, err
}
+29
View File
@@ -0,0 +1,29 @@
package telecom
import (
"context"
)
// SystemAPI handles system-related API calls
type SystemAPI struct {
client *HTTPClient
}
// NewSystemAPI creates a new SystemAPI
func NewSystemAPI(client *HTTPClient) *SystemAPI {
return &SystemAPI{client: client}
}
// GetStats retrieves system statistics
func (s *SystemAPI) GetStats(ctx context.Context) (*SystemStats, error) {
var stats SystemStats
err := s.client.Get(ctx, "/v1/system/stats", &stats)
return &stats, err
}
// GetHealth retrieves system health status
func (s *SystemAPI) GetHealth(ctx context.Context) (*HealthStatus, error) {
var health HealthStatus
err := s.client.Get(ctx, "/v1/health", &health)
return &health, err
}
+59 -231
View File
@@ -1,44 +1,45 @@
package telecom
import (
"bytes"
"context"
"encoding/json"
"fmt"
"net/http"
"time"
)
// Client represents the Telecom Platform SDK client
type Client struct {
config *Config
httpClient *HTTPClient
config *Config
authProvider *AuthProvider
httpClient *HTTPClient
// API modules
Subscribers *SubscriberAPI
Usage *UsageAPI
Payments *PaymentAPI
RatingPlans *RatingPlanAPI
System *SystemAPI
GraphQL *GraphQLAPI
}
// Config holds the SDK configuration
type Config struct {
APIURL string
APIKey string
Timeout time.Duration
Retries int
EnableHTTP bool
}
// HTTPClient handles HTTP requests
type HTTPClient struct {
client *http.Client
apiKey string
baseURL string
APIURL string
APIKey string
JWTSecret string
Timeout time.Duration
MaxRetries int
RetryDelay time.Duration
EnableHTTP bool
EnableLogging bool
}
// DefaultConfig returns a default configuration
func DefaultConfig() *Config {
return &Config{
APIURL: "http://localhost:8000",
APIKey: "",
Timeout: 30 * time.Second,
Retries: 3,
EnableHTTP: true,
APIURL: "http://localhost:8000",
Timeout: 30 * time.Second,
MaxRetries: 3,
RetryDelay: 1 * time.Second,
EnableHTTP: true,
EnableLogging: false,
}
}
@@ -48,226 +49,53 @@ func NewClient(config *Config) (*Client, error) {
config = DefaultConfig()
}
client := &Client{
config: config,
authProvider := NewAuthProvider(config.APIKey, config.JWTSecret)
var httpClient *HTTPClient
if config.EnableHTTP {
httpClient = NewHTTPClient(
config.APIURL,
authProvider,
config.Timeout,
config.MaxRetries,
config.RetryDelay,
config.EnableLogging,
)
}
// Initialize HTTP client
if config.EnableHTTP {
client.httpClient = &HTTPClient{
client: &http.Client{
Timeout: config.Timeout,
},
apiKey: config.APIKey,
baseURL: config.APIURL,
}
client := &Client{
config: config,
authProvider: authProvider,
httpClient: httpClient,
}
// Initialize API modules
client.Subscribers = NewSubscriberAPI(httpClient)
client.Usage = NewUsageAPI(httpClient)
client.Payments = NewPaymentAPI(httpClient)
client.RatingPlans = NewRatingPlanAPI(httpClient)
client.System = NewSystemAPI(httpClient)
client.GraphQL = NewGraphQLAPI(httpClient)
return client, nil
}
// Close closes the client connections
func (c *Client) Close() error {
if c.httpClient != nil {
return c.httpClient.Close()
}
return nil
}
// HTTP Methods
// Authentication methods
// GetSubscriber retrieves a subscriber by ID
func (c *Client) GetSubscriber(ctx context.Context, id int64) (*Subscriber, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
var subscriber Subscriber
err := c.httpClient.Get(ctx, fmt.Sprintf("/v1/subscribers/%d", id), &subscriber)
return &subscriber, err
// GenerateJWTToken generates a JWT token for authentication
func (c *Client) GenerateJWTToken(userID string, expiryHours int, additionalClaims map[string]interface{}) (string, error) {
return c.authProvider.GenerateJWTToken(userID, expiryHours, additionalClaims)
}
// ListSubscribers retrieves a list of subscribers
func (c *Client) ListSubscribers(ctx context.Context, page, pageSize int32) (*SubscriberList, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
params := map[string]string{
"page": fmt.Sprintf("%d", page),
"page_size": fmt.Sprintf("%d", pageSize),
}
var list SubscriberList
err := c.httpClient.Get(ctx, "/v1/subscribers", &list, params)
return &list, err
}
// CreateSubscriber creates a new subscriber
func (c *Client) CreateSubscriber(ctx context.Context, req *CreateSubscriberRequest) (*Subscriber, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
var subscriber Subscriber
err := c.httpClient.Post(ctx, "/v1/subscribers", req, &subscriber)
return &subscriber, err
}
// UpdateSubscriber updates an existing subscriber
func (c *Client) UpdateSubscriber(ctx context.Context, id int64, req *UpdateSubscriberRequest) (*Subscriber, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
var subscriber Subscriber
err := c.httpClient.Put(ctx, fmt.Sprintf("/v1/subscribers/%d", id), req, &subscriber)
return &subscriber, err
}
// DeleteSubscriber deletes a subscriber
func (c *Client) DeleteSubscriber(ctx context.Context, id int64) error {
if !c.config.EnableHTTP {
return fmt.Errorf("HTTP client not enabled")
}
return c.httpClient.Delete(ctx, fmt.Sprintf("/v1/subscribers/%d", id))
}
// GetUsageStats retrieves usage statistics for a subscriber
func (c *Client) GetUsageStats(ctx context.Context, subscriberID int64, startDate, endDate time.Time) (*UsageStats, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
params := map[string]string{
"start_date": startDate.Format(time.RFC3339),
"end_date": endDate.Format(time.RFC3339),
}
var stats UsageStats
err := c.httpClient.Get(ctx, fmt.Sprintf("/v1/subscribers/%d/usage", subscriberID), &stats, params)
return &stats, err
}
// CreatePaymentTransaction creates a new payment transaction
func (c *Client) CreatePaymentTransaction(ctx context.Context, req *CreatePaymentRequest) (*PaymentTransaction, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
var transaction PaymentTransaction
err := c.httpClient.Post(ctx, "/v1/payments/transactions", req, &transaction)
return &transaction, err
}
// GetSystemStats retrieves system statistics
func (c *Client) GetSystemStats(ctx context.Context) (*SystemStats, error) {
if !c.config.EnableHTTP {
return nil, fmt.Errorf("HTTP client not enabled")
}
var stats SystemStats
err := c.httpClient.Get(ctx, "/v1/system/stats", &stats)
return &stats, err
}
// HTTPClient implementation
// Get makes an HTTP GET request
func (h *HTTPClient) Get(ctx context.Context, path string, result interface{}, params ...map[string]string) error {
req, err := http.NewRequestWithContext(ctx, "GET", h.baseURL+path, nil)
if err != nil {
return err
}
if h.apiKey != "" {
req.Header.Set("Authorization", "Bearer "+h.apiKey)
}
if len(params) > 0 {
q := req.URL.Query()
for k, v := range params[0] {
q.Add(k, v)
}
req.URL.RawQuery = q.Encode()
}
resp, err := h.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP error: %d", resp.StatusCode)
}
return json.NewDecoder(resp.Body).Decode(result)
}
// Post makes an HTTP POST request
func (h *HTTPClient) Post(ctx context.Context, path string, body, result interface{}) error {
return h.doRequest(ctx, "POST", path, body, result)
}
// Put makes an HTTP PUT request
func (h *HTTPClient) Put(ctx context.Context, path string, body, result interface{}) error {
return h.doRequest(ctx, "PUT", path, body, result)
}
// Delete makes an HTTP DELETE request
func (h *HTTPClient) Delete(ctx context.Context, path string) error {
req, err := http.NewRequestWithContext(ctx, "DELETE", h.baseURL+path, nil)
if err != nil {
return err
}
if h.apiKey != "" {
req.Header.Set("Authorization", "Bearer "+h.apiKey)
}
resp, err := h.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK && resp.StatusCode != http.StatusNoContent {
return fmt.Errorf("HTTP error: %d", resp.StatusCode)
}
return nil
}
// doRequest makes an HTTP request with a body
func (h *HTTPClient) doRequest(ctx context.Context, method, path string, body, result interface{}) error {
var bodyBytes []byte
var err error
if body != nil {
bodyBytes, err = json.Marshal(body)
if err != nil {
return err
}
}
req, err := http.NewRequestWithContext(ctx, method, h.baseURL+path, bytes.NewReader(bodyBytes))
if err != nil {
return err
}
if h.apiKey != "" {
req.Header.Set("Authorization", "Bearer "+h.apiKey)
}
req.Header.Set("Content-Type", "application/json")
resp, err := h.client.Do(req)
if err != nil {
return err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return fmt.Errorf("HTTP error: %d", resp.StatusCode)
}
return json.NewDecoder(resp.Body).Decode(result)
// ValidateJWTToken validates a JWT token
func (c *Client) ValidateJWTToken(token string) (map[string]interface{}, error) {
return c.authProvider.ValidateJWTToken(token)
}
+61
View File
@@ -0,0 +1,61 @@
package telecom
import (
"context"
"fmt"
"time"
)
// UsageAPI handles usage-related API calls
type UsageAPI struct {
client *HTTPClient
}
// NewUsageAPI creates a new UsageAPI
func NewUsageAPI(client *HTTPClient) *UsageAPI {
return &UsageAPI{client: client}
}
// GetStats retrieves usage statistics for a subscriber
func (u *UsageAPI) GetStats(ctx context.Context, subscriberID int64, startDate, endDate time.Time) (*UsageStats, error) {
params := map[string]string{
"start_date": startDate.Format(time.RFC3339),
"end_date": endDate.Format(time.RFC3339),
}
var stats UsageStats
err := u.client.Get(ctx, fmt.Sprintf("/v1/subscribers/%d/usage", subscriberID), &stats, params)
return &stats, err
}
// ListEvents retrieves a list of usage events
func (u *UsageAPI) ListEvents(ctx context.Context, subscriberID int64, usageType string, startDate, endDate time.Time, page, pageSize int32) (*UsageEventList, error) {
params := map[string]string{
"page": fmt.Sprintf("%d", page),
"page_size": fmt.Sprintf("%d", pageSize),
}
if subscriberID > 0 {
params["subscriber_id"] = fmt.Sprintf("%d", subscriberID)
}
if usageType != "" {
params["usage_type"] = usageType
}
if !startDate.IsZero() {
params["start_date"] = startDate.Format(time.RFC3339)
}
if !endDate.IsZero() {
params["end_date"] = endDate.Format(time.RFC3339)
}
var list UsageEventList
err := u.client.Get(ctx, "/v1/usage/events", &list, params)
return &list, err
}
// GetRealtime retrieves real-time usage for a subscriber
func (u *UsageAPI) GetRealtime(ctx context.Context, subscriberID int64) (*RealTimeUsage, error) {
var usage RealTimeUsage
err := u.client.Get(ctx, fmt.Sprintf("/v1/subscribers/%d/realtime", subscriberID), &usage)
return &usage, err
}
+10
View File
@@ -4,6 +4,7 @@ Async Python SDK for the Telecom Platform with full type hints and modern async/
## Features
- **Modular Architecture**: Separate modules for authentication, API clients, and WebSocket
- **Async/Await Support**: Full async/await support with aiohttp
- **Type Safety**: Complete type hints with Pydantic models
- **WebSocket Support**: Real-time updates via WebSocket
@@ -32,6 +33,15 @@ pip install -r requirements.txt
pip install -e .
```
## Architecture
The SDK is organized into modular components:
- `auth.py` - Authentication provider handling API keys and JWT tokens
- `api.py` - Main API client with HTTP request handling and retry logic
- `websocket.py` - WebSocket client for real-time updates
- `types.py` - Type definitions and Pydantic models
## Quick Start
```python