auto disconnect

Signed-off-by: 21pages <pages21@163.com>
This commit is contained in:
21pages 2023-09-13 13:45:40 +08:00
parent 75f5212661
commit 0a0653358c
40 changed files with 308 additions and 2 deletions

View File

@ -302,6 +302,53 @@ Future<String> changeDirectAccessPort(
return controller.text;
}
Future<String> changeAutoDisconnectTimeout(String old) async {
final controller = TextEditingController(text: old);
await gFFI.dialogManager.show((setState, close, context) {
return CustomAlertDialog(
title: Text(translate("Timeout in minutes")),
content: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
const SizedBox(height: 8.0),
Row(
children: [
Expanded(
child: TextField(
maxLines: null,
keyboardType: TextInputType.number,
decoration: InputDecoration(
hintText: '10',
isCollapsed: true,
suffix: IconButton(
padding: EdgeInsets.zero,
icon: const Icon(Icons.clear, size: 16),
onPressed: () => controller.clear())),
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')),
],
controller: controller,
autofocus: true),
),
],
),
],
),
actions: [
dialogButton("Cancel", onPressed: close, isOutline: true),
dialogButton("OK", onPressed: () async {
await bind.mainSetOption(
key: 'auto-disconnect-timeout', value: controller.text);
close();
}),
],
onCancel: close,
);
});
return controller.text;
}
class DialogTextField extends StatelessWidget {
final String title;
final String? hintText;

View File

@ -728,6 +728,7 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
reverse: true, enabled: enabled),
...directIp(context),
whitelist(),
...autoDisconnect(context),
]);
}
@ -906,6 +907,63 @@ class _SafetyState extends State<_Safety> with AutomaticKeepAliveClientMixin {
));
}));
}
List<Widget> autoDisconnect(BuildContext context) {
TextEditingController controller = TextEditingController();
update() => setState(() {});
RxBool applyEnabled = false.obs;
final optionKey = 'allow-auto-disconnect';
final timeoutKey = 'auto-disconnect-timeout';
return [
_OptionCheckBox(context, 'auto_disconnect_option_tip', optionKey,
update: update, enabled: !locked),
() {
bool enabled =
option2bool(optionKey, bind.mainGetOptionSync(key: optionKey));
if (!enabled) applyEnabled.value = false;
controller.text = bind.mainGetOptionSync(key: timeoutKey);
return Offstage(
offstage: !enabled,
child: _SubLabeledWidget(
context,
'Timeout in minutes',
Row(children: [
SizedBox(
width: 95,
child: TextField(
controller: controller,
enabled: enabled && !locked,
onChanged: (_) => applyEnabled.value = true,
inputFormatters: [
FilteringTextInputFormatter.allow(RegExp(
r'^([0-9]|[1-9]\d|[1-9]\d{2}|[1-9]\d{3}|[1-5]\d{4}|6[0-4]\d{3}|65[0-4]\d{2}|655[0-2]\d|6553[0-5])$')),
],
decoration: const InputDecoration(
hintText: '10',
contentPadding:
EdgeInsets.symmetric(vertical: 12, horizontal: 12),
),
).marginOnly(right: 15),
),
Obx(() => ElevatedButton(
onPressed: applyEnabled.value && enabled && !locked
? () async {
applyEnabled.value = false;
await bind.mainSetOption(
key: timeoutKey, value: controller.text);
}
: null,
child: Text(
translate('Apply'),
),
))
]),
enabled: enabled && !locked,
),
);
}(),
];
}
}
class _Network extends StatefulWidget {

View File

@ -45,10 +45,12 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
var _enableDirectIPAccess = false;
var _enableRecordSession = false;
var _autoRecordIncomingSession = false;
var _allowAutoDisconnect = false;
var _localIP = "";
var _directAccessPort = "";
var _fingerprint = "";
var _buildDate = "";
var _autoDisconnectTimeout = "";
@override
void initState() {
@ -151,6 +153,20 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
_buildDate = buildDate;
}
final allowAutoDisconnect = option2bool('allow-auto-disconnect',
await bind.mainGetOption(key: 'allow-auto-disconnect'));
if (allowAutoDisconnect != _allowAutoDisconnect) {
update = true;
_allowAutoDisconnect = allowAutoDisconnect;
}
final autoDisconnectTimeout =
await bind.mainGetOption(key: 'auto-disconnect-timeout');
if (autoDisconnectTimeout != _autoDisconnectTimeout) {
update = true;
_autoDisconnectTimeout = autoDisconnectTimeout;
}
if (update) {
setState(() {});
}
@ -306,6 +322,48 @@ class _SettingsState extends State<SettingsPage> with WidgetsBindingObserver {
await bind.mainSetOption(key: 'direct-server', value: value);
setState(() {});
},
),
SettingsTile.switchTile(
title: Row(
mainAxisAlignment: MainAxisAlignment.spaceBetween,
crossAxisAlignment: CrossAxisAlignment.center,
children: [
Expanded(
child: Column(
crossAxisAlignment: CrossAxisAlignment.start,
children: [
Text(translate("auto_disconnect_option_tip")),
Offstage(
offstage: !_allowAutoDisconnect,
child: Text(
'${_autoDisconnectTimeout.isEmpty ? '10' : _autoDisconnectTimeout} min',
style: Theme.of(context).textTheme.bodySmall,
)),
])),
Offstage(
offstage: !_allowAutoDisconnect,
child: IconButton(
padding: EdgeInsets.zero,
icon: Icon(
Icons.edit,
size: 20,
),
onPressed: () async {
final timeout = await changeAutoDisconnectTimeout(
_autoDisconnectTimeout);
setState(() {
_autoDisconnectTimeout = timeout;
});
}))
]),
initialValue: _allowAutoDisconnect,
onToggle: (_) async {
_allowAutoDisconnect = !_allowAutoDisconnect;
String value =
bool2option('allow-auto-disconnect', _allowAutoDisconnect);
await bind.mainSetOption(key: 'allow-auto-disconnect', value: value);
setState(() {});
},
)
];
if (_hasIgnoreBattery) {

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", "超时(分钟)"),
("auto_disconnect_option_tip", "自动关闭不活跃的会话"),
("Connection failed due to inactivity", "由于长时间无操作, 连接被自动断开"),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -88,5 +88,7 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", "Don't show again"),
("I Agree", "I Agree"),
("Decline", "Decline"),
("auto_disconnect_option_tip", "Automatically close incoming sessions on user inactivity"),
("Connection failed due to inactivity", "Automatically disconnected due to inactivity"),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -549,7 +549,10 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("scam_text1", ""),
("scam_text2", ""),
("Don't show again", ""),
("I Agree",""),
("Decline",""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -551,5 +551,8 @@ pub static ref T: std::collections::HashMap<&'static str, &'static str> =
("Don't show again", ""),
("I Agree", ""),
("Decline", ""),
("Timeout in minutes", ""),
("auto_disconnect_option_tip", ""),
("Connection failed due to inactivity", ""),
].iter().cloned().collect();
}

View File

@ -204,6 +204,7 @@ pub struct Connection {
delay_response_instant: Instant,
#[cfg(not(any(target_os = "android", target_os = "ios")))]
start_cm_ipc_para: Option<StartCmIpcPara>,
auto_disconnect_timer: Option<(Instant, u64)>,
}
impl ConnInner {
@ -343,6 +344,7 @@ impl Connection {
rx_desktop_ready,
tx_cm_stream_ready,
}),
auto_disconnect_timer: None,
};
let addr = hbb_common::try_into_v4(addr);
if !conn.on_open(addr).await {
@ -605,6 +607,13 @@ impl Connection {
_ = second_timer.tick() => {
#[cfg(windows)]
conn.portable_check();
if let Some((instant, minute)) = conn.auto_disconnect_timer.as_ref() {
if instant.elapsed().as_secs() > minute * 60 {
conn.send_close_reason_no_retry("Connection failed due to inactivity").await;
conn.on_close("auto disconnect", true).await;
break;
}
}
}
_ = test_delay_timer.tick() => {
if last_recv_time.elapsed() >= SEC30 {
@ -1139,6 +1148,7 @@ impl Connection {
let mut s = s.write().unwrap();
#[cfg(not(any(target_os = "android", target_os = "ios")))]
let _h = try_start_record_cursor_pos();
self.auto_disconnect_timer = Self::get_auto_disconenct_timer();
s.add_connection(self.inner.clone(), &noperms);
}
}
@ -1612,6 +1622,7 @@ impl Connection {
}
self.input_mouse(me, self.inner.id());
}
self.update_auto_disconnect_timer();
}
Some(message::Union::PointerDeviceEvent(pde)) => {
#[cfg(any(target_os = "android", target_os = "ios"))]
@ -1647,6 +1658,7 @@ impl Connection {
MOUSE_MOVE_TIME.store(get_time(), Ordering::SeqCst);
self.input_pointer(pde, self.inner.id());
}
self.update_auto_disconnect_timer();
}
#[cfg(any(target_os = "android", target_os = "ios"))]
Some(message::Union::KeyEvent(..)) => {}
@ -1702,6 +1714,7 @@ impl Connection {
self.input_key(me, false);
}
}
self.update_auto_disconnect_timer();
}
Some(message::Union::Clipboard(_cb)) =>
{
@ -1890,6 +1903,7 @@ impl Connection {
Some(misc::Union::ChatMessage(c)) => {
self.send_to_cm(ipc::Data::ChatMessage { text: c.text });
self.chat_unanswered = true;
self.update_auto_disconnect_timer();
}
Some(misc::Union::Option(o)) => {
self.update_options(&o).await;
@ -1898,6 +1912,7 @@ impl Connection {
if r {
super::video_service::refresh();
}
self.update_auto_disconnect_timer();
}
Some(misc::Union::VideoReceived(_)) => {
video_service::notify_video_frame_fetched(
@ -2027,6 +2042,7 @@ impl Connection {
let mut msg = Message::new();
msg.set_misc(misc);
self.send(msg).await;
self.update_auto_disconnect_timer();
}
#[cfg(not(any(target_os = "android", target_os = "ios")))]
@ -2384,6 +2400,26 @@ impl Connection {
}
self.pressed_modifiers.clear();
}
fn get_auto_disconenct_timer() -> Option<(Instant, u64)> {
if Config::get_option("allow-auto-disconnect") == "Y" {
let mut minute: u64 = Config::get_option("auto-disconnect-timeout")
.parse()
.unwrap_or(10);
if minute == 0 {
minute = 10;
}
Some((Instant::now(), minute))
} else {
None
}
}
fn update_auto_disconnect_timer(&mut self) {
self.auto_disconnect_timer
.as_mut()
.map(|t| t.0 = Instant::now());
}
}
pub fn insert_switch_sides_uuid(id: String, uuid: uuid::Uuid) {