@@ -69,6 +69,7 @@ import { reuseInFlight } from "@cocalc/util/reuse-in-flight";
69
69
import { type SysConatServer , sysApiSubject , sysApi } from "./sys" ;
70
70
import { forkedConatServer } from "./start-server" ;
71
71
import { stickyChoice } from "./sticky" ;
72
+ import { EventEmitter } from "events" ;
72
73
73
74
const logger = getLogger ( "conat:core:server" ) ;
74
75
@@ -151,9 +152,9 @@ export interface Options {
151
152
localClusterSize ?: number ;
152
153
}
153
154
154
- type State = "ready" | "closed" ;
155
+ type State = "init" | " ready" | "closed" ;
155
156
156
- export class ConatServer {
157
+ export class ConatServer extends EventEmitter {
157
158
public readonly io ;
158
159
public readonly id : string ;
159
160
@@ -165,7 +166,7 @@ export class ConatServer {
165
166
private sockets : { [ id : string ] : any } = { } ;
166
167
private stats : { [ id : string ] : ConnectionStats } = { } ;
167
168
private usage : UsageMonitor ;
168
- public state : State = "ready " ;
169
+ public state : State = "init " ;
169
170
170
171
private subscriptions : { [ socketId : string ] : Set < string > } = { } ;
171
172
private interest : Patterns < { [ queue : string ] : Set < string > } > = new Patterns ( ) ;
@@ -183,6 +184,7 @@ export class ConatServer {
183
184
private queuedClusterUpdates : Update [ ] = [ ] ;
184
185
185
186
constructor ( options : Options ) {
187
+ super ( ) ;
186
188
const {
187
189
httpServer,
188
190
port = 3000 ,
@@ -266,13 +268,26 @@ export class ConatServer {
266
268
}
267
269
this . initUsage ( ) ;
268
270
this . io . on ( "connection" , this . handleSocket ) ;
271
+ this . init ( ) ;
272
+ }
273
+
274
+ private setState = ( state : State ) => {
275
+ if ( this . state == state ) return ;
276
+ this . emit ( state ) ;
277
+ this . state = state ;
278
+ } ;
279
+
280
+ private isClosed = ( ) => this . state == "closed" ;
281
+
282
+ private init = async ( ) => {
269
283
if ( this . options . systemAccountPassword ) {
270
- this . initSystemService ( ) ;
284
+ await this . initSystemService ( ) ;
271
285
}
272
286
if ( this . clusterName ) {
273
- this . initCluster ( ) ;
287
+ await this . initCluster ( ) ;
274
288
}
275
- }
289
+ this . setState ( "ready" ) ;
290
+ } ;
276
291
277
292
private initUsage = ( ) => {
278
293
this . usage = new UsageMonitor ( {
@@ -287,17 +302,17 @@ export class ConatServer {
287
302
// thought at all about what to do here, really.
288
303
// Hopefully experience can teach us.
289
304
isHealthy = ( ) => {
290
- if ( this . state == "closed" ) {
305
+ if ( this . isClosed ( ) ) {
291
306
return false ;
292
307
}
293
308
return true ;
294
309
} ;
295
310
296
311
close = async ( ) => {
297
- if ( this . state == "closed" ) {
312
+ if ( this . isClosed ( ) ) {
298
313
return ;
299
314
}
300
- this . state = "closed" ;
315
+ this . setState ( "closed" ) ;
301
316
302
317
if ( this . clusterStreams != null ) {
303
318
for ( const name in this . clusterStreams ) {
@@ -414,7 +429,7 @@ export class ConatServer {
414
429
///////////////////////////////////////
415
430
416
431
private updateInterest = async ( interest : InterestUpdate ) => {
417
- if ( this . state != "ready" ) return ;
432
+ if ( this . isClosed ( ) ) return ;
418
433
// publish to the stream
419
434
this . updateClusterStream ( { interest } ) ;
420
435
// update our local state
@@ -812,7 +827,7 @@ export class ConatServer {
812
827
const count = await this . publish ( { subject, data, from : user } ) ;
813
828
respond ?.( { count } ) ;
814
829
} catch ( err ) {
815
- console . log ( this . id , "ERROR" , err ) ;
830
+ // console.log(this.id, "ERROR", err);
816
831
if ( err . code == 403 ) {
817
832
socket . emit ( "permission" , {
818
833
message : err . message ,
@@ -1016,11 +1031,11 @@ export class ConatServer {
1016
1031
}
1017
1032
this . log ( `Cluster autoscan interval ${ this . options . autoscanInterval } ms` ) ;
1018
1033
let lastCount = 1 ;
1019
- while ( this . state != "closed" ) {
1034
+ while ( ! this . isClosed ( ) ) {
1020
1035
let x ;
1021
1036
try {
1022
1037
x = await this . scan ( ) ;
1023
- if ( this . state == ( "closed" as any ) ) return ;
1038
+ if ( this . isClosed ( ) ) return ;
1024
1039
} catch ( err ) {
1025
1040
// this should never happen unless there is a serious bug (?).
1026
1041
this . log ( `WARNING/BUG?: serious problem scanning -- ${ err } ` ) ;
@@ -1048,7 +1063,7 @@ export class ConatServer {
1048
1063
1049
1064
private scanSoon = throttle (
1050
1065
async ( ) => {
1051
- if ( this . state == "closed" || ! this . options . autoscanInterval ) {
1066
+ if ( this . isClosed ( ) || ! this . options . autoscanInterval ) {
1052
1067
return ;
1053
1068
}
1054
1069
let x ;
@@ -1278,7 +1293,7 @@ export class ConatServer {
1278
1293
// the number of links created (count), so if it returns 0 when called on all nodes, then
1279
1294
// we're done until new nodes are added.
1280
1295
scan = reuseInFlight ( async ( ) : Promise < { count : number ; errors : any [ ] } > => {
1281
- if ( this . state == "closed" ) {
1296
+ if ( this . isClosed ( ) ) {
1282
1297
return { count : 0 , errors : [ ] } ;
1283
1298
}
1284
1299
const knownByUs = new Set ( this . clusterAddresses ( this . clusterName ) ) ;
@@ -1296,7 +1311,7 @@ export class ConatServer {
1296
1311
const knownByRemoteNode = new Set (
1297
1312
await sys . clusterAddresses ( this . clusterName ) ,
1298
1313
) ;
1299
- if ( this . state == "closed" ) return ;
1314
+ if ( this . isClosed ( ) ) return ;
1300
1315
for ( const address of knownByRemoteNode ) {
1301
1316
if ( ! knownByUs . has ( address ) ) {
1302
1317
unknownToUs . add ( address ) ;
@@ -1305,7 +1320,7 @@ export class ConatServer {
1305
1320
if ( ! knownByRemoteNode . has ( this . address ( ) ) ) {
1306
1321
// we know about them, but they don't know about us, so ask them to link to us.
1307
1322
await sys . join ( this . address ( ) ) ;
1308
- if ( this . state == ( "closed" as any ) ) return ;
1323
+ if ( this . isClosed ( ) ) return ;
1309
1324
count += 1 ;
1310
1325
}
1311
1326
} catch ( err ) {
@@ -1338,7 +1353,7 @@ export class ConatServer {
1338
1353
} )
1339
1354
. map ( ( link ) => f ( link . client ) ) ,
1340
1355
) ;
1341
- if ( unknownToUs . size == 0 || this . state == ( "closed" as any ) ) {
1356
+ if ( unknownToUs . size == 0 || this . isClosed ( ) ) {
1342
1357
return { count, errors } ;
1343
1358
}
1344
1359
@@ -1471,11 +1486,7 @@ export class ConatServer {
1471
1486
timeout = MAX_INTEREST_TIMEOUT ;
1472
1487
}
1473
1488
const start = Date . now ( ) ;
1474
- while (
1475
- this . state != "closed" &&
1476
- this . sockets [ socketId ] &&
1477
- ! signal ?. aborted
1478
- ) {
1489
+ while ( ! this . isClosed ( ) && this . sockets [ socketId ] && ! signal ?. aborted ) {
1479
1490
if ( Date . now ( ) - start >= timeout ) {
1480
1491
throw Error ( "timeout" ) ;
1481
1492
}
@@ -1485,11 +1496,7 @@ export class ConatServer {
1485
1496
} catch {
1486
1497
continue ;
1487
1498
}
1488
- if (
1489
- ( this . state as any ) == "closed" ||
1490
- ! this . sockets [ socketId ] ||
1491
- signal ?. aborted
1492
- ) {
1499
+ if ( this . isClosed ( ) || ! this . sockets [ socketId ] || signal ?. aborted ) {
1493
1500
return false ;
1494
1501
}
1495
1502
const hasMatch = this . interest . hasMatch ( subject ) ;
0 commit comments