xp_nix/xp_server/bin/xp_nix.dart

194 lines
5.6 KiB
Dart

import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'package:sqlite3/sqlite3.dart';
import 'package:xp_nix/src/monitors/productivity_monitor.dart';
import 'package:xp_nix/src/config/config_manager.dart';
import 'package:xp_nix/src/logging/logger.dart';
import 'package:xp_nix/src/web/dashboard_server.dart';
import 'package:xp_nix/src/database/database_manager.dart';
import 'package:xp_nix/src/detectors/idle_monitor.dart';
import 'package:xp_nix/src/providers/system_time_provider.dart';
import 'package:xp_nix/src/enhancers/hyprland_enhancer.dart';
import 'package:xp_nix/src/build/dashboard_builder.dart';
late final Database _db;
late final IdleMonitor _idleMonitor;
late final SystemTimeProvider _timeProvider;
late final HyprlandEnhancer _desktopEnhancer;
late final ProductivityMonitor _monitor;
late final DashboardServer _dashboardServer;
// Enhanced main function with interactive commands and one-shot mode
void main(List<String> args) async {
// Parse command line arguments
String dbPath = 'productivity_tracker.db';
int port = 8080;
for (int i = 0; i < args.length; i++) {
switch (args[i]) {
case '--db':
if (i + 1 < args.length) {
dbPath = args[i + 1];
i++; // Skip next argument as it's the db path
} else {
print('Error: --db flag requires a database path');
exit(1);
}
break;
case '--port':
if (i + 1 < args.length) {
port = int.tryParse(args[i + 1]) ?? 8080;
i++; // Skip next argument as it's the port number
} else {
print('Error: --port flag requires a port number');
exit(1);
}
break;
case '--help':
case '-h':
print('''
XP Nix Server
Usage: dart xp_nix.dart [options]
Options:
--db PATH Database file path (default: productivity_tracker.db)
--port PORT Server port (default: 8080)
--help, -h Show this help message
Examples:
dart xp_nix.dart
dart xp_nix.dart --db test_data.db --port 8081
''');
exit(0);
}
}
print('🗄️ Using database: $dbPath');
print('🌐 Starting server on port: $port');
// Initialize logging system
await Logger.instance.initialize(level: LogLevel.info, logDirectory: 'logs', maxFileSizeMB: 10, maxFiles: 5);
// Initialize configuration manager
await ConfigManager.instance.initialize();
_db = sqlite3.open(dbPath);
// Create production dependencies
_idleMonitor = IdleMonitor();
_timeProvider = SystemTimeProvider();
_desktopEnhancer = HyprlandEnhancer();
// Create monitor with dependency injection
_monitor = ProductivityMonitor(
db: _db,
idleMonitor: _idleMonitor,
timeProvider: _timeProvider,
desktopEnhancer: _desktopEnhancer,
// No activity detector provided - will use legacy polling mode
);
_dashboardServer = DashboardServer.withDatabase(DatabaseManager(_db));
ProcessSignal.sigint.watch().listen((_) async {
Logger.info('Shutting down XP Nix...');
print('\nShutting down...');
_quit();
});
// Start the dashboard server
try {
await _dashboardServer.start(port);
Logger.info('Dashboard available at: ${_dashboardServer.dashboardUrl}');
print('🌐 Dashboard available at: ${_dashboardServer.dashboardUrl}');
} catch (e) {
Logger.error('Failed to start dashboard server: $e');
print('⚠️ Dashboard server failed to start: $e');
_quit();
}
_monitor.start();
_monitor.printDetailedStats();
// Add command listener for manual controls
stdin.transform(utf8.decoder).transform(LineSplitter()).listen((line) {
final parts = line.trim().split(' ');
final command = parts[0].toLowerCase();
switch (command) {
case 'stats':
_monitor.printDetailedStats();
break;
case 'test':
if (parts.length > 1) {
final level = int.tryParse(parts[1]) ?? 1;
_monitor.testTheme(level);
}
break;
case 'restore':
_monitor.restoreDesktop();
break;
case 'refresh':
_monitor.refreshConfig();
break;
case 'build':
_handleBuildCommand();
break;
case 'help':
print('''
Available commands:
- stats: Show current productivity stats
- test [level]: Test theme for specific level
- restore: Restore desktop backup
- refresh: Refresh base config from current system config
- build: Build Flutter dashboard and copy to static files
- help: Show this help
''');
break;
}
});
print('💡 Type "help" for available commands');
// Keep running and show stats periodically
while (true) {
await Future.delayed(Duration(seconds: 1));
if (DateTime.now().second == 0 && DateTime.now().minute % 10 == 0) {
_monitor.printDetailedStats();
}
}
}
/// Handles the build command to rebuild the Flutter dashboard
void _handleBuildCommand() async {
print('🚀 Starting dashboard build process...');
// Check if Flutter is available
if (!await DashboardBuilder.checkFlutterAvailable()) {
print('❌ Flutter is not available in the system PATH');
print(' Please ensure Flutter is installed and available in your PATH');
return;
}
// Build the dashboard
final success = await DashboardBuilder.buildDashboard();
if (success) {
print('🎉 Dashboard build completed successfully!');
print(' The server is now serving the updated Flutter dashboard');
} else {
print('❌ Dashboard build failed. Check the logs for more details.');
}
}
Future<void> _quit() async {
_monitor.stop();
await _dashboardServer.stop();
await Logger.instance.dispose();
_db.dispose();
exit(0);
}