-
Notifications
You must be signed in to change notification settings - Fork 15
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: provide a way to listen to progress and logger messages #741
Changes from 1 commit
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,22 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:at_utils/at_logger.dart'; | ||
import 'package:logging/logging.dart'; | ||
|
||
class StreamingLoggingHandler implements LoggingHandler { | ||
final LoggingHandler _wrappedLoggingHandler; | ||
final StreamController<String> _logSC = StreamController.broadcast(); | ||
|
||
StreamingLoggingHandler(this._wrappedLoggingHandler); | ||
|
||
@override | ||
void call(LogRecord record) { | ||
_wrappedLoggingHandler.call(record); | ||
_logSC.add('${record.level.name}' | ||
'|${record.time}' | ||
'|${record.loggerName}' | ||
'|${record.message}'); | ||
} | ||
|
||
Stream<String> get stream => _logSC.stream; | ||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,6 +10,7 @@ class SshnpUnsignedImpl extends SshnpCore | |
SshnpUnsignedImpl({ | ||
required super.atClient, | ||
required super.params, | ||
required super.logStream, | ||
}) { | ||
if (Platform.isWindows) { | ||
throw SshnpError( | ||
|
@@ -90,7 +91,7 @@ class SshnpUnsignedImpl extends SshnpCore | |
..sharedBy = params.clientAtSign | ||
..sharedWith = params.sshnpdAtSign | ||
..metadata = (Metadata()..ttl = 10000), | ||
'$localPort ${srvdChannel.clientPort} ${keyUtil.username} ${srvdChannel.host} $sessionId', | ||
'$localPort ${srvdChannel.daemonPort} ${keyUtil.username} ${srvdChannel.host} $sessionId', | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made the legacy impl code consistent with the current impls (dart, openssh) |
||
checkForFinalDeliveryStatus: false, | ||
waitForFinalDeliveryStatus: false, | ||
); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,32 +1,44 @@ | ||
import 'dart:async'; | ||
|
||
import 'package:at_client/at_client.dart' hide StringBuffer; | ||
import 'package:at_utils/at_logger.dart'; | ||
import 'package:noports_core/src/common/streaming_logging_handler.dart'; | ||
import 'package:noports_core/sshnp_foundation.dart'; | ||
|
||
abstract interface class SshnpRemoteProcess { | ||
Future<void> get done; | ||
|
||
Stream<List<int>> get stderr; | ||
|
||
StreamSink<List<int>> get stdin; | ||
|
||
Stream<List<int>> get stdout; | ||
} | ||
|
||
abstract interface class Sshnp { | ||
static final StreamingLoggingHandler _slh = | ||
StreamingLoggingHandler(AtSignLogger.defaultLoggingHandler); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Make one of our StreamingLoggingHandlers, and wrap the current defaultLoggingHandler in it |
||
|
||
/// Legacy v3.x.x client | ||
@Deprecated( | ||
'Legacy unsigned client - only for connecting with ^3.0.0 daemons') | ||
factory Sshnp.unsigned({ | ||
required AtClient atClient, | ||
required SshnpParams params, | ||
}) { | ||
return SshnpUnsignedImpl(atClient: atClient, params: params); | ||
AtSignLogger.defaultLoggingHandler = _slh; | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. set the defaultLoggingHandler to our StreamingLoggingHandler |
||
return SshnpUnsignedImpl( | ||
atClient: atClient, params: params, logStream: _slh.stream); | ||
} | ||
|
||
/// Think of this as the "default" client - calls openssh | ||
factory Sshnp.openssh({ | ||
required AtClient atClient, | ||
required SshnpParams params, | ||
}) { | ||
return SshnpOpensshLocalImpl(atClient: atClient, params: params); | ||
AtSignLogger.defaultLoggingHandler = _slh; | ||
return SshnpOpensshLocalImpl( | ||
atClient: atClient, params: params, logStream: _slh.stream); | ||
} | ||
|
||
/// Uses a dartssh2 ssh client - requires that you pass in the identity keypair | ||
|
@@ -35,8 +47,12 @@ abstract interface class Sshnp { | |
required SshnpParams params, | ||
required AtSshKeyPair? identityKeyPair, | ||
}) { | ||
AtSignLogger.defaultLoggingHandler = _slh; | ||
var sshnp = SshnpDartPureImpl( | ||
atClient: atClient, params: params, identityKeyPair: identityKeyPair); | ||
atClient: atClient, | ||
params: params, | ||
identityKeyPair: identityKeyPair, | ||
logStream: _slh.stream); | ||
if (identityKeyPair != null) { | ||
sshnp.keyUtil.addKeyPair(keyPair: identityKeyPair); | ||
} | ||
|
@@ -72,4 +88,11 @@ abstract interface class Sshnp { | |
/// - Iterable<String> of atSigns of sshnpd that did not respond | ||
/// - Map<String, dynamic> where the keys are all atSigns included in the maps, and the values being their device info | ||
Future<SshnpDeviceList> listDevices(); | ||
|
||
/// Yields a string every time something interesting happens with regards to | ||
/// progress towards establishing the ssh connection. | ||
Stream<String>? get progressStream; | ||
|
||
/// Yields every log message that is written to [stderr] | ||
Stream<String>? get logStream; | ||
XavierChanth marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} |
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -122,7 +122,7 @@ abstract class SrvdChannel<T> with AsyncInitialization, AtClientBindings { | |
if (params.host.startsWith('@')) { | ||
srv = srvGenerator( | ||
host, | ||
daemonPort!, // everything was backwards back then | ||
clientPort, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Made the legacy impl code consistent with the current impls (dart, openssh) |
||
localPort: params.localSshdPort, | ||
bindLocalPort: false, | ||
); | ||
|
@@ -212,7 +212,7 @@ abstract class SrvdChannel<T> with AsyncInitialization, AtClientBindings { | |
counter++; | ||
if (counter > 150) { | ||
logger.warning('Timed out waiting for srvd response'); | ||
throw ('Connection timeout to srvd $host service\nhint: make sure host is valid and online'); | ||
throw ('Connection timeout to srvd $host service'); | ||
} | ||
} | ||
} | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -72,6 +72,17 @@ void main(List<String> args) async { | |
throw e; | ||
}); | ||
|
||
// A listen progress listener for the CLI | ||
// Will only log if verbose is false, since if verbose is true | ||
// there will already be a boatload of log messages | ||
logProgress(String s) { | ||
if (!(params?.verbose ?? true)) { | ||
stderr.writeln('${DateTime.now()} : $s'); | ||
} | ||
} | ||
|
||
sshnp.progressStream?.listen((s) => logProgress(s)); | ||
|
||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Added a simple progress listener into the sshnp CLI so that, if run in non-verbose mode, the user will get enough output to keep them from wondering what is going on and why. (If run in verbose mode, a normal user gets too much information) |
||
if (params.listDevices) { | ||
stderr.writeln('Searching for devices...'); | ||
var deviceList = await sshnp.listDevices(); | ||
|
@@ -114,6 +125,7 @@ void main(List<String> args) async { | |
stdout.write('$res\n'); | ||
exit(0); | ||
} else { | ||
logProgress('Starting user session'); | ||
Process process = await Process.start( | ||
res.command, | ||
res.args, | ||
|
@@ -130,22 +142,22 @@ void main(List<String> args) async { | |
printUsage(error: error); | ||
exit(1); | ||
} on SshnpError catch (error, stackTrace) { | ||
stderr.writeln(error.toString()); | ||
stderr.writeln('\nError : $error'); | ||
if (params?.verbose ?? true) { | ||
stderr.writeln('\nStack Trace: ${stackTrace.toString()}'); | ||
stderr.writeln('\nStack Trace: $stackTrace'); | ||
} | ||
exit(1); | ||
} catch (error, stackTrace) { | ||
stderr.writeln(error.toString()); | ||
stderr.writeln('\nStack Trace: ${stackTrace.toString()}'); | ||
stderr.writeln('\nError : $error'); | ||
stderr.writeln('\nStack Trace: $stackTrace'); | ||
exit(1); | ||
} | ||
}, (Object error, StackTrace stackTrace) async { | ||
if (error is SSHError) { | ||
stderr.writeln('\nError: ${error.toString()}'); | ||
stderr.writeln('\n\nError: $error'); | ||
} else { | ||
stderr.writeln('Error: ${error.toString()}'); | ||
stderr.writeln('\nStack Trace: ${stackTrace.toString()}'); | ||
stderr.writeln('\nError: $error'); | ||
stderr.writeln('\nStack Trace: $stackTrace'); | ||
} | ||
exit(1); | ||
}); | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A new at_logger LoggingHandler so we have a way to provide a stream of log messages