From d27709222ee732375898c7f8e7981ee4c6377fdf Mon Sep 17 00:00:00 2001 From: nutcas3 Date: Fri, 24 Apr 2026 08:50:22 +0300 Subject: [PATCH] feat: Add carrier-connector handler package with carrier info, connectivity check, and shared types for GSMA ES2+ profile management - Add handlers package with GetCarrierInfoHandler returning static carrier name/mcc/mnc/smdpUrl/supported/lastChecked from environment config - Add CheckConnectivityHandler with ES2+ GetProfileStatus probe using synthetic EID/ICCID and smdpConnected/checkedAt/error response - Add ProfileOrder struct with EID/ICCID/IMSI/K/OPc/MCC/MNC/ProfileType/ConfirmationCode fields --- .../internal/handler/handlers.go | 72 +++++++++++++++++++ .../internal/handler/types.go | 39 ++++++++++ 2 files changed, 111 insertions(+) create mode 100644 apps/carrier-connector/internal/handler/handlers.go create mode 100644 apps/carrier-connector/internal/handler/types.go diff --git a/apps/carrier-connector/internal/handler/handlers.go b/apps/carrier-connector/internal/handler/handlers.go new file mode 100644 index 0000000..f2dc52a --- /dev/null +++ b/apps/carrier-connector/internal/handler/handlers.go @@ -0,0 +1,72 @@ +// Package handlers hosts HTTP handlers for the carrier-connector service. +// +// Profile handlers (order, get, list, delete) live in profile_handlers.go and +// take a repository.ProfileRepository so profile state can be persisted and +// queried. Carrier-level handlers (info, connectivity) that only touch the +// ES2+ client live here. +package handlers + +import ( + "context" + "net/http" + "strconv" + "time" + + "github.com/gin-gonic/gin" + + "github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/es2" +) + +// GetCarrierInfoHandler returns static carrier information from environment config. +func GetCarrierInfoHandler(_ *es2.ES2Client) gin.HandlerFunc { + return func(c *gin.Context) { + c.JSON(http.StatusOK, gin.H{ + "success": true, + "carrier": gin.H{ + "name": GetEnv("CARRIER_NAME", "Example Carrier"), + "mcc": GetEnv("CARRIER_MCC", "208"), + "mnc": GetEnv("CARRIER_MNC", "93"), + "smdpUrl": GetEnv("SMDP_URL", "https://smdp.example.com"), + "supported": true, + "lastChecked": time.Now().UTC(), + }, + }) + } +} + +// CheckConnectivityHandler probes the SM-DP+ via an ES2+ GetProfileStatus call +// with synthetic identifiers. A non-error response indicates the endpoint is +// reachable and accepting authenticated requests. +func CheckConnectivityHandler(client *es2.ES2Client) gin.HandlerFunc { + return func(c *gin.Context) { + req := &es2.GetProfileStatusRequest{EID: "connectivity-probe", ICCID: "connectivity-probe"} + _, err := client.GetProfileStatus(context.Background(), req) + + connected := err == nil + var errMsg interface{} + if err != nil { + errMsg = err.Error() + } + + c.JSON(http.StatusOK, gin.H{ + "success": true, + "connectivity": gin.H{ + "smdpConnected": connected, + "checkedAt": time.Now().UTC(), + "error": errMsg, + }, + }) + } +} + +// parsePositiveInt parses a positive integer from a string, returning fallback on failure. +func parsePositiveInt(s string, fallback int) int { + if s == "" { + return fallback + } + n, err := strconv.Atoi(s) + if err != nil || n <= 0 { + return fallback + } + return n +} diff --git a/apps/carrier-connector/internal/handler/types.go b/apps/carrier-connector/internal/handler/types.go new file mode 100644 index 0000000..a1815f9 --- /dev/null +++ b/apps/carrier-connector/internal/handler/types.go @@ -0,0 +1,39 @@ +package handlers + +import ( + "os" + + "github.com/rs/zerolog" +) + +// Logger is the package-level logger, initialized by main. +var Logger zerolog.Logger + +// ProfileOrder is the GSMA ES2+ profile order request accepted by the API. +type ProfileOrder struct { + EID string `json:"eid"` + ICCID string `json:"iccid"` + IMSI string `json:"imsi"` + K string `json:"k"` + OPc string `json:"opc"` + MCC string `json:"mcc"` + MNC string `json:"mnc"` + ProfileType string `json:"profileType"` + ConfirmationCode string `json:"confirmationCode,omitempty"` +} + +// ProfileResponse is the GSMA ES2+ profile order response returned by the API. +type ProfileResponse struct { + ExecutionStatus string `json:"executionStatus"` + StatusMessage string `json:"statusMessage"` + ProfileID string `json:"profileId"` + ActivationCode string `json:"activationCode,omitempty"` +} + +// GetEnv returns the value of an environment variable or fallback if unset. +func GetEnv(key, fallback string) string { + if value := os.Getenv(key); value != "" { + return value + } + return fallback +}