JJ_MKVMaker/lib/core/remote_registry.dart

80 lines
3.3 KiB
Dart

/// 약속 (modular_sync #6 · F11): 원격 서버 등록 하나 - 설정의 서버 목록 ([RemoteRegistry.configure]) → 서버 id 마다 클라이언트 하나
/// ([RemoteRegistry.client]). WebDAV · SFTP · SMB · FTP 가 같은 몸통을 쓰고, 서버마다 다른 것은 셋뿐: 비밀 값 목록 · "설정 없음" 오류 · 만들기.
/// 다시 접속 (예전 클라이언트를 닫고 다음에 새로) 하는 바뀜 - 예전 4벌과 똑같이 (관리자 10/24 조건 ①):
/// 서버를 지움 · 새로 들어옴 · toJson 이 다름 (비밀이 아닌 모든 칸: 주소 · 포트 · 사용자 · 루트 · 보안 · 지문 · 공유 · 도메인 · insecure …) ·
/// 비밀 값이 다름 (WebDAV · SMB · FTP = password, SFTP = password · privateKey · keyPassphrase)
/// 문 ([requireSecretGate]): 비밀 값이 있으면 마스터 확인 (SecretGate) 을 지나야 연다 - 못 지나면 [DavLockedException] (연결 전에)
library;
import 'dart:convert';
import '../l10n/tr.dart';
import 'remote_fs.dart';
import 'secret_gate.dart';
import 'webdav.dart' show DavLockedException;
class RemoteRegistry<S, C extends RemoteClient> {
RemoteRegistry({required this.idOf, required this.toJson, required this.secretsOf, required this.create, required this.missing, this.onDrop});
final String Function(S server) idOf;
final Map<String, Object?> Function(S server) toJson;
/// 비밀 값들 (toJson 에 없는 것 - 바뀌면 다시 접속)
final List<String> Function(S server) secretsOf;
final C Function(S server) create;
/// 등록에 없는 id 로 [client] 를 부를 때의 오류
final Exception Function(String id) missing;
/// 클라이언트를 버릴 때 (다시 접속 · 지움) - SMB 의 지난 연결 서명 기록 지우기 등
final void Function(String id)? onDrop;
final _clients = <String, C>{};
final _servers = <String, S>{};
bool _same(S old, S now) {
final a = secretsOf(old), b = secretsOf(now);
if (a.length != b.length) return false;
for (var i = 0; i < a.length; i++) {
if (a[i] != b[i]) return false;
}
return jsonEncode(toJson(old)) == jsonEncode(toJson(now));
}
void configure(List<S> servers) {
final keep = {for (final s in servers) idOf(s): s};
for (final id in _clients.keys.toList()) {
final old = _servers[id], now = keep[id];
if (now == null || old == null || !_same(old, now)) {
_clients.remove(id)?.close();
onDrop?.call(id);
}
}
_servers
..clear()
..addAll(keep);
}
List<S> get servers => _servers.values.toList();
S? server(String id) => _servers[id];
/// 열린 클라이언트를 모두 닫는다 (다음 [client] 에서 새로 - 연결 규칙이 바뀐 때)
void closeAll() {
for (final c in _clients.values) {
c.close();
}
_clients.clear();
}
C client(String id) {
final s = _servers[id];
if (s == null) throw missing(id);
return _clients.putIfAbsent(id, () => create(s));
}
}
/// 문: 비밀 값이 있으면 마스터 확인을 지나야 한다 (못 지나면 연결 전에 [DavLockedException]). 비밀 값이 없으면 묻지 않는다
Future<void> requireSecretGate(bool hasSecret) async {
if (hasSecret && !await SecretGate.pass()) throw DavLockedException(tr(secretGateMessage));
}