Files
telecom-platform/apps/carrier-connector/internal/smdp/operations.go
T
nutcas3 ae8b7bdce1 feat: Refactor profile handlers into modular core components with simplified operations
- Split profile_handlers.go into profile_handlers_core.go, profile_handlers_management_core.go, and profile_handlers_management_delete.go
- Simplify OrderProfileHandlerWithRepo with ICCID/IMSI-only validation and "downloaded" state
- Remove webhook and message queue notifications from order handler
- Add UpdateProfileHandler with state validation for downloaded/activated/deactivated/expired
- Add DeleteProfileHandler with existence
2026-05-01 23:26:41 +03:00

172 lines
4.8 KiB
Go

package smdp
import (
"context"
"fmt"
"time"
"github.com/nutcas3/telecom-platform/apps/carrier-connector/internal/es2"
"github.com/sirupsen/logrus"
)
func (m *SMDPManager) DownloadProfile(ctx context.Context, req *ProfileRequest) (*ProfileResponse, error) {
startTime := time.Now()
m.logger.WithFields(logrus.Fields{
"eid": req.EID,
"preferred": req.PreferredCarrier,
}).Info("Processing profile download request")
selectedCarrier, err := m.SelectCarrier(ctx)
if err != nil {
return &ProfileResponse{
Success: false,
StatusMessage: fmt.Sprintf("Carrier selection failed: %v", err),
ResponseTime: time.Since(startTime),
}, err
}
response, err := m.downloadWithRetry(ctx, req, selectedCarrier, 0)
if err != nil && m.config.EnableFailover {
m.logger.WithError(err).Warn("Primary carrier failed, attempting failover")
return m.handleFailover(ctx, req, selectedCarrier.ID, startTime)
}
response.ResponseTime = time.Since(startTime)
return response, err
}
func (m *SMDPManager) downloadWithRetry(ctx context.Context, req *ProfileRequest, carrier *Carrier, attempt int) (*ProfileResponse, error) {
m.clientsMutex.RLock()
client, exists := m.es2Clients[carrier.ID]
m.clientsMutex.RUnlock()
if !exists {
return nil, fmt.Errorf("ES2+ client not found for carrier %s", carrier.ID)
}
downloadReq := &es2.DownloadProfileRequest{
EID: req.EID,
ICCID: req.ICCID,
ProfileType: req.ProfileType,
ConfirmationCode: req.ConfirmationCode,
}
startTime := time.Now()
resp, err := client.DownloadProfile(ctx, downloadReq)
responseTime := time.Since(startTime)
m.updateCarrierMetrics(carrier.ID, err == nil, responseTime, err)
if err != nil {
m.logger.WithFields(logrus.Fields{
"carrier_id": carrier.ID,
"attempt": attempt + 1,
"error": err,
}).Error("Profile download failed")
if attempt < m.config.MaxRetries {
time.Sleep(m.config.RetryDelay)
return m.downloadWithRetry(ctx, req, carrier, attempt+1)
}
return &ProfileResponse{
Success: false,
CarrierID: carrier.ID,
StatusMessage: fmt.Sprintf("Download failed after %d attempts: %v", attempt+1, err),
ResponseTime: responseTime,
}, err
}
m.logger.WithFields(logrus.Fields{
"carrier_id": carrier.ID,
"execution_status": resp.ExecutionStatus,
"response_time": responseTime,
}).Info("Profile download successful")
return &ProfileResponse{
Success: true,
CarrierID: carrier.ID,
ExecutionStatus: resp.ExecutionStatus,
StatusMessage: resp.StatusMessage,
ResponseTime: responseTime,
}, nil
}
// handleFailover attempts to download profile using alternative carriers
func (m *SMDPManager) handleFailover(ctx context.Context, req *ProfileRequest, failedCarrierID string, startTime time.Time) (*ProfileResponse, error) {
m.carriersMutex.RLock()
defer m.carriersMutex.RUnlock()
var retriedOn []string
for carrierID, carrier := range m.carriers {
if carrierID == failedCarrierID || !carrier.IsActive || carrier.HealthStatus != CarrierStatusHealthy {
continue
}
m.logger.WithField("carrier_id", carrierID).Info("Attempting failover to carrier")
response, err := m.downloadWithRetry(ctx, req, carrier, 0)
if err == nil && response.Success {
response.RetriedOn = retriedOn
response.ResponseTime = time.Since(startTime)
return response, nil
}
retriedOn = append(retriedOn, carrierID)
}
return &ProfileResponse{
Success: false,
StatusMessage: "All carriers failed during failover",
ResponseTime: time.Since(startTime),
RetriedOn: retriedOn,
}, fmt.Errorf("failover exhausted all carriers")
}
// updateCarrierMetrics updates the metrics for a carrier
func (m *SMDPManager) updateCarrierMetrics(carrierID string, success bool, responseTime time.Duration, err error) {
m.carriersMutex.Lock()
defer m.carriersMutex.Unlock()
carrier, exists := m.carriers[carrierID]
if !exists {
return
}
carrier.Metrics.TotalRequests++
if success {
carrier.Metrics.SuccessfulRequests++
} else {
carrier.Metrics.FailedRequests++
carrier.Metrics.LastError = err.Error()
carrier.Metrics.LastErrorTime = time.Now()
}
if carrier.Metrics.TotalRequests == 1 {
carrier.Metrics.AverageResponseTime = responseTime
} else {
carrier.Metrics.AverageResponseTime = time.Duration(
(int64(carrier.Metrics.AverageResponseTime)*int64(carrier.Metrics.TotalRequests-1) + int64(responseTime)) / int64(carrier.Metrics.TotalRequests),
)
}
carrier.Metrics.RequestRate = float64(carrier.Metrics.TotalRequests) / time.Since(time.Now().Add(-time.Minute)).Seconds()
}
func (m *SMDPManager) getHighestPriorityCarrier(carriers []*Carrier) *Carrier {
if len(carriers) == 0 {
return nil
}
highestPriority := carriers[0]
for _, carrier := range carriers {
if carrier.Priority > highestPriority.Priority {
highestPriority = carrier
}
}
return highestPriority
}