Aves_mio0.88/lib/remote/remote_db_uris.dart
2026-10-03 12:51:15 +02:00

143 lines
4 KiB
Dart

// lib/remote/remote_db_uris.dart
import 'dart:convert';
class RemoteDbUris {
// Schema personalizzato che non attiva ContentResolver.
static const _scheme = 'aves-remote';
static const _hostRemoteId = 'rid';
static const _hostRemotePath = 'path';
static const _hostAnon = 'anon';
/// Costruisce un URI fittizio univoco e stabile per un elemento remoto.
///
/// Priorità:
/// 1. remoteId, se presente
/// 2. remotePath, se presente
/// 3. anon, fallback estremo non stabile
///
/// Esempi:
/// - `aves-remote://rid/<remoteId>`
/// - `aves-remote://path/<base64url(remotePath)>`
/// - `aves-remote://anon/<timestamp>`
static String make({String? remoteId, String? remotePath}) {
final rid = remoteId?.trim();
if (rid != null && rid.isNotEmpty) {
return '$_scheme://$_hostRemoteId/${Uri.encodeComponent(rid)}';
}
final path = remotePath?.trim();
if (path != null && path.isNotEmpty) {
final b64 = base64Url.encode(utf8.encode(path));
return '$_scheme://$_hostRemotePath/$b64';
}
// Estremo fallback, pochissimo probabile.
// Nota: non è stabile tra sync diversi, quindi non usarlo se puoi evitarlo.
return '$_scheme://$_hostAnon/${DateTime.now().microsecondsSinceEpoch}';
}
/// Riconosce se un URI è fittizio remoto.
static bool isSynthetic(String? uri) {
if (uri == null) return false;
final raw = uri.trim();
if (raw.isEmpty) return false;
final parsed = Uri.tryParse(raw);
return parsed != null && parsed.scheme == _scheme;
}
/// Estrae il remoteId da un URI remoto sintetico.
///
/// Formato supportato:
/// `aves-remote://rid/<remoteId>`
///
/// Esempio:
/// `aves-remote://rid/f46da4...`
///
/// Ritorna:
/// `f46da4...`
static String? remoteIdFromUri(String? uri) {
final parsed = _tryParseSynthetic(uri);
if (parsed == null) return null;
if (parsed.host != _hostRemoteId) return null;
if (parsed.pathSegments.isEmpty) return null;
final rid = Uri.decodeComponent(parsed.pathSegments.first).trim();
return rid.isEmpty ? null : rid;
}
/// Estrae il remotePath da un URI remoto sintetico.
///
/// Formato supportato:
/// `aves-remote://path/<base64url(remotePath)>`
static String? remotePathFromUri(String? uri) {
final parsed = _tryParseSynthetic(uri);
if (parsed == null) return null;
if (parsed.host != _hostRemotePath) return null;
if (parsed.pathSegments.isEmpty) return null;
final encoded = parsed.pathSegments.first.trim();
if (encoded.isEmpty) return null;
try {
return utf8.decode(base64Url.decode(encoded)).trim();
} catch (_) {
return null;
}
}
/// Ritorna true se l'URI contiene un remoteId estraibile.
static bool hasRemoteId(String? uri) {
return remoteIdFromUri(uri) != null;
}
/// Ritorna true se l'URI contiene un remotePath estraibile.
static bool hasRemotePath(String? uri) {
return remotePathFromUri(uri) != null;
}
/// Ricostruisce una URI canonica partendo da una URI esistente.
///
/// Utile se in futuro vuoi normalizzare formati vecchi.
///
/// Per ora:
/// - se contiene remoteId, rigenera da remoteId;
/// - se contiene remotePath, rigenera da remotePath;
/// - altrimenti ritorna l'URI originale se sintetica;
/// - altrimenti null.
static String? normalize(String? uri) {
if (!isSynthetic(uri)) return null;
final rid = remoteIdFromUri(uri);
if (rid != null && rid.isNotEmpty) {
return make(remoteId: rid);
}
final path = remotePathFromUri(uri);
if (path != null && path.isNotEmpty) {
return make(remotePath: path);
}
final raw = uri?.trim();
return raw == null || raw.isEmpty ? null : raw;
}
/// Helper interno: parse sicuro solo per URI sintetiche remote.
static Uri? _tryParseSynthetic(String? uri) {
if (uri == null) return null;
final raw = uri.trim();
if (raw.isEmpty) return null;
final parsed = Uri.tryParse(raw);
if (parsed == null) return null;
if (parsed.scheme != _scheme) return null;
return parsed;
}
}