stormcloud-video-player 0.8.38 → 0.8.40

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -308,10 +308,56 @@ function buildPlayerTopic(licenseKey, channel) {
308
308
  // src/utils/mqttClient.ts
309
309
  var import_mqtt = __toESM(require("mqtt"), 1);
310
310
  var LOG = "[StormcloudVideoPlayer][MQTT]";
311
+ var KEEPALIVE_SECONDS = 30;
312
+ var CONNECT_TIMEOUT_MS = 1e4;
313
+ var RECONNECT_BASE_MS = 5e3;
314
+ var RECONNECT_MAX_MS = 6e4;
315
+ var MAX_RECONNECT_ATTEMPTS = 8;
316
+ var COOLDOWN_MS = 10 * 6e4;
311
317
  var client = null;
312
318
  var status = "disconnected";
313
- function initMQTTClient() {
314
- if (client || !isMQTTEnabled()) return;
319
+ var reconnectAttempts = 0;
320
+ var reconnectTimer = null;
321
+ var stopped = false;
322
+ function clearReconnectTimer() {
323
+ if (reconnectTimer) {
324
+ clearTimeout(reconnectTimer);
325
+ reconnectTimer = null;
326
+ }
327
+ }
328
+ function teardownClient() {
329
+ if (client) {
330
+ try {
331
+ client.removeAllListeners();
332
+ client.end(true);
333
+ } catch (unused) {}
334
+ client = null;
335
+ }
336
+ }
337
+ function scheduleReconnect() {
338
+ if (stopped || !isMQTTEnabled() || reconnectTimer) return;
339
+ if (reconnectAttempts >= MAX_RECONNECT_ATTEMPTS) {
340
+ console.warn("".concat(LOG, " giving up after ").concat(reconnectAttempts, " attempts; cooling down for ").concat(COOLDOWN_MS / 6e4, "m"));
341
+ teardownClient();
342
+ status = "disconnected";
343
+ reconnectTimer = setTimeout(function() {
344
+ reconnectTimer = null;
345
+ reconnectAttempts = 0;
346
+ openConnection();
347
+ }, COOLDOWN_MS);
348
+ return;
349
+ }
350
+ var delay = Math.min(RECONNECT_MAX_MS, RECONNECT_BASE_MS * Math.pow(2, reconnectAttempts));
351
+ var jitter = Math.floor(Math.random() * 1e3);
352
+ reconnectAttempts += 1;
353
+ reconnectTimer = setTimeout(function() {
354
+ reconnectTimer = null;
355
+ openConnection();
356
+ }, delay + jitter);
357
+ }
358
+ function openConnection() {
359
+ if (stopped || !isMQTTEnabled()) return;
360
+ teardownClient();
315
361
  var url = buildMQTTBrokerUrl();
316
362
  status = "connecting";
317
363
  var clientId = "stormcloud-vp-".concat(Math.random().toString(36).slice(2, 9));
@@ -320,41 +366,57 @@ function initMQTTClient() {
320
366
  clientId: clientId,
321
367
  username: mqttConfig.username,
322
368
  password: mqttConfig.password,
323
- keepalive: 60,
369
+ keepalive: KEEPALIVE_SECONDS,
324
370
  clean: true,
325
- reconnectPeriod: 5e3,
326
- connectTimeout: 1e4,
327
- queueQoSZero: false
371
+ // Disable MQTT.js internal reconnect; we manage reconnection ourselves.
372
+ reconnectPeriod: 0,
373
+ connectTimeout: CONNECT_TIMEOUT_MS,
374
+ queueQoSZero: false,
375
+ reschedulePings: true,
376
+ // Root-cause fix for the Tizen 4.0 "Keepalive timeout" loop: MQTT.js's
377
+ // default timerVariant "auto" runs the keepalive interval inside a
378
+ // Blob-URL Web Worker (via worker-timers). On Samsung Tizen 4.0 (old
379
+ // WebKit) served from a file:// origin that worker can't tick reliably,
380
+ // so the keepalive counter trips onKeepaliveTimeout almost immediately
381
+ // after connect. Force the native setInterval timer instead; the main
382
+ // thread is free because video is decoded by the native AVPlay pipeline.
383
+ timerVariant: "native"
328
384
  });
329
385
  } catch (err) {
330
386
  status = "error";
331
387
  console.warn("".concat(LOG, " connect() threw:"), err);
388
+ scheduleReconnect();
332
389
  return;
333
390
  }
334
391
  client.on("connect", function() {
335
392
  status = "connected";
393
+ reconnectAttempts = 0;
394
+ clearReconnectTimer();
336
395
  console.info("".concat(LOG, " connected to ").concat(url));
337
396
  });
338
- client.on("reconnect", function() {
339
- status = "connecting";
340
- console.info("".concat(LOG, " reconnecting…"));
341
- });
342
397
  client.on("offline", function() {
343
- status = "disconnected";
398
+ if (status === "connected") status = "disconnected";
344
399
  console.warn("".concat(LOG, " offline"));
400
+ scheduleReconnect();
345
401
  });
346
402
  client.on("error", function(err) {
347
403
  status = "error";
348
404
  console.warn("".concat(LOG, " error:"), err.message);
405
+ scheduleReconnect();
349
406
  });
350
407
  client.on("close", function() {
351
- if (status === "connected") {
352
- status = "disconnected";
353
- }
408
+ if (status === "connected") status = "disconnected";
409
+ scheduleReconnect();
354
410
  });
355
411
  }
412
+ function initMQTTClient() {
413
+ if (client || !isMQTTEnabled()) return;
414
+ stopped = false;
415
+ reconnectAttempts = 0;
416
+ openConnection();
417
+ }
356
418
  function ensureMQTTClient() {
357
- if (isMQTTEnabled() && !client) {
419
+ if (isMQTTEnabled() && !client && !reconnectTimer) {
358
420
  initMQTTClient();
359
421
  }
360
422
  }
@@ -363,7 +425,7 @@ function publishMQTT(topic, payload) {
363
425
  return false;
364
426
  }
365
427
  ensureMQTTClient();
366
- if (!client) {
428
+ if (!client || !client.connected) {
367
429
  return false;
368
430
  }
369
431
  try {