143 lines
4 KiB
Dart
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;
|
|
}
|
|
}
|