@@ -160,13 +160,28 @@ function prepareWebSocketUrl(options, awsAccessId, awsSecretKey, awsSTSToken) {
160160 awsAccessId , awsSecretKey , options . region , awsServiceName , '' , today , now , options . debug , awsSTSToken ) ;
161161}
162162
163+ function prepareWebSocketCustomAuthUrl ( options ) {
164+ var path = '/mqtt' ;
165+ var hostName = options . host ;
166+
167+ // Include the port number in the hostname if it's not
168+ // the standard wss port (443).
169+ //
170+ if ( ! isUndefined ( options . port ) && options . port !== 443 ) {
171+ hostName = options . host + ':' + options . port ;
172+ }
173+
174+ return 'wss://' + hostName + path ;
175+ }
176+
163177function arrayEach ( array , iterFunction ) {
164178 for ( var idx in array ) {
165179 if ( Object . prototype . hasOwnProperty . call ( array , idx ) ) {
166180 iterFunction . call ( this , array [ idx ] , parseInt ( idx , 10 ) ) ;
167181 }
168182 }
169- }
183+ }
184+
170185function getCredentials ( ini ) {
171186 //Get shared credential function from AWS SDK.
172187 var map = { } ;
@@ -295,6 +310,8 @@ function DeviceClient(options) {
295310 var drainingTimer = null ;
296311 var drainTimeMs = 250 ;
297312
313+ //Default keep alive time interval in seconds.
314+ var defaultKeepalive = 300 ;
298315 //
299316 // These properties control the reconnect behavior of the MQTT Client. If
300317 // the MQTT client becomes disconnected, it will attempt to reconnect after
@@ -342,10 +359,28 @@ function DeviceClient(options) {
342359 //
343360 // Validate options, set default reconnect period if not specified.
344361 //
362+ var metricPrefix = "?SDK=JavaScript&Version=" ;
363+ var pjson = require ( '../package.json' ) ;
364+ var sdkVersion = pjson . version ;
365+ var defaultUsername = metricPrefix + sdkVersion ;
366+
345367 if ( isUndefined ( options ) ||
346368 Object . keys ( options ) . length === 0 ) {
347369 throw new Error ( exceptions . INVALID_CONNECT_OPTIONS ) ;
348370 }
371+ if ( isUndefined ( options . keepalive ) ) {
372+ options . keepalive = defaultKeepalive ;
373+ }
374+ //
375+ // Metrics will be enabled by default unless the user explicitly disables it
376+ //
377+ if ( isUndefined ( options . enableMetrics ) || options . enableMetrics === true ) {
378+ if ( isUndefined ( options . username ) ) {
379+ options . username = defaultUsername ;
380+ } else {
381+ options . username += defaultUsername ;
382+ }
383+ }
349384 if ( ! isUndefined ( options . baseReconnectTimeMs ) ) {
350385 baseReconnectTimeMs = options . baseReconnectTimeMs ;
351386 }
@@ -373,6 +408,10 @@ function DeviceClient(options) {
373408 currentReconnectTimeMs = baseReconnectTimeMs ;
374409 options . reconnectPeriod = currentReconnectTimeMs ;
375410 options . fastDisconnectDetection = true ;
411+ //
412+ //SDK has its own logic to deal with auto resubscribe
413+ //
414+ options . resubscribe = false ;
376415
377416 //
378417 // Verify that the reconnection timing parameters make sense.
@@ -414,47 +453,60 @@ function DeviceClient(options) {
414453
415454 //read and map certificates
416455 tlsReader ( options ) ;
417- } else if ( options . protocol === 'wss' ) {
418- //
419- // AWS access id and secret key
420- // It first check Input options and Environment variables
421- // If that not available, it will try to load credentials from default credential file
422- if ( ! isUndefined ( options . accessKeyId ) ) {
423- awsAccessId = options . accessKeyId ;
424- } else {
425- awsAccessId = process . env . AWS_ACCESS_KEY_ID ;
426- }
427- if ( ! isUndefined ( options . secretKey ) ) {
428- awsSecretKey = options . secretKey ;
429- } else {
430- awsSecretKey = process . env . AWS_SECRET_ACCESS_KEY ;
431- }
432- if ( ! isUndefined ( options . sessionToken ) ) {
433- awsSTSToken = options . sessionToken ;
434- } else {
435- awsSTSToken = process . env . AWS_SESSION_TOKEN ;
436- }
437- if ( isUndefined ( awsAccessId ) || isUndefined ( awsSecretKey ) ) {
438- var filename ;
439- try {
440- if ( ! isUndefined ( options . filename ) ) {
441- filename = options . filename ;
442- } else {
443- filename = _loadDefaultFilename ( ) ;
444- }
445- var user_profile = options . profile || process . env . AWS_PROFILE || 'default' ;
446- var creds = getCredentials ( fs . readFileSync ( filename , 'utf-8' ) ) ;
447- var profile = creds [ user_profile ] ;
448- awsAccessId = profile . aws_access_key_id ;
449- awsSecretKey = profile . aws_secret_access_key ;
450- awsSTSToken = profile . aws_session_token ;
456+ } else if ( options . protocol === 'wss' || options . protocol === 'wss-custom-auth' ) {
457+ if ( options . protocol === 'wss' ) {
458+ //
459+ // AWS access id and secret key
460+ // It first check Input options and Environment variables
461+ // If that not available, it will try to load credentials from default credential file
462+ if ( ! isUndefined ( options . accessKeyId ) ) {
463+ awsAccessId = options . accessKeyId ;
464+ } else {
465+ awsAccessId = process . env . AWS_ACCESS_KEY_ID ;
466+ }
467+ if ( ! isUndefined ( options . secretKey ) ) {
468+ awsSecretKey = options . secretKey ;
469+ } else {
470+ awsSecretKey = process . env . AWS_SECRET_ACCESS_KEY ;
471+ }
472+ if ( ! isUndefined ( options . sessionToken ) ) {
473+ awsSTSToken = options . sessionToken ;
474+ } else {
475+ awsSTSToken = process . env . AWS_SESSION_TOKEN ;
476+ }
477+ if ( isUndefined ( awsAccessId ) || isUndefined ( awsSecretKey ) ) {
478+ var filename ;
479+ try {
480+ if ( ! isUndefined ( options . filename ) ) {
481+ filename = options . filename ;
482+ } else {
483+ filename = _loadDefaultFilename ( ) ;
484+ }
485+ var user_profile = options . profile || process . env . AWS_PROFILE || 'default' ;
486+ var creds = getCredentials ( fs . readFileSync ( filename , 'utf-8' ) ) ;
487+ var profile = creds [ user_profile ] ;
488+ awsAccessId = profile . aws_access_key_id ;
489+ awsSecretKey = profile . aws_secret_access_key ;
490+ awsSTSToken = profile . aws_session_token ;
451491 } catch ( e ) {
452492 console . log ( e ) ;
453- console . log ( " Failed to read credentials from " + filename ) ;
493+ console . log ( ' Failed to read credentials from ' + filename ) ;
454494 }
495+ }
496+ // AWS Access Key ID and AWS Secret Key must be defined
497+ if ( isUndefined ( awsAccessId ) || ( isUndefined ( awsSecretKey ) ) ) {
498+ console . log ( 'To connect via WebSocket/SigV4, AWS Access Key ID and AWS Secret Key must be passed either in options or as environment variables; see README.md' ) ;
499+ throw new Error ( exceptions . INVALID_CONNECT_OPTIONS ) ;
500+ }
501+ } else {
502+ if ( isUndefined ( options . customAuthHeaders ) ) {
503+ console . log ( 'To authenticate with a custom authorizer, you must provide the required HTTP headers; see README.md' ) ;
504+ throw new Error ( exceptions . INVALID_CONNECT_OPTIONS ) ;
505+ }
455506 }
456- if ( ! isUndefined ( options . host ) ) {
457- var pattern = / [ a - z A - Z 0 - 9 ] + \. i o t \. ( [ a - z ] + - [ a - z ] + - [ 0 - 9 ] + ) \. a m a z o n a w s \. .+ / ;
507+
508+ if ( ! isUndefined ( options . host ) && isUndefined ( options . region ) ) {
509+ var pattern = / [ a - z A - Z 0 - 9 ] + \. i o t \. ( [ a - z ] + - [ a - z ] + - [ 0 - 9 ] + ) \. a m a z o n a w s \. .+ / ;
458510 var region = pattern . exec ( options . host ) ;
459511 if ( region === null ) {
460512 console . log ( 'Host endpoint is not valid' ) ;
@@ -463,11 +515,6 @@ function DeviceClient(options) {
463515 options . region = region [ 1 ] ;
464516 }
465517 }
466- // AWS Access Key ID and AWS Secret Key must be defined
467- if ( isUndefined ( awsAccessId ) || ( isUndefined ( awsSecretKey ) ) ) {
468- console . log ( 'To connect via WebSocket/SigV4, AWS Access Key ID and AWS Secret Key must be passed either in options or as environment variables; see README.md' ) ;
469- throw new Error ( exceptions . INVALID_CONNECT_OPTIONS ) ;
470- }
471518 // set port, do not override existing definitions if available
472519 if ( isUndefined ( options . port ) ) {
473520 options . port = 443 ;
@@ -480,7 +527,11 @@ function DeviceClient(options) {
480527 } else {
481528 options . websocketOptions . protocol = 'mqttv3.1' ;
482529 }
483- }
530+
531+ if ( options . protocol === 'wss-custom-auth' ) {
532+ options . websocketOptions . headers = options . customAuthHeaders ;
533+ }
534+ }
484535
485536 if ( ( ! isUndefined ( options ) ) && ( options . debug === true ) ) {
486537 console . log ( options ) ;
@@ -556,7 +607,8 @@ function DeviceClient(options) {
556607 }
557608
558609 function _wrapper ( client ) {
559- if ( options . protocol === 'wss' ) {
610+ var protocol = options . protocol ;
611+ if ( protocol === 'wss' ) {
560612 var url ;
561613 //
562614 // If the access id and secret key are available, prepare the URL.
@@ -573,8 +625,15 @@ function DeviceClient(options) {
573625 }
574626
575627 options . url = url ;
628+ } else if ( protocol === 'wss-custom-auth' ) {
629+ options . url = prepareWebSocketCustomAuthUrl ( options ) ;
630+ if ( options . debug === true ) {
631+ console . log ( 'using websockets custom auth, will connect to \'' + options . url + '\'...' ) ;
632+ }
633+ // Treat the request as a standard websocket request from here onwards
634+ protocol = 'wss' ;
576635 }
577- return protocols [ options . protocol ] ( client , options ) ;
636+ return protocols [ protocol ] ( client , options ) ;
578637 }
579638
580639 var device = new mqtt . MqttClient ( _wrapper , options ) ;
@@ -748,6 +807,12 @@ function DeviceClient(options) {
748807 device . on ( 'error' , function ( error ) {
749808 that . emit ( 'error' , error ) ;
750809 } ) ;
810+ device . on ( 'packetsend' , function ( packet ) {
811+ that . emit ( 'packetsend' , packet ) ;
812+ } ) ;
813+ device . on ( 'packetreceive' , function ( packet ) {
814+ that . emit ( 'packetreceive' , packet ) ;
815+ } ) ;
751816 device . on ( 'message' , function ( topic , message , packet ) {
752817 that . emit ( 'message' , topic , message , packet ) ;
753818 } ) ;
@@ -834,6 +899,15 @@ function DeviceClient(options) {
834899 awsSecretKey = secretKey ;
835900 awsSTSToken = sessionToken ;
836901 } ;
902+ this . getWebsocketHeaders = function ( ) {
903+ return options . websocketOptions . headers ;
904+ } ;
905+ //
906+ // Call this function to update the custom auth headers
907+ //
908+ this . updateCustomAuthHeaders = function ( newHeaders ) {
909+ options . websocketOptions . headers = newHeaders ;
910+ } ;
837911 //
838912 // Used for integration testing only
839913 //
@@ -855,3 +929,4 @@ module.exports.DeviceClient = DeviceClient;
855929// Exported for unit testing only
856930//
857931module . exports . prepareWebSocketUrl = prepareWebSocketUrl ;
932+ module . exports . prepareWebSocketCustomAuthUrl = prepareWebSocketCustomAuthUrl ;
0 commit comments