feat: Refactor carrier-connector to use GSMA ES2+ protocol with dedicated client package and context-aware profile download

- Add context import and config/es2 package imports for GSMA ES2+ protocol implementation
- Remove ES2Client struct definition and move to internal/es2 package
- Update ProfileOrder struct with EID/ConfirmationCode fields for GSMA ES2+ compliance
- Update ProfileResponse struct with ExecutionStatus/StatusMessage fields replacing Status
- Add ES2Config initialization with Base
This commit is contained in:
nutcas3
2026-04-24 07:39:17 +03:00
parent 2fe8678782
commit 065fe6727f
+39 -20
View File
@@ -1,6 +1,7 @@
package main package main
import ( import (
"context"
"crypto/tls" "crypto/tls"
"fmt" "fmt"
"net/http" "net/http"
@@ -11,31 +12,32 @@ import (
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
"github.com/go-resty/resty/v2" "github.com/go-resty/resty/v2"
"github.com/joho/godotenv" "github.com/joho/godotenv"
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/config"
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/es2"
"github.com/rs/zerolog" "github.com/rs/zerolog"
) )
var logger zerolog.Logger var logger zerolog.Logger
type ES2Client struct { // GSMA ES2+ Profile Order Request
baseURL string
apiKey string
httpClient *resty.Client
}
type ProfileOrder struct { type ProfileOrder struct {
ICCID string `json:"iccid"` EID string `json:"eid"`
IMSI string `json:"imsi"` ICCID string `json:"iccid"`
K string `json:"k"` IMSI string `json:"imsi"`
OPc string `json:"opc"` K string `json:"k"`
MCC string `json:"mcc"` OPc string `json:"opc"`
MNC string `json:"mnc"` MCC string `json:"mcc"`
ProfileType string `json:"profileType"` MNC string `json:"mnc"`
ProfileType string `json:"profileType"`
ConfirmationCode string `json:"confirmationCode,omitempty"`
} }
// GSMA ES2+ Profile Order Response
type ProfileResponse struct { type ProfileResponse struct {
ActivationCode string `json:"activationCode"` ExecutionStatus string `json:"executionStatus"`
ProfileID string `json:"profileId"` StatusMessage string `json:"statusMessage"`
Status string `json:"status"` ProfileID string `json:"profileId"`
ActivationCode string `json:"activationCode,omitempty"`
} }
func main() { func main() {
@@ -50,12 +52,21 @@ func main() {
logger.Info().Msg("No .env file found, using system environment") logger.Info().Msg("No .env file found, using system environment")
} }
// Initialize ES2+ client // Initialize ES2+ client with GSMA protocol
smdpURL := getEnv("SMDP_URL", "https://smdp.example.com") smdpURL := getEnv("SMDP_URL", "https://smdp.example.com")
apiKey := getEnv("SMDP_API_KEY", "test-api-key") apiKey := getEnv("SMDP_API_KEY", "test-api-key")
requesterID := getEnv("FUNCTIONALITY_REQUESTER_ID", "carrier-connector")
insecure := getEnv("INSECURE_SKIP_VERIFY", "false") == "true"
port := getEnv("PORT", "8080") port := getEnv("PORT", "8080")
client := NewES2Client(smdpURL, apiKey) es2Config := &config.ES2Config{
BaseURL: smdpURL,
APIKey: apiKey,
FunctionalityRequesterID: requesterID,
InsecureSkipVerify: insecure,
}
client := es2.NewES2Client(es2Config)
// Initialize Gin router // Initialize Gin router
router := gin.Default() router := gin.Default()
@@ -170,7 +181,7 @@ func (c *ES2Client) OrderProfile(order *ProfileOrder) (*ProfileResponse, error)
// API Handlers // API Handlers
func orderProfileHandler(client *ES2Client) gin.HandlerFunc { func orderProfileHandler(client *es2.ES2Client) gin.HandlerFunc {
return func(c *gin.Context) { return func(c *gin.Context) {
var order ProfileOrder var order ProfileOrder
@@ -197,7 +208,15 @@ func orderProfileHandler(client *ES2Client) gin.HandlerFunc {
Str("iccid", order.ICCID). Str("iccid", order.ICCID).
Msg("API request: Ordering eSIM profile from SM-DP+") Msg("API request: Ordering eSIM profile from SM-DP+")
response, err := client.OrderProfile(&order) // Convert ProfileOrder to DownloadProfileRequest for GSMA ES2+ protocol
downloadReq := &es2.DownloadProfileRequest{
EID: order.EID,
ICCID: order.ICCID,
ProfileType: order.ProfileType,
ConfirmationCode: order.ConfirmationCode,
}
downloadResp, err := client.DownloadProfile(context.Background(), downloadReq)
if err != nil { if err != nil {
logger.Error().Err(err).Str("imsi", order.IMSI).Msg("Failed to order profile") logger.Error().Err(err).Str("imsi", order.IMSI).Msg("Failed to order profile")
c.JSON(http.StatusInternalServerError, gin.H{ c.JSON(http.StatusInternalServerError, gin.H{