feat: Windows compatibility (#836)

* feat: win compatibility

* fix

* fix: uptime parse

* opt.: linux uptime accuracy

* fix: windows temperature fetching

* opt.

* opt.: powershell exec

* refactor: address PR review feedback and improve code quality

### Major Improvements:
- **Refactored Windows status parsing**: Broke down large `_getWindowsStatus` method into 13 smaller, focused helper methods for better maintainability and readability
- **Extracted system detection logic**: Created dedicated `SystemDetector` helper class to separate OS detection concerns from ServerProvider
- **Improved concurrency handling**: Implemented proper synchronization for server updates using Future-based locks to prevent race conditions

### Bug Fixes:
- **Fixed CPU percentage parsing**: Removed incorrect '*100' multiplication in BSD CPU parsing (values were already percentages)
- **Enhanced memory parsing**: Added validation and error handling to BSD memory fallback parsing with proper logging
- **Improved uptime parsing**: Added support for multiple Windows date formats and robust error handling with validation
- **Fixed division by zero**: Added safety checks in Swap.usedPercent getter

### Code Quality Enhancements:
- **Added comprehensive documentation**: Documented Windows CPU counter limitations and approach
- **Strengthened error handling**: Added detailed logging and validation throughout parsing methods
- **Improved robustness**: Enhanced BSD CPU parsing with percentage validation and warnings
- **Better separation of concerns**: Each parsing method now has single responsibility

### Files Changed:
- `lib/data/helper/system_detector.dart` (new): System detection helper
- `lib/data/model/server/cpu.dart`: Fixed percentage parsing and added validation
- `lib/data/model/server/memory.dart`: Enhanced fallback parsing and division-by-zero protection
- `lib/data/model/server/server_status_update_req.dart`: Refactored into 13 focused parsing methods
- `lib/data/provider/server.dart`: Improved synchronization and extracted system detection

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

Co-Authored-By: Claude <noreply@anthropic.com>

* refactor: parse & shell fn struct

---------

Co-authored-by: Claude <noreply@anthropic.com>
This commit is contained in:
lollipopkit🏳️‍⚧️
2025-08-08 16:56:36 +08:00
committed by GitHub
parent 46a12bc844
commit 3a615449e3
103 changed files with 9591 additions and 1906 deletions

View File

@@ -12,21 +12,9 @@ extension SftpFileX on SftpFileMode {
UnixPerm toUnixPerm() {
return UnixPerm(
user: UnixPermOp(
r: userRead,
w: userWrite,
x: userExecute,
),
group: UnixPermOp(
r: groupRead,
w: groupWrite,
x: groupExecute,
),
other: UnixPermOp(
r: otherRead,
w: otherWrite,
x: otherExecute,
),
user: UnixPermOp(r: userRead, w: userWrite, x: userExecute),
group: UnixPermOp(r: groupRead, w: groupWrite, x: groupExecute),
other: UnixPermOp(r: otherRead, w: otherWrite, x: otherExecute),
);
}
}

View File

@@ -4,6 +4,7 @@ import 'dart:typed_data';
import 'package:dartssh2/dartssh2.dart';
import 'package:fl_lib/fl_lib.dart';
import 'package:flutter/widgets.dart';
import 'package:server_box/data/model/server/system.dart';
import 'package:server_box/data/res/misc.dart';
@@ -13,6 +14,52 @@ typedef OnStdin = void Function(SSHSession session);
typedef PwdRequestFunc = Future<String?> Function(String? user);
extension SSHClientX on SSHClient {
/// Create a persistent PowerShell session for Windows commands
Future<(SSHSession, String)> execPowerShell(
OnStdin onStdin, {
SSHPtyConfig? pty,
OnStdout? onStdout,
OnStdout? onStderr,
bool stdout = true,
bool stderr = true,
Map<String, String>? env,
}) async {
final session = await execute(
'powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass',
pty: pty,
environment: env,
);
final result = BytesBuilder(copy: false);
final stdoutDone = Completer<void>();
final stderrDone = Completer<void>();
session.stdout.listen(
(e) {
onStdout?.call(e.string, session);
if (stdout) result.add(e);
},
onDone: stdoutDone.complete,
onError: stderrDone.completeError,
);
session.stderr.listen(
(e) {
onStderr?.call(e.string, session);
if (stderr) result.add(e);
},
onDone: stderrDone.complete,
onError: stderrDone.completeError,
);
onStdin(session);
await stdoutDone.future;
await stderrDone.future;
return (session, result.takeBytes().string);
}
Future<(SSHSession, String)> exec(
OnStdin onStdin, {
String? entry,
@@ -22,9 +69,14 @@ extension SSHClientX on SSHClient {
bool stdout = true,
bool stderr = true,
Map<String, String>? env,
SystemType? systemType,
}) async {
final session = await execute(
entry ?? 'cat | sh',
entry ??
switch (systemType) {
SystemType.windows => 'powershell -NoLogo -NoProfile -NonInteractive -ExecutionPolicy Bypass',
_ => 'cat | sh',
},
pty: pty,
environment: env,
);
@@ -81,9 +133,7 @@ extension SSHClientX on SSHClient {
isRequestingPwd = true;
final user = Miscs.pwdRequestWithUserReg.firstMatch(data)?.group(1);
if (context == null) return;
final pwd = context.mounted
? await context.showPwdDialog(title: user, id: id)
: null;
final pwd = context.mounted ? await context.showPwdDialog(title: user, id: id) : null;
if (pwd == null || pwd.isEmpty) {
session.stdin.close();
} else {