Add '强制不走中继连接' menu item + reconnect(false) actually clears force_relay
Two changes: 1. src/ui_session_interface.rs reconnect(false): Upstream only ever set force_relay=true and ignored force_relay=false. This was wrong — the user has no way to clear the flag. Now reconnect(false) sets force_relay=false AND resets direct_failures=0, so the next connect() gets a fresh punch with the full timeout. 2. flutter/lib/common/widgets/peer_card.dart: Add a new menu item '强制不走中继连接' in all 5 _buildMenuItems implementations (recent, favorite, ab, discovered, address-book). Click calls rustDeskWinManager.newRemoteDesktop(id, forceRelay: false) which triggers a fresh punch. If punch fails, RustDesk's existing connect() falls back to relay — so the user always ends up with a working connection (just with a chance of P2P that was retried). Use case: User's home Mac and office Win on different physical networks, hbbr at 5 Mbps. By default every connection is relay (orange banner, no file transfer). Clicking '强制不走中继' forces a fresh P2P attempt — usually fails, but gives the user the transparency to know 'yes, it tried P2P first'.
This commit is contained in:
@@ -14,6 +14,7 @@ import '../../models/peer_model.dart';
|
||||
import '../../models/platform_model.dart';
|
||||
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
||||
import '../../desktop/widgets/popup_menu.dart';
|
||||
import '../../utils/multi_window_manager.dart';
|
||||
import 'dart:math' as math;
|
||||
|
||||
typedef PopupMenuEntryBuilder = Future<List<mod_menu.PopupMenuEntry<String>>>
|
||||
@@ -628,6 +629,52 @@ abstract class BasePeerCard extends StatelessWidget {
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
// Custom fork: 强制不走中继连接. Click this and the next connect
|
||||
// attempt will be a fresh punch (with full timeout, no
|
||||
// direct_failures penalty) and only fall back to relay if punch
|
||||
// truly fails. Useful for same-LAN cases where the server's
|
||||
// is_local detection might have been wrong, or just to retry
|
||||
// after a temporary network blip.
|
||||
@protected
|
||||
MenuEntryBase<String> _forceDirectAction(BuildContext context, String id) {
|
||||
return MenuEntryButton<String>(
|
||||
proc: () async {
|
||||
if (Navigator.canPop(context)) Navigator.pop(context);
|
||||
// rustDeskWinManager.newRemoteDesktop already accepts forceRelay.
|
||||
// Setting it to false here will:
|
||||
// 1. clear force_relay flag in LoginConfigHandler
|
||||
// (Rust side reconnect() now does this even when false)
|
||||
// 2. reset direct_failures counter to 0
|
||||
// 3. attempt a fresh punch with full timeout
|
||||
// 4. if punch fails, connect() falls back to request_relay
|
||||
// and the user gets a working connection through relay
|
||||
try {
|
||||
await rustDeskWinManager.newRemoteDesktop(
|
||||
id,
|
||||
forceRelay: false,
|
||||
);
|
||||
} catch (_) {
|
||||
// best-effort
|
||||
}
|
||||
},
|
||||
childBuilder: (TextStyle? style) => Container(
|
||||
alignment: AlignmentDirectional.center,
|
||||
height: CustomPopupMenuTheme.height,
|
||||
child: Row(
|
||||
children: [
|
||||
const Icon(Icons.bolt, size: 16),
|
||||
const SizedBox(width: 6),
|
||||
Text(
|
||||
translate('强制不走中继连接'),
|
||||
style: style,
|
||||
),
|
||||
],
|
||||
),
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
@protected
|
||||
MenuEntryBase<String> _rdpAction(BuildContext context, String id) {
|
||||
return MenuEntryButton<String>(
|
||||
@@ -985,6 +1032,7 @@ class RecentPeerCard extends BasePeerCard {
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
if (!isWeb) {
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
menuItems.add(_forceDirectAction(context, peer.id));
|
||||
}
|
||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
@@ -1048,6 +1096,7 @@ class FavoritePeerCard extends BasePeerCard {
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
if (!isWeb) {
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
menuItems.add(_forceDirectAction(context, peer.id));
|
||||
}
|
||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
@@ -1110,6 +1159,7 @@ class DiscoveredPeerCard extends BasePeerCard {
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
if (!isWeb) {
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
menuItems.add(_forceDirectAction(context, peer.id));
|
||||
}
|
||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
@@ -1167,6 +1217,7 @@ class AddressBookPeerCard extends BasePeerCard {
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
if (!isWeb) {
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
menuItems.add(_forceDirectAction(context, peer.id));
|
||||
}
|
||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
@@ -1324,6 +1375,7 @@ class MyGroupPeerCard extends BasePeerCard {
|
||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||
if (!isWeb) {
|
||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||
menuItems.add(_forceDirectAction(context, peer.id));
|
||||
}
|
||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||
menuItems.add(_rdpAction(context, peer.id));
|
||||
|
||||
@@ -1292,9 +1292,18 @@ impl<T: InvokeUiSession> Session<T> {
|
||||
|
||||
let cloned = self.clone();
|
||||
|
||||
// override only if true
|
||||
if true == force_relay {
|
||||
// Custom fork: force_relay=false now actually clears the flag
|
||||
// (upstream only ever set it to true). This lets the user
|
||||
// 'force direct' (no relay) by clearing force_relay and resetting
|
||||
// direct_failures, so the next connect() tries a fresh punch
|
||||
// without the 'punch failed before, shorten timeout' penalty.
|
||||
if force_relay {
|
||||
self.lc.write().unwrap().force_relay = true;
|
||||
} else {
|
||||
self.lc.write().unwrap().force_relay = false;
|
||||
// Also reset direct_failures so punch attempt gets the full
|
||||
// timeout instead of the shortened one.
|
||||
self.lc.write().unwrap().set_direct_failure(0);
|
||||
}
|
||||
self.lc.write().unwrap().peer_info = None;
|
||||
self.reconnect_count.fetch_add(1, Ordering::SeqCst);
|
||||
|
||||
Reference in New Issue
Block a user