mirror of
https://github.com/andwati/telecom-platform.git
synced 2026-11-02 01:42:19 +00:00
- 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
172 lines
4.8 KiB
Go
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
|
|
}
|