This commit is contained in:
@@ -1,3 +1,4 @@
|
||||
import { protocolUint32ToDb, protocolUint32FromDb } from '../common/protocol-uint32';
|
||||
import { resolveReceiptAttempt } from './receipt-attempt-resolver';
|
||||
import { completionContext } from './completion-context';
|
||||
import { Logger, NotFoundException } from '@nestjs/common';
|
||||
@@ -39,6 +40,7 @@ export class SendReceiptService {
|
||||
) {}
|
||||
|
||||
async intakeReceipt(data: GatewayReceiptEventDto) {
|
||||
protocolUint32ToDb(data.sequenceId);
|
||||
const channel = await this.prisma.smsChannel.findUnique({
|
||||
where: { id: data.channelId },
|
||||
select: {
|
||||
@@ -55,34 +57,45 @@ export class SendReceiptService {
|
||||
}
|
||||
const deliveredAt = data.deliveredAt ? new Date(data.deliveredAt) : new Date();
|
||||
const receiptKey = receiptEventKey(data, data.channelId);
|
||||
const inbox = await this.prisma.upstreamReceiptInbox.upsert({
|
||||
where: { receiptKey },
|
||||
update: {
|
||||
incomingConnectionId: data.connectionId,
|
||||
},
|
||||
create: {
|
||||
receiptKey,
|
||||
incomingChannelId: data.channelId,
|
||||
incomingConnectionId: data.connectionId,
|
||||
upstreamAccount: channel.account,
|
||||
upstreamHost: channel.gatewayHost,
|
||||
upstreamPort: channel.gatewayPort,
|
||||
protocol: channel.protocol,
|
||||
protocolVersion: channel.cmppVersion,
|
||||
provisionalMessageId: data.messageId,
|
||||
sequenceId: data.sequenceId,
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
phoneNumber: data.phoneNumber?.trim() || null,
|
||||
receiptStatus: data.receiptStatus,
|
||||
rawStatus: data.rawStatus,
|
||||
errorCode: data.errorCode,
|
||||
errorMessage: data.errorMessage,
|
||||
deliveredAt,
|
||||
gatewayReceivedAt: data.deliveredAt ? new Date(data.deliveredAt) : null,
|
||||
status: 'pending',
|
||||
nextRetryAt: new Date(),
|
||||
},
|
||||
});
|
||||
const inbox = await this.prisma.upstreamReceiptInbox
|
||||
.upsert({
|
||||
where: { receiptKey },
|
||||
update: {
|
||||
incomingConnectionId: data.connectionId,
|
||||
},
|
||||
create: {
|
||||
receiptKey,
|
||||
incomingChannelId: data.channelId,
|
||||
incomingConnectionId: data.connectionId,
|
||||
upstreamAccount: channel.account,
|
||||
upstreamHost: channel.gatewayHost,
|
||||
upstreamPort: channel.gatewayPort,
|
||||
protocol: channel.protocol,
|
||||
protocolVersion: channel.cmppVersion,
|
||||
provisionalMessageId: data.messageId,
|
||||
sequenceId: protocolUint32ToDb(data.sequenceId),
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
phoneNumber: data.phoneNumber?.trim() || null,
|
||||
receiptStatus: data.receiptStatus,
|
||||
rawStatus: data.rawStatus,
|
||||
errorCode: data.errorCode,
|
||||
errorMessage: data.errorMessage,
|
||||
deliveredAt,
|
||||
gatewayReceivedAt: data.deliveredAt ? new Date(data.deliveredAt) : null,
|
||||
status: 'pending',
|
||||
nextRetryAt: new Date(),
|
||||
},
|
||||
})
|
||||
.catch(async (error: unknown) => {
|
||||
// Prisma can emulate an upsert when the optional update is empty. Another
|
||||
// callback may win the unique receiptKey insert; acknowledge only the
|
||||
// exact durable fact, never swallow unrelated persistence failures.
|
||||
if (error instanceof Prisma.PrismaClientKnownRequestError && error.code === 'P2002') {
|
||||
const existing = await this.prisma.upstreamReceiptInbox.findUnique({ where: { receiptKey } });
|
||||
if (existing) return existing;
|
||||
}
|
||||
throw error;
|
||||
});
|
||||
if (['pending', 'retrying'].includes(inbox.status)) {
|
||||
setImmediate(() => void this.facade.processUpstreamReceiptInboxRecord(inbox.id));
|
||||
}
|
||||
@@ -143,7 +156,7 @@ export class SendReceiptService {
|
||||
messageId: inbox.provisionalMessageId ?? undefined,
|
||||
channelId: inbox.incomingChannelId,
|
||||
connectionId: inbox.incomingConnectionId ?? undefined,
|
||||
sequenceId: inbox.sequenceId ?? undefined,
|
||||
sequenceId: protocolUint32FromDb(inbox.sequenceId),
|
||||
gatewayMessageId: inbox.gatewayMessageId,
|
||||
phoneNumber: inbox.phoneNumber ?? undefined,
|
||||
receiptStatus: normalizeReceiptStatus(inbox.receiptStatus),
|
||||
@@ -223,6 +236,7 @@ export class SendReceiptService {
|
||||
cmppVersion: string;
|
||||
},
|
||||
) {
|
||||
protocolUint32ToDb(data.sequenceId);
|
||||
const resolved = await this.facade.resolveReceiptMessage(data, incomingIdentity);
|
||||
const logicalChannelId = resolved.channelId ?? data.channelId;
|
||||
const receiptKey = receiptEventKey(data, logicalChannelId);
|
||||
@@ -245,7 +259,7 @@ export class SendReceiptService {
|
||||
},
|
||||
data: {
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
sequenceId: data.sequenceId,
|
||||
sequenceId: protocolUint32ToDb(data.sequenceId),
|
||||
},
|
||||
});
|
||||
}
|
||||
@@ -262,7 +276,7 @@ export class SendReceiptService {
|
||||
messageId: resolved.messageId,
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
phoneNumber: data.phoneNumber?.trim() || message.phoneNumber,
|
||||
sequenceId: data.sequenceId,
|
||||
sequenceId: protocolUint32ToDb(data.sequenceId),
|
||||
receiptStatus: data.receiptStatus,
|
||||
rawStatus: data.rawStatus,
|
||||
errorCode: data.errorCode,
|
||||
@@ -573,7 +587,7 @@ export class SendReceiptService {
|
||||
update: {
|
||||
submitRecordId: submitRecord?.id ?? submitRecordId ?? null,
|
||||
channelId: data.channelId ?? message.channelId ?? null,
|
||||
sequenceId: data.sequenceId ?? null,
|
||||
sequenceId: protocolUint32ToDb(data.sequenceId) ?? null,
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
receiptStatus: data.receiptStatus,
|
||||
rawStatus: data.rawStatus,
|
||||
@@ -590,7 +604,7 @@ export class SendReceiptService {
|
||||
attempt: 0,
|
||||
segmentTotal: Math.max(1, Number(message.billingUnits ?? 1)),
|
||||
segmentIndex: 1,
|
||||
sequenceId: data.sequenceId ?? null,
|
||||
sequenceId: protocolUint32ToDb(data.sequenceId) ?? null,
|
||||
gatewayMessageId: data.gatewayMessageId,
|
||||
submitStatus: submitRecord?.submitStatus ?? 'accepted',
|
||||
receiptStatus: data.receiptStatus,
|
||||
|
||||
Reference in New Issue
Block a user