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