Skip to content

Commit

Permalink
Merge pull request #726 from atsign-foundation/713-the-desktop-app-is…
Browse files Browse the repository at this point in the history
…-stuck-on-a-loading-screen-when-a-hung-session-occurs

fix: terminal can be closed if session is hung
  • Loading branch information
XavierChanth committed Jan 26, 2024
2 parents 34dff78 + 0e2f36b commit 6b4967a
Show file tree
Hide file tree
Showing 3 changed files with 90 additions and 79 deletions.
Expand Up @@ -185,6 +185,11 @@ class TerminalSessionFamilyController extends FamilyNotifier<TerminalSession, St
ref.read(terminalSessionProfileNameFamilyCounter(state._profileName!).notifier)._removeSession(state.sessionId);
}
}

void write(String data) {
state.terminal.write(data);
state.terminal.cursorNextLine(1);
}
}

/// Counter for the number of terminal sessions by profileName - issues and tracks the display name for each session
Expand Down
@@ -1,21 +1,12 @@
import 'dart:developer';

import 'package:at_client_mobile/at_client_mobile.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:noports_core/sshnp.dart';
import 'package:sshnp_flutter/src/controllers/navigation_controller.dart';
import 'package:sshnp_flutter/src/controllers/navigation_rail_controller.dart';
import 'package:sshnp_flutter/src/controllers/terminal_session_controller.dart';
import 'package:sshnp_flutter/src/presentation/widgets/profile_screen_widgets/profile_actions/profile_action_button.dart';
import 'package:sshnp_flutter/src/repository/private_key_manager_repository.dart';
import 'package:sshnp_flutter/src/utility/sizes.dart';

import '../../../../repository/profile_private_key_manager_repository.dart';
import '../../utility/custom_snack_bar.dart';

class ProfileTerminalAction extends ConsumerStatefulWidget {
final SshnpParams params;
const ProfileTerminalAction(this.params, {Key? key}) : super(key: key);
Expand All @@ -42,77 +33,9 @@ class _ProfileTerminalActionState extends ConsumerState<ProfileTerminalAction> {
}

Future<void> onPressed() async {
ref.read(navigationRailController.notifier).setRoute(AppRoute.terminal);
if (mounted) {
showProgress('Starting Shell Session...');
}

/// Issue a new session id
final sessionId = ref.watch(terminalSessionController.notifier).createSession();

/// Create the session controller for the new session id
final sessionController = ref.watch(terminalSessionFamilyController(sessionId).notifier);

try {
AtClient atClient = AtClientManager.getInstance().atClient;

final profilePrivateKey =
await ProfilePrivateKeyManagerRepository.readProfilePrivateKeyManager(widget.params.profileName ?? '');
final privateKeyManager =
await PrivateKeyManagerRepository.readPrivateKeyManager(profilePrivateKey.privateKeyNickname);

final keyPair = privateKeyManager.toAtSshKeyPair();

final sshnp = Sshnp.dartPure(
params: SshnpParams.merge(
widget.params,
SshnpPartialParams(
verbose: kDebugMode,
idleTimeout: 30,
),
),
atClient: atClient,
identityKeyPair: keyPair,
);

final result = await sshnp.run();
if (result is SshnpError) {
throw result;
}

if (result is SshnpCommand) {
if (sshnp.canRunShell) {
if (mounted) {
context.pop();
showProgress('running shell session...');
}
log('running shell session...');

SshnpRemoteProcess shell = await sshnp.runShell();
if (mounted) {
context.pop();
showProgress('starting terminal session...');
}
log('starting terminal session');
sessionController.startSession(
shell,
terminalTitle: '${widget.params.sshnpdAtSign}-${widget.params.device}',
);
}

sessionController.issueDisplayName(widget.params.profileName!);

ref.read(navigationRailController.notifier).setRoute(AppRoute.terminal);
if (mounted) {
context.pushReplacementNamed(AppRoute.terminal.name);
}
}
} catch (e) {
sessionController.dispose();
if (mounted) {
log('error: ${e.toString()}');
context.pop();
CustomSnackBar.error(content: e.toString());
}
context.pushReplacementNamed(AppRoute.terminal.name, extra: {'params': widget.params, 'runShell': true});
}
}

Expand Down
@@ -1,12 +1,22 @@
import 'dart:developer';

import 'package:at_onboarding_flutter/at_onboarding_flutter.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_gen/gen_l10n/app_localizations.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:flutter_svg/flutter_svg.dart';
import 'package:go_router/go_router.dart';
import 'package:noports_core/sshnp.dart';
import 'package:sshnp_flutter/src/controllers/terminal_session_controller.dart';
import 'package:sshnp_flutter/src/presentation/widgets/navigation/app_navigation_rail.dart';
import 'package:sshnp_flutter/src/utility/sizes.dart';
import 'package:xterm/xterm.dart';

import '../../../repository/private_key_manager_repository.dart';
import '../../../repository/profile_private_key_manager_repository.dart';
import '../utility/custom_snack_bar.dart';

// * Once the onboarding process is completed you will be taken to this screen
class TerminalScreenDesktopView extends ConsumerStatefulWidget {
const TerminalScreenDesktopView({Key? key}) : super(key: key);
Expand All @@ -18,6 +28,79 @@ class TerminalScreenDesktopView extends ConsumerStatefulWidget {
class _TerminalScreenDesktopViewState extends ConsumerState<TerminalScreenDesktopView> with TickerProviderStateMixin {
final terminalController = TerminalController();

@override
void initState() {
super.initState();

WidgetsBinding.instance.addPostFrameCallback(
(_) async {
final Map shellInfo = (GoRouterState.of(context).extra ?? {'runShell': false}) as Map;
if (shellInfo['runShell']) {
/// Issue a new session id
final sessionId = ref.watch(terminalSessionController.notifier).createSession();

/// Create the session controller for the new session id
final sessionController = ref.watch(terminalSessionFamilyController(sessionId).notifier);

sessionController.issueDisplayName(shellInfo['params'].profileName!);

sessionController.write('Starting Shell Session...');
log('Starting Shell Session...');

try {
AtClient atClient = AtClientManager.getInstance().atClient;

final profilePrivateKey = await ProfilePrivateKeyManagerRepository.readProfilePrivateKeyManager(
shellInfo['params'].profileName ?? '');
final privateKeyManager =
await PrivateKeyManagerRepository.readPrivateKeyManager(profilePrivateKey.privateKeyNickname);

final keyPair = privateKeyManager.toAtSshKeyPair();

final sshnp = Sshnp.dartPure(
params: SshnpParams.merge(
shellInfo['params'],
SshnpPartialParams(
verbose: kDebugMode,
idleTimeout: 30,
),
),
atClient: atClient,
identityKeyPair: keyPair,
);

final result = await sshnp.run();
if (result is SshnpError) {
throw result;
}

if (result is SshnpCommand) {
if (sshnp.canRunShell) {
sessionController.write('running shell session...');
log('running shell session...');

SshnpRemoteProcess shell = await sshnp.runShell();
sessionController.write('starting terminal session...');
log('starting terminal session');
sessionController.startSession(
shell,
terminalTitle: '${shellInfo['sshnpdAtSign']}-${shellInfo['params'].device}',
);
}
}
} catch (e) {
sessionController.dispose();
if (mounted) {
log('error: ${e.toString()}');

CustomSnackBar.error(content: e.toString());
}
}
}
},
);
}

@override
void dispose() {
terminalController.dispose();
Expand Down

0 comments on commit 6b4967a

Please sign in to comment.