@@ -474,6 +474,9 @@ export class MainServer extends Server {
474
474
private readonly proxyTimeout = 5000 ;
475
475
476
476
private settings : Settings = { } ;
477
+ private heartbeatTimer ?: NodeJS . Timeout ;
478
+ private heartbeatInterval = 60000 ;
479
+ private lastHeartbeat = 0 ;
477
480
478
481
public constructor ( options : ServerOptions , args : ParsedArgs ) {
479
482
super ( options ) ;
@@ -491,6 +494,7 @@ export class MainServer extends Server {
491
494
}
492
495
493
496
protected async handleWebSocket ( socket : net . Socket , parsedUrl : url . UrlWithParsedQuery ) : Promise < void > {
497
+ this . heartbeat ( ) ;
494
498
if ( ! parsedUrl . query . reconnectionToken ) {
495
499
throw new Error ( "Reconnection token is missing from query parameters" ) ;
496
500
}
@@ -514,6 +518,7 @@ export class MainServer extends Server {
514
518
parsedUrl : url . UrlWithParsedQuery ,
515
519
request : http . IncomingMessage ,
516
520
) : Promise < Response > {
521
+ this . heartbeat ( ) ;
517
522
switch ( base ) {
518
523
case "/" : return this . getRoot ( request , parsedUrl ) ;
519
524
case "/resource" :
@@ -876,4 +881,48 @@ export class MainServer extends Server {
876
881
( this . services . get ( ILogService ) as ILogService ) . warn ( error . message ) ;
877
882
}
878
883
}
884
+
885
+ /**
886
+ * Return the file path for the heartbeat file.
887
+ */
888
+ private get heartbeatPath ( ) : string {
889
+ const environment = this . services . get ( IEnvironmentService ) as IEnvironmentService ;
890
+ return path . join ( environment . userDataPath , "heartbeat" ) ;
891
+ }
892
+
893
+ /**
894
+ * Return all online connections regardless of type.
895
+ */
896
+ private get onlineConnections ( ) : Connection [ ] {
897
+ const online = < Connection [ ] > [ ] ;
898
+ this . connections . forEach ( ( connections ) => {
899
+ connections . forEach ( ( connection ) => {
900
+ if ( typeof connection . offline === "undefined" ) {
901
+ online . push ( connection ) ;
902
+ }
903
+ } ) ;
904
+ } ) ;
905
+ return online ;
906
+ }
907
+
908
+ /**
909
+ * Write to the heartbeat file if we haven't already done so within the
910
+ * timeout and start or reset a timer that keeps running as long as there are
911
+ * active connections. Failures are logged as warnings.
912
+ */
913
+ private heartbeat ( ) : void {
914
+ const now = Date . now ( ) ;
915
+ if ( now - this . lastHeartbeat >= this . heartbeatInterval ) {
916
+ util . promisify ( fs . writeFile ) ( this . heartbeatPath , "" ) . catch ( ( error ) => {
917
+ ( this . services . get ( ILogService ) as ILogService ) . warn ( error . message ) ;
918
+ } ) ;
919
+ this . lastHeartbeat = now ;
920
+ clearTimeout ( this . heartbeatTimer ! ) ; // We can clear undefined so ! is fine.
921
+ this . heartbeatTimer = setTimeout ( ( ) => {
922
+ if ( this . onlineConnections . length > 0 ) {
923
+ this . heartbeat ( ) ;
924
+ }
925
+ } , this . heartbeatInterval ) ;
926
+ }
927
+ }
879
928
}
0 commit comments