Add KeetaNetCombinedAnchorHTTPServer to merge routes from multiple servers#267
Add KeetaNetCombinedAnchorHTTPServer to merge routes from multiple servers#267
Conversation
…le servers Agent-Logs-Url: https://github.com/KeetaNetwork/anchor/sessions/adb8fb18-e173-4efe-b121-250f7a36612b Co-authored-by: ezraripps <19670988+ezraripps@users.noreply.github.com>
| /** | ||
| * Static helper that allows KeetaNetCombinedAnchorHTTPServer (and other | ||
| * subclasses) to invoke buildRoutes() on an arbitrary | ||
| * KeetaNetAnchorHTTPServer instance. Protected access is valid here | ||
| * because we are inside the KeetaNetAnchorHTTPServer class body. | ||
| */ | ||
| protected static callBuildRoutes(server: KeetaNetAnchorHTTPServer): Promise<Routes> { | ||
| return(server.buildRoutes()); | ||
| } |
There was a problem hiding this comment.
This method should not be needed, if it is needed for testing you can access via server'buildRoutes' in tests as TS allows bypassing private flag that way, or by creating a class that overrides that method.
There was a problem hiding this comment.
Removed callBuildRoutes. initRoutes now calls buildRoutes() via bracket notation directly on each child: (child as unknown as { buildRoutes(): Promise<Routes> }).buildRoutes() (ac464cb).
|
|
||
| constructor(config: KeetaAnchorCombinedHTTPServerConfig) { | ||
| super(config); | ||
| this.#children = [...config.servers]; |
There was a problem hiding this comment.
Why set this here then ignore it in initRoutes, it should probably just be used in initRoutes, if not we need to verify that both values are the same
There was a problem hiding this comment.
Fixed in ac464cb — initRoutes now uses the config parameter directly (config.servers) instead of this.#children. The #children field is kept only for the start() override where the base class's private #config isn't accessible.
There was a problem hiding this comment.
We should figure out a better way than having two sources of truth
There was a problem hiding this comment.
Fixed in 3973da7. Added protected get config(): ConfigType to the base class and removed the #children field entirely. Both initRoutes and start() now read from this.config.servers — one source of truth.
There was a problem hiding this comment.
Fixed in 3973da7 — removed #children and added protected get config() on the base class. Both initRoutes and start() now use this.config.servers.
| */ | ||
| const url = this.url; | ||
| for (const child of this.#children) { | ||
| child.url = url; |
There was a problem hiding this comment.
What if the child already has a URL set? We should ensure they either do not or it is the same.
There was a problem hiding this comment.
Added validation in ac464cb. Before propagating the URL, start() now tries to read each child's existing URL. If the child already has a static URL set and it differs from the combined server's URL, it throws: Error: Child server url "..." does not match combined server url "...". A test for this case is also added.
| await super.start(); | ||
|
|
||
| /* | ||
| * Propagate the combined server's URL to all child server |
There was a problem hiding this comment.
Should we perform this validation here, or somewhere else?
There was a problem hiding this comment.
Validation happens in start() after super.start() — that's the earliest point where the combined server's URL is known (it depends on the port assigned by the OS when no static URL is configured). For the common case of a static string/URL config, we could check earlier, but doing it uniformly in start() keeps the logic in one place.
| protected buildRoutes(): Promise<Routes> { | ||
| return(this.initRoutes(this.#config)); | ||
| } |
There was a problem hiding this comment.
Why have a method that overrides initRoutes? It does the same thing
There was a problem hiding this comment.
buildRoutes() is a protected proxy that packages initRoutes(this.#config) into a no-argument call. It's needed because initRoutes is generic over ConfigType — you can't call it on an arbitrary child instance from outside the class without knowing (or storing) its config type. The method allows KeetaNetCombinedAnchorHTTPServer to invoke the correct initRoutes on each child via bracket notation without a cast that loses type information.
…utes, validate child URLs Agent-Logs-Url: https://github.com/KeetaNetwork/anchor/sessions/f2463b59-588b-4959-99c0-b9e5ac7293c2 Co-authored-by: ezraripps <19670988+ezraripps@users.noreply.github.com>
| const retval = urlObj.toString(); | ||
|
|
||
| return(retval); | ||
| return(urlObj.toString()); |
There was a problem hiding this comment.
These were incidental style cleanups made during the URL getter restructuring (inlining const retval = ...). Reverted in 3973da7 to keep the diff focused on the functional change.
| newURLObj.search = ''; | ||
|
|
||
| const retval = newURLObj.toString(); | ||
| return(newURLObj.toString()); |
There was a problem hiding this comment.
Same as above — incidental style change, reverted in 3973da7.
|
|
||
| constructor(config: KeetaAnchorCombinedHTTPServerConfig) { | ||
| super(config); | ||
| this.#children = [...config.servers]; |
There was a problem hiding this comment.
We should figure out a better way than having two sources of truth
| try { | ||
| childURL = child.url; | ||
| } catch { | ||
| /* child has no static URL set; the URL will be propagated below */ |
There was a problem hiding this comment.
Why would this throw? If it does, should we check the specific error and throw unknown?
There was a problem hiding this comment.
The url getter throws new Error('Server not started') when no static URL is set and the server hasn't started. Fixed in 3973da7: the catch now explicitly re-throws anything that isn't that specific error, so unexpected errors are not silently swallowed.
|
…revert cosmetic url changes Agent-Logs-Url: https://github.com/KeetaNetwork/anchor/sessions/0bd3f93f-6749-464f-867d-98a392a18242 Co-authored-by: ezraripps <19670988+ezraripps@users.noreply.github.com>



urlgetter to allow reading a statically-set URL (string/URL instance) even when the server is not started// @ts-ignorein constructor by changing#url/urlsetter from polymorphicthiscallback type to explicitKeetaNetAnchorHTTPServercallback typeprotected get config()toKeetaNetAnchorHTTPServerso subclasses have a single source of truthprotected buildRoutes()method toKeetaNetAnchorHTTPServer(delegates toinitRoutes(this.#config))KeetaAnchorCombinedHTTPServerConfiginterfaceKeetaNetCombinedAnchorHTTPServerclass:#childrenfield — usesthis.config.servers(single source of truth via protected getter)initRoutesusesconfig.serversparameterstart()usesthis.config.serversfor URL propagationstart()validates that any child with a pre-set URL matches the combined server's URL, re-throwing unknown errors from the URL getter