From d114f1960f67ccf323fca81eec02765a4d7865f7 Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Thu, 23 Apr 2026 02:56:24 +0300 Subject: [PATCH] refactor: Replace interface{} with any alias and optimize string formatting with fmt.Appendf - Replace map[string]interface{} with map[string]any in GraphQL, metrics, payment gateway, and webhook handlers - Replace []byte(fmt.Sprintf()) with fmt.Appendf(nil, ...) for cursor encoding in GraphQL resolvers and tests - Replace strings.HasPrefix/TrimPrefix with strings.CutPrefix for webhook signature parsing - Replace stripe.Int64/Bool with new() constructor for Stripe payment parameters - Rename Error --- apps/api-server/internal/graphql/generated.go | 4 +- apps/api-server/internal/graphql/resolvers.go | 12 ++--- .../internal/graphql/resolvers_test.go | 2 +- .../internal/handlers/subscriber.go | 3 +- .../api-server/internal/metrics/timeseries.go | 14 +++--- apps/api-server/internal/payment/gateway.go | 48 +++++++++---------- .../internal/payment/gateways/stripe.go | 10 ++-- apps/api-server/internal/payment/webhook.go | 22 ++++----- 8 files changed, 58 insertions(+), 57 deletions(-) diff --git a/apps/api-server/internal/graphql/generated.go b/apps/api-server/internal/graphql/generated.go index 7d82700..18ca3af 100644 --- a/apps/api-server/internal/graphql/generated.go +++ b/apps/api-server/internal/graphql/generated.go @@ -370,6 +370,6 @@ func (e *executableSchema) Exec(ctx context.Context) graphql.ResponseHandler { return nil } -func (e *executableSchema) Extensions() map[string]interface{} { - return map[string]interface{}{} +func (e *executableSchema) Extensions() map[string]any { + return map[string]any{} } diff --git a/apps/api-server/internal/graphql/resolvers.go b/apps/api-server/internal/graphql/resolvers.go index 493f7e9..77c95c4 100644 --- a/apps/api-server/internal/graphql/resolvers.go +++ b/apps/api-server/internal/graphql/resolvers.go @@ -54,8 +54,8 @@ func strPtr(s string) *string { return new(s) } func buildConnectionPageInfo(offset, count int, total int64) *PageInfo { var startCursor, endCursor *string if count > 0 { - startCursor = strPtr(base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+1)))) - endCursor = strPtr(base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+count)))) + startCursor = strPtr(base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+1))) + endCursor = strPtr(base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+count))) } return &PageInfo{ HasNextPage: int64(offset+count) < total, @@ -104,7 +104,7 @@ func (r *Resolver) Subscribers(ctx context.Context, first *int, after *string, f s := sub // avoid loop-variable capture edges[i] = &SubscriberEdge{ Node: &s, - Cursor: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+i+1))), + Cursor: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+i+1)), } } @@ -143,7 +143,7 @@ func (r *Resolver) UsageEvents(ctx context.Context, first *int, after *string, i for i, event := range events { edges[i] = &UsageEventEdge{ Node: event, - Cursor: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+i+1))), + Cursor: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+i+1)), } } @@ -225,7 +225,7 @@ func (r *Resolver) Invoices(ctx context.Context, first *int, after *string, imsi for i, inv := range invoices { edges[i] = &InvoiceEdge{ Node: inv, - Cursor: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+i+1))), + Cursor: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+i+1)), } } @@ -271,7 +271,7 @@ func (r *Resolver) Alerts(ctx context.Context, first *int, after *string, subscr for i, alert := range alerts { edges[i] = &AlertEdge{ Node: alert, - Cursor: base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("%d", offset+i+1))), + Cursor: base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "%d", offset+i+1)), } } diff --git a/apps/api-server/internal/graphql/resolvers_test.go b/apps/api-server/internal/graphql/resolvers_test.go index 4969341..5bacf5b 100644 --- a/apps/api-server/internal/graphql/resolvers_test.go +++ b/apps/api-server/internal/graphql/resolvers_test.go @@ -118,7 +118,7 @@ func TestResolverRoot_Methods(t *testing.T) { // Helper functions for testing (these should match the implementations in resolvers.go) func encodeCursor(offset int) string { - return base64.StdEncoding.EncodeToString([]byte(fmt.Sprintf("cursor:%d", offset))) + return base64.StdEncoding.EncodeToString(fmt.Appendf(nil, "cursor:%d", offset)) } func decodeCursor(cursor string) (int, error) { diff --git a/apps/api-server/internal/handlers/subscriber.go b/apps/api-server/internal/handlers/subscriber.go index e3d55be..5f346d9 100644 --- a/apps/api-server/internal/handlers/subscriber.go +++ b/apps/api-server/internal/handlers/subscriber.go @@ -264,7 +264,8 @@ func (h *SubscriberHandler) TerminateSubscriber(c *gin.Context) { } // ErrorResponse represents an API error response -type ErrorResponse struct { +type SubscriberErrorResponse struct { Error string `json:"error"` + Code string `json:"code"` Details string `json:"details,omitempty"` } diff --git a/apps/api-server/internal/metrics/timeseries.go b/apps/api-server/internal/metrics/timeseries.go index 8199d68..d6f8897 100644 --- a/apps/api-server/internal/metrics/timeseries.go +++ b/apps/api-server/internal/metrics/timeseries.go @@ -79,7 +79,7 @@ func (ts *TimeSeriesStorage) StoreUsageMetrics(ctx context.Context, metrics Usag "subscriber_id": metrics.SubscriberID, "imsi": metrics.IMSI, }, - map[string]interface{}{ + map[string]any{ "data_up": metrics.DataUp, "data_down": metrics.DataDown, "voice_seconds": metrics.VoiceSeconds, @@ -96,7 +96,7 @@ func (ts *TimeSeriesStorage) StoreSystemMetrics(ctx context.Context, metrics Sys point := influxdb2.NewPoint( "system", map[string]string{}, - map[string]interface{}{ + map[string]any{ "active_sessions": metrics.ActiveSessions, "cpu_usage": metrics.CPUUsage, "memory_usage": metrics.MemoryUsage, @@ -119,7 +119,7 @@ func (ts *TimeSeriesStorage) StoreChargingMetrics(ctx context.Context, metrics C "currency": metrics.Currency, "status": metrics.Status, }, - map[string]interface{}{ + map[string]any{ "balance": metrics.Balance, "amount": metrics.Amount, }, @@ -136,7 +136,7 @@ func (ts *TimeSeriesStorage) StorePacketMetrics(ctx context.Context, subscriberI map[string]string{ "subscriber_id": subscriberID, }, - map[string]interface{}{ + map[string]any{ "packets_processed": packetsProcessed, "packets_dropped": packetsDropped, "bytes_processed": bytesProcessed, @@ -295,7 +295,7 @@ func (ts *TimeSeriesStorage) GetChargingHistory(ctx context.Context, subscriberI } // GetTopDataUsers retrieves top data users for a time period -func (ts *TimeSeriesStorage) GetTopDataUsers(ctx context.Context, start, end time.Time, limit int) ([]map[string]interface{}, error) { +func (ts *TimeSeriesStorage) GetTopDataUsers(ctx context.Context, start, end time.Time, limit int) ([]map[string]any, error) { query := fmt.Sprintf(` from(bucket: "%s") |> range(start: %s, stop: %s) @@ -312,10 +312,10 @@ func (ts *TimeSeriesStorage) GetTopDataUsers(ctx context.Context, start, end tim return nil, fmt.Errorf("failed to query top data users: %w", err) } - var users []map[string]interface{} + var users []map[string]any for result.Next() { record := result.Record() - user := map[string]interface{}{ + user := map[string]any{ "subscriber_id": record.ValueByKey("subscriber_id"), "total_data": record.ValueByKey("total_data"), "data_up": record.ValueByKey("data_up"), diff --git a/apps/api-server/internal/payment/gateway.go b/apps/api-server/internal/payment/gateway.go index ac4e5f8..6172f7f 100644 --- a/apps/api-server/internal/payment/gateway.go +++ b/apps/api-server/internal/payment/gateway.go @@ -179,7 +179,7 @@ func (s *StripeGateway) ProcessPayment(ctx context.Context, req *PaymentRequest) return nil, fmt.Errorf("failed to create payment intent: %w", err) } - intent, ok := intentResp.(map[string]interface{}) + intent, ok := intentResp.(map[string]any) if !ok { return nil, fmt.Errorf("invalid payment intent response") } @@ -188,7 +188,7 @@ func (s *StripeGateway) ProcessPayment(ctx context.Context, req *PaymentRequest) var failureReason *string if status == PaymentStatusFailed { - if lastPaymentError, ok := intent["last_payment_error"].(map[string]interface{}); ok { + if lastPaymentError, ok := intent["last_payment_error"].(map[string]any); ok { if message, ok := lastPaymentError["message"].(string); ok { failureReason = &message } @@ -197,8 +197,8 @@ func (s *StripeGateway) ProcessPayment(ctx context.Context, req *PaymentRequest) var redirectURL *string if status == PaymentStatusPending { - if nextAction, ok := intent["next_action"].(map[string]interface{}); ok { - if url, ok := nextAction["redirect_to_url"].(map[string]interface{}); ok { + if nextAction, ok := intent["next_action"].(map[string]any); ok { + if url, ok := nextAction["redirect_to_url"].(map[string]any); ok { if redirect, ok := url["url"].(string); ok { redirectURL = &redirect } @@ -220,7 +220,7 @@ func (s *StripeGateway) ProcessPayment(ctx context.Context, req *PaymentRequest) // RefundPayment refunds a payment via Stripe func (s *StripeGateway) RefundPayment(ctx context.Context, transactionID string, amount float64) (*RefundResponse, error) { - refundData := map[string]interface{}{ + refundData := map[string]any{ "payment_intent": transactionID, "amount": int64(amount * 100), // Stripe uses cents } @@ -230,7 +230,7 @@ func (s *StripeGateway) RefundPayment(ctx context.Context, transactionID string, return nil, fmt.Errorf("failed to create refund: %w", err) } - refund, ok := refundResp.(map[string]interface{}) + refund, ok := refundResp.(map[string]any) if !ok { return nil, fmt.Errorf("invalid refund response") } @@ -262,7 +262,7 @@ func (s *StripeGateway) GetPaymentStatus(ctx context.Context, transactionID stri return nil, fmt.Errorf("failed to get payment intent: %w", err) } - intent, ok := intentResp.(map[string]interface{}) + intent, ok := intentResp.(map[string]any) if !ok { return nil, fmt.Errorf("invalid payment intent response") } @@ -273,12 +273,12 @@ func (s *StripeGateway) GetPaymentStatus(ctx context.Context, transactionID stri return nil, fmt.Errorf("failed to get refunds: %w", err) } - refundsData, _ := refundsResp.(map[string]interface{}) - refundsList, _ := refundsData["data"].([]interface{}) + refundsData, _ := refundsResp.(map[string]any) + refundsList, _ := refundsData["data"].([]any) refunds := make([]RefundInfo, len(refundsList)) for i, refundInterface := range refundsList { - refund, _ := refundInterface.(map[string]interface{}) + refund, _ := refundInterface.(map[string]any) createdAt, _ := time.Parse(time.RFC3339, refund["created"].(string)) refunds[i] = RefundInfo{ RefundID: refund["id"].(string), @@ -291,7 +291,7 @@ func (s *StripeGateway) GetPaymentStatus(ctx context.Context, transactionID stri createdAt, _ := time.Parse(time.RFC3339, intent["created"].(string)) var failureReason *string - if lastPaymentError, ok := intent["last_payment_error"].(map[string]interface{}); ok { + if lastPaymentError, ok := intent["last_payment_error"].(map[string]any); ok { if message, ok := lastPaymentError["message"].(string); ok { failureReason = &message } @@ -311,7 +311,7 @@ func (s *StripeGateway) GetPaymentStatus(ctx context.Context, transactionID stri // CreatePaymentMethod creates a payment method in Stripe func (s *StripeGateway) CreatePaymentMethod(ctx context.Context, req *CreatePaymentMethodRequest) (*PaymentMethod, error) { - pmData := map[string]interface{}{ + pmData := map[string]any{ "type": s.mapPaymentMethodType(req.Type), "card": map[string]string{ "token": req.Token, @@ -324,13 +324,13 @@ func (s *StripeGateway) CreatePaymentMethod(ctx context.Context, req *CreatePaym return nil, fmt.Errorf("failed to create payment method: %w", err) } - pm, ok := pmResp.(map[string]interface{}) + pm, ok := pmResp.(map[string]any) if !ok { return nil, fmt.Errorf("invalid payment method response") } // Attach payment method to customer - attachData := map[string]interface{}{ + attachData := map[string]any{ "customer": req.CustomerID, } _, err = s.makeStripeRequest(ctx, "POST", "/v1/payment_methods/"+pm["id"].(string)+"/attach", attachData) @@ -340,7 +340,7 @@ func (s *StripeGateway) CreatePaymentMethod(ctx context.Context, req *CreatePaym // Set as default if requested if req.IsDefault { - customerData := map[string]interface{}{ + customerData := map[string]any{ "invoice_settings": map[string]string{ "default_payment_method": pm["id"].(string), }, @@ -351,7 +351,7 @@ func (s *StripeGateway) CreatePaymentMethod(ctx context.Context, req *CreatePaym } } - card, _ := pm["card"].(map[string]interface{}) + card, _ := pm["card"].(map[string]any) createdAt, _ := time.Parse(time.RFC3339, pm["created"].(string)) return &PaymentMethod{ @@ -388,10 +388,10 @@ func (s *StripeGateway) ValidateWebhook(ctx context.Context, signature string, b var timestamp, v1Signature string for _, part := range parts { part = strings.TrimSpace(part) - if strings.HasPrefix(part, "t=") { - timestamp = strings.TrimPrefix(part, "t=") - } else if strings.HasPrefix(part, "v1=") { - v1Signature = strings.TrimPrefix(part, "v1=") + if after, ok := strings.CutPrefix(part, "t="); ok { + timestamp = after + } else if after, ok := strings.CutPrefix(part, "v1="); ok { + v1Signature = after } } @@ -406,7 +406,7 @@ func (s *StripeGateway) ValidateWebhook(ctx context.Context, signature string, b } // Helper methods -func (s *StripeGateway) makeStripeRequest(ctx context.Context, method, path string, data interface{}) (interface{}, error) { +func (s *StripeGateway) makeStripeRequest(ctx context.Context, method, path string, data any) (any, error) { url := "https://api.stripe.com" + path var body io.Reader @@ -439,9 +439,9 @@ func (s *StripeGateway) makeStripeRequest(ctx context.Context, method, path stri } if resp.StatusCode >= 400 { - var errorResp map[string]interface{} + var errorResp map[string]any if err := json.Unmarshal(respBody, &errorResp); err == nil { - if errorMsg, ok := errorResp["error"].(map[string]interface{}); ok { + if errorMsg, ok := errorResp["error"].(map[string]any); ok { if message, ok := errorMsg["message"].(string); ok { return nil, fmt.Errorf("stripe error: %s", message) } @@ -450,7 +450,7 @@ func (s *StripeGateway) makeStripeRequest(ctx context.Context, method, path stri return nil, fmt.Errorf("stripe error: %s", string(respBody)) } - var result interface{} + var result any if err := json.Unmarshal(respBody, &result); err != nil { return nil, fmt.Errorf("failed to unmarshal response: %w", err) } diff --git a/apps/api-server/internal/payment/gateways/stripe.go b/apps/api-server/internal/payment/gateways/stripe.go index dbdab0c..a2f5cda 100644 --- a/apps/api-server/internal/payment/gateways/stripe.go +++ b/apps/api-server/internal/payment/gateways/stripe.go @@ -42,7 +42,7 @@ func NewStripeGateway(secretKey, webhookSecret string) *StripeGateway { func (g *StripeGateway) ProcessPayment(ctx context.Context, req *PaymentRequest) (*PaymentResponse, error) { // Create payment intent params := &stripe.PaymentIntentParams{ - Amount: stripe.Int64(int64(req.Amount * 100)), // Convert to cents + Amount: new(int64(req.Amount * 100)), // Convert to cents Currency: stripe.String(string(req.Currency)), Metadata: map[string]string{ "subscriber_id": fmt.Sprintf("%d", req.SubscriberID), @@ -132,7 +132,7 @@ func (g *StripeGateway) ProcessRefund(ctx context.Context, transactionID string, } if amount > 0 { - params.Amount = stripe.Int64(int64(amount * 100)) // Convert to cents + params.Amount = new(int64(amount * 100)) // Convert to cents } refund, err := refund.New(params) @@ -185,10 +185,10 @@ func (g *StripeGateway) CreateInvoice(ctx context.Context, customerID string, it for _, item := range items { itemParams := &stripe.InvoiceItemParams{ Customer: stripe.String(customerID), - Amount: stripe.Int64(int64(item.Amount * 100)), + Amount: new(int64(item.Amount * 100)), Currency: stripe.String(string(item.Currency)), Description: stripe.String(item.Description), - Quantity: stripe.Int64(int64(item.Quantity)), + Quantity: new(int64(item.Quantity)), } _, err := invoiceitem.New(itemParams) @@ -200,7 +200,7 @@ func (g *StripeGateway) CreateInvoice(ctx context.Context, customerID string, it // Create the invoice params := &stripe.InvoiceParams{ Customer: stripe.String(customerID), - AutoAdvance: stripe.Bool(true), + AutoAdvance: new(true), } inv, err := invoice.New(params) diff --git a/apps/api-server/internal/payment/webhook.go b/apps/api-server/internal/payment/webhook.go index 2780c53..9542021 100644 --- a/apps/api-server/internal/payment/webhook.go +++ b/apps/api-server/internal/payment/webhook.go @@ -15,12 +15,12 @@ import ( // WebhookEvent represents a payment webhook event type WebhookEvent struct { - ID string `json:"id"` - Type string `json:"type"` - Object string `json:"object"` - Created int64 `json:"created"` - Livemode bool `json:"livemode"` - Data map[string]interface{} `json:"data"` + ID string `json:"id"` + Type string `json:"type"` + Object string `json:"object"` + Created int64 `json:"created"` + Livemode bool `json:"livemode"` + Data map[string]any `json:"data"` } // WebhookHandler handles payment webhooks @@ -97,7 +97,7 @@ func (wh *WebhookHandler) HandleStripeWebhook(c *gin.Context) { // handlePaymentSucceeded handles successful payment events func (wh *WebhookHandler) handlePaymentSucceeded(ctx context.Context, event WebhookEvent) error { - paymentIntent, ok := event.Data["object"].(map[string]interface{}) + paymentIntent, ok := event.Data["object"].(map[string]any) if !ok { return fmt.Errorf("invalid payment intent object") } @@ -145,7 +145,7 @@ func (wh *WebhookHandler) handlePaymentSucceeded(ctx context.Context, event Webh // handlePaymentFailed handles failed payment events func (wh *WebhookHandler) handlePaymentFailed(ctx context.Context, event WebhookEvent) error { - paymentIntent, ok := event.Data["object"].(map[string]interface{}) + paymentIntent, ok := event.Data["object"].(map[string]any) if !ok { return fmt.Errorf("invalid payment intent object") } @@ -166,7 +166,7 @@ func (wh *WebhookHandler) handlePaymentFailed(ctx context.Context, event Webhook transaction.UpdatedAt = time.Now() // Add failure reason if available - if lastPaymentError, ok := paymentIntent["last_payment_error"].(map[string]interface{}); ok { + if lastPaymentError, ok := paymentIntent["last_payment_error"].(map[string]any); ok { if message, ok := lastPaymentError["message"].(string); ok { transaction.Description += " - Failed: " + message } @@ -199,7 +199,7 @@ func (wh *WebhookHandler) handlePaymentFailed(ctx context.Context, event Webhook // handlePaymentCanceled handles canceled payment events func (wh *WebhookHandler) handlePaymentCanceled(ctx context.Context, event WebhookEvent) error { - paymentIntent, ok := event.Data["object"].(map[string]interface{}) + paymentIntent, ok := event.Data["object"].(map[string]any) if !ok { return fmt.Errorf("invalid payment intent object") } @@ -230,7 +230,7 @@ func (wh *WebhookHandler) handlePaymentCanceled(ctx context.Context, event Webho // handleDisputeCreated handles dispute events func (wh *WebhookHandler) handleDisputeCreated(ctx context.Context, event WebhookEvent) error { - dispute, ok := event.Data["object"].(map[string]interface{}) + dispute, ok := event.Data["object"].(map[string]any) if !ok { return fmt.Errorf("invalid dispute object") }