130 lines
4.2 KiB
Dart
130 lines
4.2 KiB
Dart
|
|
import 'dart:convert';
|
||
|
|
import 'dart:typed_data';
|
||
|
|
import '../datasources/local_database.dart';
|
||
|
|
import '../datasources/backend_api.dart';
|
||
|
|
import '../../core/constants/app_constants.dart';
|
||
|
|
import '../../core/errors/exceptions.dart';
|
||
|
|
import '../../core/utils/retry_utils.dart';
|
||
|
|
import '../../domain/entities/contenedor.dart';
|
||
|
|
import '../../domain/entities/destino.dart';
|
||
|
|
import '../../domain/entities/pendiente.dart';
|
||
|
|
|
||
|
|
class ContenedorRepository {
|
||
|
|
final BackendApi _api = BackendApi();
|
||
|
|
|
||
|
|
Future<Map<String, dynamic>> enviar(Contenedor contenedor, Destino destino) async {
|
||
|
|
try {
|
||
|
|
final result = await _api.enviarContenedor(contenedor, destino);
|
||
|
|
await _registrarEnvio(contenedor, destino, result);
|
||
|
|
return result;
|
||
|
|
} catch (e) {
|
||
|
|
await _agregarAPendientes(contenedor, destino);
|
||
|
|
rethrow;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> _registrarEnvio(
|
||
|
|
Contenedor contenedor,
|
||
|
|
Destino destino,
|
||
|
|
Map<String, dynamic> response,
|
||
|
|
) async {
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
await db.insert('registro', {
|
||
|
|
'hash': contenedor.hash,
|
||
|
|
'titulo': contenedor.titulo,
|
||
|
|
'hora_envio': DateTime.now().toIso8601String(),
|
||
|
|
'primera_conf': response['received_at'],
|
||
|
|
'ultima_conf': response['received_at'],
|
||
|
|
'destino_id': destino.id,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
// Pendientes
|
||
|
|
Future<void> _agregarAPendientes(Contenedor contenedor, Destino destino) async {
|
||
|
|
final count = await getPendientesCount();
|
||
|
|
if (count >= AppConstants.maxPendientes) {
|
||
|
|
throw QueueFullException();
|
||
|
|
}
|
||
|
|
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
final contenidoJson = jsonEncode(contenedor.toJson());
|
||
|
|
|
||
|
|
await db.insert('pendientes', {
|
||
|
|
'hash': contenedor.hash,
|
||
|
|
'titulo': contenedor.titulo,
|
||
|
|
'contenido': Uint8List.fromList(utf8.encode(contenidoJson)),
|
||
|
|
'intentos': 1,
|
||
|
|
'ultimo_intento': DateTime.now().toIso8601String(),
|
||
|
|
'proximo_intento': RetryUtils.calculateNextRetry(1).toIso8601String(),
|
||
|
|
'destino_id': destino.id,
|
||
|
|
});
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<int> getPendientesCount() async {
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
final result = await db.rawQuery('SELECT COUNT(*) as count FROM pendientes');
|
||
|
|
return result.first['count'] as int;
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<List<Pendiente>> getPendientes() async {
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
final results = await db.query('pendientes', orderBy: 'ultimo_intento DESC');
|
||
|
|
return results.map((m) => Pendiente.fromMap(m)).toList();
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> reintentar(Pendiente pendiente, Destino destino) async {
|
||
|
|
if (!pendiente.puedeReintentar) return;
|
||
|
|
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
final contenidoStr = utf8.decode(pendiente.contenido);
|
||
|
|
final contenidoJson = jsonDecode(contenidoStr) as Map<String, dynamic>;
|
||
|
|
|
||
|
|
// Reconstruct basic contenedor for retry
|
||
|
|
final contenedor = Contenedor(
|
||
|
|
hash: contenidoJson['hash'] as String,
|
||
|
|
titulo: contenidoJson['titulo'] as String?,
|
||
|
|
descripcion: contenidoJson['descripcion'] as String?,
|
||
|
|
etiquetas: (contenidoJson['etiquetas'] as List<dynamic>?)
|
||
|
|
?.map((e) => e as String)
|
||
|
|
.toList() ??
|
||
|
|
[],
|
||
|
|
);
|
||
|
|
|
||
|
|
try {
|
||
|
|
await _api.enviarContenedor(contenedor, destino);
|
||
|
|
await db.delete('pendientes', where: 'hash = ?', whereArgs: [pendiente.hash]);
|
||
|
|
} catch (e) {
|
||
|
|
final nuevoIntento = pendiente.intentos + 1;
|
||
|
|
if (nuevoIntento >= AppConstants.maxReintentos) {
|
||
|
|
// Keep in queue but mark as exhausted
|
||
|
|
await db.update(
|
||
|
|
'pendientes',
|
||
|
|
{
|
||
|
|
'intentos': nuevoIntento,
|
||
|
|
'ultimo_intento': DateTime.now().toIso8601String(),
|
||
|
|
'proximo_intento': null,
|
||
|
|
},
|
||
|
|
where: 'hash = ?',
|
||
|
|
whereArgs: [pendiente.hash],
|
||
|
|
);
|
||
|
|
} else {
|
||
|
|
await db.update(
|
||
|
|
'pendientes',
|
||
|
|
{
|
||
|
|
'intentos': nuevoIntento,
|
||
|
|
'ultimo_intento': DateTime.now().toIso8601String(),
|
||
|
|
'proximo_intento': RetryUtils.calculateNextRetry(nuevoIntento).toIso8601String(),
|
||
|
|
},
|
||
|
|
where: 'hash = ?',
|
||
|
|
whereArgs: [pendiente.hash],
|
||
|
|
);
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
Future<void> eliminarPendiente(String hash) async {
|
||
|
|
final db = await LocalDatabase.database;
|
||
|
|
await db.delete('pendientes', where: 'hash = ?', whereArgs: [hash]);
|
||
|
|
}
|
||
|
|
}
|