LCOV - code coverage report
Current view: top level - _classes/herald - app_sync.dart (source / functions) Hit Total Coverage
Test: lcov.info Lines: 0 72 0.0 %
Date: 2024-10-04 11:08:31 Functions: 0 0 -

          Line data    Source code
       1             : // Copyright 2023 The terCAD team. All rights reserved.
       2             : // Use of this source code is governed by a CC BY-NC-ND 4.0 license that can be found in the LICENSE file.
       3             : 
       4             : import 'package:app_finance/_classes/storage/app_preferences.dart';
       5             : import 'package:flutter/foundation.dart';
       6             : import 'package:peerdart/peerdart.dart';
       7             : import 'package:uuid/uuid.dart';
       8             : 
       9             : class SyncStatus {
      10             :   final String id;
      11             :   bool? status;
      12           0 :   SyncStatus(this.id, [this.status]);
      13             : }
      14             : 
      15             : class SyncPeer extends SyncStatus {
      16             :   DataConnection connection;
      17           0 :   SyncPeer(super.id, this.connection);
      18             : }
      19             : 
      20             : class AppSync extends ChangeNotifier {
      21             :   late Peer peer;
      22             :   final Map<String, SyncPeer> _status = {};
      23             :   final Map<Type, Function> _cb = {};
      24             :   final Map<Type, Function> _cbBin = {};
      25             : 
      26           0 :   AppSync() : super() {
      27           0 :     final id = getUuid();
      28           0 :     if (id != null && id.isNotEmpty) {
      29           0 :       enable(id);
      30           0 :       connect();
      31             :     }
      32             :   }
      33             : 
      34           0 :   List<String> _get() {
      35           0 :     return AppPreferences.get(AppPreferences.prefP2P)?.split(',').where((e) => e.isNotEmpty).toList() ?? [];
      36             :   }
      37             : 
      38           0 :   void add(String uuid) {
      39           0 :     List<String> peers = _get();
      40           0 :     peers.add(uuid);
      41           0 :     AppPreferences.set(AppPreferences.prefP2P, (<String>{}..addAll(peers)).toList().join(',')).then((_) => connect());
      42             :   }
      43             : 
      44           0 :   void del(String uuid) {
      45           0 :     _status[uuid]?.connection.dispose();
      46           0 :     _status.remove(uuid);
      47           0 :     AppPreferences.set(AppPreferences.prefP2P, (_get()..remove(uuid)).join(',')).then((_) => notifyListeners());
      48             :   }
      49             : 
      50           0 :   void connect() {
      51           0 :     List<String> peers = _get();
      52           0 :     for (int i = 0; i < peers.length; i++) {
      53           0 :       trace(peers[i]);
      54             :     }
      55             :   }
      56             : 
      57           0 :   void trace(String id) {
      58           0 :     if (!peer.open) {
      59           0 :       peer.reconnect();
      60             :     }
      61           0 :     if (_status[id] == null) {
      62           0 :       _status[id] = SyncPeer(id, peer.connect(id));
      63           0 :     } else if (!_status[id]!.connection.open) {
      64           0 :       peer.removeConnection(_status[id]!.connection);
      65           0 :       _status[id]!.connection = peer.connect(id);
      66             :     }
      67             :     // TBD: when connected, verify postponed messages
      68           0 :     _status[id]!.connection.once('open').then((v) {
      69           0 :       _status[id]!.status = true;
      70           0 :       notifyListeners();
      71             :     });
      72           0 :     _status[id]!.connection.once('close').then((v) {
      73           0 :       _status[id]!.status = false;
      74           0 :       notifyListeners();
      75             :     });
      76             :   }
      77             : 
      78           0 :   List<SyncStatus> getPeers() {
      79           0 :     return _status.values.map((e) => SyncStatus(e.id, e.status)).toList();
      80             :   }
      81             : 
      82           0 :   void follow(Type type, Function callback) => _cb[type] = callback;
      83             : 
      84           0 :   void followBinary(Type type, Function callback) => _cbBin[type] = callback;
      85             : 
      86           0 :   void unfollow(Type type) {
      87           0 :     _cb.remove(type);
      88           0 :     _cbBin.remove(type);
      89             :   }
      90             : 
      91           0 :   bool isActive() {
      92           0 :     return AppPreferences.get(AppPreferences.prefPeer) != null;
      93             :   }
      94             : 
      95           0 :   void disable() {
      96           0 :     AppPreferences.clear(AppPreferences.prefPeer);
      97           0 :     AppPreferences.clear(AppPreferences.prefP2P);
      98           0 :     peer.dispose();
      99             :   }
     100             : 
     101           0 :   void enable([String? id]) {
     102           0 :     id ??= getUuid(true);
     103           0 :     peer = Peer(id: id); //, options: PeerOptions(debug: LogLevel.All));
     104           0 :     peer.on<DataConnection>('connection').listen(_listen);
     105             :   }
     106             : 
     107           0 :   _listen(DataConnection conn) {
     108           0 :     conn.on('data').listen((data) {
     109           0 :       _cb.forEach((_, callback) => callback(data));
     110             :     });
     111           0 :     conn.on('binary').listen((data) {
     112           0 :       _cbBin.forEach((_, callback) => callback(data));
     113             :     });
     114             :   }
     115             : 
     116           0 :   send(String data, [String? uuid]) {
     117             :     if (uuid != null) {
     118           0 :       if (_status[uuid]?.status == true) {
     119           0 :         _status[uuid]!.connection.send(data);
     120             :       }
     121             :     } else {
     122           0 :       final keyList = _status.keys.toList();
     123           0 :       for (int i = 0; i < keyList.length; i++) {
     124           0 :         if (_status[keyList[i]]?.status == true && _status[keyList[i]]!.connection.open) {
     125           0 :           _status[keyList[i]]!.connection.send(data);
     126             :         } else {
     127             :           // .. postpone message
     128             :         }
     129             :       }
     130             :     }
     131             :   }
     132             : 
     133           0 :   ping(String uuid) {
     134           0 :     if (_status[uuid]?.status == true) {
     135           0 :       _status[uuid]!.connection.sendBinary(Uint8List.fromList(getUuid()?.codeUnits ?? [0]));
     136             :     }
     137             :   }
     138             : 
     139           0 :   String getNewUuid() {
     140           0 :     return const Uuid().v4();
     141             :   }
     142             : 
     143           0 :   String? getUuid([bool force = false]) {
     144           0 :     String? id = AppPreferences.get(AppPreferences.prefPeer);
     145             :     if (force) {
     146           0 :       AppPreferences.set(AppPreferences.prefPeer, id = getNewUuid());
     147             :     }
     148             :     return id;
     149             :   }
     150             : }

Generated by: LCOV version 1.14