Compare commits

...

8 Commits

Author SHA1 Message Date
Pascal Bourque
d9d6fc2861 Merge branch 'main' into 180-rapid-succession-of-aws_error_mqtt_unexpected_hangup-errors 2025-11-28 09:19:03 -05:00
Pascal Bourque
1b680b693f Example: process devices serially instead of in parallel 2025-11-28 08:43:23 -05:00
Pascal Bourque
181c9238da Merge branch 'main' into 180-rapid-succession-of-aws_error_mqtt_unexpected_hangup-errors 2025-11-23 10:35:14 -05:00
Pascal Bourque
6c24d59760 Added option to enable AWS CRT debug logging 2025-11-23 10:29:41 -05:00
Pascal Bourque
f7c3dc07b3 Recreate MQTT client on interrupt when credentials have expired 2025-11-23 09:53:45 -05:00
Pascal Bourque
2a2a843534 Increased ping timeout 2025-11-16 10:53:35 -05:00
Pascal Bourque
2d49a4ddb9 Hash username in MQTT client ID generation
Replaces the plain username in the MQTT client ID with a SHA-1 hash for improved privacy and to avoid exposing usernames in client identifiers.
2025-11-09 10:57:45 -05:00
Pascal Bourque
5fce04543a Improve MQTT clientId handling and interrupt recovery
Adds process PID to MQTT clientId to reduce collision risk and enhances logging with clientId context. Implements a guard against re-entrant MQTT resets during interrupt storms, clears connection promise before disconnect, and ensures device subscriptions are re-established after recovery. Also adds handling for new error type and improves error reporting.
2025-11-09 10:52:31 -05:00
3 changed files with 24 additions and 10 deletions

View File

@@ -20,6 +20,7 @@ const rootLogger = pino({
/** Main entry point of the example application. */
async function main() {
let session: MysaSession | undefined;
try {
rootLogger.info('Loading session...');
const sessionJson = await readFile('session.json', 'utf8');
@@ -27,7 +28,11 @@ async function main() {
} catch {
rootLogger.info('No valid session file found.');
}
const client = new MysaApiClient(session, { logger: rootLogger.child({ module: 'mysa-js-sdk' }) });
const client = new MysaApiClient(session, {
logger: rootLogger.child({ module: 'mysa-js-sdk' }),
isAwsCrtDebugLoggingEnabled: process.env.AWS_CRT_DEBUG_LOGGING === '1'
});
client.emitter.on('sessionChanged', async (newSession) => {
if (newSession) {
@@ -96,14 +101,12 @@ async function main() {
});
}
await Promise.all(
Object.entries(devices.DevicesObj).map(async ([deviceId, device]) => {
const serial = await client.getDeviceSerialNumber(deviceId);
rootLogger.info(`Serial number for device '${deviceId}' (${device.Name ?? 'Unknown'}): ${serial}`);
for (const [deviceId, device] of Object.entries(devices.DevicesObj)) {
const serial = await client.getDeviceSerialNumber(deviceId);
rootLogger.info(`Serial number for device '${deviceId}' (${device.Name ?? 'Unknown'}): ${serial}`);
await client.startRealtimeUpdates(deviceId);
})
);
await client.startRealtimeUpdates(deviceId);
}
}
main().catch((error) => {

View File

@@ -18,7 +18,7 @@ import {
CognitoUserPool,
CognitoUserSession
} from 'amazon-cognito-identity-js';
import { iot, mqtt } from 'aws-iot-device-sdk-v2';
import { io, iot, mqtt } from 'aws-iot-device-sdk-v2';
import { hash } from 'crypto';
import dayjs, { Dayjs } from 'dayjs';
import duration from 'dayjs/plugin/duration.js';
@@ -152,6 +152,10 @@ export class MysaApiClient {
this._logger = options?.logger || new VoidLogger();
this._fetcher = options?.fetcher || fetch;
if (options?.isAwsCrtDebugLoggingEnabled) {
io.enable_logging(io.LogLevel.DEBUG);
}
if (session) {
this._cognitoUser = new CognitoUser({
Username: session.username,
@@ -741,7 +745,7 @@ export class MysaApiClient {
.with_client_id(this._mqttClientId)
.with_clean_session(false)
.with_keep_alive_seconds(30)
.with_ping_timeout_ms(3000)
.with_ping_timeout_ms(10000)
.with_protocol_operation_timeout_ms(60000)
.with_reconnect_min_sec(1)
.with_reconnect_max_sec(30);

View File

@@ -15,4 +15,11 @@ export interface MysaApiClientOptions {
* @defaultValue The global `fetch` function.
*/
fetcher?: typeof fetch;
/**
* Whether to enable debug logging for AWS CRT.
*
* @defaultValue `false`
*/
isAwsCrtDebugLoggingEnabled?: boolean;
}