mirror of
https://github.com/rustdesk/rustdesk.git
synced 2024-12-24 11:30:06 +08:00
refact, separate remote window, tmp commit
Signed-off-by: dignow <linlong1265@gmail.com>
This commit is contained in:
parent
902f56c499
commit
1970795093
@ -1216,7 +1216,7 @@ FFI get gFFI => _globalFFI;
|
|||||||
|
|
||||||
Future<void> initGlobalFFI() async {
|
Future<void> initGlobalFFI() async {
|
||||||
debugPrint("_globalFFI init");
|
debugPrint("_globalFFI init");
|
||||||
_globalFFI = FFI();
|
_globalFFI = FFI(null);
|
||||||
debugPrint("_globalFFI init end");
|
debugPrint("_globalFFI init end");
|
||||||
// after `put`, can also be globally found by Get.find<FFI>();
|
// after `put`, can also be globally found by Get.find<FFI>();
|
||||||
Get.put(_globalFFI, permanent: true);
|
Get.put(_globalFFI, permanent: true);
|
||||||
|
@ -37,6 +37,9 @@ const String kWindowEventNewFileTransfer = "new_file_transfer";
|
|||||||
const String kWindowEventNewPortForward = "new_port_forward";
|
const String kWindowEventNewPortForward = "new_port_forward";
|
||||||
const String kWindowEventActiveSession = "active_session";
|
const String kWindowEventActiveSession = "active_session";
|
||||||
const String kWindowEventGetRemoteList = "get_remote_list";
|
const String kWindowEventGetRemoteList = "get_remote_list";
|
||||||
|
const String kWindowEventGetSessionIdList = "get_session_id_list";
|
||||||
|
|
||||||
|
const String kWindowEventCloseForSeparateWindow = "close_for_separate_window";
|
||||||
|
|
||||||
const String kOptionSeparateRemoteWindow = "enable-separate-remote-window";
|
const String kOptionSeparateRemoteWindow = "enable-separate-remote-window";
|
||||||
|
|
||||||
|
@ -6,6 +6,7 @@ import 'package:flutter/material.dart';
|
|||||||
import 'package:flutter/services.dart';
|
import 'package:flutter/services.dart';
|
||||||
import 'package:flutter_hbb/common.dart';
|
import 'package:flutter_hbb/common.dart';
|
||||||
import 'package:flutter_hbb/consts.dart';
|
import 'package:flutter_hbb/consts.dart';
|
||||||
|
import 'package:flutter_hbb/utils/multi_window_manager.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_home_page.dart';
|
||||||
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
import 'package:flutter_hbb/desktop/pages/desktop_tab_page.dart';
|
||||||
import 'package:flutter_hbb/models/platform_model.dart';
|
import 'package:flutter_hbb/models/platform_model.dart';
|
||||||
@ -248,7 +249,7 @@ class _General extends StatefulWidget {
|
|||||||
|
|
||||||
class _GeneralState extends State<_General> {
|
class _GeneralState extends State<_General> {
|
||||||
final RxBool serviceStop = Get.find<RxBool>(tag: 'stop-service');
|
final RxBool serviceStop = Get.find<RxBool>(tag: 'stop-service');
|
||||||
RxBool serviceBtnEabled = true.obs;
|
RxBool serviceBtnEnabled = true.obs;
|
||||||
|
|
||||||
@override
|
@override
|
||||||
Widget build(BuildContext context) {
|
Widget build(BuildContext context) {
|
||||||
@ -300,14 +301,14 @@ class _GeneralState extends State<_General> {
|
|||||||
return _Card(title: 'Service', children: [
|
return _Card(title: 'Service', children: [
|
||||||
Obx(() => _Button(serviceStop.value ? 'Start' : 'Stop', () {
|
Obx(() => _Button(serviceStop.value ? 'Start' : 'Stop', () {
|
||||||
() async {
|
() async {
|
||||||
serviceBtnEabled.value = false;
|
serviceBtnEnabled.value = false;
|
||||||
await start_service(serviceStop.value);
|
await start_service(serviceStop.value);
|
||||||
// enable the button after 1 second
|
// enable the button after 1 second
|
||||||
Future.delayed(const Duration(seconds: 1), () {
|
Future.delayed(const Duration(seconds: 1), () {
|
||||||
serviceBtnEabled.value = true;
|
serviceBtnEnabled.value = true;
|
||||||
});
|
});
|
||||||
}();
|
}();
|
||||||
}, enabled: serviceBtnEabled.value))
|
}, enabled: serviceBtnEnabled.value))
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -318,7 +319,14 @@ class _GeneralState extends State<_General> {
|
|||||||
isServer: false),
|
isServer: false),
|
||||||
_OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'),
|
_OptionCheckBox(context, 'Adaptive Bitrate', 'enable-abr'),
|
||||||
_OptionCheckBox(
|
_OptionCheckBox(
|
||||||
context, 'Separate remote window', kOptionSeparateRemoteWindow, isServer: false),
|
context,
|
||||||
|
'Separate remote window',
|
||||||
|
kOptionSeparateRemoteWindow,
|
||||||
|
isServer: false,
|
||||||
|
update: () {
|
||||||
|
rustDeskWinManager.separateWindows();
|
||||||
|
},
|
||||||
|
),
|
||||||
];
|
];
|
||||||
// though this is related to GUI, but opengl problem affects all users, so put in config rather than local
|
// though this is related to GUI, but opengl problem affects all users, so put in config rather than local
|
||||||
children.add(Tooltip(
|
children.add(Tooltip(
|
||||||
@ -1678,7 +1686,6 @@ Widget _OptionCheckBox(BuildContext context, String label, String key,
|
|||||||
isServer
|
isServer
|
||||||
? await mainSetBoolOption(key, option)
|
? await mainSetBoolOption(key, option)
|
||||||
: await mainSetLocalBoolOption(key, option);
|
: await mainSetLocalBoolOption(key, option);
|
||||||
;
|
|
||||||
update?.call();
|
update?.call();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -80,7 +80,7 @@ class _FileManagerPageState extends State<FileManagerPage>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_ffi = FFI();
|
_ffi = FFI(null);
|
||||||
_ffi.start(widget.id,
|
_ffi.start(widget.id,
|
||||||
isFileTransfer: true,
|
isFileTransfer: true,
|
||||||
password: widget.password,
|
password: widget.password,
|
||||||
|
@ -54,7 +54,7 @@ class _PortForwardPageState extends State<PortForwardPage>
|
|||||||
@override
|
@override
|
||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_ffi = FFI();
|
_ffi = FFI(null);
|
||||||
_ffi.start(widget.id,
|
_ffi.start(widget.id,
|
||||||
isPortForward: true,
|
isPortForward: true,
|
||||||
password: widget.password,
|
password: widget.password,
|
||||||
|
@ -28,10 +28,13 @@ import '../widgets/tabbar_widget.dart';
|
|||||||
|
|
||||||
final SimpleWrapper<bool> _firstEnterImage = SimpleWrapper(false);
|
final SimpleWrapper<bool> _firstEnterImage = SimpleWrapper(false);
|
||||||
|
|
||||||
|
final Map<String, bool> noCloseSessionOnDispose = {};
|
||||||
|
|
||||||
class RemotePage extends StatefulWidget {
|
class RemotePage extends StatefulWidget {
|
||||||
RemotePage({
|
RemotePage({
|
||||||
Key? key,
|
Key? key,
|
||||||
required this.id,
|
required this.id,
|
||||||
|
required this.sessionId,
|
||||||
required this.password,
|
required this.password,
|
||||||
required this.toolbarState,
|
required this.toolbarState,
|
||||||
required this.tabController,
|
required this.tabController,
|
||||||
@ -40,6 +43,7 @@ class RemotePage extends StatefulWidget {
|
|||||||
}) : super(key: key);
|
}) : super(key: key);
|
||||||
|
|
||||||
final String id;
|
final String id;
|
||||||
|
final SessionID? sessionId;
|
||||||
final String? password;
|
final String? password;
|
||||||
final ToolbarState toolbarState;
|
final ToolbarState toolbarState;
|
||||||
final String? switchUuid;
|
final String? switchUuid;
|
||||||
@ -91,7 +95,7 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
void initState() {
|
void initState() {
|
||||||
super.initState();
|
super.initState();
|
||||||
_initStates(widget.id);
|
_initStates(widget.id);
|
||||||
_ffi = FFI();
|
_ffi = FFI(widget.sessionId);
|
||||||
Get.put(_ffi, tag: widget.id);
|
Get.put(_ffi, tag: widget.id);
|
||||||
_ffi.imageModel.addCallbackOnFirstImage((String peerId) {
|
_ffi.imageModel.addCallbackOnFirstImage((String peerId) {
|
||||||
showKBLayoutTypeChooserIfNeeded(
|
showKBLayoutTypeChooserIfNeeded(
|
||||||
@ -199,6 +203,8 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
|
|
||||||
@override
|
@override
|
||||||
Future<void> dispose() async {
|
Future<void> dispose() async {
|
||||||
|
final closeSession = noCloseSessionOnDispose.remove(widget.id) ?? false;
|
||||||
|
|
||||||
// https://github.com/flutter/flutter/issues/64935
|
// https://github.com/flutter/flutter/issues/64935
|
||||||
super.dispose();
|
super.dispose();
|
||||||
debugPrint("REMOTE PAGE dispose session $sessionId ${widget.id}");
|
debugPrint("REMOTE PAGE dispose session $sessionId ${widget.id}");
|
||||||
@ -209,11 +215,13 @@ class _RemotePageState extends State<RemotePage>
|
|||||||
_ffi.dialogManager.hideMobileActionsOverlay();
|
_ffi.dialogManager.hideMobileActionsOverlay();
|
||||||
_ffi.recordingModel.onClose();
|
_ffi.recordingModel.onClose();
|
||||||
_rawKeyFocusNode.dispose();
|
_rawKeyFocusNode.dispose();
|
||||||
await _ffi.close();
|
await _ffi.close(closeSession: closeSession);
|
||||||
_timer?.cancel();
|
_timer?.cancel();
|
||||||
_ffi.dialogManager.dismissAll();
|
_ffi.dialogManager.dismissAll();
|
||||||
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
if (closeSession) {
|
||||||
overlays: SystemUiOverlay.values);
|
await SystemChrome.setEnabledSystemUIMode(SystemUiMode.manual,
|
||||||
|
overlays: SystemUiOverlay.values);
|
||||||
|
}
|
||||||
if (!Platform.isLinux) {
|
if (!Platform.isLinux) {
|
||||||
await Wakelock.disable();
|
await Wakelock.disable();
|
||||||
}
|
}
|
||||||
|
@ -52,6 +52,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
_toolbarState = ToolbarState();
|
_toolbarState = ToolbarState();
|
||||||
RemoteCountState.init();
|
RemoteCountState.init();
|
||||||
final peerId = params['id'];
|
final peerId = params['id'];
|
||||||
|
final sessionId = params['session_id'];
|
||||||
if (peerId != null) {
|
if (peerId != null) {
|
||||||
ConnectionTypeState.init(peerId);
|
ConnectionTypeState.init(peerId);
|
||||||
tabController.onSelected = (id) {
|
tabController.onSelected = (id) {
|
||||||
@ -73,6 +74,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
page: RemotePage(
|
page: RemotePage(
|
||||||
key: ValueKey(peerId),
|
key: ValueKey(peerId),
|
||||||
id: peerId,
|
id: peerId,
|
||||||
|
sessionId: sessionId == null ? null : SessionID(sessionId),
|
||||||
password: params['password'],
|
password: params['password'],
|
||||||
toolbarState: _toolbarState,
|
toolbarState: _toolbarState,
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
@ -99,6 +101,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
final args = jsonDecode(call.arguments);
|
final args = jsonDecode(call.arguments);
|
||||||
final id = args['id'];
|
final id = args['id'];
|
||||||
final switchUuid = args['switch_uuid'];
|
final switchUuid = args['switch_uuid'];
|
||||||
|
final sessionId = args['session_id'];
|
||||||
windowOnTop(windowId());
|
windowOnTop(windowId());
|
||||||
ConnectionTypeState.init(id);
|
ConnectionTypeState.init(id);
|
||||||
_toolbarState.setShow(
|
_toolbarState.setShow(
|
||||||
@ -112,6 +115,7 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
page: RemotePage(
|
page: RemotePage(
|
||||||
key: ValueKey(id),
|
key: ValueKey(id),
|
||||||
id: id,
|
id: id,
|
||||||
|
sessionId: sessionId == null ? null : SessionID(sessionId),
|
||||||
password: args['password'],
|
password: args['password'],
|
||||||
toolbarState: _toolbarState,
|
toolbarState: _toolbarState,
|
||||||
tabController: tabController,
|
tabController: tabController,
|
||||||
@ -136,6 +140,15 @@ class _ConnectionTabPageState extends State<ConnectionTabPage> {
|
|||||||
.map((e) => e.key)
|
.map((e) => e.key)
|
||||||
.toList()
|
.toList()
|
||||||
.join(',');
|
.join(',');
|
||||||
|
} else if (call.method == kWindowEventGetSessionIdList) {
|
||||||
|
return tabController.state.value.tabs
|
||||||
|
.map((e) => '${e.key},${(e.page as RemotePage).ffi.sessionId}')
|
||||||
|
.toList()
|
||||||
|
.join(';');
|
||||||
|
} else if (call.method == kWindowEventCloseForSeparateWindow) {
|
||||||
|
final peerId = call.arguments;
|
||||||
|
noCloseSessionOnDispose[peerId] = true;
|
||||||
|
tabController.closeBy(peerId);
|
||||||
}
|
}
|
||||||
_update_remote_count();
|
_update_remote_count();
|
||||||
});
|
});
|
||||||
|
@ -1579,6 +1579,7 @@ class FFI {
|
|||||||
/// dialogManager use late to ensure init after main page binding [globalKey]
|
/// dialogManager use late to ensure init after main page binding [globalKey]
|
||||||
late final dialogManager = OverlayDialogManager();
|
late final dialogManager = OverlayDialogManager();
|
||||||
|
|
||||||
|
late final bool isSessionAdded;
|
||||||
late final SessionID sessionId;
|
late final SessionID sessionId;
|
||||||
late final ImageModel imageModel; // session
|
late final ImageModel imageModel; // session
|
||||||
late final FfiModel ffiModel; // session
|
late final FfiModel ffiModel; // session
|
||||||
@ -1596,8 +1597,9 @@ class FFI {
|
|||||||
late final InputModel inputModel; // session
|
late final InputModel inputModel; // session
|
||||||
late final ElevationModel elevationModel; // session
|
late final ElevationModel elevationModel; // session
|
||||||
|
|
||||||
FFI() {
|
FFI(SessionID? sId) {
|
||||||
sessionId = isDesktop ? Uuid().v4obj() : _constSessionId;
|
isSessionAdded = sId != null;
|
||||||
|
sessionId = sId ?? (isDesktop ? Uuid().v4obj() : _constSessionId);
|
||||||
imageModel = ImageModel(WeakReference(this));
|
imageModel = ImageModel(WeakReference(this));
|
||||||
ffiModel = FfiModel(WeakReference(this));
|
ffiModel = FfiModel(WeakReference(this));
|
||||||
cursorModel = CursorModel(WeakReference(this));
|
cursorModel = CursorModel(WeakReference(this));
|
||||||
@ -1637,17 +1639,19 @@ class FFI {
|
|||||||
imageModel.id = id;
|
imageModel.id = id;
|
||||||
cursorModel.id = id;
|
cursorModel.id = id;
|
||||||
}
|
}
|
||||||
// ignore: unused_local_variable
|
if (isSessionAdded) {
|
||||||
final addRes = bind.sessionAddSync(
|
// ignore: unused_local_variable
|
||||||
sessionId: sessionId,
|
final addRes = bind.sessionAddSync(
|
||||||
id: id,
|
sessionId: sessionId,
|
||||||
isFileTransfer: isFileTransfer,
|
id: id,
|
||||||
isPortForward: isPortForward,
|
isFileTransfer: isFileTransfer,
|
||||||
isRdp: isRdp,
|
isPortForward: isPortForward,
|
||||||
switchUuid: switchUuid ?? "",
|
isRdp: isRdp,
|
||||||
forceRelay: forceRelay ?? false,
|
switchUuid: switchUuid ?? "",
|
||||||
password: password ?? "",
|
forceRelay: forceRelay ?? false,
|
||||||
);
|
password: password ?? "",
|
||||||
|
);
|
||||||
|
}
|
||||||
final stream = bind.sessionStart(sessionId: sessionId, id: id);
|
final stream = bind.sessionStart(sessionId: sessionId, id: id);
|
||||||
final cb = ffiModel.startEventListener(sessionId, id);
|
final cb = ffiModel.startEventListener(sessionId, id);
|
||||||
final useTextureRender = bind.mainUseTextureRender();
|
final useTextureRender = bind.mainUseTextureRender();
|
||||||
@ -1712,7 +1716,7 @@ class FFI {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Close the remote session.
|
/// Close the remote session.
|
||||||
Future<void> close() async {
|
Future<void> close({bool closeSession = true}) async {
|
||||||
closed = true;
|
closed = true;
|
||||||
chatModel.close();
|
chatModel.close();
|
||||||
if (imageModel.image != null && !isWebDesktop) {
|
if (imageModel.image != null && !isWebDesktop) {
|
||||||
@ -1730,7 +1734,9 @@ class FFI {
|
|||||||
ffiModel.clear();
|
ffiModel.clear();
|
||||||
canvasModel.clear();
|
canvasModel.clear();
|
||||||
inputModel.resetModifiers();
|
inputModel.resetModifiers();
|
||||||
await bind.sessionClose(sessionId: sessionId);
|
if (closeSession) {
|
||||||
|
await bind.sessionClose(sessionId: sessionId);
|
||||||
|
}
|
||||||
debugPrint('model $id closed');
|
debugPrint('model $id closed');
|
||||||
id = '';
|
id = '';
|
||||||
}
|
}
|
||||||
|
@ -43,6 +43,46 @@ class RustDeskMultiWindowManager {
|
|||||||
final List<int> _fileTransferWindows = List.empty(growable: true);
|
final List<int> _fileTransferWindows = List.empty(growable: true);
|
||||||
final List<int> _portForwardWindows = List.empty(growable: true);
|
final List<int> _portForwardWindows = List.empty(growable: true);
|
||||||
|
|
||||||
|
separateWindows() async {
|
||||||
|
for (final windowId in _remoteDesktopWindows) {
|
||||||
|
final sessionIdList = await DesktopMultiWindow.invokeMethod(
|
||||||
|
windowId, kWindowEventGetSessionIdList, null);
|
||||||
|
if (sessionIdList != null) {
|
||||||
|
for (final idPair in sessionIdList.split(';')) {
|
||||||
|
final peerSession = idPair.split(',');
|
||||||
|
var params = {
|
||||||
|
'type': WindowType.RemoteDesktop.index,
|
||||||
|
'id': peerSession[0],
|
||||||
|
'sessionId': peerSession[1],
|
||||||
|
};
|
||||||
|
await newSessionWindow(WindowType.RemoteDesktop, peerSession[0],
|
||||||
|
jsonEncode(params), _remoteDesktopWindows);
|
||||||
|
await DesktopMultiWindow.invokeMethod(
|
||||||
|
windowId, kWindowEventCloseForSeparateWindow, peerSession[0]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
newSessionWindow(
|
||||||
|
WindowType type, String remoteId, String msg, List<int> windows) async {
|
||||||
|
final windowController = await DesktopMultiWindow.createWindow(msg);
|
||||||
|
windowController
|
||||||
|
..setFrame(const Offset(0, 0) &
|
||||||
|
Size(1280 + windowController.windowId * 20,
|
||||||
|
720 + windowController.windowId * 20))
|
||||||
|
..center()
|
||||||
|
..setTitle(getWindowNameWithId(
|
||||||
|
remoteId,
|
||||||
|
overrideType: type,
|
||||||
|
));
|
||||||
|
if (Platform.isMacOS) {
|
||||||
|
Future.microtask(() => windowController.show());
|
||||||
|
}
|
||||||
|
registerActiveWindow(windowController.windowId);
|
||||||
|
windows.add(windowController.windowId);
|
||||||
|
}
|
||||||
|
|
||||||
Future<dynamic> newSession(
|
Future<dynamic> newSession(
|
||||||
WindowType type,
|
WindowType type,
|
||||||
String methodName,
|
String methodName,
|
||||||
@ -68,24 +108,6 @@ class RustDeskMultiWindowManager {
|
|||||||
}
|
}
|
||||||
final msg = jsonEncode(params);
|
final msg = jsonEncode(params);
|
||||||
|
|
||||||
newSessionWindow() async {
|
|
||||||
final windowController = await DesktopMultiWindow.createWindow(msg);
|
|
||||||
windowController
|
|
||||||
..setFrame(const Offset(0, 0) &
|
|
||||||
Size(1280 + windowController.windowId * 20,
|
|
||||||
720 + windowController.windowId * 20))
|
|
||||||
..center()
|
|
||||||
..setTitle(getWindowNameWithId(
|
|
||||||
remoteId,
|
|
||||||
overrideType: type,
|
|
||||||
));
|
|
||||||
if (Platform.isMacOS) {
|
|
||||||
Future.microtask(() => windowController.show());
|
|
||||||
}
|
|
||||||
registerActiveWindow(windowController.windowId);
|
|
||||||
windows.add(windowController.windowId);
|
|
||||||
}
|
|
||||||
|
|
||||||
// separate window for file transfer is not supported
|
// separate window for file transfer is not supported
|
||||||
bool separateWindow = forceSeparateWindow ||
|
bool separateWindow = forceSeparateWindow ||
|
||||||
(type != WindowType.FileTransfer &&
|
(type != WindowType.FileTransfer &&
|
||||||
@ -111,11 +133,11 @@ class RustDeskMultiWindowManager {
|
|||||||
windows.add(windowController.windowId);
|
windows.add(windowController.windowId);
|
||||||
return invokeRes;
|
return invokeRes;
|
||||||
} else {
|
} else {
|
||||||
await newSessionWindow();
|
await newSessionWindow(type, remoteId, msg, windows);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (windows.isEmpty) {
|
if (windows.isEmpty) {
|
||||||
await newSessionWindow();
|
await newSessionWindow(type, remoteId, msg, windows);
|
||||||
} else {
|
} else {
|
||||||
return call(type, methodName, msg);
|
return call(type, methodName, msg);
|
||||||
}
|
}
|
||||||
|
@ -782,11 +782,15 @@ pub fn session_start_(
|
|||||||
);
|
);
|
||||||
#[cfg(not(feature = "flutter_texture_render"))]
|
#[cfg(not(feature = "flutter_texture_render"))]
|
||||||
log::info!("Session {} start, render by flutter paint widget", id);
|
log::info!("Session {} start, render by flutter paint widget", id);
|
||||||
|
let is_pre_added = session.event_stream.read().unwrap().is_some();
|
||||||
|
session.close_event_stream();
|
||||||
*session.event_stream.write().unwrap() = Some(event_stream);
|
*session.event_stream.write().unwrap() = Some(event_stream);
|
||||||
let session = session.clone();
|
if !is_pre_added {
|
||||||
std::thread::spawn(move || {
|
let session = session.clone();
|
||||||
io_loop(session);
|
std::thread::spawn(move || {
|
||||||
});
|
io_loop(session);
|
||||||
|
});
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
} else {
|
} else {
|
||||||
bail!("No session with peer id {}", id)
|
bail!("No session with peer id {}", id)
|
||||||
|
Loading…
Reference in New Issue
Block a user