Initial cloud-services repo - gateway service + pkg modules
This commit is contained in:
150
pkg/tmobile/wrapper.go
Normal file
150
pkg/tmobile/wrapper.go
Normal file
@@ -0,0 +1,150 @@
|
||||
package tmobile
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"fiskerinc.com/modules/grpc/sms"
|
||||
"fiskerinc.com/modules/kafka"
|
||||
"fiskerinc.com/modules/logger"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// I want to move the check sms loop into a less thread intensive action
|
||||
// This is done in the following way
|
||||
// Have a single/limit a couple look at all the messages we need to see if they are successfully sent
|
||||
// If they are successfully sent then we notify something else that will properly return the status
|
||||
|
||||
// Currently the return is going to be the hardest part
|
||||
// Wrapper wraps the client with an auto-refresh and auth-token retry.
|
||||
|
||||
type SMSClientWrapper interface {
|
||||
Start(ctx context.Context)
|
||||
SendSMS(ctx context.Context, req *SendSMSRequest) (out *SMSDetailsResponse, err error)
|
||||
SendSMSQueue(ctx context.Context, req *SendSMSRequest) (out *SMSQueueResponse, err error)
|
||||
HandleChangeRatePlan(context.Context, *ChangeRatePlanRequest) (*ChangeRatePlanResponse, error)
|
||||
HandleCustomAttributes(context.Context, *CustomAtributesRequest) (*CustomAtributesResponse, error)
|
||||
HandleGetProducts(context.Context, *sms.GetAvailableProductsRequest) (*sms.GetAvailableProductsResponse, error)
|
||||
HandleDeviceDetails(context.Context, *DeviceDetailsRequest) (*DeviceDetailsResponse, error)
|
||||
HandleChangeDeviceStatus(ctx context.Context, cda ChangeDeviceActivation) (err error)
|
||||
}
|
||||
|
||||
type SMSClient struct {
|
||||
client TMobClienter
|
||||
queue *RunningQueue
|
||||
}
|
||||
|
||||
|
||||
func NewSMSClient(client TMobClienter, kafkaProducer kafka.ProducerInterface) *SMSClient {
|
||||
nc := &SMSClient{
|
||||
client: client,
|
||||
}
|
||||
nc.queue = NewQueue(client, kafkaProducer)
|
||||
return nc
|
||||
}
|
||||
|
||||
func (w *SMSClient) Start(ctx context.Context) {
|
||||
}
|
||||
|
||||
// If the SMS is not delivered, out will be null, and this will need to be checked
|
||||
func (w *SMSClient) SendSMS(ctx context.Context, req *SendSMSRequest) (out *SMSDetailsResponse, err error) {
|
||||
logger.Debug().Msgf("Sending SMS: %+v", req)
|
||||
|
||||
var smr *SendSMSResponse
|
||||
|
||||
// Giving 3 tries for a gateway failure
|
||||
for x := 0; x < 3; x++ {
|
||||
smr, err = w.client.SendSMS(ctx, req)
|
||||
if err != nil {
|
||||
if errors.Is(err, ErrBadGatewayCode) {
|
||||
logger.Warn().Err(err).Msgf("ICCID %s gateway failure sending sms", req.ICCID)
|
||||
time.Sleep(time.Millisecond * 300) // 300 milliseconds seems to work best for me
|
||||
continue
|
||||
}
|
||||
if errors.Is(err, ErrAccessTokenExpired) {
|
||||
logger.Err(err).Msgf("Access token for sms expired, should never happen")
|
||||
}
|
||||
return nil, errors.WithMessagef(err, "failed to send SMS to ICCID: %s", req.ICCID)
|
||||
}
|
||||
break
|
||||
}
|
||||
|
||||
if smr == nil {
|
||||
return nil, errors.WithMessagef(err, "failed to send SMS to ICCID: %s", req.ICCID)
|
||||
}
|
||||
|
||||
expDur := time.Second * 5
|
||||
logger.Debug().Msgf("SMS sent, expires in %d ms, id: %s currently %d", expDur.Milliseconds(), smr.SmsMessageID, time.Now().UnixMilli())
|
||||
|
||||
waitTill := time.After(expDur)
|
||||
checkTimer := time.NewTicker(time.Millisecond * 300)
|
||||
for {
|
||||
select {
|
||||
case <-waitTill:
|
||||
logger.Debug().Msgf("SMS with id %s not delivered after %d ms currently %d", smr.SmsMessageID, expDur.Milliseconds(), time.Now().UnixMilli())
|
||||
return nil, ErrTimeoutSendingMessage // Lots of messages seem to hit here
|
||||
case <-checkTimer.C:
|
||||
// Doing the wait before the first check, increases the chance of a first check success
|
||||
out, err = w.client.Details(ctx, smr.SmsMessageID)
|
||||
if err != nil {
|
||||
// Ignoring and retrying a bad gateway request
|
||||
if errors.Is(err, ErrBadGatewayCode) {
|
||||
logger.Warn().Err(err).Msgf("Bad gateway request from t-mobileICCID %s, Message ID: %s", req.ICCID, smr.SmsMessageID)
|
||||
continue
|
||||
}
|
||||
// If we get this error, t-mobile has rejected our details request
|
||||
logger.Err(err).Msgf("failed to get sms details with smsMsgID: %s to ICCID: %s", smr.SmsMessageID, req.ICCID)
|
||||
return nil, errors.WithMessagef(err, "failed to get sms details with smsMsgID: %s to ICCID: %s", smr.SmsMessageID, req.ICCID)
|
||||
}
|
||||
|
||||
if !req.await {
|
||||
return out, nil
|
||||
}
|
||||
|
||||
switch out.Status {
|
||||
case Pending, CancelPending:
|
||||
logger.Debug().Msgf("MSG %s had Pending Status", smr.SmsMessageID)
|
||||
continue
|
||||
case Delivered:
|
||||
return out, nil
|
||||
default:
|
||||
logger.Warn().Msgf("Fell through to default of sms status id: %s status: %s", smr.SmsMessageID, out.Status)
|
||||
return out, errors.WithMessagef(
|
||||
ErrBadMsgStatus,
|
||||
"message with id %s failed with status %s",
|
||||
out.SmsMsgID,
|
||||
out.Status,
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (w *SMSClient) SendSMSQueue(ctx context.Context, req *SendSMSRequest) (out *SMSQueueResponse, err error) {
|
||||
msgID, err := w.queue.SendSMS(ctx, req)
|
||||
out = &SMSQueueResponse{}
|
||||
out.SmsMsgID = msgID
|
||||
out.SentSuccessful = err == nil
|
||||
return
|
||||
}
|
||||
|
||||
func (w *SMSClient) HandleChangeRatePlan(ctx context.Context, req *ChangeRatePlanRequest) (*ChangeRatePlanResponse, error) {
|
||||
return w.client.ChangeRatePlan(ctx, req)
|
||||
}
|
||||
|
||||
func (w *SMSClient) HandleCustomAttributes(ctx context.Context, req *CustomAtributesRequest) (*CustomAtributesResponse, error) {
|
||||
return w.client.CustomAttributes(ctx, req)
|
||||
}
|
||||
|
||||
func (w *SMSClient) HandleGetProducts(ctx context.Context, req *sms.GetAvailableProductsRequest) (*sms.GetAvailableProductsResponse, error) {
|
||||
return w.client.GetProducts(ctx, req)
|
||||
}
|
||||
|
||||
func (w *SMSClient) HandleDeviceDetails(ctx context.Context, req *DeviceDetailsRequest) (*DeviceDetailsResponse, error) {
|
||||
return w.client.DeviceDetails(ctx, req)
|
||||
}
|
||||
|
||||
func (w *SMSClient) HandleChangeDeviceStatus(ctx context.Context, cda ChangeDeviceActivation) (err error) {
|
||||
return w.client.ChangeDeviceStatus(ctx, cda)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user