@@ -180,10 +180,7 @@ class MinerProcess {
180180 try {
181181 // Check if the process has exited by looking at its PID
182182 final pid = _externalMinerProcess! .pid;
183- final result = await Process .run ('kill' , ['-0' , pid.toString ()]);
184- if (result.exitCode != 0 ) {
185- minerStillRunning = false ;
186- }
183+ minerStillRunning = await _isProcessRunning (pid);
187184 } catch (e) {
188185 minerStillRunning = false ;
189186 }
@@ -346,8 +343,7 @@ class MinerProcess {
346343 Future .delayed (const Duration (seconds: 2 )).then ((_) async {
347344 // Check if process is still running and force kill if necessary
348345 try {
349- final result = await Process .run ('kill' , ['-0' , _externalMinerProcess! .pid.toString ()]);
350- if (result.exitCode == 0 ) {
346+ if (await _isProcessRunning (_externalMinerProcess! .pid)) {
351347 print ('MinerProcess: External miner still running, force killing...' );
352348 _externalMinerProcess! .kill (ProcessSignal .sigkill);
353349 }
@@ -378,8 +374,7 @@ class MinerProcess {
378374 Future .delayed (const Duration (seconds: 2 )).then ((_) async {
379375 // Check if process is still running and force kill if necessary
380376 try {
381- final result = await Process .run ('kill' , ['-0' , _nodeProcess.pid.toString ()]);
382- if (result.exitCode == 0 ) {
377+ if (await _isProcessRunning (_nodeProcess.pid)) {
383378 print ('MinerProcess: Node process still running, force killing...' );
384379 _nodeProcess.kill (ProcessSignal .sigkill);
385380 }
@@ -447,30 +442,67 @@ class MinerProcess {
447442 }
448443 }
449444
445+ /// Check if a process with the given PID is running
446+ Future <bool > _isProcessRunning (int pid) async {
447+ try {
448+ if (Platform .isWindows) {
449+ final result = await Process .run ('tasklist' , ['/FI' , 'PID eq $pid ' ]);
450+ return result.stdout.toString ().contains (' $pid ' );
451+ } else {
452+ final result = await Process .run ('kill' , ['-0' , pid.toString ()]);
453+ return result.exitCode == 0 ;
454+ }
455+ } catch (e) {
456+ return false ;
457+ }
458+ }
459+
450460 /// Helper method to force kill a process by PID with verification
451461 Future <void > _forceKillProcess (int pid, String processName) async {
452462 try {
453463 print ('MinerProcess: Force killing $processName process (PID: $pid )' );
454464
455- // First try SIGKILL via kill command for better reliability
456- final killResult = await Process .run ('kill' , ['-9' , pid.toString ()]);
465+ if (Platform .isWindows) {
466+ final killResult = await Process .run ('taskkill' , ['/F' , '/PID' , pid.toString ()]);
467+ if (killResult.exitCode == 0 ) {
468+ print ('MinerProcess: Successfully force killed $processName (PID: $pid )' );
469+ } else {
470+ print ('MinerProcess: taskkill failed for $processName (PID: $pid ), exit code: ${killResult .exitCode }' );
471+ }
472+
473+ await Future .delayed (const Duration (milliseconds: 500 ));
457474
458- if (killResult.exitCode == 0 ) {
459- print ('MinerProcess: Successfully force killed $processName (PID: $pid )' );
475+ // Verify
476+ final checkResult = await Process .run ('tasklist' , ['/FI' , 'PID eq $pid ' ]);
477+ if (checkResult.stdout.toString ().contains (' $pid ' )) {
478+ print ('MinerProcess: WARNING - $processName (PID: $pid ) may still be running' );
479+ // Try by name as last resort
480+ final binaryName = processName.contains ('miner' ) ? 'quantus-miner.exe' : 'quantus-node.exe' ;
481+ await Process .run ('taskkill' , ['/F' , '/IM' , binaryName]);
482+ } else {
483+ print ('MinerProcess: Verified $processName (PID: $pid ) is terminated' );
484+ }
460485 } else {
461- print ( 'MinerProcess: kill command failed for $ processName (PID: $ pid ), exit code: ${ killResult . exitCode }' );
462- }
486+ // First try SIGKILL via kill command for better reliability
487+ final killResult = await Process . run ( 'kill' , [ '-9' , pid. toString ()]);
463488
464- // Wait a moment then verify the process is dead
465- await Future .delayed (const Duration (milliseconds: 500 ));
489+ if (killResult.exitCode == 0 ) {
490+ print ('MinerProcess: Successfully force killed $processName (PID: $pid )' );
491+ } else {
492+ print ('MinerProcess: kill command failed for $processName (PID: $pid ), exit code: ${killResult .exitCode }' );
493+ }
466494
467- final checkResult = await Process .run ('kill' , ['-0' , pid.toString ()]);
468- if (checkResult.exitCode != 0 ) {
469- print ('MinerProcess: Verified $processName (PID: $pid ) is terminated' );
470- } else {
471- print ('MinerProcess: WARNING - $processName (PID: $pid ) may still be running' );
472- // Try pkill as last resort
473- await Process .run ('pkill' , ['-9' , '-f' , processName.contains ('miner' ) ? 'quantus-miner' : 'quantus-node' ]);
495+ // Wait a moment then verify the process is dead
496+ await Future .delayed (const Duration (milliseconds: 500 ));
497+
498+ final checkResult = await Process .run ('kill' , ['-0' , pid.toString ()]);
499+ if (checkResult.exitCode != 0 ) {
500+ print ('MinerProcess: Verified $processName (PID: $pid ) is terminated' );
501+ } else {
502+ print ('MinerProcess: WARNING - $processName (PID: $pid ) may still be running' );
503+ // Try pkill as last resort
504+ await Process .run ('pkill' , ['-9' , '-f' , processName.contains ('miner' ) ? 'quantus-miner' : 'quantus-node' ]);
505+ }
474506 }
475507 } catch (e) {
476508 print ('MinerProcess: Error in _forceKillProcess for $processName : $e ' );
@@ -575,8 +607,13 @@ class MinerProcess {
575607 /// Check if a port is currently in use
576608 Future <bool > _isPortInUse (int port) async {
577609 try {
578- final result = await Process .run ('lsof' , ['-i' , ':$port ' ]);
579- return result.exitCode == 0 && result.stdout.toString ().isNotEmpty;
610+ if (Platform .isWindows) {
611+ final result = await Process .run ('netstat' , ['-ano' ]);
612+ return result.exitCode == 0 && result.stdout.toString ().contains (':$port ' );
613+ } else {
614+ final result = await Process .run ('lsof' , ['-i' , ':$port ' ]);
615+ return result.exitCode == 0 && result.stdout.toString ().isNotEmpty;
616+ }
580617 } catch (e) {
581618 // lsof might not be available, try netstat as fallback
582619 try {
@@ -592,13 +629,32 @@ class MinerProcess {
592629 /// Kill process using a specific port
593630 Future <void > _killProcessOnPort (int port) async {
594631 try {
595- // Find process using the port
596- final result = await Process .run ('lsof' , ['-ti' , ':$port ' ]);
597- if (result.exitCode == 0 ) {
598- final pids = result.stdout.toString ().trim ().split ('\n ' );
599- for (final pid in pids) {
600- if (pid.isNotEmpty) {
601- await Process .run ('kill' , ['-9' , pid.trim ()]);
632+ if (Platform .isWindows) {
633+ final result = await Process .run ('netstat' , ['-ano' ]);
634+ if (result.exitCode == 0 ) {
635+ final lines = result.stdout.toString ().split ('\n ' );
636+ for (final line in lines) {
637+ if (line.contains (':$port ' )) {
638+ final parts = line.trim ().split (RegExp (r'\s+' ));
639+ if (parts.isNotEmpty) {
640+ final pid = parts.last;
641+ // Verify it's a valid PID number
642+ if (int .tryParse (pid) != null ) {
643+ await Process .run ('taskkill' , ['/F' , '/PID' , pid]);
644+ }
645+ }
646+ }
647+ }
648+ }
649+ } else {
650+ // Find process using the port
651+ final result = await Process .run ('lsof' , ['-ti' , ':$port ' ]);
652+ if (result.exitCode == 0 ) {
653+ final pids = result.stdout.toString ().trim ().split ('\n ' );
654+ for (final pid in pids) {
655+ if (pid.isNotEmpty) {
656+ await Process .run ('kill' , ['-9' , pid.trim ()]);
657+ }
602658 }
603659 }
604660 }
@@ -618,30 +674,39 @@ class MinerProcess {
618674 /// Cleanup any existing quantus-miner processes
619675 Future <void > _cleanupExistingMinerProcesses () async {
620676 try {
621- // Find all quantus-miner processes
622- final result = await Process .run ('pgrep' , ['-f' , 'quantus-miner' ]);
623- if (result.exitCode == 0 ) {
624- final pids = result.stdout.toString ().trim ().split ('\n ' );
625- for (final pid in pids) {
626- if (pid.isNotEmpty) {
627- try {
628- // Try graceful termination first
629- await Process .run ('kill' , ['-15' , pid.trim ()]);
630- await Future .delayed (const Duration (seconds: 1 ));
631-
632- // Check if still running, force kill if needed
633- final checkResult = await Process .run ('kill' , ['-0' , pid.trim ()]);
634- if (checkResult.exitCode == 0 ) {
635- await Process .run ('kill' , ['-9' , pid.trim ()]);
677+ if (Platform .isWindows) {
678+ try {
679+ await Process .run ('taskkill' , ['/F' , '/IM' , 'quantus-miner.exe' ]);
680+ await Future .delayed (const Duration (seconds: 2 ));
681+ } catch (_) {
682+ // Process might not exist
683+ }
684+ } else {
685+ // Find all quantus-miner processes
686+ final result = await Process .run ('pgrep' , ['-f' , 'quantus-miner' ]);
687+ if (result.exitCode == 0 ) {
688+ final pids = result.stdout.toString ().trim ().split ('\n ' );
689+ for (final pid in pids) {
690+ if (pid.isNotEmpty) {
691+ try {
692+ // Try graceful termination first
693+ await Process .run ('kill' , ['-15' , pid.trim ()]);
694+ await Future .delayed (const Duration (seconds: 1 ));
695+
696+ // Check if still running, force kill if needed
697+ final checkResult = await Process .run ('kill' , ['-0' , pid.trim ()]);
698+ if (checkResult.exitCode == 0 ) {
699+ await Process .run ('kill' , ['-9' , pid.trim ()]);
700+ }
701+ } catch (e) {
702+ // Ignore cleanup errors
636703 }
637- } catch (e) {
638- // Ignore cleanup errors
639704 }
640705 }
641- }
642706
643- // Wait a moment for processes to fully terminate
644- await Future .delayed (const Duration (seconds: 2 ));
707+ // Wait a moment for processes to fully terminate
708+ await Future .delayed (const Duration (seconds: 2 ));
709+ }
645710 }
646711 } catch (e) {
647712 // Ignore cleanup errors
@@ -651,30 +716,39 @@ class MinerProcess {
651716 /// Cleanup any existing quantus-node processes
652717 Future <void > _cleanupExistingNodeProcesses () async {
653718 try {
654- // Find all quantus-node processes
655- final result = await Process .run ('pgrep' , ['-f' , 'quantus-node' ]);
656- if (result.exitCode == 0 ) {
657- final pids = result.stdout.toString ().trim ().split ('\n ' );
658- for (final pid in pids) {
659- if (pid.isNotEmpty) {
660- try {
661- // Try graceful termination first
662- await Process .run ('kill' , ['-15' , pid.trim ()]);
663- await Future .delayed (const Duration (seconds: 2 ));
664-
665- // Check if still running, force kill if needed
666- final checkResult = await Process .run ('kill' , ['-0' , pid.trim ()]);
667- if (checkResult.exitCode == 0 ) {
668- await Process .run ('kill' , ['-9' , pid.trim ()]);
719+ if (Platform .isWindows) {
720+ try {
721+ await Process .run ('taskkill' , ['/F' , '/IM' , 'quantus-node.exe' ]);
722+ await Future .delayed (const Duration (seconds: 2 ));
723+ } catch (_) {
724+ // Process might not exist
725+ }
726+ } else {
727+ // Find all quantus-node processes
728+ final result = await Process .run ('pgrep' , ['-f' , 'quantus-node' ]);
729+ if (result.exitCode == 0 ) {
730+ final pids = result.stdout.toString ().trim ().split ('\n ' );
731+ for (final pid in pids) {
732+ if (pid.isNotEmpty) {
733+ try {
734+ // Try graceful termination first
735+ await Process .run ('kill' , ['-15' , pid.trim ()]);
736+ await Future .delayed (const Duration (seconds: 2 ));
737+
738+ // Check if still running, force kill if needed
739+ final checkResult = await Process .run ('kill' , ['-0' , pid.trim ()]);
740+ if (checkResult.exitCode == 0 ) {
741+ await Process .run ('kill' , ['-9' , pid.trim ()]);
742+ }
743+ } catch (e) {
744+ // Ignore cleanup errors
669745 }
670- } catch (e) {
671- // Ignore cleanup errors
672746 }
673747 }
674- }
675748
676- // Wait a moment for processes to fully terminate
677- await Future .delayed (const Duration (seconds: 3 ));
749+ // Wait a moment for processes to fully terminate
750+ await Future .delayed (const Duration (seconds: 3 ));
751+ }
678752 }
679753 } catch (e) {
680754 // Ignore cleanup errors
0 commit comments