56 lines
2.1 KiB
Dart
56 lines
2.1 KiB
Dart
import 'dart:async';
|
|
import 'dart:convert';
|
|
import 'dart:io';
|
|
|
|
import 'package:path/path.dart' as p;
|
|
|
|
/// 88: SFTP 시험 서버 (tool/sftp_test_server.py, paramiko 3.5.1). 파이썬은 JJ_SFTP_PY, 없으면 ..\tools\sftp_test_py 의 venv
|
|
final sftpTestPython = Platform.environment['JJ_SFTP_PY'] ??
|
|
p.normalize(p.join(Directory.current.path, '..', 'tools', 'sftp_test_py', Platform.isWindows ? 'Scripts/python.exe' : 'bin/python'));
|
|
|
|
/// 시험 서버를 띄울 수 있는지 (없으면 그 시험은 건너뛴다)
|
|
bool get sftpTestServerAvailable => File(sftpTestPython).existsSync();
|
|
|
|
class SftpTestServer {
|
|
final Process process;
|
|
final int port;
|
|
|
|
/// 서버 호스트 키의 지문 ("SHA256:…")
|
|
final String fingerprint;
|
|
SftpTestServer._(this.process, this.port, this.fingerprint);
|
|
|
|
/// [root] 폴더를 내놓는 서버. [hostKeyFile] 이 없으면 만든다 (같은 파일이면 같은 키)
|
|
static Future<SftpTestServer> start({
|
|
required String root,
|
|
required String hostKeyFile,
|
|
String user = 'jj',
|
|
String? password = 'pw',
|
|
String? pubkey,
|
|
String keytype = 'ed25519',
|
|
bool legacyOnly = false,
|
|
}) async {
|
|
final pr = await Process.start(sftpTestPython, [
|
|
'tool/sftp_test_server.py',
|
|
'--root', root,
|
|
'--hostkey', hostKeyFile,
|
|
'--keytype', keytype,
|
|
'--user', user,
|
|
if (password != null) ...['--password', password],
|
|
if (pubkey != null) ...['--pubkey', pubkey],
|
|
if (legacyOnly) '--legacy-only',
|
|
]);
|
|
final lines = pr.stdout.transform(utf8.decoder).transform(const LineSplitter()).asBroadcastStream();
|
|
pr.stderr.drain<void>();
|
|
final port = int.parse((await lines.firstWhere((l) => l.startsWith('PORT '))).split(' ')[1]);
|
|
final fp = (await lines.firstWhere((l) => l.startsWith('FINGERPRINT '))).split(' ')[1];
|
|
return SftpTestServer._(pr, port, fp);
|
|
}
|
|
|
|
/// 끝내기 (표준 입력을 닫으면 서버가 끝난다)
|
|
Future<void> stop() async {
|
|
await process.stdin.close().catchError((_) {});
|
|
process.kill();
|
|
await process.exitCode.timeout(const Duration(seconds: 5), onTimeout: () => -1);
|
|
}
|
|
}
|