fix: debug, terminal web (#12375)

Signed-off-by: fufesou <linlong1266@gmail.com>
This commit is contained in:
fufesou
2025-07-22 19:26:50 +08:00
committed by GitHub
parent 9bca5ac000
commit 61194182eb
8 changed files with 73 additions and 15 deletions

View File

@@ -551,7 +551,7 @@ abstract class BasePeerCard extends StatelessWidget {
MenuEntryBase<String> _terminalAction(BuildContext context) {
return _connectCommonAction(
context,
translate('Terminal'),
'${translate('Terminal')} (beta)',
isTerminal: true,
);
}
@@ -560,7 +560,7 @@ abstract class BasePeerCard extends StatelessWidget {
MenuEntryBase<String> _terminalRunAsAdminAction(BuildContext context) {
return _connectCommonAction(
context,
translate('Terminal (Run as administrator)'),
'${translate('Terminal (Run as administrator)')} (beta)',
isTerminalRunAsAdmin: true,
);
}

View File

@@ -183,7 +183,7 @@ List<TTextMenu> toolbarControls(BuildContext context, String id, FFI ffi) {
);
v.add(
TTextMenu(
child: Text(translate('Terminal')),
child: Text('${translate('Terminal')} (beta)'),
onPressed: () => connectWithToken(isTerminal: true)),
);
v.add(

View File

@@ -563,7 +563,7 @@ class _ConnectionPageState extends State<ConnectionPage>
() => onConnect(isViewCamera: true)
),
(
'Terminal',
'${translate('Terminal')} (beta)',
() => onConnect(isTerminal: true)
),
]

View File

@@ -378,7 +378,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
},
),
SettingsTile.switchTile(
title: Text('${translate('Adaptive bitrate')} (beta)'),
title: Text(translate('Adaptive bitrate')),
initialValue: _enableAbr,
onToggle: isOptionFixed(kOptionEnableAbr)
? null
@@ -540,7 +540,7 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
enhancementsTiles.add(SettingsTile.switchTile(
initialValue: _enableStartOnBoot,
title: Column(crossAxisAlignment: CrossAxisAlignment.start, children: [
Text("${translate('Start on boot')} (beta)"),
Text(translate('Start on boot')),
Text(
'* ${translate('Start the screen sharing service on boot, requires special permissions')}',
style: Theme.of(context).textTheme.bodySmall),

View File

@@ -3214,7 +3214,7 @@ class FFI {
}
void routeTerminalResponse(Map<String, dynamic> evt) {
final int terminalId = evt['terminal_id'] ?? 0;
final int terminalId = TerminalModel.getTerminalIdFromEvt(evt);
// Route to specific terminal model if it exists
final model = _terminalModels[terminalId];

View File

@@ -165,9 +165,58 @@ class TerminalModel with ChangeNotifier {
}
}
static int getTerminalIdFromEvt(Map<String, dynamic> evt) {
if (evt.containsKey('terminal_id')) {
final v = evt['terminal_id'];
if (v is int) {
// Desktop and mobile send terminal_id as an int
return v;
} else if (v is String) {
// Web sends terminal_id as a string
final parsed = int.tryParse(v);
if (parsed != null) {
return parsed;
} else {
debugPrint(
'[TerminalModel] Failed to parse terminal_id as integer: $v. Expected a numeric string.');
return 0;
}
} else {
// Unexpected type, log and handle gracefully
debugPrint(
'[TerminalModel] Unexpected terminal_id type: ${v.runtimeType}, value: $v. Expected int or String.');
return 0;
}
} else {
debugPrint('[TerminalModel] Event does not contain terminal_id');
return 0;
}
}
static bool getSuccessFromEvt(Map<String, dynamic> evt) {
if (evt.containsKey('success')) {
final v = evt['success'];
if (v is bool) {
// Desktop and mobile
return v;
} else if (v is String) {
// Web
return v.toLowerCase() == 'true';
} else {
// Unexpected type, log and handle gracefully
debugPrint(
'[TerminalModel] Unexpected success type: ${v.runtimeType}, value: $v. Expected bool or String.');
return false;
}
} else {
debugPrint('[TerminalModel] Event does not contain success');
return false;
}
}
void handleTerminalResponse(Map<String, dynamic> evt) {
final String? type = evt['type'];
final int evtTerminalId = evt['terminal_id'] ?? 0;
final int evtTerminalId = getTerminalIdFromEvt(evt);
// Only handle events for this terminal
if (evtTerminalId != terminalId) {
@@ -193,7 +242,7 @@ class TerminalModel with ChangeNotifier {
}
void _handleTerminalOpened(Map<String, dynamic> evt) {
final bool success = evt['success'] ?? false;
final bool success = getSuccessFromEvt(evt);
final String message = evt['message'] ?? '';
final String? serviceId = evt['service_id'];

View File

@@ -908,8 +908,18 @@ class RustdeskImpl {
return js.context.callMethod('getByName', ['option:local', key]);
}
// Do not return the real environment variables.
// Use the global variable as the environment variable in web.
String mainGetEnv({required String key, dynamic hint}) {
throw UnimplementedError("mainGetEnv");
return js.context.callMethod('getByName', ['envvar', key]);
}
// Use the global variable as the environment variable in web.
void mainSetEnv({required String key, String? value, dynamic hint}) {
js.context.callMethod('setByName', [
'envvar',
jsonEncode({'name': key, 'value': value})
]);
}
Future<void> mainSetLocalOption(
@@ -1960,9 +1970,7 @@ class RustdeskImpl {
}
Future<void> sessionCloseTerminal(
{required UuidValue sessionId,
required int terminalId,
dynamic hint}) {
{required UuidValue sessionId, required int terminalId, dynamic hint}) {
return Future(() => js.context.callMethod('setByName', [
'close_terminal',
jsonEncode({

View File

@@ -131,7 +131,7 @@ fn get_or_create_service(
// Ensure cleanup task is running
ensure_cleanup_task();
service.lock().unwrap().reset_status();
service.lock().unwrap().reset_status(is_persistent);
Ok(service)
}
@@ -600,7 +600,8 @@ impl PersistentTerminalService {
!self.sessions.is_empty()
}
fn reset_status(&mut self) {
fn reset_status(&mut self, is_persistent: bool) {
self.is_persistent = is_persistent;
self.needs_session_sync = true;
for session in self.sessions.values() {
let mut session = session.lock().unwrap();