Route sms.ts through its handlers, all of it #34

Merged
lilleman merged 2 commits from sms-handlers into main 2026-09-28 00:57:37 +02:00
4 changed files with 16 additions and 12 deletions
Showing only changes of commit 76c6783317 - Show all commits
+4
View File
@@ -48,6 +48,7 @@ type Send = (input: PduObjectInput) => Promise<Result<{ pduObj: PduObject }>>;
/** What the incoming side asks of the session it serves; the session decides how. */ /** What the incoming side asks of the session it serves; the session decides how. */
export type IncomingDeps = { export type IncomingDeps = {
acceptsOptionalParams: () => boolean;
answer: (pduObj: PduObject, status?: ErrorName, params?: Record<string, ParamValue>) => Promise<VoidResult>; answer: (pduObj: PduObject, status?: ErrorName, params?: Record<string, ParamValue>) => Promise<VoidResult>;
bindAllows: (cmdName: string) => boolean; bindAllows: (cmdName: string) => boolean;
boundAs: () => BindType | undefined; boundAs: () => BindType | undefined;
@@ -318,6 +319,9 @@ export class IncomingRequests {
pduObjs, pduObjs,
to: paramText(first.params.destination_addr), to: paramText(first.params.destination_addr),
}, { }, {
acceptsOptionalParams: () => this.deps.acceptsOptionalParams(),
answer: (pduObj, status, params) => this.deps.answer(pduObj, status, params),
bindAllows: cmdName => this.deps.bindAllows(cmdName),
lostLink: () => this.linkGeneration !== generation, lostLink: () => this.linkGeneration !== generation,
onAnswered: release, onAnswered: release,
// Past the refusal only while a drain is still waiting for this message; an ordinary send after. // Past the refusal only while a drain is still waiting for this message; an ordinary send after.
+1
View File
@@ -247,6 +247,7 @@ export class Session extends EventEmitter<SessionEvents> {
private incomingDeps(onRequest: OnRequest | undefined): IncomingDeps { private incomingDeps(onRequest: OnRequest | undefined): IncomingDeps {
return { return {
acceptsOptionalParams: () => this.acceptsOptionalParams(),
answer: (pduObj, status, params) => this.sendReturn(pduObj, status, params), answer: (pduObj, status, params) => this.sendReturn(pduObj, status, params),
bindAllows: cmdName => this.bindAllows(cmdName), bindAllows: cmdName => this.bindAllows(cmdName),
boundAs: () => this.boundAs, boundAs: () => this.boundAs,
+11 -7
View File
@@ -1,5 +1,6 @@
import type { ErrorName } from './defs/errors.ts'; import type { ErrorName } from './defs/errors.ts';
import type { MessageState } from './defs/constants.ts'; import type { MessageState } from './defs/constants.ts';
import type { ParamValue } from './defs/types.ts';
import type { PduObject, PduObjectInput, TlvInputs } from './pdu.ts'; import type { PduObject, PduObjectInput, TlvInputs } from './pdu.ts';
import type { Result, VoidResult } from './result.ts'; import type { Result, VoidResult } from './result.ts';
import type { Session } from './session.ts'; import type { Session } from './session.ts';
@@ -68,6 +69,9 @@ export type SmsInput = {
/** What the session's incoming side gives a message so it can be answered and accounted for. */ /** What the session's incoming side gives a message so it can be answered and accounted for. */
export type SmsHandlers = { export type SmsHandlers = {
acceptsOptionalParams: () => boolean;
answer: (pduObj: PduObject, status: ErrorName, params: Record<string, ParamValue>) => Promise<VoidResult>;
bindAllows: (cmdName: string) => boolean;
lostLink: () => boolean; lostLink: () => boolean;
onAnswered: () => void; onAnswered: () => void;
send: (input: PduObjectInput) => Promise<Result<{ pduObj: PduObject }>>; send: (input: PduObjectInput) => Promise<Result<{ pduObj: PduObject }>>;
@@ -89,7 +93,7 @@ export function createSms(input: SmsInput, handlers: SmsHandlers): Sms {
from: input.from, from: input.from,
message: input.message, message: input.message,
pduObjs: input.pduObjs, pduObjs: input.pduObjs,
sendDlr: status => sendDlr(sms, handlers.send, status), sendDlr: status => sendDlr(sms, handlers, status),
sendResp: options => (input.answeredAs === undefined sendResp: options => (input.answeredAs === undefined
? sendResp(sms, answered, options ?? {}, handlers) ? sendResp(sms, answered, options ?? {}, handlers)
: answeredOnArrival(options ?? {}, handlers)), : answeredOnArrival(options ?? {}, handlers)),
@@ -130,7 +134,7 @@ async function sendResp(
sms: Sms, sms: Sms,
answered: { smsId: string }, answered: { smsId: string },
options: SendRespOptions, options: SendRespOptions,
handlers: Pick<SmsHandlers, 'lostLink' | 'onAnswered'>, handlers: Pick<SmsHandlers, 'answer' | 'lostLink' | 'onAnswered'>,
): Promise<VoidResult> { ): Promise<VoidResult> {
const total = sms.pduObjs.length; const total = sms.pduObjs.length;
@@ -149,7 +153,7 @@ async function sendResp(
return { err: new Error('The link this message arrived on is gone, so nothing would correlate the response') }; return { err: new Error('The link this message arrived on is gone, so nothing would correlate the response') };
} }
const results = await Promise.all(sms.pduObjs.map((pduObj, index) => sms.session.sendReturn( const results = await Promise.all(sms.pduObjs.map((pduObj, index) => handlers.answer(
pduObj, pduObj,
options.status ?? 'ESME_ROK', options.status ?? 'ESME_ROK',
respIdParams(pduObj.cmdName, segmentId(answered.smsId, index, total)), respIdParams(pduObj.cmdName, segmentId(answered.smsId, index, total)),
@@ -210,10 +214,10 @@ function collectReceipt(sent: Result<{ pduObj: PduObject }>[]): SendDlrResult {
async function sendDlr( async function sendDlr(
sms: Sms, sms: Sms,
send: SmsHandlers['send'], handlers: Pick<SmsHandlers, 'acceptsOptionalParams' | 'bindAllows' | 'send'>,
status: MessageState = 'DELIVERED', status: MessageState = 'DELIVERED',
): Promise<SendDlrResult> { ): Promise<SendDlrResult> {
if (!sms.session.bindAllows('deliver_sm')) { if (!handlers.bindAllows('deliver_sm')) {
return { return {
err: new Error('A transmitter-bound session does not carry deliver_sm'), err: new Error('A transmitter-bound session does not carry deliver_sm'),
pduObjs: [], pduObjs: [],
@@ -226,7 +230,7 @@ async function sendDlr(
const sent = await Promise.all(sms.pduObjs.map((_segment, index) => { const sent = await Promise.all(sms.pduObjs.map((_segment, index) => {
const smsId = segmentId(sms.smsId, index, total); const smsId = segmentId(sms.smsId, index, total);
return send({ return handlers.send({
cmdName: 'deliver_sm', cmdName: 'deliver_sm',
params: { params: {
destination_addr: sms.from, destination_addr: sms.from,
@@ -236,7 +240,7 @@ async function sendDlr(
short_message: receiptText(sms, smsId, status), short_message: receiptText(sms, smsId, status),
source_addr: sms.to, source_addr: sms.to,
}, },
...(sms.session.acceptsOptionalParams() ? { tlvs: receiptTlvs(smsId, status) } : {}), ...(handlers.acceptsOptionalParams() ? { tlvs: receiptTlvs(smsId, status) } : {}),
}); });
})); }));
return collectReceipt(sent); return collectReceipt(sent);
-5
View File
@@ -199,11 +199,6 @@ next work ([decision](docs/decisions.md#internals-and-tests)).
### Locality — next, ahead of everything below; 5–6 today, and the gate is 7 ### Locality — next, ahead of everything below; 5–6 today, and the gate is 7
- [ ] **Route `sms.ts` through its handlers, all of it.** `createSms()` already injects
`handlers.send`, and then reaches `sms.session.sendReturn()`, `sms.session.bindAllows()` and
`sms.session.acceptsOptionalParams()` anyway — two channels to one collaborator. `Sms.session`
stays public as data the application reads.
- [ ] **Give the held-message protocol one name and one home.** `emitSms()` is the unit 8 of 9 - [ ] **Give the held-message protocol one name and one home.** `emitSms()` is the unit 8 of 9
readers named and 4 would least want to modify, and every one proposed the same fix. It runs readers named and 4 would least want to modify, and every one proposed the same fix. It runs
five mechanisms in one scope: a hold keyed by array identity, a `working` counter seeded from five mechanisms in one scope: a hold keyed by array identity, a `working` counter seeded from