Wait out the messages the application holds before shutting a session down
This commit is contained in:
@@ -1,9 +1,11 @@
|
||||
import type { DlrMerger } from './dlr-merger.ts';
|
||||
import type { OnRequest } from './session-options.ts';
|
||||
import type { PduObject } from './pdu.ts';
|
||||
import type { PduObject, PduObjectInput } from './pdu.ts';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { Session } from './session.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { SmsIdFormat } from './sms-id.ts';
|
||||
import { HeldMessages } from './held-messages.ts';
|
||||
import { Reassembler, decodeSegments } from './reassembly.ts';
|
||||
import { bindCommands, defaults } from './session-options.ts';
|
||||
import { concatInfo } from './udh.ts';
|
||||
@@ -19,6 +21,8 @@ export type IncomingRequestsOptions = {
|
||||
maxReassembly?: number | undefined;
|
||||
onRequest?: OnRequest | undefined;
|
||||
reassemblyTimeout?: number | undefined;
|
||||
/** Past the drain gate: a receipt answering a message the shutdown is still waiting for. */
|
||||
sendHeld: (input: PduObjectInput) => Promise<Result<{ pduObj: PduObject }>>;
|
||||
session: Session;
|
||||
smsIdFormat?: SmsIdFormat | undefined;
|
||||
systemId?: string | undefined;
|
||||
@@ -27,9 +31,11 @@ export type IncomingRequestsOptions = {
|
||||
/** Everything the peer asks of a session: messages, receipts, links and the answers to them. */
|
||||
export class IncomingRequests {
|
||||
private readonly dlrMerger: DlrMerger;
|
||||
private readonly held = new HeldMessages();
|
||||
private readonly log: SmppLog;
|
||||
private readonly onRequest: OnRequest | undefined;
|
||||
private readonly reassembler: Reassembler;
|
||||
private readonly sendHeld: IncomingRequestsOptions['sendHeld'];
|
||||
private readonly session: Session;
|
||||
private readonly smsIdFormat: SmsIdFormat;
|
||||
private readonly systemId: string;
|
||||
@@ -44,6 +50,7 @@ export class IncomingRequests {
|
||||
maxOctets: options.maxOctets,
|
||||
timeout: options.reassemblyTimeout ?? defaults.reassemblyTimeout,
|
||||
});
|
||||
this.sendHeld = options.sendHeld;
|
||||
this.session = options.session;
|
||||
this.smsIdFormat = options.smsIdFormat ?? {};
|
||||
this.systemId = options.systemId ?? defaults.systemId;
|
||||
@@ -82,11 +89,23 @@ export class IncomingRequests {
|
||||
}
|
||||
}
|
||||
|
||||
/** Drops the segments of every message that never became whole. */
|
||||
/** Drops the segments of every message that never became whole, and of every one still held. */
|
||||
clear(): void {
|
||||
this.held.clear();
|
||||
this.reassembler.clear();
|
||||
}
|
||||
|
||||
/** Waits out the messages the application still holds, and says how many it never answered. */
|
||||
async drain(timeout: number, signal?: AbortSignal): Promise<VoidResult> {
|
||||
const unanswered = await this.held.idle(timeout, signal);
|
||||
|
||||
if (unanswered === 0) return {};
|
||||
|
||||
this.log.warn('session - shutting down with messages unanswered', { timeout, unanswered });
|
||||
|
||||
return { err: new Error(`Shut down with ${String(unanswered)} message(s) unanswered`) };
|
||||
}
|
||||
|
||||
private async unhandled(pduObj: PduObject): Promise<void> {
|
||||
if (bindCommands.includes(pduObj.cmdName)) {
|
||||
this.log.info('session - bind on an already bound session', { cmdName: pduObj.cmdName });
|
||||
@@ -139,12 +158,21 @@ export class IncomingRequests {
|
||||
|
||||
if (!first) return;
|
||||
|
||||
this.session.emit('sms', createSms({
|
||||
const sms = createSms({
|
||||
from: paramText(first.params.source_addr),
|
||||
message: decodeSegments(pduObjs),
|
||||
pduObjs,
|
||||
session: this.session,
|
||||
to: paramText(first.params.destination_addr),
|
||||
}));
|
||||
}, {
|
||||
// A turn later, so a listener sending its receipt straight after the response still holds.
|
||||
onAnswered: () => { setImmediate(() => { this.held.release(pduObjs); }); },
|
||||
send: this.sendHeld,
|
||||
});
|
||||
|
||||
this.held.hold(pduObjs);
|
||||
|
||||
// A message nobody took is not work a shutdown can wait for.
|
||||
if (!this.session.emit('sms', sms)) this.held.release(pduObjs);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user