From 55f0c027d27b1bca5fdbfa2691713a89bf000e61 Mon Sep 17 00:00:00 2001 From: Sline Date: Sat, 4 Oct 2025 02:49:49 +0800 Subject: [PATCH] fix: start tamagotchi (#630) --- .../scripts/dev-with-server.ts | 121 ++++++++++++++++++ apps/stage-tamagotchi/src/main/index.ts | 6 +- 2 files changed, 126 insertions(+), 1 deletion(-) create mode 100644 apps/stage-tamagotchi/scripts/dev-with-server.ts diff --git a/apps/stage-tamagotchi/scripts/dev-with-server.ts b/apps/stage-tamagotchi/scripts/dev-with-server.ts new file mode 100644 index 000000000..d2f075472 --- /dev/null +++ b/apps/stage-tamagotchi/scripts/dev-with-server.ts @@ -0,0 +1,121 @@ +#!/usr/bin/env tsx +/** + * Development script to start both the WebSocket server and Tamagotchi app + * This ensures the server-runtime is running before starting the app + */ + +import type { Buffer } from 'node:buffer' + +import process from 'node:process' + +import { spawn } from 'node:child_process' + +const isWindows = process.platform === 'win32' + +console.log('šŸš€ Starting AIRI WebSocket server and Tamagotchi app...\n') + +// Start the WebSocket server in the background +console.log('šŸ“” Starting WebSocket server on port 6121...') +const serverProcess = spawn( + 'pnpm', + ['-F', '@proj-airi/server-runtime', 'dev'], + { + stdio: ['pipe', 'pipe', 'pipe'], // Change from 'inherit' to capture output + shell: isWindows, + }, +) + +// Wait for the server to be ready by listening for a ready message +console.log('ā³ Waiting for server to initialize...\n') +const serverReady = new Promise((resolve, reject) => { + // Listen typically outputs a URL when ready, looking for patterns like: + // "Listening on http://localhost:6121" or similar + const readyPatterns = [ + /listening.*:6121/i, + /ready.*:6121/i, + /localhost:6121/i, + /http:\/\/localhost:6121/i, + ] + + const timeout = setTimeout(() => { + console.log('āš ļø Server ready timeout reached, continuing anyway...') + resolve() // Resolve even if we don't see the message to avoid hanging + }, 10000) // 10 second timeout + + // Handle errors from the server process + serverProcess.on('error', (error) => { + console.error('Failed to start server:', error) + clearTimeout(timeout) + reject(error) + }) + + const checkOutput = (data: Buffer) => { + const output = data.toString() + console.log(output) // Still output to console for visibility + + if (readyPatterns.some(pattern => pattern.test(output))) { + clearTimeout(timeout) + resolve() + } + } + + serverProcess.stdout?.on('data', checkOutput) + serverProcess.stderr?.on('data', checkOutput) +}) + +await serverReady + +// Start the Tamagotchi app +console.log('šŸŽ® Starting Tamagotchi app...\n') +const tamagotchiProcess = spawn( + 'pnpm', + ['-F', '@proj-airi/stage-tamagotchi', 'app:dev'], + { + stdio: 'inherit', + shell: isWindows, + }, +) + +let isCleaningUp = false + +// Handle cleanup on exit +function cleanup() { + if (isCleaningUp) + return + isCleaningUp = true + console.log('\nšŸ›‘ Shutting down...') + try { + if (serverProcess && !serverProcess.killed) { + serverProcess.kill() + } + } + catch (error) { + console.error('Error killing server process:', error) + } + try { + if (tamagotchiProcess && !tamagotchiProcess.killed) { + tamagotchiProcess.kill() + } + } + catch (error) { + console.error('Error killing tamagotchi process:', error) + } +} + +process.on('SIGINT', cleanup) +process.on('SIGTERM', cleanup) + +// Wait for processes +const serverExit = new Promise(resolve => serverProcess.on('exit', code => resolve({ name: 'Server', code }))) +const tamagotchiExit = new Promise(resolve => tamagotchiProcess.on('exit', code => resolve({ name: 'Tamagotchi', code }))) + +const firstToExit = await Promise.race([serverExit, tamagotchiExit]) + +console.log(`${firstToExit.name} process exited with code ${firstToExit.code}, shutting down...`) +cleanup() + +// Wait for both processes to terminate before exiting the script. +await Promise.all([serverExit, tamagotchiExit]) + +console.log('All child processes have terminated.') +process.exit(firstToExit.code ?? 0) diff --git a/apps/stage-tamagotchi/src/main/index.ts b/apps/stage-tamagotchi/src/main/index.ts index 8ec3f657a..7b86d049f 100644 --- a/apps/stage-tamagotchi/src/main/index.ts +++ b/apps/stage-tamagotchi/src/main/index.ts @@ -61,7 +61,9 @@ function createWindow(): void { }) mainWindow.setAlwaysOnTop(true) - mainWindow.setWindowButtonVisibility(false) + if (isMacOS) { + mainWindow.setWindowButtonVisibility(false) + } mainWindow.on('ready-to-show', () => mainWindow!.show()) mainWindow.webContents.setWindowOpenHandler((details) => { shell.openExternal(details.url) @@ -125,6 +127,8 @@ app.whenReady().then(() => { app.on('browser-window-created', (_, window) => optimizer.watchWindowShortcuts(window)) createWindow() +}).catch((err) => { + console.error('Error during app initialization:', err) }) // Quit when all windows are closed, except on macOS. There, it's common