Skip to content

Commit 28d6d9a

Browse files
committed
Update
1 parent d668882 commit 28d6d9a

File tree

7 files changed

+52
-80
lines changed

7 files changed

+52
-80
lines changed

CHANGELOG.md

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
## [3.6.0-pre] - 2023-04-7
2+
* Basic ZMODEM support
3+
14
## [3.5.0] - 2023-04-20
25
* Support customizing word separators for selection [#160]. Thanks [@itzhoujun].
36
* Fix incorrect tab stop handling [#161]. Thanks [@itzhoujun].

example/lib/zmodem.dart

Lines changed: 3 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ import 'dart:io';
33
import 'dart:typed_data';
44

55
import 'package:dartssh2/dartssh2.dart';
6-
import 'package:example/src/virtual_keyboard.dart';
76
import 'package:file_picker/file_picker.dart';
87
import 'package:flutter/cupertino.dart';
98
import 'package:path/path.dart' as path;
@@ -37,9 +36,7 @@ class MyHomePage extends StatefulWidget {
3736
}
3837

3938
class _MyHomePageState extends State<MyHomePage> {
40-
late final terminal = Terminal(inputHandler: keyboard);
41-
42-
final keyboard = VirtualKeyboard(defaultInputHandler);
39+
late final terminal = Terminal();
4340

4441
var title = host;
4542

@@ -56,6 +53,7 @@ class _MyHomePageState extends State<MyHomePage> {
5653
await SSHSocket.connect(host, port),
5754
username: username,
5855
onPasswordRequest: () => password,
56+
printTrace: print,
5957
);
6058

6159
terminal.write('Connected\r\n');
@@ -165,14 +163,7 @@ class _MyHomePageState extends State<MyHomePage> {
165163
backgroundColor:
166164
CupertinoTheme.of(context).barBackgroundColor.withOpacity(0.5),
167165
),
168-
child: Column(
169-
children: [
170-
Expanded(
171-
child: TerminalView(terminal),
172-
),
173-
VirtualKeyboardView(keyboard),
174-
],
175-
),
166+
child: TerminalView(terminal),
176167
);
177168
}
178169
}

example/pubspec.lock

Lines changed: 1 addition & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -113,13 +113,6 @@ packages:
113113
url: "https://pub.dartlang.org"
114114
source: hosted
115115
version: "4.21.3"
116-
dart_console:
117-
dependency: transitive
118-
description:
119-
name: dart_console
120-
url: "https://pub.dartlang.org"
121-
source: hosted
122-
version: "1.1.2"
123116
dart_style:
124117
dependency: transitive
125118
description:
@@ -226,13 +219,6 @@ packages:
226219
url: "https://pub.dartlang.org"
227220
source: hosted
228221
version: "4.0.2"
229-
intl:
230-
dependency: transitive
231-
description:
232-
name: intl
233-
url: "https://pub.dartlang.org"
234-
source: hosted
235-
version: "0.17.0"
236222
js:
237223
dependency: transitive
238224
description:
@@ -461,7 +447,7 @@ packages:
461447
name: zmodem
462448
url: "https://pub.dartlang.org"
463449
source: hosted
464-
version: "0.0.4"
450+
version: "0.0.6"
465451
sdks:
466452
dart: ">=2.18.0 <3.0.0"
467453
flutter: ">=3.0.0"

example/test/widget_test.dart

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,10 +5,10 @@
55
// gestures. You can also use WidgetTester to find child widgets in the widget
66
// tree, read text, and verify that the values of widget properties are correct.
77

8-
import 'package:flutter/material.dart';
8+
// import 'package:flutter/material.dart';
99
import 'package:flutter_test/flutter_test.dart';
1010

11-
import 'package:example/main.dart';
11+
// import 'package:example/main.dart';
1212

1313
void main() {
1414
testWidgets('Counter increments smoke test', (WidgetTester tester) async {

lib/zmodem.dart

Lines changed: 40 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,7 @@ class ZModemMux {
5050
final Stream<Uint8List> stdout;
5151

5252
/// The sink to write data to the underlying data channel.
53-
final StreamSink stdin;
53+
final StreamSink<List<int>> stdin;
5454

5555
/// The callback to receive data that should be written to the terminal.
5656
ZModemInputHandler? onTerminalInput;
@@ -71,7 +71,7 @@ class ZModemMux {
7171
/// space is available in local buffers.
7272
late final StreamSubscription<Uint8List> _stdoutSubscription;
7373

74-
late final _terminalInputSink = StreamController<List<int>>(
74+
late final _terminalSink = StreamController<List<int>>(
7575
// onPause: _stdoutSubscription.pause,
7676
// onResume: _stdoutSubscription.resume,
7777
)
@@ -93,16 +93,13 @@ class ZModemMux {
9393
/// buffered if a ZModem session is active.
9494
void terminalWrite(String input) {
9595
if (_session == null) {
96-
print('-->t: ${input}');
9796
stdin.add(utf8.encode(input) as Uint8List);
9897
}
9998
}
10099

101100
/// This is the entry point of multiplexing, dispatching data to ZModem or
102101
/// terminal depending on the current state.
103102
void _handleStdout(Uint8List chunk) {
104-
print('<--: ${chunk.dump()}');
105-
106103
if (_session != null) {
107104
_handleZModem(chunk);
108105
return;
@@ -112,7 +109,7 @@ class ZModemMux {
112109
return;
113110
}
114111

115-
_terminalInputSink.add(chunk);
112+
_terminalSink.add(chunk);
116113
}
117114

118115
/// Detects a ZModem session in [chunk] and starts it if found. Returns true
@@ -122,12 +119,11 @@ class ZModemMux {
122119
chunk.listIndexOf(_zmodemReceiverInit);
123120

124121
if (index != null) {
125-
_terminalInputSink.add(Uint8List.sublistView(chunk, 0, index));
122+
_terminalSink.add(Uint8List.sublistView(chunk, 0, index));
126123

127124
_session = ZModemCore(
128-
onTrace: print,
129125
onPlainText: (text) {
130-
_terminalInputSink.add([text]);
126+
_terminalSink.add([text]);
131127
},
132128
);
133129

@@ -138,32 +134,29 @@ class ZModemMux {
138134
return false;
139135
}
140136

141-
void _handleZModem(Uint8List chunk) {
142-
print('_handleZModem');
143-
// print('bytes: ${chunk.map((e) => e.toRadixString(16)).toList()}');
144-
137+
void _handleZModem(Uint8List chunk) async {
145138
for (final event in _session!.receive(chunk)) {
146-
print('event: $event');
147-
148139
/// remote is sz
149140
if (event is ZFileOfferedEvent) {
150141
_handleZFileOfferedEvent(event);
151142
} else if (event is ZFileDataEvent) {
152143
_handleZFileDataEvent(event);
153144
} else if (event is ZFileEndEvent) {
154-
_handleZFileEndEvent(event);
145+
await _handleZFileEndEvent(event);
155146
} else if (event is ZSessionFinishedEvent) {
156-
_handleZSessionFinishedEvent(event);
147+
await _handleZSessionFinishedEvent(event);
157148
}
158149

159150
/// remote is rz
160151
else if (event is ZReadyToSendEvent) {
161-
_handleFileRequestEvent(event);
152+
await _handleFileRequestEvent(event);
162153
} else if (event is ZFileAcceptedEvent) {
163-
_handleFileAcceptedEvent(event);
154+
await _handleFileAcceptedEvent(event);
164155
} else if (event is ZFileSkippedEvent) {
165156
_handleFileSkippedEvent(event);
166157
}
158+
159+
_flush();
167160
}
168161

169162
_flush();
@@ -174,7 +167,6 @@ class ZModemMux {
174167

175168
if (onFileOffer == null) {
176169
_session!.skipFile();
177-
_flush();
178170
return;
179171
}
180172

@@ -185,37 +177,38 @@ class ZModemMux {
185177
_receiveSink!.add(event.data as Uint8List);
186178
}
187179

188-
void _handleZFileEndEvent(ZFileEndEvent event) async {
180+
Future<void> _handleZFileEndEvent(ZFileEndEvent event) async {
189181
await _closeReceiveSink();
190182
}
191183

192-
void _handleZSessionFinishedEvent(ZSessionFinishedEvent event) async {
184+
Future<void> _handleZSessionFinishedEvent(ZSessionFinishedEvent event) async {
185+
_flush();
193186
await _reset();
194187
}
195188

196-
void _handleFileRequestEvent(ZReadyToSendEvent event) async {
189+
Future<void> _handleFileRequestEvent(ZReadyToSendEvent event) async {
197190
_fileOffers ??= (await onFileRequest?.call())?.iterator;
198191

199192
_moveToNextOffer();
200193
}
201194

202-
void _handleFileAcceptedEvent(ZFileAcceptedEvent event) async {
195+
Future<void> _handleFileAcceptedEvent(ZFileAcceptedEvent event) async {
203196
final data = _fileOffers!.current.accept(event.offset);
204197
var bytesSent = 0;
205198

206-
final subscription = data.listen(
207-
(chunk) {
208-
bytesSent += chunk.length;
209-
print('bytesSent: $bytesSent');
210-
_session!.sendFileData(chunk);
211-
_flush();
212-
},
213-
onDone: () {
214-
print('bytesSent fin: $bytesSent');
215-
_session!.finishSending(event.offset + bytesSent);
216-
_flush();
217-
},
199+
await stdin.addStream(
200+
data.transform(
201+
StreamTransformer<Uint8List, Uint8List>.fromHandlers(
202+
handleData: (chunk, sink) {
203+
bytesSent += chunk.length;
204+
_session!.sendFileData(chunk);
205+
sink.add(_session!.dataToSend());
206+
},
207+
),
208+
),
218209
);
210+
211+
_session!.finishSending(event.offset + bytesSent);
219212
}
220213

221214
void _handleFileSkippedEvent(ZFileSkippedEvent event) {
@@ -225,16 +218,12 @@ class ZModemMux {
225218

226219
/// Sends next file offer if available, or closes the session if not.
227220
void _moveToNextOffer() {
228-
print('_offerNextFileIfNeeded');
229-
230221
if (_fileOffers?.moveNext() != true) {
231-
print('no more files');
232222
_closeSession();
233223
return;
234224
}
235225

236226
_session!.offerFile(_fileOffers!.current.info);
237-
_flush();
238227
}
239228

240229
/// Creates a [ZModemOffer] ƒrom the info from remote peer that can be used
@@ -258,20 +247,24 @@ class ZModemMux {
258247

259248
void _createReceiveSink() {
260249
_receiveSink = StreamController<Uint8List>(
261-
// onPause: _stdoutSubscription.pause,
262-
onResume: _stdoutSubscription.resume,
250+
onPause: () {
251+
// _stdoutSubscription.pause();
252+
},
253+
onResume: () {
254+
// _stdoutSubscription.resume();
255+
},
263256
);
264257
}
265258

266259
Future<void> _closeReceiveSink() async {
260+
_stdoutSubscription.resume();
267261
await _receiveSink?.close();
268262
_receiveSink = null;
269263
}
270264

271265
/// Requests remote to close the session.
272-
Future<void> _closeSession() async {
266+
void _closeSession() {
273267
_session!.finishSession();
274-
_flush();
275268
}
276269

277270
/// Clears all ZModem state.
@@ -284,15 +277,14 @@ class ZModemMux {
284277
/// Sends all pending data packets to the remote. No data is automatically
285278
/// sent to the remote without calling this method.
286279
void _flush() {
287-
final dataToSend = _session!.dataToSend();
288-
if (dataToSend.isNotEmpty) {
289-
// print('-->: ${dataToSend.dump()}');
280+
final dataToSend = _session?.dataToSend();
281+
if (dataToSend != null && dataToSend.isNotEmpty) {
290282
stdin.add(dataToSend);
291283
}
292284
}
293285
}
294286

295-
extension on List<int> {
287+
extension ListExtension on List<int> {
296288
String dump() {
297289
return map((e) => e.toRadixString(16).padLeft(2, '0')).join(' ');
298290
}

pubspec.lock

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -582,7 +582,7 @@ packages:
582582
name: zmodem
583583
url: "https://pub.dartlang.org"
584584
source: hosted
585-
version: "0.0.5"
585+
version: "0.0.6"
586586
sdks:
587587
dart: ">=2.18.0 <3.0.0"
588588
flutter: ">=3.0.0"

pubspec.yaml

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
name: xterm
22
description: xterm.dart is a fast and fully-featured terminal emulator for Flutter applications, with support for mobile and desktop platforms.
3-
version: 3.5.0
3+
version: 3.6.0-pre
44
homepage: https://github.com/TerminalStudio/xterm.dart
55

66
environment:
@@ -15,7 +15,7 @@ dependencies:
1515
equatable: ^2.0.3
1616
flutter:
1717
sdk: flutter
18-
zmodem: ^0.0.5
18+
zmodem: ^0.0.6
1919

2020
dev_dependencies:
2121
flutter_test:

0 commit comments

Comments
 (0)