Initial commit

This commit is contained in:
gasaichandesu
2025-08-30 19:47:42 +04:00
commit 58d7808a8d
100 changed files with 6186 additions and 0 deletions
@@ -0,0 +1,64 @@
import 'dart:async';
import 'dart:io';
import 'package:crypto/crypto.dart' as c;
import 'package:injectable/injectable.dart';
import 'package:moonwell_launcher/features/downloader/domain/repositories/file_system.dart';
@LazySingleton(as: FileSystem)
class IoFileSystem implements FileSystem {
@override
Future<void> ensureParentExists(String path) =>
File(path).parent.create(recursive: true);
@override
Future<bool> exists(String path) => File(path).exists();
@override
Future<int> sizeOf(String path) async => (await File(path).stat()).size;
@override
Future<void> truncate(String path) async =>
File(path).writeAsBytes(const [], flush: true);
@override
Future<void> createEmpty(String path) => File(path).create(recursive: true);
@override
Future<StreamSink<List<int>>> openAppend(String path) async =>
File(path).openWrite(mode: FileMode.append);
@override
Future<bool> verifyFile(
String path, {
required String expected,
required String algo,
}) async {
final file = File(path);
if (!await file.exists()) return false;
final digestHex = await _computeDigestHex(file, algo);
return _constantTimeEquals(digestHex.toLowerCase(), expected.toLowerCase());
}
Future<String> _computeDigestHex(File file, String algo) async {
final hash = switch (algo.toLowerCase()) {
'md5' => c.md5,
'sha256' => c.sha256,
_ => throw ArgumentError('Unsupported checksum algo: $algo'),
};
// Stream the file into the hash converter; no extra buffers.
final digest = await hash.bind(file.openRead()).first; // -> c.Digest
return digest.toString(); // lowercase hex
}
bool _constantTimeEquals(String a, String b) {
if (a.length != b.length) return false;
var result = 0;
for (var i = 0; i < a.length; i++) {
result |= a.codeUnitAt(i) ^ b.codeUnitAt(i);
}
return result == 0;
}
}
@@ -0,0 +1,30 @@
import 'package:injectable/injectable.dart';
import 'package:minio/minio.dart';
import 'package:moonwell_launcher/features/downloader/domain/entities/remote_object_meta.dart';
import 'package:moonwell_launcher/features/downloader/domain/repositories/storage_reader.dart';
/// MinIO storage reader implementation.
@LazySingleton(as: StorageReader)
class MinioStorageReader implements StorageReader {
final Minio _client;
MinioStorageReader(this._client);
@override
Future<Stream<List<int>>> readFromOffset({
required String bucket,
required String key,
required int startOffset,
}) {
return _client.getPartialObject(bucket, key, startOffset);
}
@override
Future<RemoteObjectMeta> stat({
required String bucket,
required String key,
}) async {
final s = await _client.statObject(bucket, key);
return RemoteObjectMeta(size: s.size ?? 0, eTag: s.etag ?? '');
}
}