@grest-ts/discovery-local 0.0.5
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/dist/src/index-node.d.ts +5 -0
- package/dist/src/index-node.d.ts.map +1 -0
- package/dist/src/index-node.js +5 -0
- package/dist/src/index-node.js.map +1 -0
- package/dist/src/local/GGDiscoveryIPC.d.ts +14 -0
- package/dist/src/local/GGDiscoveryIPC.d.ts.map +1 -0
- package/dist/src/local/GGDiscoveryIPC.js +9 -0
- package/dist/src/local/GGDiscoveryIPC.js.map +1 -0
- package/dist/src/local/GGLocalDiscoveryClient.d.ts +28 -0
- package/dist/src/local/GGLocalDiscoveryClient.d.ts.map +1 -0
- package/dist/src/local/GGLocalDiscoveryClient.js +77 -0
- package/dist/src/local/GGLocalDiscoveryClient.js.map +1 -0
- package/dist/src/local/GGLocalDiscoveryResilientClient.d.ts +15 -0
- package/dist/src/local/GGLocalDiscoveryResilientClient.d.ts.map +1 -0
- package/dist/src/local/GGLocalDiscoveryResilientClient.js +95 -0
- package/dist/src/local/GGLocalDiscoveryResilientClient.js.map +1 -0
- package/dist/src/local/GGLocalDiscoveryServer.d.ts +30 -0
- package/dist/src/local/GGLocalDiscoveryServer.d.ts.map +1 -0
- package/dist/src/local/GGLocalDiscoveryServer.js +123 -0
- package/dist/src/local/GGLocalDiscoveryServer.js.map +1 -0
- package/dist/src/local/routing/RoutingStrategy.d.ts +5 -0
- package/dist/src/local/routing/RoutingStrategy.d.ts.map +1 -0
- package/dist/src/local/routing/RoutingStrategy.js +2 -0
- package/dist/src/local/routing/RoutingStrategy.js.map +1 -0
- package/dist/src/local/routing/strategies/FirstStrategy.d.ts +9 -0
- package/dist/src/local/routing/strategies/FirstStrategy.d.ts.map +1 -0
- package/dist/src/local/routing/strategies/FirstStrategy.js +9 -0
- package/dist/src/local/routing/strategies/FirstStrategy.js.map +1 -0
- package/dist/src/local/routing/strategies/LastStrategy.d.ts +9 -0
- package/dist/src/local/routing/strategies/LastStrategy.d.ts.map +1 -0
- package/dist/src/local/routing/strategies/LastStrategy.js +9 -0
- package/dist/src/local/routing/strategies/LastStrategy.js.map +1 -0
- package/dist/src/local/routing/strategies/RandomStrategy.d.ts +9 -0
- package/dist/src/local/routing/strategies/RandomStrategy.d.ts.map +1 -0
- package/dist/src/local/routing/strategies/RandomStrategy.js +9 -0
- package/dist/src/local/routing/strategies/RandomStrategy.js.map +1 -0
- package/dist/src/local/routing/strategies/RoundRobinStrategy.d.ts +11 -0
- package/dist/src/local/routing/strategies/RoundRobinStrategy.d.ts.map +1 -0
- package/dist/src/local/routing/strategies/RoundRobinStrategy.js +14 -0
- package/dist/src/local/routing/strategies/RoundRobinStrategy.js.map +1 -0
- package/dist/src/tsconfig.json +16 -0
- package/dist/testkit/GGLocalRoutingStrategySelector.d.ts +12 -0
- package/dist/testkit/GGLocalRoutingStrategySelector.d.ts.map +1 -0
- package/dist/testkit/GGLocalRoutingStrategySelector.js +28 -0
- package/dist/testkit/GGLocalRoutingStrategySelector.js.map +1 -0
- package/dist/testkit/index-testkit.d.ts +2 -0
- package/dist/testkit/index-testkit.d.ts.map +1 -0
- package/dist/testkit/index-testkit.js +2 -0
- package/dist/testkit/index-testkit.js.map +1 -0
- package/dist/tsconfig.publish.tsbuildinfo +1 -0
- package/package.json +62 -0
- package/src/index-node.ts +4 -0
- package/src/local/GGDiscoveryIPC.ts +17 -0
- package/src/local/GGLocalDiscoveryClient.ts +94 -0
- package/src/local/GGLocalDiscoveryResilientClient.ts +104 -0
- package/src/local/GGLocalDiscoveryServer.ts +143 -0
- package/src/local/routing/RoutingStrategy.ts +7 -0
- package/src/local/routing/strategies/FirstStrategy.ts +11 -0
- package/src/local/routing/strategies/LastStrategy.ts +11 -0
- package/src/local/routing/strategies/RandomStrategy.ts +11 -0
- package/src/local/routing/strategies/RoundRobinStrategy.ts +17 -0
- package/src/tsconfig.json +16 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Grest Games OÜ
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-node.d.ts","sourceRoot":"","sources":["../../src/index-node.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-node.js","sourceRoot":"","sources":["../../src/index-node.ts"],"names":[],"mappings":"AAAA,cAAc,gCAAgC,CAAA;AAC9C,cAAc,gCAAgC,CAAA;AAC9C,cAAc,iCAAiC,CAAA;AAC/C,cAAc,yCAAyC,CAAA"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
import { GGServiceDiscoveryEntry } from "./GGLocalDiscoveryClient";
|
|
2
|
+
export interface DiscoverApiResult {
|
|
3
|
+
success: boolean;
|
|
4
|
+
url?: string;
|
|
5
|
+
error?: string;
|
|
6
|
+
}
|
|
7
|
+
export declare const GGDiscoveryIPC: {
|
|
8
|
+
discoveryServer: {
|
|
9
|
+
register: import("@grest-ts/ipc").IPCServerRequest<GGServiceDiscoveryEntry[], void>;
|
|
10
|
+
unregister: import("@grest-ts/ipc").IPCServerRequest<GGServiceDiscoveryEntry[], void>;
|
|
11
|
+
discoverApi: import("@grest-ts/ipc").IPCServerRequest<string, DiscoverApiResult>;
|
|
12
|
+
};
|
|
13
|
+
};
|
|
14
|
+
//# sourceMappingURL=GGDiscoveryIPC.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGDiscoveryIPC.d.ts","sourceRoot":"","sources":["../../../src/local/GGDiscoveryIPC.ts"],"names":[],"mappings":"AAEA,OAAO,EAAC,uBAAuB,EAAC,MAAM,0BAA0B,CAAC;AAEjE,MAAM,WAAW,iBAAiB;IAC9B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,KAAK,CAAC,EAAE,MAAM,CAAC;CAClB;AAED,eAAO,MAAM,cAAc;;;;;;CAM1B,CAAA"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { IPCServer } from "@grest-ts/ipc";
|
|
2
|
+
export const GGDiscoveryIPC = {
|
|
3
|
+
discoveryServer: {
|
|
4
|
+
register: IPCServer.defineRequest("discovery/register"),
|
|
5
|
+
unregister: IPCServer.defineRequest("discovery/unregister"),
|
|
6
|
+
discoverApi: IPCServer.defineRequest("discovery/discoverApi"),
|
|
7
|
+
}
|
|
8
|
+
};
|
|
9
|
+
//# sourceMappingURL=GGDiscoveryIPC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGDiscoveryIPC.js","sourceRoot":"","sources":["../../../src/local/GGDiscoveryIPC.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAUxC,MAAM,CAAC,MAAM,cAAc,GAAG;IAC1B,eAAe,EAAE;QACb,QAAQ,EAAE,SAAS,CAAC,aAAa,CAAkC,oBAAoB,CAAC;QACxF,UAAU,EAAE,SAAS,CAAC,aAAa,CAAkC,sBAAsB,CAAC;QAC5F,WAAW,EAAE,SAAS,CAAC,aAAa,CAA4B,uBAAuB,CAAC;KAC3F;CACJ,CAAA"}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { GGDiscoveryClient, GGServiceRegistration } from "@grest-ts/discovery";
|
|
2
|
+
import { IPCClient } from "@grest-ts/ipc";
|
|
3
|
+
/**
|
|
4
|
+
* ENV variable key when running in tests, for example - this would be PORT of the service discovery instance.
|
|
5
|
+
* If running in tests, the test itself also acts as a service discovery of sorts, allowing multiple instances to run in parallel.
|
|
6
|
+
*/
|
|
7
|
+
export declare const GG_LOCAL_ROUTER_PORT = "GG_LOCAL_ROUTER_PORT";
|
|
8
|
+
export declare class GGLocalDiscoveryClient extends GGDiscoveryClient {
|
|
9
|
+
readonly isLocal = true;
|
|
10
|
+
readonly port: number;
|
|
11
|
+
protected readonly entries: GGServiceDiscoveryEntry[];
|
|
12
|
+
protected readonly client: IPCClient;
|
|
13
|
+
constructor(port?: number);
|
|
14
|
+
registerRoutes(registrations: GGServiceRegistration[]): void;
|
|
15
|
+
discoverApi(apiName: string): Promise<string>;
|
|
16
|
+
register(): Promise<void>;
|
|
17
|
+
unregister(): Promise<void>;
|
|
18
|
+
protected ensureConnected(): Promise<void>;
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* What consumers need to discover and connect to a service
|
|
22
|
+
*/
|
|
23
|
+
export interface GGServiceDiscoveryEntry {
|
|
24
|
+
api: string;
|
|
25
|
+
baseUrl: string;
|
|
26
|
+
pathPrefix: string;
|
|
27
|
+
}
|
|
28
|
+
//# sourceMappingURL=GGLocalDiscoveryClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryClient.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryClient.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,iBAAiB,EAAE,qBAAqB,EAAC,MAAM,qBAAqB,CAAC;AAE3F,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AAKxC;;;GAGG;AACH,eAAO,MAAM,oBAAoB,yBAAyB,CAAA;AAE1D,qBAAa,sBAAuB,SAAQ,iBAAiB;IAEzD,SAAyB,OAAO,QAAQ;IACxC,SAAgB,IAAI,SAAC;IACrB,SAAS,CAAC,QAAQ,CAAC,OAAO,EAAE,uBAAuB,EAAE,CAAM;IAC3D,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,SAAS,CAAC;gBAEzB,IAAI,CAAC,EAAE,MAAM;IAgBlB,cAAc,CAAC,aAAa,EAAE,qBAAqB,EAAE,GAAG,IAAI;IAUtD,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IAa7C,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAQzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;cAWxB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;CAKnD;AAED;;GAEG;AACH,MAAM,WAAW,uBAAuB;IACpC,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,EAAE,MAAM,CAAC;CACtB"}
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { GG_DISCOVERY, GGDiscoveryClient } from "@grest-ts/discovery";
|
|
2
|
+
import { GGLog } from "@grest-ts/logger";
|
|
3
|
+
import { IPCClient } from "@grest-ts/ipc";
|
|
4
|
+
import { GGLocator, GGLocatorServiceType } from "@grest-ts/locator";
|
|
5
|
+
import { GGDiscoveryIPC } from "./GGDiscoveryIPC.js";
|
|
6
|
+
import { SERVER_ERROR } from "@grest-ts/schema";
|
|
7
|
+
/**
|
|
8
|
+
* ENV variable key when running in tests, for example - this would be PORT of the service discovery instance.
|
|
9
|
+
* If running in tests, the test itself also acts as a service discovery of sorts, allowing multiple instances to run in parallel.
|
|
10
|
+
*/
|
|
11
|
+
export const GG_LOCAL_ROUTER_PORT = "GG_LOCAL_ROUTER_PORT";
|
|
12
|
+
export class GGLocalDiscoveryClient extends GGDiscoveryClient {
|
|
13
|
+
isLocal = true;
|
|
14
|
+
port;
|
|
15
|
+
entries = [];
|
|
16
|
+
client;
|
|
17
|
+
constructor(port) {
|
|
18
|
+
if (port === undefined) {
|
|
19
|
+
throw new Error("No port specified for local router");
|
|
20
|
+
}
|
|
21
|
+
super();
|
|
22
|
+
this.port = port;
|
|
23
|
+
this.client = new IPCClient(port);
|
|
24
|
+
GGLog.info(this, "Started on port: " + this.port);
|
|
25
|
+
GGLocator.getScope().setWithLifecycle(GG_DISCOVERY, this, {
|
|
26
|
+
type: GGLocatorServiceType.SERVICE_DISCOVERY,
|
|
27
|
+
start: () => this.register(),
|
|
28
|
+
teardown: () => this.unregister()
|
|
29
|
+
});
|
|
30
|
+
}
|
|
31
|
+
registerRoutes(registrations) {
|
|
32
|
+
for (const reg of registrations) {
|
|
33
|
+
this.entries.push({
|
|
34
|
+
api: reg.api,
|
|
35
|
+
baseUrl: `${reg.protocol}://localhost:${reg.port}`,
|
|
36
|
+
pathPrefix: reg.pathPrefix
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async discoverApi(apiName) {
|
|
41
|
+
await this.ensureConnected();
|
|
42
|
+
const res = await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.discoverApi, apiName);
|
|
43
|
+
if (res.success && res.url) {
|
|
44
|
+
return res.url;
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
throw new SERVER_ERROR({
|
|
48
|
+
displayMessage: res.error ?? "Unknown error",
|
|
49
|
+
debugData: { apiName }
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async register() {
|
|
54
|
+
await this.ensureConnected();
|
|
55
|
+
if (this.entries.length > 0) {
|
|
56
|
+
await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.register, this.entries);
|
|
57
|
+
}
|
|
58
|
+
GGLog.info(this, `Registered ${this.entries.length} routes`);
|
|
59
|
+
}
|
|
60
|
+
async unregister() {
|
|
61
|
+
if (this.entries.length > 0 && this.client.isConnected()) {
|
|
62
|
+
try {
|
|
63
|
+
await this.client.sendFrameworkRequest(GGDiscoveryIPC.discoveryServer.unregister, this.entries);
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
GGLog.error(this, err);
|
|
67
|
+
}
|
|
68
|
+
}
|
|
69
|
+
this.client.disconnect();
|
|
70
|
+
}
|
|
71
|
+
async ensureConnected() {
|
|
72
|
+
if (!this.client.isConnected()) {
|
|
73
|
+
await this.client.connect();
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
//# sourceMappingURL=GGLocalDiscoveryClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryClient.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { GGLocalDiscoveryClient } from "./GGLocalDiscoveryClient";
|
|
2
|
+
export declare class GGLocalDiscoveryResilientClient extends GGLocalDiscoveryClient {
|
|
3
|
+
private discoveryServer?;
|
|
4
|
+
private isLeader;
|
|
5
|
+
private isShuttingDown;
|
|
6
|
+
constructor(port?: number);
|
|
7
|
+
register(): Promise<void>;
|
|
8
|
+
unregister(): Promise<void>;
|
|
9
|
+
private becomeLeaderOrFollower;
|
|
10
|
+
private connectToLeader;
|
|
11
|
+
protected ensureConnected(): Promise<void>;
|
|
12
|
+
private delay;
|
|
13
|
+
private isConnectionError;
|
|
14
|
+
}
|
|
15
|
+
//# sourceMappingURL=GGLocalDiscoveryResilientClient.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryResilientClient.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryResilientClient.ts"],"names":[],"mappings":"AAGA,OAAO,EAAC,sBAAsB,EAAC,MAAM,0BAA0B,CAAC;AAEhE,qBAAa,+BAAgC,SAAQ,sBAAsB;IAEvE,OAAO,CAAC,eAAe,CAAC,CAAyB;IACjD,OAAO,CAAC,QAAQ,CAAS;IACzB,OAAO,CAAC,cAAc,CAAS;gBAEnB,IAAI,SAAO;IAID,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAOzB,UAAU,IAAI,OAAO,CAAC,IAAI,CAAC;YAUnC,sBAAsB;YAgBtB,eAAe;cAuBJ,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC;IAoBzD,OAAO,CAAC,KAAK;IAIb,OAAO,CAAC,iBAAiB;CAQ5B"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
import { GGLog } from "@grest-ts/logger";
|
|
2
|
+
import { IPCServer } from "@grest-ts/ipc";
|
|
3
|
+
import { GGLocalDiscoveryServer } from "./GGLocalDiscoveryServer.js";
|
|
4
|
+
import { GGLocalDiscoveryClient } from "./GGLocalDiscoveryClient.js";
|
|
5
|
+
export class GGLocalDiscoveryResilientClient extends GGLocalDiscoveryClient {
|
|
6
|
+
discoveryServer;
|
|
7
|
+
isLeader = false;
|
|
8
|
+
isShuttingDown = false;
|
|
9
|
+
constructor(port = 9000) {
|
|
10
|
+
super(port);
|
|
11
|
+
}
|
|
12
|
+
async register() {
|
|
13
|
+
if (!this.isLeader && !this.discoveryServer && !this.client.isConnected()) {
|
|
14
|
+
await this.becomeLeaderOrFollower();
|
|
15
|
+
}
|
|
16
|
+
await super.register();
|
|
17
|
+
}
|
|
18
|
+
async unregister() {
|
|
19
|
+
this.isShuttingDown = true;
|
|
20
|
+
await super.unregister();
|
|
21
|
+
if (this.discoveryServer) {
|
|
22
|
+
await this.discoveryServer.teardown();
|
|
23
|
+
this.discoveryServer = undefined;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
async becomeLeaderOrFollower() {
|
|
27
|
+
if (this.isShuttingDown)
|
|
28
|
+
return;
|
|
29
|
+
const server = new IPCServer(this.port);
|
|
30
|
+
const router = new GGLocalDiscoveryServer(server);
|
|
31
|
+
if (await router.start()) {
|
|
32
|
+
this.discoveryServer = router;
|
|
33
|
+
this.isLeader = true;
|
|
34
|
+
GGLog.info(this, "This instance is LEADER");
|
|
35
|
+
}
|
|
36
|
+
else {
|
|
37
|
+
this.isLeader = false;
|
|
38
|
+
GGLog.info(this, "This instance is FOLLOWER");
|
|
39
|
+
await this.connectToLeader();
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
async connectToLeader() {
|
|
43
|
+
if (this.isShuttingDown)
|
|
44
|
+
return;
|
|
45
|
+
try {
|
|
46
|
+
await this.client.connect();
|
|
47
|
+
this.client.onClose(async () => {
|
|
48
|
+
if (this.isShuttingDown)
|
|
49
|
+
return;
|
|
50
|
+
GGLog.warn(this, "Leader died");
|
|
51
|
+
await this.becomeLeaderOrFollower();
|
|
52
|
+
if (this.isLeader && this.entries.length > 0) {
|
|
53
|
+
await super.register();
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
GGLog.debug(this, "Connected to leader");
|
|
57
|
+
}
|
|
58
|
+
catch (err) {
|
|
59
|
+
GGLog.error(this, `Failed to connect to leader: ${err.message}`);
|
|
60
|
+
await this.delay(1000);
|
|
61
|
+
await this.connectToLeader();
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
async ensureConnected() {
|
|
65
|
+
const maxRetries = 20;
|
|
66
|
+
let retryCount = 0;
|
|
67
|
+
while (true) {
|
|
68
|
+
try {
|
|
69
|
+
await super.ensureConnected();
|
|
70
|
+
return;
|
|
71
|
+
}
|
|
72
|
+
catch (err) {
|
|
73
|
+
if (retryCount < maxRetries && this.isConnectionError(err)) {
|
|
74
|
+
GGLog.debug(this, `Waiting for router...`);
|
|
75
|
+
await this.delay(Math.min(500 * Math.pow(1.5, retryCount), 5000));
|
|
76
|
+
retryCount++;
|
|
77
|
+
continue;
|
|
78
|
+
}
|
|
79
|
+
throw err;
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
delay(ms) {
|
|
84
|
+
return new Promise(resolve => setTimeout(resolve, ms));
|
|
85
|
+
}
|
|
86
|
+
isConnectionError(err) {
|
|
87
|
+
const codes = ['ECONNREFUSED', 'ETIMEDOUT', 'ECONNRESET'];
|
|
88
|
+
const hasCode = (code) => code !== undefined && codes.includes(code);
|
|
89
|
+
return hasCode(err?.code) ||
|
|
90
|
+
hasCode(err?.cause?.code) ||
|
|
91
|
+
hasCode(err?.originalError?.code) ||
|
|
92
|
+
hasCode(err?.originalError?.cause?.code);
|
|
93
|
+
}
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=GGLocalDiscoveryResilientClient.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryResilientClient.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryResilientClient.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
import { IPCServer } from "@grest-ts/ipc";
|
|
2
|
+
import { RoutingStrategy } from "./routing/RoutingStrategy";
|
|
3
|
+
import { FirstStrategy } from "./routing/strategies/FirstStrategy";
|
|
4
|
+
import { LastStrategy } from "./routing/strategies/LastStrategy";
|
|
5
|
+
import { RandomStrategy } from "./routing/strategies/RandomStrategy";
|
|
6
|
+
import { RoundRobinStrategy } from "./routing/strategies/RoundRobinStrategy";
|
|
7
|
+
import { GGServiceDiscoveryEntry } from "./GGLocalDiscoveryClient";
|
|
8
|
+
export declare const ROUTING_STRATEGIES: {
|
|
9
|
+
readonly first: FirstStrategy;
|
|
10
|
+
readonly last: LastStrategy;
|
|
11
|
+
readonly random: RandomStrategy;
|
|
12
|
+
readonly roundRobin: RoundRobinStrategy;
|
|
13
|
+
};
|
|
14
|
+
export type RoutingStrategyName = "first" | "last" | "roundRobin" | "random" | RoutingStrategy;
|
|
15
|
+
export declare class GGLocalDiscoveryServer {
|
|
16
|
+
private readonly server;
|
|
17
|
+
private readonly routes;
|
|
18
|
+
private readonly routingStrategies;
|
|
19
|
+
constructor(server: IPCServer);
|
|
20
|
+
start(): Promise<boolean>;
|
|
21
|
+
teardown(): Promise<void>;
|
|
22
|
+
setRoutingStrategy(api: string, strategy: RoutingStrategyName | RoutingStrategy): void;
|
|
23
|
+
private getRoutingStrategy;
|
|
24
|
+
getRoute(api: string): GGServiceDiscoveryEntry | undefined;
|
|
25
|
+
addRoute(route: GGServiceDiscoveryEntry): void;
|
|
26
|
+
removeRoute(api: string, baseUrl?: string): void;
|
|
27
|
+
getRoutingUrl(api: string): string;
|
|
28
|
+
private matchRoute;
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=GGLocalDiscoveryServer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryServer.d.ts","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryServer.ts"],"names":[],"mappings":"AACA,OAAO,EAAC,SAAS,EAAC,MAAM,eAAe,CAAC;AACxC,OAAO,EAAC,eAAe,EAAC,MAAM,2BAA2B,CAAC;AAC1D,OAAO,EAAC,aAAa,EAAC,MAAM,oCAAoC,CAAC;AACjE,OAAO,EAAC,YAAY,EAAC,MAAM,mCAAmC,CAAC;AAC/D,OAAO,EAAC,cAAc,EAAC,MAAM,qCAAqC,CAAC;AACnE,OAAO,EAAC,kBAAkB,EAAC,MAAM,yCAAyC,CAAC;AAE3E,OAAO,EAAC,uBAAuB,EAAC,MAAM,0BAA0B,CAAC;AAEjE,eAAO,MAAM,kBAAkB;;;;;CAKrB,CAAC;AAEX,MAAM,MAAM,mBAAmB,GAAG,OAAO,GAAG,MAAM,GAAG,YAAY,GAAG,QAAQ,GAAG,eAAe,CAAC;AAE/F,qBAAa,sBAAsB;IAE/B,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAY;IACnC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqD;IAC5E,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA2C;gBAEjE,MAAM,EAAE,SAAS;IAwBhB,KAAK,IAAI,OAAO,CAAC,OAAO,CAAC;IAQzB,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;IAO/B,kBAAkB,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,mBAAmB,GAAG,eAAe,GAAG,IAAI;IAM7F,OAAO,CAAC,kBAAkB;IAInB,QAAQ,CAAC,GAAG,EAAE,MAAM,GAAG,uBAAuB,GAAG,SAAS;IAS1D,QAAQ,CAAC,KAAK,EAAE,uBAAuB,GAAG,IAAI;IAO9C,WAAW,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,GAAG,IAAI;IAqBhD,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM;IAUzC,OAAO,CAAC,UAAU;CAqBrB"}
|
|
@@ -0,0 +1,123 @@
|
|
|
1
|
+
import { GGLog } from "@grest-ts/logger";
|
|
2
|
+
import { FirstStrategy } from "./routing/strategies/FirstStrategy.js";
|
|
3
|
+
import { LastStrategy } from "./routing/strategies/LastStrategy.js";
|
|
4
|
+
import { RandomStrategy } from "./routing/strategies/RandomStrategy.js";
|
|
5
|
+
import { RoundRobinStrategy } from "./routing/strategies/RoundRobinStrategy.js";
|
|
6
|
+
import { GGDiscoveryIPC } from "./GGDiscoveryIPC.js";
|
|
7
|
+
export const ROUTING_STRATEGIES = {
|
|
8
|
+
first: new FirstStrategy(),
|
|
9
|
+
last: new LastStrategy(),
|
|
10
|
+
random: new RandomStrategy(),
|
|
11
|
+
roundRobin: new RoundRobinStrategy(),
|
|
12
|
+
};
|
|
13
|
+
export class GGLocalDiscoveryServer {
|
|
14
|
+
server;
|
|
15
|
+
routes = new Map();
|
|
16
|
+
routingStrategies = new Map();
|
|
17
|
+
constructor(server) {
|
|
18
|
+
this.server = server;
|
|
19
|
+
// Socket handlers for framework communication
|
|
20
|
+
this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.register, async (routes) => {
|
|
21
|
+
routes.forEach(route => this.addRoute(route));
|
|
22
|
+
});
|
|
23
|
+
this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.unregister, async (routes) => {
|
|
24
|
+
routes.forEach(route => this.removeRoute(route.api));
|
|
25
|
+
});
|
|
26
|
+
this.server.onFrameworkMessage(GGDiscoveryIPC.discoveryServer.discoverApi, async (apiName) => {
|
|
27
|
+
if (this.getRoute(apiName)) {
|
|
28
|
+
return { success: true, url: this.server.getUrl() };
|
|
29
|
+
}
|
|
30
|
+
return { success: false, error: "Service '" + apiName + "' is not registered! Did you forget to start it?" };
|
|
31
|
+
});
|
|
32
|
+
this.server.setRouteProxyResolver((path) => {
|
|
33
|
+
return this.matchRoute(path)?.baseUrl || undefined;
|
|
34
|
+
});
|
|
35
|
+
}
|
|
36
|
+
async start() {
|
|
37
|
+
const result = await this.server.start();
|
|
38
|
+
if (result) {
|
|
39
|
+
GGLog.info(this, `Router started on ${this.server.getUrl()}`);
|
|
40
|
+
}
|
|
41
|
+
return result;
|
|
42
|
+
}
|
|
43
|
+
async teardown() {
|
|
44
|
+
this.routes.clear();
|
|
45
|
+
this.routingStrategies.clear();
|
|
46
|
+
await this.server.teardown();
|
|
47
|
+
GGLog.info(this, 'Router stopped');
|
|
48
|
+
}
|
|
49
|
+
setRoutingStrategy(api, strategy) {
|
|
50
|
+
const strategyInstance = typeof strategy === 'string' ? ROUTING_STRATEGIES[strategy] : strategy;
|
|
51
|
+
this.routingStrategies.set(api, strategyInstance);
|
|
52
|
+
GGLog.debug(this, `Set routing strategy for ${api}: ${strategyInstance.constructor.name}`);
|
|
53
|
+
}
|
|
54
|
+
getRoutingStrategy(api) {
|
|
55
|
+
return this.routingStrategies.get(api) ?? ROUTING_STRATEGIES.roundRobin;
|
|
56
|
+
}
|
|
57
|
+
getRoute(api) {
|
|
58
|
+
const instances = this.routes.get(api);
|
|
59
|
+
if (!instances || instances.length === 0) {
|
|
60
|
+
return undefined;
|
|
61
|
+
}
|
|
62
|
+
const strategy = this.getRoutingStrategy(api);
|
|
63
|
+
return strategy.select(instances, api);
|
|
64
|
+
}
|
|
65
|
+
addRoute(route) {
|
|
66
|
+
const existing = this.routes.get(route.api) ?? [];
|
|
67
|
+
existing.push(route);
|
|
68
|
+
this.routes.set(route.api, existing);
|
|
69
|
+
GGLog.info(this, `Added route: ${route.pathPrefix} (${route.api}) -> ${route.baseUrl}`);
|
|
70
|
+
}
|
|
71
|
+
removeRoute(api, baseUrl) {
|
|
72
|
+
const instances = this.routes.get(api);
|
|
73
|
+
if (!instances)
|
|
74
|
+
return;
|
|
75
|
+
if (baseUrl) {
|
|
76
|
+
// Remove specific instance
|
|
77
|
+
const filtered = instances.filter(r => r.baseUrl !== baseUrl);
|
|
78
|
+
if (filtered.length === 0) {
|
|
79
|
+
this.routes.delete(api);
|
|
80
|
+
}
|
|
81
|
+
else {
|
|
82
|
+
this.routes.set(api, filtered);
|
|
83
|
+
}
|
|
84
|
+
GGLog.info(this, `Removed route instance: ${api} -> ${baseUrl}`);
|
|
85
|
+
}
|
|
86
|
+
else {
|
|
87
|
+
// Remove all instances for this API
|
|
88
|
+
const route = instances[0];
|
|
89
|
+
this.routes.delete(api);
|
|
90
|
+
GGLog.info(this, `Removed route: ${route?.pathPrefix} (${api})`);
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
getRoutingUrl(api) {
|
|
94
|
+
if (!this.getRoute(api)) {
|
|
95
|
+
throw new Error(`API '${api}' not registered in router`);
|
|
96
|
+
}
|
|
97
|
+
if (!this.server.getUrl()) {
|
|
98
|
+
throw new Error("Router not started yet!");
|
|
99
|
+
}
|
|
100
|
+
return this.server.getUrl();
|
|
101
|
+
}
|
|
102
|
+
matchRoute(path) {
|
|
103
|
+
let bestApi;
|
|
104
|
+
let longestMatch = 0;
|
|
105
|
+
// Find the best matching API based on path prefix
|
|
106
|
+
for (const [api, instances] of this.routes.entries()) {
|
|
107
|
+
if (instances.length === 0)
|
|
108
|
+
continue;
|
|
109
|
+
const pathPrefix = instances[0].pathPrefix;
|
|
110
|
+
if (path.startsWith(pathPrefix) && pathPrefix.length > longestMatch) {
|
|
111
|
+
bestApi = api;
|
|
112
|
+
longestMatch = pathPrefix.length;
|
|
113
|
+
}
|
|
114
|
+
}
|
|
115
|
+
if (!bestApi)
|
|
116
|
+
return undefined;
|
|
117
|
+
// Use routing strategy to select which instance, passing the full path
|
|
118
|
+
const instances = this.routes.get(bestApi);
|
|
119
|
+
const strategy = this.getRoutingStrategy(bestApi);
|
|
120
|
+
return strategy.select(instances, path);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
//# sourceMappingURL=GGLocalDiscoveryServer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"GGLocalDiscoveryServer.js","sourceRoot":"","sources":["../../../src/local/GGLocalDiscoveryServer.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoutingStrategy.d.ts","sourceRoot":"","sources":["../../../../src/local/routing/RoutingStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,uBAAuB,EAAC,MAAM,2BAA2B,CAAC;AAElE,MAAM,WAAW,eAAe;IAE5B,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,uBAAuB,CAAC;CACvF"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoutingStrategy.js","sourceRoot":"","sources":["../../../../src/local/routing/RoutingStrategy.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RoutingStrategy } from "../RoutingStrategy";
|
|
2
|
+
import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
|
|
3
|
+
/**
|
|
4
|
+
* Always route to the first registered instance.
|
|
5
|
+
*/
|
|
6
|
+
export declare class FirstStrategy implements RoutingStrategy {
|
|
7
|
+
select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=FirstStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FirstStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/FirstStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,aAAc,YAAW,eAAe;IACjD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"FirstStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/FirstStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,aAAa;IACtB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,CAAC,CAAC,CAAC;IACxB,CAAC;CACJ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RoutingStrategy } from "../RoutingStrategy";
|
|
2
|
+
import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
|
|
3
|
+
/**
|
|
4
|
+
* Always route to the last registered instance.
|
|
5
|
+
*/
|
|
6
|
+
export declare class LastStrategy implements RoutingStrategy {
|
|
7
|
+
select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=LastStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LastStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/LastStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,YAAa,YAAW,eAAe;IAChD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"LastStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/LastStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,YAAY;IACrB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,SAAS,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC3C,CAAC;CACJ"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { RoutingStrategy } from "../RoutingStrategy";
|
|
2
|
+
import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
|
|
3
|
+
/**
|
|
4
|
+
* Randomly select an instance for each request.
|
|
5
|
+
*/
|
|
6
|
+
export declare class RandomStrategy implements RoutingStrategy {
|
|
7
|
+
select(instances: GGServiceDiscoveryEntry[]): GGServiceDiscoveryEntry;
|
|
8
|
+
}
|
|
9
|
+
//# sourceMappingURL=RandomStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RandomStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RandomStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;GAEG;AACH,qBAAa,cAAe,YAAW,eAAe;IAClD,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,GAAG,uBAAuB;CAGxE"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RandomStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RandomStrategy.ts"],"names":[],"mappings":"AAGA;;GAEG;AACH,MAAM,OAAO,cAAc;IACvB,MAAM,CAAC,SAAoC;QACvC,OAAO,SAAS,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC,MAAM,EAAE,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC;IACnE,CAAC;CACJ"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { RoutingStrategy } from "../RoutingStrategy";
|
|
2
|
+
import { GGServiceDiscoveryEntry } from "../../GGLocalDiscoveryClient";
|
|
3
|
+
/**
|
|
4
|
+
* Cycle through instances in order, per path.
|
|
5
|
+
* Each unique path maintains its own counter.
|
|
6
|
+
*/
|
|
7
|
+
export declare class RoundRobinStrategy implements RoutingStrategy {
|
|
8
|
+
private readonly counters;
|
|
9
|
+
select(instances: GGServiceDiscoveryEntry[], path: string): GGServiceDiscoveryEntry;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=RoundRobinStrategy.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoundRobinStrategy.d.ts","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RoundRobinStrategy.ts"],"names":[],"mappings":"AAAA,OAAO,EAAC,eAAe,EAAC,MAAM,oBAAoB,CAAC;AACnD,OAAO,EAAC,uBAAuB,EAAC,MAAM,8BAA8B,CAAC;AAErE;;;GAGG;AACH,qBAAa,kBAAmB,YAAW,eAAe;IACtD,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAkC;IAE3D,MAAM,CAAC,SAAS,EAAE,uBAAuB,EAAE,EAAE,IAAI,EAAE,MAAM,GAAG,uBAAuB;CAMtF"}
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Cycle through instances in order, per path.
|
|
3
|
+
* Each unique path maintains its own counter.
|
|
4
|
+
*/
|
|
5
|
+
export class RoundRobinStrategy {
|
|
6
|
+
counters = new Map();
|
|
7
|
+
select(instances, path) {
|
|
8
|
+
const counter = this.counters.get(path) ?? 0;
|
|
9
|
+
const instance = instances[counter % instances.length];
|
|
10
|
+
this.counters.set(path, counter + 1);
|
|
11
|
+
return instance;
|
|
12
|
+
}
|
|
13
|
+
}
|
|
14
|
+
//# sourceMappingURL=RoundRobinStrategy.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"RoundRobinStrategy.js","sourceRoot":"","sources":["../../../../../src/local/routing/strategies/RoundRobinStrategy.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,MAAM,OAAO,kBAAkB;IACV,QAAQ,GAAwB,IAAI,GAAG,EAAE,CAAC;IAE3D,MAAM,CAAC,SAAoC,EAAE,IAAY;QACrD,MAAM,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7C,MAAM,QAAQ,GAAG,SAAS,CAAC,OAAO,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC;QACvD,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,IAAI,EAAE,OAAO,GAAG,CAAC,CAAC,CAAC;QACrC,OAAO,QAAQ,CAAC;IACpB,CAAC;CACJ"}
|