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 0 : return NativeImplementationsIsolate(
145 0 : computeCallbackFromRunInBackground(runInBackground),
146 : );
147 : }
148 :
149 0 : Future<T> runInBackground<T, U>(
150 : FutureOr<T> Function(U arg) function, U arg) async {
151 0 : final compute = this.compute;
152 0 : return await compute(function, arg);
153 : }
154 :
155 0 : @override
156 : Future<Uint8List?> decryptFile(
157 : EncryptedFile file, {
158 : bool retryInDummy = true,
159 : }) {
160 0 : return runInBackground<Uint8List?, EncryptedFile>(
161 0 : NativeImplementations.dummy.decryptFile,
162 : file,
163 : );
164 : }
165 :
166 0 : @override
167 : Future<RoomKeys> generateUploadKeys(
168 : GenerateUploadKeysArgs args, {
169 : bool retryInDummy = true,
170 : }) async {
171 0 : return runInBackground<RoomKeys, GenerateUploadKeysArgs>(
172 0 : NativeImplementations.dummy.generateUploadKeys,
173 : args,
174 : );
175 : }
176 :
177 0 : @override
178 : Future<Uint8List> keyFromPassphrase(
179 : KeyFromPassphraseArgs args, {
180 : bool retryInDummy = true,
181 : }) {
182 0 : return runInBackground<Uint8List, KeyFromPassphraseArgs>(
183 0 : NativeImplementations.dummy.keyFromPassphrase,
184 : args,
185 : );
186 : }
187 :
188 0 : @override
189 : Future<MatrixImageFileResizedResponse?> shrinkImage(
190 : MatrixImageFileResizeArguments args, {
191 : bool retryInDummy = false,
192 : }) {
193 0 : return runInBackground<MatrixImageFileResizedResponse?,
194 : MatrixImageFileResizeArguments>(
195 0 : NativeImplementations.dummy.shrinkImage,
196 : args,
197 : );
198 : }
199 :
200 0 : @override
201 : FutureOr<MatrixImageFileResizedResponse?> calcImageMetadata(
202 : Uint8List bytes, {
203 : bool retryInDummy = false,
204 : }) {
205 0 : return runInBackground<MatrixImageFileResizedResponse?, Uint8List>(
206 0 : NativeImplementations.dummy.calcImageMetadata,
207 : bytes,
208 : );
209 : }
210 : }
|