@@ -25,6 +25,7 @@ import * as url from "url";
2525import { Subscription } from "rxjs/Subscription" ;
2626import { Readable } from "stream" ;
2727import { IClientPublishOptions } from "mqtt" ;
28+ import MQTTMessagePool from "./mqtt-message-pool" ;
2829
2930const { debug, warn } = createLoggers ( "binding-mqtt" , "mqtt-client" ) ;
3031
@@ -35,6 +36,7 @@ declare interface MqttClientSecurityParameters {
3536
3637export default class MqttClient implements ProtocolClient {
3738 private scheme : string ;
39+ private pools : Map < string , MQTTMessagePool > = new Map ( ) ;
3840
3941 constructor ( private config : MqttClientConfig = { } , secure = false ) {
4042 this . scheme = "mqtt" + ( secure ? "s" : "" ) ;
@@ -55,52 +57,78 @@ export default class MqttClient implements ProtocolClient {
5557 // Current specification allows only form["mqv:filter"]
5658 const filter = requestUri . pathname . slice ( 1 ) ?? form [ "mqv:filter" ] ;
5759
58- if ( this . client === undefined ) {
59- this . client = await mqtt . connectAsync ( brokerUri , this . config ) ;
60+ let pool = this . pools . get ( brokerUri ) ;
61+
62+ if ( pool == null ) {
63+ pool = new MQTTMessagePool ( ) ;
64+ this . pools . set ( brokerUri , pool ) ;
6065 }
6166
62- this . client . on ( "message" , ( receivedTopic : string , payload : Buffer ) => {
63- debug ( `Received MQTT message (topic: ${ receivedTopic } , data length: ${ payload . length } )` ) ;
64- if ( filter . includes ( receivedTopic ) ) {
65- next ( new Content ( contentType , Readable . from ( payload ) ) ) ;
67+ await pool . connect ( brokerUri , this . config ) ;
68+
69+ pool . subscribe (
70+ filter ,
71+ ( topic : string , message : Buffer ) => {
72+ next ( new Content ( contentType , Readable . from ( message ) ) ) ;
73+ } ,
74+ ( e : Error ) => {
75+ if ( error ) error ( e ) ;
6676 }
67- } ) ;
77+ ) ;
6878
69- this . client . on ( "error" , ( err : Error ) => {
70- // Connection errors are fired as a result of mqtt.connectAsync
71- // here we have to handle only parsing errors.
72- if ( error ) error ( err ) ;
73- } ) ;
79+ return new Subscription ( ( ) => { } ) ;
80+ }
81+
82+ public async readResource ( form : MqttForm ) : Promise < Content > {
83+ const contentType = form . contentType ?? ContentSerdes . DEFAULT ;
84+ const requestUri = new url . URL ( form . href ) ;
85+ const brokerUri : string = `${ this . scheme } ://` + requestUri . host ;
86+ // Keeping the path as the topic for compatibility reasons.
87+ // Current specification allows only form["mqv:filter"]
88+ const filter = requestUri . pathname . slice ( 1 ) ?? form [ "mqv:filter" ] ;
7489
75- await this . client . subscribeAsync ( filter ) ;
90+ let pool = this . pools . get ( brokerUri ) ;
7691
77- return new Subscription ( ( ) => {
78- if ( ! this . client ) {
79- warn (
80- `MQTT Client is undefined. This means that the client either failed to connect or was never initialized.`
81- ) ;
82- return ;
83- }
84- this . client . unsubscribe ( filter ) ;
92+ if ( pool == null ) {
93+ pool = new MQTTMessagePool ( ) ;
94+ this . pools . set ( brokerUri , pool ) ;
95+ }
96+
97+ await pool . connect ( brokerUri , this . config ) ;
98+
99+ const result = await new Promise < Content > ( ( resolve , reject ) => {
100+ pool ! . subscribe (
101+ filter ,
102+ ( topic : string , message : Buffer ) => {
103+ resolve ( new Content ( contentType , Readable . from ( message ) ) ) ;
104+ } ,
105+ ( e : Error ) => {
106+ reject ( e ) ;
107+ }
108+ ) ;
85109 } ) ;
86- }
87110
88- public async readResource ( form : MqttForm ) : Promise < Content > {
89- throw new Error ( "Method not implemented." ) ;
111+ await pool . unsubscribe ( filter ) ;
112+ return result ;
90113 }
91114
92115 public async writeResource ( form : MqttForm , content : Content ) : Promise < void > {
93116 const requestUri = new url . URL ( form . href ) ;
94117 const brokerUri = `${ this . scheme } ://${ requestUri . host } ` ;
95118 const topic = requestUri . pathname . slice ( 1 ) ?? form [ "mqv:topic" ] ;
96119
97- if ( this . client === undefined ) {
98- this . client = await mqtt . connectAsync ( brokerUri , this . config ) ;
120+ let pool = this . pools . get ( brokerUri ) ;
121+
122+ if ( pool == null ) {
123+ pool = new MQTTMessagePool ( ) ;
124+ this . pools . set ( brokerUri , pool ) ;
99125 }
100126
127+ await pool . connect ( brokerUri , this . config ) ;
128+
101129 // if not input was provided, set up an own body otherwise take input as body
102130 const buffer = content === undefined ? Buffer . from ( "" ) : await content . toBuffer ( ) ;
103- await this . client . publishAsync ( topic , buffer , {
131+ await pool . publish ( topic , buffer , {
104132 retain : form [ "mqv:retain" ] ,
105133 qos : this . mapQoS ( form [ "mqv:qos" ] ) ,
106134 } ) ;
@@ -111,13 +139,18 @@ export default class MqttClient implements ProtocolClient {
111139 const topic = requestUri . pathname . slice ( 1 ) ;
112140 const brokerUri = `${ this . scheme } ://${ requestUri . host } ` ;
113141
114- if ( this . client === undefined ) {
115- this . client = await mqtt . connectAsync ( brokerUri , this . config ) ;
142+ let pool = this . pools . get ( brokerUri ) ;
143+
144+ if ( pool == null ) {
145+ pool = new MQTTMessagePool ( ) ;
146+ this . pools . set ( brokerUri , pool ) ;
116147 }
117148
149+ await pool . connect ( brokerUri , this . config ) ;
150+
118151 // if not input was provided, set up an own body otherwise take input as body
119152 const buffer = content === undefined ? Buffer . from ( "" ) : await content . toBuffer ( ) ;
120- await this . client . publishAsync ( topic , buffer , {
153+ await pool . publish ( topic , buffer , {
121154 retain : form [ "mqv:retain" ] ,
122155 qos : this . mapQoS ( form [ "mqv:qos" ] ) ,
123156 } ) ;
@@ -127,10 +160,12 @@ export default class MqttClient implements ProtocolClient {
127160
128161 public async unlinkResource ( form : TD . Form ) : Promise < void > {
129162 const requestUri = new url . URL ( form . href ) ;
163+ const brokerUri : string = `${ this . scheme } ://` + requestUri . host ;
130164 const topic = requestUri . pathname . slice ( 1 ) ;
131165
132- if ( this . client != null && this . client . connected ) {
133- await this . client . unsubscribeAsync ( topic ) ;
166+ const pool = this . pools . get ( brokerUri ) ;
167+ if ( pool != null ) {
168+ await pool . unsubscribe ( topic ) ;
134169 debug ( `MqttClient unsubscribed from topic '${ topic } '` ) ;
135170 }
136171 }
@@ -147,6 +182,9 @@ export default class MqttClient implements ProtocolClient {
147182 }
148183
149184 public async stop ( ) : Promise < void > {
185+ for ( const pool of this . pools . values ( ) ) {
186+ await pool . end ( ) ;
187+ }
150188 if ( this . client ) return this . client . endAsync ( ) ;
151189 }
152190
0 commit comments