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 '../../models/platform_model.dart';
|
||||||
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
import '../../desktop/widgets/material_mod_popup_menu.dart' as mod_menu;
|
||||||
import '../../desktop/widgets/popup_menu.dart';
|
import '../../desktop/widgets/popup_menu.dart';
|
||||||
|
import '../../utils/multi_window_manager.dart';
|
||||||
import 'dart:math' as math;
|
import 'dart:math' as math;
|
||||||
|
|
||||||
typedef PopupMenuEntryBuilder = Future<List<mod_menu.PopupMenuEntry<String>>>
|
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
|
@protected
|
||||||
MenuEntryBase<String> _rdpAction(BuildContext context, String id) {
|
MenuEntryBase<String> _rdpAction(BuildContext context, String id) {
|
||||||
return MenuEntryButton<String>(
|
return MenuEntryButton<String>(
|
||||||
@@ -985,6 +1032,7 @@ class RecentPeerCard extends BasePeerCard {
|
|||||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||||
if (!isWeb) {
|
if (!isWeb) {
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
|
menuItems.add(_forceDirectAction(context, peer.id));
|
||||||
}
|
}
|
||||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||||
menuItems.add(_rdpAction(context, peer.id));
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
@@ -1048,6 +1096,7 @@ class FavoritePeerCard extends BasePeerCard {
|
|||||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||||
if (!isWeb) {
|
if (!isWeb) {
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
|
menuItems.add(_forceDirectAction(context, peer.id));
|
||||||
}
|
}
|
||||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||||
menuItems.add(_rdpAction(context, peer.id));
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
@@ -1110,6 +1159,7 @@ class DiscoveredPeerCard extends BasePeerCard {
|
|||||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||||
if (!isWeb) {
|
if (!isWeb) {
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
|
menuItems.add(_forceDirectAction(context, peer.id));
|
||||||
}
|
}
|
||||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||||
menuItems.add(_rdpAction(context, peer.id));
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
@@ -1167,6 +1217,7 @@ class AddressBookPeerCard extends BasePeerCard {
|
|||||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||||
if (!isWeb) {
|
if (!isWeb) {
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
|
menuItems.add(_forceDirectAction(context, peer.id));
|
||||||
}
|
}
|
||||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||||
menuItems.add(_rdpAction(context, peer.id));
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
@@ -1324,6 +1375,7 @@ class MyGroupPeerCard extends BasePeerCard {
|
|||||||
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
// menuItems.add(await _openNewConnInOptAction(peer.id));
|
||||||
if (!isWeb) {
|
if (!isWeb) {
|
||||||
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
menuItems.add(await _forceAlwaysRelayAction(peer.id));
|
||||||
|
menuItems.add(_forceDirectAction(context, peer.id));
|
||||||
}
|
}
|
||||||
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
if (isWindows && peer.platform == kPeerPlatformWindows) {
|
||||||
menuItems.add(_rdpAction(context, peer.id));
|
menuItems.add(_rdpAction(context, peer.id));
|
||||||
|
|||||||
@@ -1292,9 +1292,18 @@ impl<T: InvokeUiSession> Session<T> {
|
|||||||
|
|
||||||
let cloned = self.clone();
|
let cloned = self.clone();
|
||||||
|
|
||||||
// override only if true
|
// Custom fork: force_relay=false now actually clears the flag
|
||||||
if true == force_relay {
|
// (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;
|
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.lc.write().unwrap().peer_info = None;
|
||||||
self.reconnect_count.fetch_add(1, Ordering::SeqCst);
|
self.reconnect_count.fetch_add(1, Ordering::SeqCst);
|
||||||
|
|||||||
Reference in New Issue
Block a user