feat: harden CMPP delivery and platform workflows
This commit is contained in:
@@ -44,18 +44,25 @@ type authRequest struct {
|
||||
}
|
||||
|
||||
type submitRequest struct {
|
||||
Account string `json:"account"`
|
||||
Account string `json:"account"`
|
||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||
PhoneNumbers []string `json:"phoneNumbers,omitempty"`
|
||||
Content string `json:"content"`
|
||||
SrcID string `json:"srcId,omitempty"`
|
||||
DestID string `json:"destId,omitempty"`
|
||||
SequenceID uint32 `json:"sequenceId,omitempty"`
|
||||
RemoteIP string `json:"remoteIp,omitempty"`
|
||||
}
|
||||
|
||||
type submitResponseMessage struct {
|
||||
PhoneNumber string `json:"phoneNumber"`
|
||||
Content string `json:"content"`
|
||||
SrcID string `json:"srcId,omitempty"`
|
||||
DestID string `json:"destId,omitempty"`
|
||||
SequenceID uint32 `json:"sequenceId,omitempty"`
|
||||
RemoteIP string `json:"remoteIp,omitempty"`
|
||||
MessageID string `json:"messageId"`
|
||||
}
|
||||
|
||||
type submitResponse struct {
|
||||
Accepted bool `json:"accepted"`
|
||||
MessageID string `json:"messageId"`
|
||||
Accepted bool `json:"accepted"`
|
||||
MessageID string `json:"messageId"`
|
||||
Messages []submitResponseMessage `json:"messages,omitempty"`
|
||||
}
|
||||
|
||||
type authResponse struct {
|
||||
@@ -68,17 +75,18 @@ type authResponse struct {
|
||||
}
|
||||
|
||||
type DownstreamReceipt struct {
|
||||
DeliveryID string `json:"deliveryId,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
MessageID string `json:"messageId"`
|
||||
GatewayMessageID string `json:"gatewayMessageId,omitempty"`
|
||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||
ReceiptStatus string `json:"receiptStatus"`
|
||||
RawStatus string `json:"rawStatus,omitempty"`
|
||||
ErrorCode string `json:"errorCode,omitempty"`
|
||||
SubmitSequenceID uint32 `json:"submitSequenceId,omitempty"`
|
||||
DeliveredAt string `json:"deliveredAt,omitempty"`
|
||||
DeliveryID string `json:"deliveryId,omitempty"`
|
||||
Account string `json:"account,omitempty"`
|
||||
ApplicationID string `json:"applicationId,omitempty"`
|
||||
MessageID string `json:"messageId"`
|
||||
GatewayMessageID string `json:"gatewayMessageId,omitempty"`
|
||||
PhoneNumber string `json:"phoneNumber,omitempty"`
|
||||
ReceiptStatus string `json:"receiptStatus"`
|
||||
RawStatus string `json:"rawStatus,omitempty"`
|
||||
ErrorCode string `json:"errorCode,omitempty"`
|
||||
SubmitSequenceID uint32 `json:"submitSequenceId,omitempty"`
|
||||
SubmitGroupMessageID string `json:"submitGroupMessageId,omitempty"`
|
||||
DeliveredAt string `json:"deliveredAt,omitempty"`
|
||||
}
|
||||
|
||||
type DownstreamUplink struct {
|
||||
@@ -267,9 +275,13 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
setInboundSubmitResponse(response.Packer, 0, 9)
|
||||
return false, nil
|
||||
}
|
||||
phones := make([]string, len(req.destTerminalIDs))
|
||||
for index, destination := range req.destTerminalIDs {
|
||||
phones[index] = strings.TrimSpace(strings.TrimRight(destination, "\x00"))
|
||||
}
|
||||
phone := ""
|
||||
if len(req.destTerminalIDs) > 0 {
|
||||
phone = strings.TrimRight(req.destTerminalIDs[0], "\x00")
|
||||
if len(phones) > 0 {
|
||||
phone = phones[0]
|
||||
}
|
||||
remote := packet.Conn.Conn.RemoteAddr()
|
||||
clientProtocol := defaultString(session.protocol, req.protocol)
|
||||
@@ -290,13 +302,14 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
contentHash := fmt.Sprintf("%x", md5.Sum([]byte(content)))
|
||||
startedAt := time.Now()
|
||||
result, err := s.submit(remote, submitRequest{
|
||||
Account: account,
|
||||
PhoneNumber: phone,
|
||||
Content: content,
|
||||
SrcID: req.srcID,
|
||||
DestID: phone,
|
||||
SequenceID: req.sequenceID,
|
||||
RemoteIP: remoteIP(remote),
|
||||
Account: account,
|
||||
PhoneNumber: phone,
|
||||
PhoneNumbers: phones,
|
||||
Content: content,
|
||||
SrcID: req.srcID,
|
||||
DestID: phone,
|
||||
SequenceID: req.sequenceID,
|
||||
RemoteIP: remoteIP(remote),
|
||||
})
|
||||
if err != nil || !result.Accepted {
|
||||
reason := "api returned accepted=false"
|
||||
@@ -312,24 +325,34 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
}
|
||||
gatewayMsgID := messageIDFrom(result.MessageID, req.sequenceID)
|
||||
setInboundSubmitResponse(response.Packer, gatewayMsgID, 0)
|
||||
rememberDownstream(downstreamSession{
|
||||
messageID: result.MessageID,
|
||||
account: account,
|
||||
enterpriseCode: session.enterpriseCode,
|
||||
protocol: clientProtocol,
|
||||
srcID: strings.TrimSpace(req.srcID),
|
||||
phoneNumber: phone,
|
||||
gatewayMsgID: gatewayMsgID,
|
||||
remoteIP: remoteIP(remote),
|
||||
connectedAt: time.Now().UTC(),
|
||||
connectionID: session.connectionID,
|
||||
conn: packet.Conn,
|
||||
mu: &sync.Mutex{},
|
||||
presence: s.PresenceStore,
|
||||
instanceID: s.gatewayInstanceID(),
|
||||
report: session.report,
|
||||
deliveryReport: session.deliveryReport,
|
||||
})
|
||||
responseMessages := result.Messages
|
||||
if len(responseMessages) == 0 {
|
||||
responseMessages = []submitResponseMessage{{PhoneNumber: phone, MessageID: result.MessageID}}
|
||||
}
|
||||
for index, acceptedMessage := range responseMessages {
|
||||
acceptedPhone := strings.TrimSpace(acceptedMessage.PhoneNumber)
|
||||
if acceptedPhone == "" && index < len(phones) {
|
||||
acceptedPhone = phones[index]
|
||||
}
|
||||
rememberDownstream(downstreamSession{
|
||||
messageID: acceptedMessage.MessageID,
|
||||
account: account,
|
||||
enterpriseCode: session.enterpriseCode,
|
||||
protocol: clientProtocol,
|
||||
srcID: strings.TrimSpace(req.srcID),
|
||||
phoneNumber: acceptedPhone,
|
||||
gatewayMsgID: gatewayMsgID,
|
||||
remoteIP: remoteIP(remote),
|
||||
connectedAt: time.Now().UTC(),
|
||||
connectionID: session.connectionID,
|
||||
conn: packet.Conn,
|
||||
mu: &sync.Mutex{},
|
||||
presence: s.PresenceStore,
|
||||
instanceID: s.gatewayInstanceID(),
|
||||
report: session.report,
|
||||
deliveryReport: session.deliveryReport,
|
||||
})
|
||||
}
|
||||
if current := findSessionByConn(packet.Conn); current != nil && current.report != nil {
|
||||
go current.report(current, "submit", "")
|
||||
}
|
||||
@@ -344,8 +367,8 @@ func (s Server) handleSubmit(response *cmpp.Response, packet *cmpp.Packet, logge
|
||||
}()
|
||||
}
|
||||
logger.Printf(
|
||||
"cmpp inbound event=submit_accepted protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s result=0 message_id=%s gateway_message_id=%d duration_ms=%d content_chars=%d content_hash=%s",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, result.MessageID, gatewayMsgID, time.Since(startedAt).Milliseconds(), len([]rune(content)), contentHash,
|
||||
"cmpp inbound event=submit_accepted protocol=%s packet_type=%s account=%s remote=%s seq=%d phone=%s dest_count=%d accepted_count=%d result=0 message_id=%s gateway_message_id=%d duration_ms=%d content_chars=%d content_hash=%s",
|
||||
clientProtocol, req.protocol, account, remote, req.sequenceID, phone, len(phones), len(responseMessages), result.MessageID, gatewayMsgID, time.Since(startedAt).Milliseconds(), len([]rune(content)), contentHash,
|
||||
)
|
||||
return false, nil
|
||||
}
|
||||
@@ -742,9 +765,9 @@ func forgetDownstream(session *downstreamSession) {
|
||||
return
|
||||
}
|
||||
downstreamRegistry.Lock()
|
||||
if session.messageID != "" {
|
||||
if current := downstreamRegistry.byMessageID[session.messageID]; current == session {
|
||||
delete(downstreamRegistry.byMessageID, session.messageID)
|
||||
for messageID, current := range downstreamRegistry.byMessageID {
|
||||
if current != nil && current.conn == session.conn {
|
||||
delete(downstreamRegistry.byMessageID, messageID)
|
||||
}
|
||||
}
|
||||
if session.account != "" {
|
||||
@@ -1003,7 +1026,7 @@ func recoverReceiptSession(event DownstreamReceipt) *downstreamSession {
|
||||
}
|
||||
recovered := *accountSession
|
||||
recovered.messageID = event.MessageID
|
||||
recovered.gatewayMsgID = messageIDFrom(event.MessageID, event.SubmitSequenceID)
|
||||
recovered.gatewayMsgID = messageIDFrom(defaultString(event.SubmitGroupMessageID, event.MessageID), event.SubmitSequenceID)
|
||||
return &recovered
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user