Skip to content

Commit

Permalink
this should work now
Browse files Browse the repository at this point in the history
  • Loading branch information
Techbot121 authored and Meta Construct committed Jan 4, 2025
1 parent c31cdab commit d87c68b
Show file tree
Hide file tree
Showing 4 changed files with 48 additions and 37 deletions.
59 changes: 31 additions & 28 deletions app/Container.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ export class Container {
readonly app: App;
private providers: ProviderFactory;
private services = {} as ServiceMap;
private initPromises = new Map<string, Promise<Service>>();
private pendingServices = new Map<string, Promise<Service>>();

constructor(app: App, providers: ProviderFactory) {
this.app = app;
Expand All @@ -27,40 +27,43 @@ export class Container {
service = await service;
}
this.services[service.name] = service;
}

async getService<T extends keyof ServiceMap>(name: T): Promise<ServiceMap[T]> {
const service = this.services[name];
if (service) {
return service as ServiceMap[T];
// Resolve any pending waiters
const pendingPromise = this.pendingServices.get(service.name);
if (pendingPromise) {
this.pendingServices.delete(service.name);
}
}

// If already initializing, wait for it
if (this.initPromises.has(String(name))) {
return this.initPromises.get(String(name)) as Promise<ServiceMap[T]>;
async getService<Name extends string>(
type: Name,
timeoutMs = 30000
): Promise<ServiceMap[Name]> {
if (this.services[type]) {
return this.services[type];
}

// Find the provider
const provider = this.providers.find(p => {
const temp = p(this);
if (temp instanceof Promise) {
return temp.then(s => s.name === name);
}
return temp.name === name;
});
// Create or return existing promise for this service
if (!this.pendingServices.has(type)) {
this.pendingServices.set(
type,
new Promise((resolve, reject) => {
const timeoutId = setTimeout(() => {
this.pendingServices.delete(type);
reject(new Error(`Timeout waiting for service: ${type}`));
}, timeoutMs);

if (!provider) {
throw new Error(`Service ${String(name)} not found`);
const checkInterval = setInterval(() => {
if (this.services[type]) {
clearTimeout(timeoutId);
clearInterval(checkInterval);
resolve(this.services[type]);
}
}, 100);
})
);
}

// Initialize the service
const promise = Promise.resolve(provider(this)).then(service => {
this.services[name] = service;
this.initPromises.delete(String(name));
return service as ServiceMap[T];
});

this.initPromises.set(String(name), promise);
return promise;
return this.pendingServices.get(type) as Promise<ServiceMap[Name]>;
}
}
8 changes: 8 additions & 0 deletions app/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,13 @@ export class App {

constructor() {
this.container = new Container(this, providers);

this.init();
}

async init(): Promise<void> {
for (const provider of this.container.getProviders()) {
await this.container.addService(provider(this.container));
}
}
}
10 changes: 5 additions & 5 deletions app/services/discord/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,11 @@ export class DiscordBot extends Service {
super(container);

this.initServices();
}

private async initServices() {
this.data = await this.container.getService("Data");
this.bridge = await this.container.getService("GameBridge");

this.discord.on("ready", async client => {
this.ready = true;
Expand All @@ -64,11 +69,6 @@ export class DiscordBot extends Service {

this.discord.login(this.config.bot.token);
}

private async initServices() {
this.data = await this.container.getService("Data");
this.bridge = await this.container.getService("GameBridge");
}
getTextChannel(channelId: string): Discord.TextChannel | undefined {
if (!this.ready) return;
return this.discord.channels.cache.get(channelId) as Discord.TextChannel;
Expand Down
8 changes: 4 additions & 4 deletions app/services/gamebridge/GameBridge.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,10 @@ export default class GameBridge extends Service {
constructor(container: Container) {
super(container);
this.setupWebApp();
}

private async setupWebApp() {
this.webApp = await this.container.getService("WebApp");
this.ws = new WebSocketServer({
httpServer: this.webApp.http,
autoAcceptConnections: false,
Expand All @@ -39,10 +43,6 @@ export default class GameBridge extends Service {
this.handleResoniteConnection();
}

private async setupWebApp() {
this.webApp = await this.container.getService("WebApp");
}

async handleConnection(req: WebSocketRequest): Promise<void> {
const ip = req.httpRequest.socket.remoteAddress;

Expand Down

0 comments on commit d87c68b

Please sign in to comment.