Line data Source code
1 : import 'dart:io';
2 : import 'dart:typed_data';
3 :
4 : import 'package:path/path.dart';
5 :
6 : import 'package:matrix/matrix.dart';
7 :
8 : mixin DatabaseFileStorage {
9 82 : bool get supportsFileStoring => fileStorageLocation != null;
10 :
11 : late final Uri? fileStorageLocation;
12 : late final Duration? deleteFilesAfterDuration;
13 :
14 : /// Map an MXC URI to a local File path
15 0 : File _getFileFromMxc(Uri mxcUri) {
16 : // Replace all special characters with underscores to avoid PathNotFoundException on Windows.
17 0 : final host = mxcUri.host.replaceAll('.', '_');
18 0 : final path = mxcUri.pathSegments.join('_');
19 0 : final query = mxcUri.queryParameters.entries
20 0 : .map((entry) => '${entry.key}${entry.value}')
21 0 : .join('_');
22 0 : final fileName = '${host}_${path}_$query';
23 0 : return File(
24 0 : join(Directory.fromUri(fileStorageLocation!).path, fileName),
25 : );
26 : }
27 :
28 5 : Future<void> storeFile(Uri mxcUri, Uint8List bytes, int time) async {
29 5 : final fileStorageLocation = this.fileStorageLocation;
30 5 : if (!supportsFileStoring || fileStorageLocation == null) return;
31 :
32 0 : final file = _getFileFromMxc(mxcUri);
33 :
34 0 : if (await file.exists()) return;
35 0 : await file.writeAsBytes(bytes);
36 : }
37 :
38 2 : Future<Uint8List?> getFile(Uri mxcUri) async {
39 2 : final fileStorageLocation = this.fileStorageLocation;
40 2 : if (!supportsFileStoring || fileStorageLocation == null) return null;
41 :
42 0 : final file = _getFileFromMxc(mxcUri);
43 :
44 0 : if (await file.exists()) return await file.readAsBytes();
45 : return null;
46 : }
47 :
48 1 : Future<bool> deleteFile(Uri mxcUri) async {
49 1 : final fileStorageLocation = this.fileStorageLocation;
50 1 : if (!supportsFileStoring || fileStorageLocation == null) return false;
51 :
52 0 : final file = _getFileFromMxc(mxcUri);
53 :
54 0 : if (await file.exists() == false) return false;
55 :
56 0 : await file.delete();
57 : return true;
58 : }
59 :
60 41 : Future<void> deleteOldFiles(int savedAt) async {
61 41 : final dirUri = fileStorageLocation;
62 41 : final deleteFilesAfterDuration = this.deleteFilesAfterDuration;
63 41 : if (!supportsFileStoring ||
64 : dirUri == null ||
65 : deleteFilesAfterDuration == null) {
66 : return;
67 : }
68 0 : final dir = Directory.fromUri(dirUri);
69 0 : final entities = await dir.list().toList();
70 0 : for (final file in entities) {
71 0 : if (file is! File) continue;
72 0 : final stat = await file.stat();
73 0 : if (DateTime.now().difference(stat.modified) > deleteFilesAfterDuration) {
74 0 : Logs().v('Delete old file', file.path);
75 0 : await file.delete();
76 : }
77 : }
78 : }
79 : }
|