@citrineos/util
Version:
The OCPP util module which supplies helpful utilities like cache and queue connectors, etc.
65 lines (64 loc) • 3.44 kB
TypeScript
import type { IConnectionManager, IMessage, IMessageConfirmation, IMessageSender, OcppRequest, OcppResponse } from '@citrineos/base';
import { AbstractMessageSender, MessageState, OcppError } from '@citrineos/base';
import type { ILogObj } from 'tslog';
import { Logger } from 'tslog';
type AnyMessage = IMessage<OcppRequest | OcppResponse | OcppError>;
/**
* A decorator around any {@link IMessageSender} that adds resilience when the
* underlying message broker is unavailable.
*
* Behaviour when the broker is **disconnected**:
* - **Call messages** (`MessageState.Request`): a `maxCallLengthSeconds` timeout is
* started. When it fires the optional {@link onCallTimeout} callback is invoked
* (e.g. to close the charger's WebSocket) and the pending entry is removed from
* memory to prevent retry accumulation.
* - **All other messages** (`MessageState.Response` / `MessageState.Unknown`): the
* message is held in an in-memory buffer and replayed in order once the broker
* reconnects.
*
* Behaviour when the broker **reconnects**:
* - All buffered non-Call messages are flushed in order through the inner sender.
* - In-flight Call timeouts continue to run (they will still close the WS connection
* because the Call was never delivered to a module).
*/
export declare class BrokerAwareMessageSender extends AbstractMessageSender implements IMessageSender {
private readonly _inner;
private readonly _connectionManager;
private readonly _maxCallLengthSeconds;
/** Pending non-Call messages waiting to be flushed after reconnection. */
private _buffer;
/**
* Active Call timeouts keyed by connection identifier (`tenantId:stationId`).
* When a timeout fires the entry is deleted and `_onCallTimeout` is invoked.
*/
private _callTimeouts;
/**
* Optional callback invoked when a Call times out while the broker is down.
* Typically used to close the corresponding WebSocket connection.
* Can be set after construction to avoid circular dependency issues.
*/
onCallTimeout?: (stationId: string, tenantId: number) => Promise<void>;
constructor(_inner: IMessageSender, _connectionManager: IConnectionManager, _maxCallLengthSeconds: number, logger?: Logger<ILogObj>);
sendRequest(message: IMessage<OcppRequest>, payload?: OcppRequest): Promise<IMessageConfirmation>;
sendResponse(message: IMessage<OcppResponse | OcppError>, payload?: OcppResponse | OcppError): Promise<IMessageConfirmation>;
send(message: AnyMessage, payload?: OcppRequest | OcppResponse | OcppError, state?: MessageState): Promise<IMessageConfirmation>;
shutdown(): Promise<void>;
/**
* Starts a `maxCallLengthSeconds` timer for a Call that cannot be delivered
* because the broker is down. On expiry the optional {@link onCallTimeout}
* callback is invoked and the timeout entry is cleaned up.
*
* Returns `{ success: true }` so the router does not immediately send a
* CallError – the charger will wait until the connection is closed by the timer.
*/
private _handleDisconnectedCall;
/** Adds a non-Call message to the in-memory buffer. */
private _bufferMessage;
/**
* Replays all buffered messages through the inner sender.
* If the broker drops again mid-flush the remaining messages are re-buffered.
*/
private _flushBuffer;
private _clearAllCallTimeouts;
}
export {};