xuty 2 år sedan
förälder
incheckning
28d6d9a1cb
7 ändrade filer med 52 tillägg och 80 borttagningar
  1. 3 0
      CHANGELOG.md
  2. 3 12
      example/lib/zmodem.dart
  3. 1 15
      example/pubspec.lock
  4. 2 2
      example/test/widget_test.dart
  5. 40 48
      lib/zmodem.dart
  6. 1 1
      pubspec.lock
  7. 2 2
      pubspec.yaml

+ 3 - 0
CHANGELOG.md

@@ -1,3 +1,6 @@
+## [3.6.0-pre] - 2023-04-7
+* Basic ZMODEM support
+
 ## [3.5.0] - 2023-04-20
 * Support customizing word separators for selection [#160]. Thanks [@itzhoujun].
 * Fix incorrect tab stop handling [#161]. Thanks [@itzhoujun].

+ 3 - 12
example/lib/zmodem.dart

@@ -3,7 +3,6 @@ import 'dart:io';
 import 'dart:typed_data';
 
 import 'package:dartssh2/dartssh2.dart';
-import 'package:example/src/virtual_keyboard.dart';
 import 'package:file_picker/file_picker.dart';
 import 'package:flutter/cupertino.dart';
 import 'package:path/path.dart' as path;
@@ -37,9 +36,7 @@ class MyHomePage extends StatefulWidget {
 }
 
 class _MyHomePageState extends State<MyHomePage> {
-  late final terminal = Terminal(inputHandler: keyboard);
-
-  final keyboard = VirtualKeyboard(defaultInputHandler);
+  late final terminal = Terminal();
 
   var title = host;
 
@@ -56,6 +53,7 @@ class _MyHomePageState extends State<MyHomePage> {
       await SSHSocket.connect(host, port),
       username: username,
       onPasswordRequest: () => password,
+      printTrace: print,
     );
 
     terminal.write('Connected\r\n');
@@ -165,14 +163,7 @@ class _MyHomePageState extends State<MyHomePage> {
         backgroundColor:
             CupertinoTheme.of(context).barBackgroundColor.withOpacity(0.5),
       ),
-      child: Column(
-        children: [
-          Expanded(
-            child: TerminalView(terminal),
-          ),
-          VirtualKeyboardView(keyboard),
-        ],
-      ),
+      child: TerminalView(terminal),
     );
   }
 }

+ 1 - 15
example/pubspec.lock

@@ -113,13 +113,6 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "4.21.3"
-  dart_console:
-    dependency: transitive
-    description:
-      name: dart_console
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "1.1.2"
   dart_style:
     dependency: transitive
     description:
@@ -226,13 +219,6 @@ packages:
       url: "https://pub.dartlang.org"
     source: hosted
     version: "4.0.2"
-  intl:
-    dependency: transitive
-    description:
-      name: intl
-      url: "https://pub.dartlang.org"
-    source: hosted
-    version: "0.17.0"
   js:
     dependency: transitive
     description:
@@ -461,7 +447,7 @@ packages:
       name: zmodem
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.0.4"
+    version: "0.0.6"
 sdks:
   dart: ">=2.18.0 <3.0.0"
   flutter: ">=3.0.0"

+ 2 - 2
example/test/widget_test.dart

@@ -5,10 +5,10 @@
 // gestures. You can also use WidgetTester to find child widgets in the widget
 // tree, read text, and verify that the values of widget properties are correct.
 
-import 'package:flutter/material.dart';
+// import 'package:flutter/material.dart';
 import 'package:flutter_test/flutter_test.dart';
 
-import 'package:example/main.dart';
+// import 'package:example/main.dart';
 
 void main() {
   testWidgets('Counter increments smoke test', (WidgetTester tester) async {

+ 40 - 48
lib/zmodem.dart

@@ -50,7 +50,7 @@ class ZModemMux {
   final Stream<Uint8List> stdout;
 
   /// The sink to write data to the underlying data channel.
-  final StreamSink stdin;
+  final StreamSink<List<int>> stdin;
 
   /// The callback to receive data that should be written to the terminal.
   ZModemInputHandler? onTerminalInput;
@@ -71,7 +71,7 @@ class ZModemMux {
   /// space is available in local buffers.
   late final StreamSubscription<Uint8List> _stdoutSubscription;
 
-  late final _terminalInputSink = StreamController<List<int>>(
+  late final _terminalSink = StreamController<List<int>>(
       // onPause: _stdoutSubscription.pause,
       // onResume: _stdoutSubscription.resume,
       )
@@ -93,7 +93,6 @@ class ZModemMux {
   /// buffered if a ZModem session is active.
   void terminalWrite(String input) {
     if (_session == null) {
-      print('-->t: ${input}');
       stdin.add(utf8.encode(input) as Uint8List);
     }
   }
@@ -101,8 +100,6 @@ class ZModemMux {
   /// This is the entry point of multiplexing, dispatching data to ZModem or
   /// terminal depending on the current state.
   void _handleStdout(Uint8List chunk) {
-    print('<--: ${chunk.dump()}');
-
     if (_session != null) {
       _handleZModem(chunk);
       return;
@@ -112,7 +109,7 @@ class ZModemMux {
       return;
     }
 
-    _terminalInputSink.add(chunk);
+    _terminalSink.add(chunk);
   }
 
   /// Detects a ZModem session in [chunk] and starts it if found. Returns true
@@ -122,12 +119,11 @@ class ZModemMux {
         chunk.listIndexOf(_zmodemReceiverInit);
 
     if (index != null) {
-      _terminalInputSink.add(Uint8List.sublistView(chunk, 0, index));
+      _terminalSink.add(Uint8List.sublistView(chunk, 0, index));
 
       _session = ZModemCore(
-        onTrace: print,
         onPlainText: (text) {
-          _terminalInputSink.add([text]);
+          _terminalSink.add([text]);
         },
       );
 
@@ -138,32 +134,29 @@ class ZModemMux {
     return false;
   }
 
-  void _handleZModem(Uint8List chunk) {
-    print('_handleZModem');
-    // print('bytes: ${chunk.map((e) => e.toRadixString(16)).toList()}');
-
+  void _handleZModem(Uint8List chunk) async {
     for (final event in _session!.receive(chunk)) {
-      print('event: $event');
-
       /// remote is sz
       if (event is ZFileOfferedEvent) {
         _handleZFileOfferedEvent(event);
       } else if (event is ZFileDataEvent) {
         _handleZFileDataEvent(event);
       } else if (event is ZFileEndEvent) {
-        _handleZFileEndEvent(event);
+        await _handleZFileEndEvent(event);
       } else if (event is ZSessionFinishedEvent) {
-        _handleZSessionFinishedEvent(event);
+        await _handleZSessionFinishedEvent(event);
       }
 
       /// remote is rz
       else if (event is ZReadyToSendEvent) {
-        _handleFileRequestEvent(event);
+        await _handleFileRequestEvent(event);
       } else if (event is ZFileAcceptedEvent) {
-        _handleFileAcceptedEvent(event);
+        await _handleFileAcceptedEvent(event);
       } else if (event is ZFileSkippedEvent) {
         _handleFileSkippedEvent(event);
       }
+
+      _flush();
     }
 
     _flush();
@@ -174,7 +167,6 @@ class ZModemMux {
 
     if (onFileOffer == null) {
       _session!.skipFile();
-      _flush();
       return;
     }
 
@@ -185,37 +177,38 @@ class ZModemMux {
     _receiveSink!.add(event.data as Uint8List);
   }
 
-  void _handleZFileEndEvent(ZFileEndEvent event) async {
+  Future<void> _handleZFileEndEvent(ZFileEndEvent event) async {
     await _closeReceiveSink();
   }
 
-  void _handleZSessionFinishedEvent(ZSessionFinishedEvent event) async {
+  Future<void> _handleZSessionFinishedEvent(ZSessionFinishedEvent event) async {
+    _flush();
     await _reset();
   }
 
-  void _handleFileRequestEvent(ZReadyToSendEvent event) async {
+  Future<void> _handleFileRequestEvent(ZReadyToSendEvent event) async {
     _fileOffers ??= (await onFileRequest?.call())?.iterator;
 
     _moveToNextOffer();
   }
 
-  void _handleFileAcceptedEvent(ZFileAcceptedEvent event) async {
+  Future<void> _handleFileAcceptedEvent(ZFileAcceptedEvent event) async {
     final data = _fileOffers!.current.accept(event.offset);
     var bytesSent = 0;
 
-    final subscription = data.listen(
-      (chunk) {
-        bytesSent += chunk.length;
-        print('bytesSent: $bytesSent');
-        _session!.sendFileData(chunk);
-        _flush();
-      },
-      onDone: () {
-        print('bytesSent fin: $bytesSent');
-        _session!.finishSending(event.offset + bytesSent);
-        _flush();
-      },
+    await stdin.addStream(
+      data.transform(
+        StreamTransformer<Uint8List, Uint8List>.fromHandlers(
+          handleData: (chunk, sink) {
+            bytesSent += chunk.length;
+            _session!.sendFileData(chunk);
+            sink.add(_session!.dataToSend());
+          },
+        ),
+      ),
     );
+
+    _session!.finishSending(event.offset + bytesSent);
   }
 
   void _handleFileSkippedEvent(ZFileSkippedEvent event) {
@@ -225,16 +218,12 @@ class ZModemMux {
 
   /// Sends next file offer if available, or closes the session if not.
   void _moveToNextOffer() {
-    print('_offerNextFileIfNeeded');
-
     if (_fileOffers?.moveNext() != true) {
-      print('no more files');
       _closeSession();
       return;
     }
 
     _session!.offerFile(_fileOffers!.current.info);
-    _flush();
   }
 
   /// Creates a [ZModemOffer] ƒrom the info from remote peer that can be used
@@ -258,20 +247,24 @@ class ZModemMux {
 
   void _createReceiveSink() {
     _receiveSink = StreamController<Uint8List>(
-      // onPause: _stdoutSubscription.pause,
-      onResume: _stdoutSubscription.resume,
+      onPause: () {
+        // _stdoutSubscription.pause();
+      },
+      onResume: () {
+        // _stdoutSubscription.resume();
+      },
     );
   }
 
   Future<void> _closeReceiveSink() async {
+    _stdoutSubscription.resume();
     await _receiveSink?.close();
     _receiveSink = null;
   }
 
   /// Requests remote to close the session.
-  Future<void> _closeSession() async {
+  void _closeSession() {
     _session!.finishSession();
-    _flush();
   }
 
   /// Clears all ZModem state.
@@ -284,15 +277,14 @@ class ZModemMux {
   /// Sends all pending data packets to the remote. No data is automatically
   /// sent to the remote without calling this method.
   void _flush() {
-    final dataToSend = _session!.dataToSend();
-    if (dataToSend.isNotEmpty) {
-      // print('-->: ${dataToSend.dump()}');
+    final dataToSend = _session?.dataToSend();
+    if (dataToSend != null && dataToSend.isNotEmpty) {
       stdin.add(dataToSend);
     }
   }
 }
 
-extension on List<int> {
+extension ListExtension on List<int> {
   String dump() {
     return map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
   }

+ 1 - 1
pubspec.lock

@@ -582,7 +582,7 @@ packages:
       name: zmodem
       url: "https://pub.dartlang.org"
     source: hosted
-    version: "0.0.5"
+    version: "0.0.6"
 sdks:
   dart: ">=2.18.0 <3.0.0"
   flutter: ">=3.0.0"

+ 2 - 2
pubspec.yaml

@@ -1,6 +1,6 @@
 name: xterm
 description: xterm.dart is a fast and fully-featured terminal emulator for Flutter applications, with support for mobile and desktop platforms.
-version: 3.5.0
+version: 3.6.0-pre
 homepage: https://github.com/TerminalStudio/xterm.dart
 
 environment:
@@ -15,7 +15,7 @@ dependencies:
   equatable: ^2.0.3
   flutter:
     sdk: flutter
-  zmodem: ^0.0.5
+  zmodem: ^0.0.6
 
 dev_dependencies:
   flutter_test: