LCOV - code coverage report
Current view: top level - lib/src/utils - native_implementations.dart (source / functions) Coverage Total Hit
Test: merged.info Lines: 23.1 % 52 12
Test Date: 2025-10-13 02:23:18 Functions: - 0 0

            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           90 :   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           90 :   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              :   final Future<void> Function()? vodozemacInit;
     137              : 
     138            0 :   NativeImplementationsIsolate(
     139              :     this.compute, {
     140              :     /// To generate upload keys, vodozemac needs to be initialized in the isolate.
     141              :     this.vodozemacInit,
     142              :   });
     143              : 
     144            0 :   Future<T> runInBackground<T, U>(
     145              :     FutureOr<T> Function(U arg) function,
     146              :     U arg,
     147              :   ) async {
     148            0 :     final compute = this.compute;
     149            0 :     return await compute(function, arg);
     150              :   }
     151              : 
     152            0 :   @override
     153              :   Future<Uint8List?> decryptFile(
     154              :     EncryptedFile file, {
     155              :     bool retryInDummy = true,
     156              :   }) {
     157            0 :     return runInBackground<Uint8List?, EncryptedFile>(
     158            0 :       (EncryptedFile args) async {
     159            0 :         await vodozemacInit?.call();
     160            0 :         return NativeImplementations.dummy.decryptFile(args);
     161              :       },
     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 :       (GenerateUploadKeysArgs args) async {
     173            0 :         await vodozemacInit?.call();
     174            0 :         return NativeImplementations.dummy.generateUploadKeys(args);
     175              :       },
     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 :       (KeyFromPassphraseArgs args) async {
     187            0 :         await vodozemacInit?.call();
     188            0 :         return NativeImplementations.dummy.keyFromPassphrase(args);
     189              :       },
     190              :       args,
     191              :     );
     192              :   }
     193              : 
     194            0 :   @override
     195              :   Future<MatrixImageFileResizedResponse?> shrinkImage(
     196              :     MatrixImageFileResizeArguments args, {
     197              :     bool retryInDummy = false,
     198              :   }) {
     199            0 :     return runInBackground<MatrixImageFileResizedResponse?,
     200              :         MatrixImageFileResizeArguments>(
     201            0 :       NativeImplementations.dummy.shrinkImage,
     202              :       args,
     203              :     );
     204              :   }
     205              : 
     206            0 :   @override
     207              :   FutureOr<MatrixImageFileResizedResponse?> calcImageMetadata(
     208              :     Uint8List bytes, {
     209              :     bool retryInDummy = false,
     210              :   }) {
     211            0 :     return runInBackground<MatrixImageFileResizedResponse?, Uint8List>(
     212            0 :       NativeImplementations.dummy.calcImageMetadata,
     213              :       bytes,
     214              :     );
     215              :   }
     216              : }
        

Generated by: LCOV version 2.0-1