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