Line data Source code
1 : import 'dart:async';
2 : import 'dart:typed_data';
3 :
4 : import 'package:matrix/encryption.dart';
5 : import 'package:matrix/matrix.dart';
6 : import 'package:matrix/src/utils/compute_callback.dart';
7 : import 'package:matrix/src/utils/crypto/encrypted_file.dart' as crypto_file;
8 :
9 : /// provides native implementations for demanding arithmetic operations
10 : /// in order to prevent the UI from blocking
11 : ///
12 : /// possible implementations might be:
13 : /// - native code
14 : /// - another Dart isolate
15 : /// - a web worker
16 : /// - a dummy implementations
17 : ///
18 : /// Rules for extension (important for [noSuchMethod] implementations)
19 : /// - always only accept exactly *one* positioned argument
20 : /// - catch the corresponding case in [NativeImplementations.noSuchMethod]
21 : /// - always write a dummy implementations
22 : abstract class NativeImplementations {
23 83 : const NativeImplementations();
24 :
25 : /// a dummy implementation executing all calls in the same thread causing
26 : /// the UI to likely freeze
27 : static const dummy = NativeImplementationsDummy();
28 :
29 : FutureOr<RoomKeys> generateUploadKeys(
30 : GenerateUploadKeysArgs args, {
31 : bool retryInDummy = true,
32 : });
33 :
34 : FutureOr<Uint8List> keyFromPassphrase(
35 : KeyFromPassphraseArgs args, {
36 : bool retryInDummy = true,
37 : });
38 :
39 : FutureOr<EncryptedFile> encryptFile(
40 : Uint8List bytes, {
41 : bool retryInDummy = true,
42 : });
43 :
44 : FutureOr<Uint8List?> decryptFile(
45 : EncryptedFile file, {
46 : bool retryInDummy = true,
47 : });
48 :
49 : FutureOr<MatrixImageFileResizedResponse?> shrinkImage(
50 : MatrixImageFileResizeArguments args, {
51 : bool retryInDummy = false,
52 : });
53 :
54 : FutureOr<MatrixImageFileResizedResponse?> calcImageMetadata(
55 : Uint8List bytes, {
56 : bool retryInDummy = false,
57 : });
58 :
59 : /// this implementation will catch any non-implemented method
60 0 : @override
61 : dynamic noSuchMethod(Invocation invocation) {
62 0 : final dynamic argument = invocation.positionalArguments.single;
63 0 : final memberName = invocation.memberName.toString().split('"')[1];
64 :
65 0 : Logs().d(
66 : 'Missing implementations of Client.nativeImplementations.$memberName. '
67 : 'You should consider implementing it. '
68 : 'Fallback from NativeImplementations.dummy used.',
69 : );
70 : switch (memberName) {
71 : // we need to pass the futures right through or we will run into type errors later!
72 0 : case 'generateUploadKeys':
73 : // ignore: discarded_futures
74 0 : return dummy.generateUploadKeys(argument);
75 0 : case 'keyFromPassphrase':
76 : // ignore: discarded_futures
77 0 : return dummy.keyFromPassphrase(argument);
78 0 : case 'decryptFile':
79 : // ignore: discarded_futures
80 0 : return dummy.decryptFile(argument);
81 0 : case 'shrinkImage':
82 0 : return dummy.shrinkImage(argument);
83 0 : case 'calcImageMetadata':
84 0 : return dummy.calcImageMetadata(argument);
85 : default:
86 0 : return super.noSuchMethod(invocation);
87 : }
88 : }
89 : }
90 :
91 : class NativeImplementationsDummy extends NativeImplementations {
92 83 : const NativeImplementationsDummy();
93 :
94 1 : @override
95 : Future<EncryptedFile> encryptFile(
96 : Uint8List bytes, {
97 : bool retryInDummy = true,
98 : }) {
99 1 : return crypto_file.encryptFile(bytes);
100 : }
101 :
102 1 : @override
103 : Future<Uint8List?> decryptFile(
104 : EncryptedFile file, {
105 : bool retryInDummy = true,
106 : }) {
107 1 : return decryptFileImplementation(file);
108 : }
109 :
110 4 : @override
111 : Future<RoomKeys> generateUploadKeys(
112 : GenerateUploadKeysArgs args, {
113 : bool retryInDummy = true,
114 : }) async {
115 4 : return generateUploadKeysImplementation(args);
116 : }
117 :
118 2 : @override
119 : Future<Uint8List> keyFromPassphrase(
120 : KeyFromPassphraseArgs args, {
121 : bool retryInDummy = true,
122 : }) {
123 2 : return generateKeyFromPassphrase(args);
124 : }
125 :
126 3 : @override
127 : MatrixImageFileResizedResponse? shrinkImage(
128 : MatrixImageFileResizeArguments args, {
129 : bool retryInDummy = false,
130 : }) {
131 3 : return MatrixImageFile.resizeImplementation(args);
132 : }
133 :
134 2 : @override
135 : MatrixImageFileResizedResponse? calcImageMetadata(
136 : Uint8List bytes, {
137 : bool retryInDummy = false,
138 : }) {
139 2 : return MatrixImageFile.calcMetadataImplementation(bytes);
140 : }
141 : }
142 :
143 : /// a [NativeImplementations] based on Flutter's `compute` function
144 : ///
145 : /// this implementations simply wraps the given [compute] function around
146 : /// the implementation of [NativeImplementations.dummy]
147 : class NativeImplementationsIsolate extends NativeImplementations {
148 : /// pass by Flutter's compute function here
149 : final ComputeCallback compute;
150 :
151 0 : NativeImplementationsIsolate(this.compute);
152 :
153 : /// creates a [NativeImplementationsIsolate] based on a [ComputeRunner] as
154 : // ignore: deprecated_member_use_from_same_package
155 : /// known from [Client.runInBackground]
156 0 : factory NativeImplementationsIsolate.fromRunInBackground(
157 : ComputeRunner runInBackground) {
158 0 : return NativeImplementationsIsolate(
159 0 : computeCallbackFromRunInBackground(runInBackground),
160 : );
161 : }
162 :
163 0 : Future<T> runInBackground<T, U>(
164 : FutureOr<T> Function(U arg) function, U arg) async {
165 0 : final compute = this.compute;
166 0 : return await compute(function, arg);
167 : }
168 :
169 0 : @override
170 : Future<EncryptedFile> encryptFile(
171 : Uint8List bytes, {
172 : bool retryInDummy = true,
173 : }) {
174 0 : return runInBackground<EncryptedFile, Uint8List>(
175 0 : NativeImplementations.dummy.encryptFile,
176 : bytes,
177 : );
178 : }
179 :
180 0 : @override
181 : Future<Uint8List?> decryptFile(
182 : EncryptedFile file, {
183 : bool retryInDummy = true,
184 : }) {
185 0 : return runInBackground<Uint8List?, EncryptedFile>(
186 0 : NativeImplementations.dummy.decryptFile,
187 : file,
188 : );
189 : }
190 :
191 0 : @override
192 : Future<RoomKeys> generateUploadKeys(
193 : GenerateUploadKeysArgs args, {
194 : bool retryInDummy = true,
195 : }) async {
196 0 : return runInBackground<RoomKeys, GenerateUploadKeysArgs>(
197 0 : NativeImplementations.dummy.generateUploadKeys,
198 : args,
199 : );
200 : }
201 :
202 0 : @override
203 : Future<Uint8List> keyFromPassphrase(
204 : KeyFromPassphraseArgs args, {
205 : bool retryInDummy = true,
206 : }) {
207 0 : return runInBackground<Uint8List, KeyFromPassphraseArgs>(
208 0 : NativeImplementations.dummy.keyFromPassphrase,
209 : args,
210 : );
211 : }
212 :
213 0 : @override
214 : Future<MatrixImageFileResizedResponse?> shrinkImage(
215 : MatrixImageFileResizeArguments args, {
216 : bool retryInDummy = false,
217 : }) {
218 0 : return runInBackground<MatrixImageFileResizedResponse?,
219 : MatrixImageFileResizeArguments>(
220 0 : NativeImplementations.dummy.shrinkImage,
221 : args,
222 : );
223 : }
224 :
225 0 : @override
226 : FutureOr<MatrixImageFileResizedResponse?> calcImageMetadata(
227 : Uint8List bytes, {
228 : bool retryInDummy = false,
229 : }) {
230 0 : return runInBackground<MatrixImageFileResizedResponse?, Uint8List>(
231 0 : NativeImplementations.dummy.calcImageMetadata,
232 : bytes,
233 : );
234 : }
235 : }
|