Skip to content

Commit 040b207

Browse files
committed
feat: bath server translations for dev widget
1 parent d265de3 commit 040b207

1 file changed

Lines changed: 89 additions & 18 deletions

File tree

cmp/compiler/src/translation-server/translation-server.ts

Lines changed: 89 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
import http from "http";
1515
import type { Socket } from "net";
1616
import { URL } from "url";
17-
import { WebSocketServer, WebSocket } from "ws";
17+
import { WebSocket, WebSocketServer } from "ws";
1818
import type { MetadataSchema, TranslationMiddlewareConfig } from "../types";
1919
import { getLogger } from "./logger";
2020
import {
@@ -63,6 +63,12 @@ export class TranslationServer {
6363
private wss: WebSocketServer | null = null;
6464
private wsClients: Set<WebSocket> = new Set();
6565

66+
// Translation activity tracking for "busy" notifications
67+
private activeTranslations = 0;
68+
private isBusy = false;
69+
private busyTimeout: NodeJS.Timeout | null = null;
70+
private readonly BUSY_DEBOUNCE_MS = 500; // Time after last translation to send "idle" event
71+
6672
constructor(options: TranslationServerOptions) {
6773
this.config = options.config;
6874
this.startPort = options.startPort || 60000;
@@ -227,6 +233,12 @@ export class TranslationServer {
227233
return;
228234
}
229235

236+
// Clear any pending busy timeout
237+
if (this.busyTimeout) {
238+
clearTimeout(this.busyTimeout);
239+
this.busyTimeout = null;
240+
}
241+
230242
// Close all WebSocket connections
231243
for (const client of this.wsClients) {
232244
client.close();
@@ -448,6 +460,57 @@ export class TranslationServer {
448460
});
449461
}
450462

463+
/**
464+
* Mark translation activity start - emits busy event if not already busy
465+
*/
466+
private startTranslationActivity(): void {
467+
this.activeTranslations++;
468+
469+
// Clear any pending idle timeout
470+
if (this.busyTimeout) {
471+
clearTimeout(this.busyTimeout);
472+
this.busyTimeout = null;
473+
}
474+
475+
// Emit busy event if this is the first active translation
476+
if (!this.isBusy && this.activeTranslations > 0) {
477+
this.isBusy = true;
478+
this.broadcast(
479+
createEvent("server:busy", {
480+
activeTranslations: this.activeTranslations,
481+
}),
482+
);
483+
this.logger.debug(
484+
`[BUSY] Server is now busy (${this.activeTranslations} active)`,
485+
);
486+
}
487+
}
488+
489+
/**
490+
* Mark translation activity end - emits idle event after debounce period
491+
*/
492+
private endTranslationActivity(): void {
493+
this.activeTranslations = Math.max(0, this.activeTranslations - 1);
494+
495+
// If no more active translations, schedule idle notification
496+
if (this.activeTranslations === 0 && this.isBusy) {
497+
// Clear any existing timeout
498+
if (this.busyTimeout) {
499+
clearTimeout(this.busyTimeout);
500+
}
501+
502+
// Wait for debounce period before sending idle event
503+
// This prevents rapid busy->idle->busy cycles when translations come in quick succession
504+
this.busyTimeout = setTimeout(() => {
505+
if (this.activeTranslations === 0) {
506+
this.isBusy = false;
507+
this.broadcast(createEvent("server:idle", {}));
508+
this.logger.debug("[IDLE] Server is now idle");
509+
}
510+
}, this.BUSY_DEBOUNCE_MS);
511+
}
512+
}
513+
451514
/**
452515
* Check if a given URL is running our translation server by calling the health endpoint
453516
*/
@@ -619,25 +682,33 @@ export class TranslationServer {
619682
this.logger.info(`🔄 Translating ${hashes.length} hashes to ${locale}`);
620683
this.logger.debug(`🔄 Hashes: ${hashes.join(", ")}`);
621684

622-
// Translate using the stored service
623-
const result = await this.translationService.translate(
624-
locale,
625-
this.metadata,
626-
hashes,
627-
);
685+
// Mark translation activity start
686+
this.startTranslationActivity();
628687

629-
// Return successful response
630-
res.writeHead(200, {
631-
"Content-Type": "application/json",
632-
"Cache-Control": "no-cache",
633-
});
634-
res.end(
635-
JSON.stringify({
688+
try {
689+
// Translate using the stored service
690+
const result = await this.translationService.translate(
636691
locale,
637-
translations: result.translations,
638-
errors: result.errors,
639-
}),
640-
);
692+
this.metadata,
693+
hashes,
694+
);
695+
696+
// Return successful response
697+
res.writeHead(200, {
698+
"Content-Type": "application/json",
699+
"Cache-Control": "no-cache",
700+
});
701+
res.end(
702+
JSON.stringify({
703+
locale,
704+
translations: result.translations,
705+
errors: result.errors,
706+
}),
707+
);
708+
} finally {
709+
// Mark translation activity end
710+
this.endTranslationActivity();
711+
}
641712
} catch (error) {
642713
this.logger.error(
643714
`Error getting batch translations for ${locale}:`,

0 commit comments

Comments
 (0)