Fix server management issues and improve overall stability

Major server management fixes:
- Replace Flatpak-specific pkill with universal process tree termination using pstree + process.kill()
- Fix signal format errors (SIGTERM/SIGKILL instead of TERM/KILL strings)
- Add 5-second cooldown after server stop to prevent race conditions with external detection
- Enable Stop Server button for external servers in UI
- Implement proper timeout handling with process tree killing

ContentDB improvements:
- Fix download retry logic and "closed" error by preventing concurrent zip extraction
- Implement smart root directory detection and stripping during package extraction
- Add game-specific timeout handling (8s for VoxeLibre vs 3s for simple games)

World creation fixes:
- Make world creation asynchronous to prevent browser hangs
- Add WebSocket notifications for world creation completion status

Other improvements:
- Remove excessive debug logging
- Improve error handling and user feedback throughout the application
- Clean up temporary files and unnecessary logging

🤖 Generated with [Claude Code](https://claude.ai/code)

Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
Nathan Schneider
2025-08-24 19:17:38 -06:00
parent 3aed09b60f
commit 2d3b1166fe
15 changed files with 851 additions and 536 deletions

View File

@@ -3,12 +3,20 @@ const path = require('path');
const fs = require('fs').promises;
class PackageRegistry {
constructor(dbPath = 'data/packages.db') {
constructor(dbPath = null) {
// If no dbPath provided, we'll set it during init based on current data directory
this.dbPath = dbPath;
this.db = null;
}
async init() {
// Set database path based on current data directory if not already set
if (!this.dbPath) {
const paths = require('./paths');
await paths.initialize();
this.dbPath = path.join(paths.minetestDir, 'luhost_packages.db');
}
// Ensure data directory exists
const dir = path.dirname(this.dbPath);
await fs.mkdir(dir, { recursive: true });
@@ -24,6 +32,24 @@ class PackageRegistry {
});
}
async reinitialize() {
// Close existing database connection
if (this.db) {
await new Promise((resolve) => {
this.db.close((err) => {
if (err) console.error('Error closing database:', err);
resolve();
});
});
}
// Clear the path so it gets recalculated
this.dbPath = null;
// Reinitialize with new path
return this.init();
}
async createTables() {
const sql = `
CREATE TABLE IF NOT EXISTS installed_packages (