pxt-common-packages 9.3.6 → 9.3.10

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.
package/libs/mqtt/mqtt.ts CHANGED
@@ -166,7 +166,7 @@ namespace mqtt {
166
166
  * Structure of an MQTT Control Packet
167
167
  * http://docs.oasis-open.org/mqtt/mqtt/v3.1.1/os/mqtt-v3.1.1-os.html#_Toc384800392
168
168
  */
169
- function createPacket(byte1: number, variable: Buffer, payload?: Buffer): Buffer {
169
+ function createPacket(byte1: number, variable: Buffer, payload?: Buffer): Buffer {
170
170
  if (payload == null) payload = control.createBuffer(0);
171
171
  return createPacketHeader(byte1, variable, payload.length).concat(payload)
172
172
  }
@@ -316,12 +316,25 @@ namespace mqtt {
316
316
  }
317
317
  }
318
318
 
319
+ export enum Status {
320
+ Disconnected = 0,
321
+ Connecting = 1,
322
+ Connected = 2,
323
+ Sending = 3,
324
+ }
325
+
319
326
  export class Client extends EventEmitter {
320
- public logPriority: ConsolePriority;
327
+ public logPriority = ConsolePriority.Debug
328
+ public tracePriority = -1 as ConsolePriority;
329
+
321
330
  private log(msg: string) {
322
331
  console.add(this.logPriority, `mqtt: ${msg}`);
323
332
  }
324
333
 
334
+ private trace(msg: string) {
335
+ console.add(this.tracePriority, `mqtt: ${msg}`);
336
+ }
337
+
325
338
  public opt: IConnectionOptions;
326
339
 
327
340
  private net: net.Net;
@@ -331,8 +344,14 @@ namespace mqtt {
331
344
  private piId: number;
332
345
 
333
346
  private buf: Buffer;
347
+ // we re-send subscriptions on re-connect
348
+ private subs: Buffer[] = [];
349
+
350
+ public status = Status.Disconnected
334
351
 
335
- public connected: boolean;
352
+ get connected() {
353
+ return this.status >= Status.Connected
354
+ }
336
355
 
337
356
  private mqttHandlers: MQTTHandler[];
338
357
 
@@ -341,8 +360,6 @@ namespace mqtt {
341
360
 
342
361
  this.wdId = Constants.Uninitialized;
343
362
  this.piId = Constants.Uninitialized;
344
- this.logPriority = ConsolePriority.Debug;
345
- this.connected = false;
346
363
  opt.port = opt.port || 8883;
347
364
  opt.clientId = opt.clientId;
348
365
 
@@ -392,15 +409,19 @@ namespace mqtt {
392
409
  this.piId = Constants.Uninitialized;
393
410
  }
394
411
 
395
- if (this.sct) {
396
- //this.sct.removeAllListeners('connect');
397
- //this.sct.removeAllListeners('data');
398
- //this.sct.removeAllListeners('close');
399
- this.sct.close();
412
+ const s = this.sct
413
+ if (s) {
414
+ this.sct = null
415
+ s.close()
400
416
  }
417
+
418
+ this.status = Status.Disconnected
401
419
  }
402
420
 
403
421
  public connect(): void {
422
+ if (this.status != Status.Disconnected)
423
+ return
424
+ this.status = Status.Connecting
404
425
  this.log(`Connecting to ${this.opt.host}:${this.opt.port}`);
405
426
  if (this.wdId === Constants.Uninitialized) {
406
427
  this.wdId = setInterval(() => {
@@ -420,7 +441,7 @@ namespace mqtt {
420
441
  this.send(Protocol.createConnect(this.opt));
421
442
  });
422
443
  this.sct.onMessage((msg: Buffer) => {
423
- this.log("incoming " + msg.length + " bytes")
444
+ this.trace("incoming " + msg.length + " bytes")
424
445
  this.handleMessage(msg);
425
446
  });
426
447
  this.sct.onError(() => {
@@ -430,32 +451,66 @@ namespace mqtt {
430
451
  this.sct.onClose(() => {
431
452
  this.log('Close.');
432
453
  this.emit('disconnected');
433
- this.connected = false;
454
+ this.status = Status.Disconnected
455
+ this.sct = null;
434
456
  });
435
457
  this.sct.connect();
436
458
  }
437
459
 
460
+ private canSend() {
461
+ let cnt = 0
462
+ while (true) {
463
+ if (this.status == Status.Connected) {
464
+ this.status = Status.Sending
465
+ return true
466
+ }
467
+ if (cnt++ < 100 && this.status == Status.Sending)
468
+ pause(20)
469
+ else {
470
+ this.log("drop pkt")
471
+ return false
472
+ }
473
+ }
474
+ }
475
+
476
+ private doneSending() {
477
+ this.trace("done send")
478
+ if (this.status == Status.Sending)
479
+ this.status = Status.Connected
480
+ }
481
+
438
482
  // Publish a message
439
483
  public publish(topic: string, message?: string | Buffer, qos: number = Constants.DefaultQos, retained: boolean = false): void {
440
484
  const buf = typeof message == "string" ? control.createBufferFromUTF8(message) : message
441
485
  message = null
442
- this.startPublish(topic, buf ? buf.length : 0, qos, retained)
443
- if (buf)
444
- this.send(buf);
486
+ if (this.startPublish(topic, buf ? buf.length : 0, qos, retained)) {
487
+ if (buf)
488
+ this.send(buf);
489
+ this.finishPublish()
490
+ }
445
491
  }
446
492
 
447
- public startPublish(topic: string, messageLen: number, qos: number = Constants.DefaultQos, retained: boolean = false): void {
448
- this.log(`publish: ${topic}`)
493
+ public startPublish(topic: string, messageLen: number, qos: number = Constants.DefaultQos, retained: boolean = false) {
494
+ if (!this.canSend()) return false
495
+ this.trace(`publish: ${topic} ${messageLen}b`)
449
496
  this.send(Protocol.createPublishHeader(topic, messageLen, qos, retained));
497
+ return true
450
498
  }
451
499
 
452
500
  public continuePublish(data: Buffer) {
453
501
  this.send(data)
454
502
  }
455
503
 
504
+ public finishPublish() {
505
+ this.doneSending()
506
+ this.emit("published")
507
+ }
508
+
456
509
  private subscribeCore(topic: string, handler: (msg: IMessage) => void, qos: number = Constants.DefaultQos): MQTTHandler {
457
510
  this.log(`subscribe: ${topic}`)
458
- this.send(Protocol.createSubscribe(topic, qos));
511
+ const sub = Protocol.createSubscribe(topic, qos)
512
+ this.subs.push(sub)
513
+ this.send1(sub);
459
514
  if (handler) {
460
515
  if (topic[topic.length - 1] == "#")
461
516
  topic = topic.slice(0, topic.length - 1)
@@ -492,7 +547,7 @@ namespace mqtt {
492
547
 
493
548
  private send(data: Buffer): void {
494
549
  if (this.sct) {
495
- this.log("send: " + data[0] + " / " + data.length + " bytes")
550
+ this.trace("send: " + data[0] + " / " + data.length + " bytes")
496
551
  // this.log("send: " + data[0] + " / " + data.length + " bytes: " + data.toHex())
497
552
  this.sct.send(data);
498
553
  }
@@ -536,17 +591,20 @@ namespace mqtt {
536
591
  if (returnCode === ConnectReturnCode.Accepted) {
537
592
  this.log('MQTT connection accepted.');
538
593
  this.emit('connected');
539
- this.connected = true;
594
+ this.status = Status.Connected;
540
595
  this.piId = setInterval(() => this.ping(), Constants.PingInterval * 1000);
596
+ for (const sub of this.subs)
597
+ this.send1(sub);
541
598
  } else {
542
599
  const connectionError: string = Client.describe(returnCode);
543
600
  this.log('MQTT connection error: ' + connectionError);
544
601
  this.emit('error', connectionError);
602
+ this.disconnect()
545
603
  }
546
604
  break;
547
605
  case ControlPacketType.Publish:
548
606
  const message: IMessage = Protocol.parsePublish(cmd, payload);
549
- this.log(`incoming: ${message.topic}`)
607
+ this.trace(`incoming: ${message.topic}`)
550
608
  let handled = false
551
609
  let cleanup = false
552
610
  if (this.mqttHandlers) {
@@ -566,7 +624,7 @@ namespace mqtt {
566
624
  this.emit('receive', message);
567
625
  if (message.qos > 0) {
568
626
  setTimeout(() => {
569
- this.send(Protocol.createPubAck(message.pid || 0));
627
+ this.send1(Protocol.createPubAck(message.pid || 0));
570
628
  }, 0);
571
629
  }
572
630
  break;
@@ -582,8 +640,15 @@ namespace mqtt {
582
640
  this.handleMessage(data.slice(payloadEnd))
583
641
  }
584
642
 
643
+ private send1(msg: Buffer) {
644
+ if (this.canSend()) {
645
+ this.send(msg)
646
+ this.doneSending()
647
+ }
648
+ }
649
+
585
650
  private ping() {
586
- this.send(Protocol.createPingReq());
651
+ this.send1(Protocol.createPingReq());
587
652
  this.emit('debug', 'Sent: Ping request.');
588
653
  }
589
654
  }