Declare the logger contract in the library instead of depending on @larvit/log
This commit is contained in:
@@ -20,7 +20,7 @@ These are not preferences. Breaking one is a defect.
|
||||
`err`. No `throw`, no rejected promises, no exceptions as control flow. Node APIs that throw are
|
||||
wrapped at the boundary and converted into a result. Programmer errors (bad arguments) are
|
||||
results too.
|
||||
2. **Log messages are static strings.** Every dynamic value goes into `@larvit/log` metadata. Never
|
||||
2. **Log messages are static strings.** Every dynamic value goes into the log metadata. Never
|
||||
interpolate, never concatenate.
|
||||
- GOOD: `log.debug('sendSms() - splitting message', { parts: msgs.length, to });`
|
||||
- BANNED: `log.debug('sendSms() - splitting into ' + msgs.length + ' parts');`
|
||||
@@ -45,7 +45,7 @@ src/
|
||||
expiring-groups.ts ExpiringGroups: the capped, expiring store both of those share
|
||||
incoming-requests.ts Every request the peer sends: messages, receipts, links, unknown commands
|
||||
link-timers.ts LinkTimers: the enquire_link heartbeat and the idle timeout
|
||||
log.ts silentLog — the default when the application passes none
|
||||
log.ts SmppLog, the logger contract, and silentLog — the default
|
||||
message.ts Encoding detection, splitting, bit counting, SMPP date formatting
|
||||
pdu.ts pduToObj / objToPdu / pduReturn — synchronous, result-returning
|
||||
pdu-framer.ts PduFramer: a byte stream cut into complete PDUs
|
||||
@@ -185,6 +185,12 @@ exactly 140.
|
||||
`server()`, so an implementation that needs 5.0 throughout can have it. The threshold at or above
|
||||
which a peer may be sent optional parameters is fixed at 0x34 by the spec and is not the same
|
||||
constant as the declared version.
|
||||
- **The logger is a five-method contract this library declares, not a dependency.** `SmppLog` in
|
||||
`log.ts` is what the code actually calls (`debug`, `error`, `info`, `verbose`, `warn`), so an
|
||||
application can satisfy it with an object literal and `@larvit/smpp` ships with no runtime
|
||||
dependencies. `@larvit/log` implements it structurally and stays a devDependency, where
|
||||
`test/tls.test.ts` passing a real `Log` as the server's logger keeps that compatibility compiled.
|
||||
|
||||
- **The TLS tests build their own self-signed certificate in DER** (`test/tls.test.ts`) instead of
|
||||
adding a devDependency or shelling out to openssl. Maintainer's call, 2026-08-26: the dev image
|
||||
`node:24.18.0-bookworm-slim` ships no openssl binary, so a shelled-out fixture would pass in CI
|
||||
|
||||
@@ -11,8 +11,7 @@ promises and the rough edges taken off.
|
||||
|
||||
## Requirements
|
||||
|
||||
Node 18 or later. The only runtime dependency is
|
||||
[`@larvit/log`](https://www.npmjs.com/package/@larvit/log).
|
||||
Node 18 or later. No runtime dependencies.
|
||||
|
||||
## Install
|
||||
|
||||
@@ -85,7 +84,7 @@ Every one is optional.
|
||||
| `responseTimeout` | `30000` | How long to wait for a response before giving up on it; `0` waits forever. |
|
||||
| `maxOutstanding` | `10` | Requests allowed on the wire at once; further sends queue. |
|
||||
| `reconnect` | off | `{ minDelay, maxDelay }` to re-bind automatically after a drop or an idle timeout, with exponential backoff. |
|
||||
| `log` | silent | A `@larvit/log` instance. |
|
||||
| `log` | silent | Any object with `debug`, `error`, `info`, `verbose` and `warn` methods — see [Logging](#logging). |
|
||||
| `signal` | — | An `AbortSignal` that cancels connecting and tears the session down. |
|
||||
|
||||
### Sending
|
||||
@@ -217,6 +216,35 @@ Runtime failures on a live connection arrive as `sessionError` and `serverError`
|
||||
deliberately not called `error`: Node turns an unhandled `error` event into a thrown exception, which
|
||||
is exactly what this library promises not to do.
|
||||
|
||||
## Logging
|
||||
|
||||
`log` takes any object with `debug`, `error`, `info`, `verbose` and `warn` methods, each
|
||||
`(msg: string, metadata?: Record<string, boolean | number | string>) => void`. Message strings are
|
||||
static and every dynamic value goes in the metadata, so entries group by message.
|
||||
|
||||
[`@larvit/log`](https://www.npmjs.com/package/@larvit/log) implements it as it stands:
|
||||
|
||||
```javascript
|
||||
import { Log } from '@larvit/log';
|
||||
import { client } from '@larvit/smpp';
|
||||
|
||||
const { err, session } = await client({ log: new Log('debug') });
|
||||
```
|
||||
|
||||
So does an object of your own, forwarding wherever you want it:
|
||||
|
||||
```javascript
|
||||
const log = {
|
||||
debug: () => undefined,
|
||||
error: (msg, metadata) => { console.error(msg, metadata); },
|
||||
info: (msg, metadata) => { console.info(msg, metadata); },
|
||||
verbose: () => undefined,
|
||||
warn: (msg, metadata) => { console.warn(msg, metadata); },
|
||||
};
|
||||
```
|
||||
|
||||
TypeScript users can import `SmppLog` to have the compiler check one.
|
||||
|
||||
## Sessions
|
||||
|
||||
### Events
|
||||
@@ -289,8 +317,8 @@ The spec tables are exported both individually (`cmds`, `consts`, `encodings`, `
|
||||
- **`defs.filters` is gone.** It was declared on every command and TLV but never invoked, so it did
|
||||
nothing. SMPP time formatting, the one part worth keeping, is exported as `smppTime`.
|
||||
- **The `error` event is `sessionError`** (and `serverError` on the server handle).
|
||||
- **`log`** takes a [`@larvit/log`](https://www.npmjs.com/package/@larvit/log) instance instead of a
|
||||
`larvitutils` one, and is silent by default.
|
||||
- **`log`** takes any object with `debug`, `error`, `info`, `verbose` and `warn` methods instead of a
|
||||
`larvitutils` one, and is silent by default. See [Logging](#logging).
|
||||
|
||||
### Behaviour that changed on the wire
|
||||
|
||||
|
||||
Generated
+2
-3
@@ -8,11 +8,9 @@
|
||||
"name": "@larvit/smpp",
|
||||
"version": "1.0.0",
|
||||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@larvit/log": "2.3.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "10.0.1",
|
||||
"@larvit/log": "2.3.0",
|
||||
"@types/node": "22.20.1",
|
||||
"eslint": "10.9.1",
|
||||
"smpp": "0.6.0-rc.4",
|
||||
@@ -221,6 +219,7 @@
|
||||
"version": "2.3.0",
|
||||
"resolved": "https://registry.npmjs.org/@larvit/log/-/log-2.3.0.tgz",
|
||||
"integrity": "sha512-gLRMDWrFnoMGdAr9NXMXRKOUeceU6Qd/CW0c6qDO+DLFT1xWrqO2ubsHyPqPzlZHVUO3w3Bk7kOWo6C2Ykn4ZQ==",
|
||||
"dev": true,
|
||||
"license": "MIT",
|
||||
"engines": {
|
||||
"node": ">=18"
|
||||
|
||||
+1
-3
@@ -49,13 +49,11 @@
|
||||
},
|
||||
"devDependencies": {
|
||||
"@eslint/js": "10.0.1",
|
||||
"@larvit/log": "2.3.0",
|
||||
"@types/node": "22.20.1",
|
||||
"eslint": "10.9.1",
|
||||
"smpp": "0.6.0-rc.4",
|
||||
"typescript": "6.0.3",
|
||||
"typescript-eslint": "8.68.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"@larvit/log": "2.3.0"
|
||||
}
|
||||
}
|
||||
|
||||
+4
-4
@@ -1,6 +1,6 @@
|
||||
import type { ConnectionOptions } from 'node:tls';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { Socket } from 'node:net';
|
||||
import { Session } from './session.ts';
|
||||
import { checkSessionOptions, undeclaredInterfaceVersion } from './session-options.ts';
|
||||
@@ -20,7 +20,7 @@ export type ClientOptions = {
|
||||
host?: string;
|
||||
idleTimeout?: number;
|
||||
interfaceVersion?: number;
|
||||
log?: LogInt;
|
||||
log?: SmppLog;
|
||||
maxOutstanding?: number;
|
||||
password?: string;
|
||||
port?: number;
|
||||
@@ -134,7 +134,7 @@ async function bind(session: Session, options: ClientOptions): Promise<VoidResul
|
||||
return {};
|
||||
}
|
||||
|
||||
function createSession(options: ClientOptions, log: LogInt, sock: Socket): Session {
|
||||
function createSession(options: ClientOptions, log: SmppLog, sock: Socket): Session {
|
||||
const enquireLinkInterval = options.enquireLinkInterval ?? defaults.enquireLinkInterval;
|
||||
|
||||
return new Session({
|
||||
@@ -157,7 +157,7 @@ function createSession(options: ClientOptions, log: LogInt, sock: Socket): Sessi
|
||||
});
|
||||
}
|
||||
|
||||
async function connect(options: ClientOptions, log: LogInt): Promise<Result<{ sock: Socket }>> {
|
||||
async function connect(options: ClientOptions, log: SmppLog): Promise<Result<{ sock: Socket }>> {
|
||||
const checked = checkSessionOptions(options);
|
||||
|
||||
if (checked.err) {
|
||||
|
||||
+3
-3
@@ -1,12 +1,12 @@
|
||||
import type { Dlr } from './dlr.ts';
|
||||
import type { MessageState } from './defs/constants.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import { ExpiringGroups } from './expiring-groups.ts';
|
||||
|
||||
export type MessageDlr = Dlr & { segments: Dlr[] };
|
||||
|
||||
export type DlrMergerOptions = {
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
max: number;
|
||||
/** Injected so expiry can be exercised without a wall clock. */
|
||||
now?: (() => number) | undefined;
|
||||
@@ -50,7 +50,7 @@ function severityOf(dlr: Dlr): number {
|
||||
|
||||
export class DlrMerger {
|
||||
private readonly groups: ExpiringGroups<Group>;
|
||||
private readonly log: LogInt;
|
||||
private readonly log: SmppLog;
|
||||
private readonly max: number;
|
||||
|
||||
constructor(options: DlrMergerOptions) {
|
||||
|
||||
@@ -1,8 +1,8 @@
|
||||
import type { DlrMerger } from './dlr-merger.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { OnRequest } from './session-options.ts';
|
||||
import type { PduObject } from './pdu.ts';
|
||||
import type { Session } from './session.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import { Reassembler, decodeSegments } from './reassembly.ts';
|
||||
import { bindCommands, defaults } from './session-options.ts';
|
||||
import { concatInfo } from './udh.ts';
|
||||
@@ -13,7 +13,7 @@ import { paramText } from './defs/types.ts';
|
||||
|
||||
export type IncomingRequestsOptions = {
|
||||
dlrMerger: DlrMerger;
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
maxOctets?: number | undefined;
|
||||
maxReassembly?: number | undefined;
|
||||
onRequest?: OnRequest | undefined;
|
||||
@@ -25,7 +25,7 @@ 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 log: LogInt;
|
||||
private readonly log: SmppLog;
|
||||
private readonly onRequest: OnRequest | undefined;
|
||||
private readonly reassembler: Reassembler;
|
||||
private readonly session: Session;
|
||||
|
||||
@@ -38,6 +38,7 @@ export type { Dlr, Receipt } from './dlr.ts';
|
||||
export type { SendRespOptions, Sms, SmsInput } from './sms.ts';
|
||||
export type { ConcatInfo } from './udh.ts';
|
||||
export type { Result, VoidResult } from './result.ts';
|
||||
export type { SmppLog } from './log.ts';
|
||||
export type {
|
||||
AuthenticateInput,
|
||||
AuthenticateResult,
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { SmppLog } from './log.ts';
|
||||
|
||||
export type LinkTimersOptions = {
|
||||
/** How long between enquire_link probes. Undefined or 0 never probes. */
|
||||
enquireLinkInterval?: number | undefined;
|
||||
/** How long a silent peer is kept. Undefined or 0 keeps it forever. */
|
||||
idleTimeout?: number | undefined;
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
onEnquireLink: () => void;
|
||||
onIdle: () => void;
|
||||
};
|
||||
|
||||
+20
-3
@@ -1,5 +1,22 @@
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import { Log } from '@larvit/log';
|
||||
export type LogMetadata = Record<string, boolean | number | string>;
|
||||
export type LogMethod = (msg: string, metadata?: LogMetadata) => void;
|
||||
|
||||
/** What the library needs from a logger. A `@larvit/log` instance satisfies it as it stands. */
|
||||
export type SmppLog = {
|
||||
debug: LogMethod;
|
||||
error: LogMethod;
|
||||
info: LogMethod;
|
||||
verbose: LogMethod;
|
||||
warn: LogMethod;
|
||||
};
|
||||
|
||||
const noop: LogMethod = () => undefined;
|
||||
|
||||
/** The default: a library that says nothing unless the application asks it to. */
|
||||
export const silentLog: LogInt = new Log({ logLevel: 'none' });
|
||||
export const silentLog: SmppLog = {
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
verbose: noop,
|
||||
warn: noop,
|
||||
};
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { PduObject } from './pdu.ts';
|
||||
import type { Result } from './result.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import { maxSeqNr } from './pdu.ts';
|
||||
|
||||
export type WaitOptions = {
|
||||
@@ -14,11 +14,11 @@ type Pending = {
|
||||
|
||||
/** Hands out sequence numbers and matches responses to the requests waiting for them. */
|
||||
export class PendingRequests {
|
||||
private readonly log: LogInt;
|
||||
private readonly log: SmppLog;
|
||||
private readonly pending = new Map<number, Pending>();
|
||||
private ourSeqNr = 1;
|
||||
|
||||
constructor(log: LogInt) {
|
||||
constructor(log: SmppLog) {
|
||||
this.log = log;
|
||||
}
|
||||
|
||||
|
||||
+3
-3
@@ -1,14 +1,14 @@
|
||||
import type { ConcatInfo } from './udh.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { ParamValue } from './defs/types.ts';
|
||||
import type { PduObject } from './pdu.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { Tlv } from './defs/tlvs.ts';
|
||||
import { ExpiringGroups } from './expiring-groups.ts';
|
||||
import { decodeMessage } from './message.ts';
|
||||
import { paramText } from './defs/types.ts';
|
||||
|
||||
export type ReassemblerOptions = {
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
max: number;
|
||||
maxOctets?: number | undefined;
|
||||
/** Injected so expiry can be exercised without a wall clock. */
|
||||
@@ -97,7 +97,7 @@ export function decodeSegments(pduObjs: PduObject[]): string {
|
||||
/** Holds the segments of incomplete multipart messages until they are whole, capped and expiring. */
|
||||
export class Reassembler {
|
||||
private readonly groups: ExpiringGroups<Group>;
|
||||
private readonly log: LogInt;
|
||||
private readonly log: SmppLog;
|
||||
private readonly max: number;
|
||||
private readonly maxOctets: number;
|
||||
private octets = 0;
|
||||
|
||||
@@ -1,10 +1,10 @@
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { Socket } from 'node:net';
|
||||
|
||||
export type ReconnectLoopOptions = {
|
||||
connect: () => Promise<Result<{ sock: Socket }>>;
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
maxDelay: number;
|
||||
minDelay: number;
|
||||
/** Brings the owner back up on a freshly opened socket. An err means try again. */
|
||||
|
||||
+2
-2
@@ -1,8 +1,8 @@
|
||||
import type { EncodingName } from './defs/encodings.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { ParamValue } from './defs/types.ts';
|
||||
import type { PduObject, PduObjectInput } from './pdu.ts';
|
||||
import type { Result } from './result.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import { consts } from './defs/constants.ts';
|
||||
import { detect } from './defs/encodings.ts';
|
||||
import { paramText } from './defs/types.ts';
|
||||
@@ -28,7 +28,7 @@ export type SendSmsResult = { err?: Error; pduObjs: PduObject[]; smsIds: string[
|
||||
|
||||
/** What sending needs from the session: a concat reference and a way onto the wire. */
|
||||
export type SendSmsDeps = {
|
||||
log: LogInt;
|
||||
log: SmppLog;
|
||||
reference: number;
|
||||
send: (input: PduObjectInput) => Promise<Result<{ pduObj: PduObject }>>;
|
||||
};
|
||||
|
||||
+7
-7
@@ -1,8 +1,8 @@
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { PduObject, TlvInput } from './pdu.ts';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { Server as NetServer, Socket } from 'node:net';
|
||||
import type { Server as TlsServer, TlsOptions } from 'node:tls';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import { EventEmitter } from 'node:events';
|
||||
import { Session, bindCommands, defaultSystemId } from './session.ts';
|
||||
import { checkSessionOptions, undeclaredInterfaceVersion } from './session-options.ts';
|
||||
@@ -26,7 +26,7 @@ export type ServerOptions = {
|
||||
host?: string;
|
||||
idleTimeout?: number;
|
||||
interfaceVersion?: number;
|
||||
log?: LogInt;
|
||||
log?: SmppLog;
|
||||
maxOutstanding?: number;
|
||||
maxOctets?: number;
|
||||
maxReassembly?: number;
|
||||
@@ -54,10 +54,10 @@ const defaults = {
|
||||
export class SmppServer extends EventEmitter<ServerEvents> {
|
||||
readonly sessions = new Set<Session>();
|
||||
|
||||
private readonly log: LogInt;
|
||||
private readonly log: SmppLog;
|
||||
private readonly server: NetServer;
|
||||
|
||||
constructor(server: NetServer, log: LogInt) {
|
||||
constructor(server: NetServer, log: SmppLog) {
|
||||
super();
|
||||
this.log = log;
|
||||
this.server = server;
|
||||
@@ -223,7 +223,7 @@ function onConnection(sock: Socket, options: ServerOptions, server: SmppServer):
|
||||
}
|
||||
|
||||
/** Node reports a rejected handshake as `tlsClientError`, which is never an `error` event. */
|
||||
function createSecureListener(tlsOptions: TlsOptions, log: LogInt): TlsServer {
|
||||
function createSecureListener(tlsOptions: TlsOptions, log: SmppLog): TlsServer {
|
||||
const listener = createTlsServer(tlsOptions);
|
||||
|
||||
listener.on('tlsClientError', err => {
|
||||
@@ -233,7 +233,7 @@ function createSecureListener(tlsOptions: TlsOptions, log: LogInt): TlsServer {
|
||||
return listener;
|
||||
}
|
||||
|
||||
function checkOptions(options: ServerOptions, log: LogInt, port: number): VoidResult {
|
||||
function checkOptions(options: ServerOptions, log: SmppLog, port: number): VoidResult {
|
||||
const checked = checkSessionOptions(options);
|
||||
|
||||
if (checked.err) return { err: checked.err };
|
||||
@@ -258,7 +258,7 @@ function checkOptions(options: ServerOptions, log: LogInt, port: number): VoidRe
|
||||
|
||||
function createListener(
|
||||
options: ServerOptions,
|
||||
log: LogInt,
|
||||
log: SmppLog,
|
||||
port: number,
|
||||
): Result<{ listener: NetServer | TlsServer; useTls: boolean }> {
|
||||
const useTls = options.tls !== undefined && options.tls !== false;
|
||||
|
||||
@@ -1,9 +1,9 @@
|
||||
import type { Dlr } from './dlr.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { MessageDlr } from './dlr-merger.ts';
|
||||
import type { PduObject } from './pdu.ts';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { Session } from './session.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { Sms } from './sms.ts';
|
||||
import type { Socket } from 'node:net';
|
||||
|
||||
@@ -48,7 +48,7 @@ export type ReconnectOptions = {
|
||||
export type SessionOptions = {
|
||||
enquireLinkInterval?: number | undefined;
|
||||
idleTimeout?: number | undefined;
|
||||
log?: LogInt | undefined;
|
||||
log?: SmppLog | undefined;
|
||||
maxOctets?: number | undefined;
|
||||
maxOutstanding?: number | undefined;
|
||||
maxReassembly?: number | undefined;
|
||||
|
||||
+2
-2
@@ -1,11 +1,11 @@
|
||||
import type { ErrorName } from './defs/errors.ts';
|
||||
import type { LogInt } from '@larvit/log';
|
||||
import type { MessageDlr } from './dlr-merger.ts';
|
||||
import type { ParamValue } from './defs/types.ts';
|
||||
import type { PduObject, PduObjectInput, TlvInput } from './pdu.ts';
|
||||
import type { ReconnectOptions, SendOptions, SessionEvents, SessionOptions } from './session-options.ts';
|
||||
import type { Result, VoidResult } from './result.ts';
|
||||
import type { SendSmsOptions, SendSmsResult } from './send-sms.ts';
|
||||
import type { SmppLog } from './log.ts';
|
||||
import type { Socket } from 'node:net';
|
||||
import { DlrMerger } from './dlr-merger.ts';
|
||||
import { EventEmitter } from 'node:events';
|
||||
@@ -35,7 +35,7 @@ export { bindCommands, defaultSystemId };
|
||||
export class Session extends EventEmitter<SessionEvents> {
|
||||
/** Replaced on reconnect, so hold the session rather than this. */
|
||||
sock: Socket;
|
||||
readonly log: LogInt;
|
||||
readonly log: SmppLog;
|
||||
|
||||
loggedIn = false;
|
||||
/** What the peer declared when binding: 0x00 if it declared none, undefined before any bind. */
|
||||
|
||||
@@ -8,6 +8,7 @@ import type { MessageDlr } from '../src/session.ts';
|
||||
import type { PduObject, PduObjectInput } from '../src/pdu.ts';
|
||||
import type { Result } from '../src/result.ts';
|
||||
import type { SendSmsResult } from '../src/send-sms.ts';
|
||||
import type { SmppLog } from '../src/log.ts';
|
||||
import type { Sms } from '../src/sms.ts';
|
||||
import type { SmppServer } from '../src/server.ts';
|
||||
import { Reassembler, decodeSegments } from '../src/reassembly.ts';
|
||||
@@ -357,12 +358,22 @@ describe('reassembly bounds', () => {
|
||||
|
||||
// The UDH is peer-controlled, and the default authenticate() accepts every peer.
|
||||
test('refuses a segment whose concatenation metadata cannot be honoured', () => {
|
||||
const reassembler = new Reassembler({ log: silentLog, max: 10, now: () => 0, timeout: 60_000 });
|
||||
const warnings: string[] = [];
|
||||
const noop = (): void => undefined;
|
||||
const log: SmppLog = {
|
||||
debug: noop,
|
||||
error: noop,
|
||||
info: noop,
|
||||
verbose: noop,
|
||||
warn: msg => { warnings.push(msg); },
|
||||
};
|
||||
const reassembler = new Reassembler({ log, max: 10, now: () => 0, timeout: 60_000 });
|
||||
|
||||
assert.equal(collect(reassembler, 1, 1, 0), undefined);
|
||||
assert.equal(collect(reassembler, 2, 0, 3), undefined);
|
||||
assert.equal(collect(reassembler, 3, 4, 3), undefined);
|
||||
assert.equal(reassembler.size, 0);
|
||||
assert.deepEqual(warnings, Array(3).fill('reassembler - dropping a segment the UDH numbers impossibly'));
|
||||
});
|
||||
|
||||
// Parts 1/2 then 2/3 would otherwise complete the stored two-part group, truncating the message.
|
||||
|
||||
Reference in New Issue
Block a user