| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | import 'package:flutter/widgets.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/common.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/common/hbbs/hbbs.dart'; | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  | import 'package:flutter_hbb/common/widgets/peers_view.dart'; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | import 'package:flutter_hbb/models/model.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/models/peer_model.dart'; | 
					
						
							|  |  |  | import 'package:flutter_hbb/models/platform_model.dart'; | 
					
						
							|  |  |  | import 'package:get/get.dart'; | 
					
						
							|  |  |  | import 'dart:convert'; | 
					
						
							| 
									
										
										
										
											2024-04-25 11:46:21 +08:00
										 |  |  | import '../utils/http_service.dart' as http; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | 
 | 
					
						
							|  |  |  | class GroupModel { | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |   final RxBool groupLoading = false.obs; | 
					
						
							|  |  |  |   final RxString groupLoadError = "".obs; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   final RxList<UserPayload> users = RxList.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   final RxList<Peer> peers = RxList.empty(growable: true); | 
					
						
							| 
									
										
										
										
											2023-06-21 09:30:32 +08:00
										 |  |  |   final RxString selectedUser = ''.obs; | 
					
						
							|  |  |  |   final RxString searchUserText = ''.obs; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   WeakReference<FFI> parent; | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |   var initialized = false; | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   var _cacheLoadOnceFlag = false; | 
					
						
							|  |  |  |   var _statusCode = 200; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   bool get emtpy => users.isEmpty && peers.isEmpty; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   GroupModel(this.parent); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-06-23 17:05:48 +08:00
										 |  |  |   Future<void> pull({force = true, quiet = false}) async { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     if (!gFFI.userModel.isLogin || groupLoading.value) return; | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |     if (!force && initialized) return; | 
					
						
							| 
									
										
										
										
											2023-06-23 17:05:48 +08:00
										 |  |  |     if (!quiet) { | 
					
						
							|  |  |  |       groupLoading.value = true; | 
					
						
							|  |  |  |       groupLoadError.value = ""; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       await _pull(); | 
					
						
							|  |  |  |     } catch (_) {} | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |     groupLoading.value = false; | 
					
						
							| 
									
										
										
										
											2023-06-23 15:10:10 +08:00
										 |  |  |     initialized = true; | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     platformFFI.tryHandle({'name': LoadEvent.group}); | 
					
						
							|  |  |  |     if (_statusCode == 401) { | 
					
						
							|  |  |  |       gFFI.userModel.reset(resetOther: true); | 
					
						
							|  |  |  |     } else { | 
					
						
							|  |  |  |       _saveCache(); | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-21 16:04:52 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<void> _pull() async { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     List<UserPayload> tmpUsers = List.empty(growable: true); | 
					
						
							|  |  |  |     if (!await _getUsers(tmpUsers)) { | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     List<Peer> tmpPeers = List.empty(growable: true); | 
					
						
							|  |  |  |     if (!await _getPeers(tmpPeers)) { | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |       return; | 
					
						
							|  |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     // me first
 | 
					
						
							|  |  |  |     var index = tmpUsers | 
					
						
							|  |  |  |         .indexWhere((user) => user.name == gFFI.userModel.userName.value); | 
					
						
							|  |  |  |     if (index != -1) { | 
					
						
							|  |  |  |       var user = tmpUsers.removeAt(index); | 
					
						
							|  |  |  |       tmpUsers.insert(0, user); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     users.value = tmpUsers; | 
					
						
							|  |  |  |     if (!users.any((u) => u.name == selectedUser.value)) { | 
					
						
							|  |  |  |       selectedUser.value = ''; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |     // recover online
 | 
					
						
							|  |  |  |     final oldOnlineIDs = peers.where((e) => e.online).map((e) => e.id).toList(); | 
					
						
							|  |  |  |     peers.value = tmpPeers; | 
					
						
							|  |  |  |     peers | 
					
						
							|  |  |  |         .where((e) => oldOnlineIDs.contains(e.id)) | 
					
						
							|  |  |  |         .map((e) => e.online = true) | 
					
						
							|  |  |  |         .toList(); | 
					
						
							|  |  |  |     groupLoadError.value = ''; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Future<bool> _getUsers(List<UserPayload> tmpUsers) async { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     final api = "${await bind.mainGetApiServer()}/api/users"; | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       var uri0 = Uri.parse(api); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       final pageSize = 100; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       var total = 0; | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |       int current = 0; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       do { | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |         current += 1; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |         var uri = Uri( | 
					
						
							|  |  |  |             scheme: uri0.scheme, | 
					
						
							|  |  |  |             host: uri0.host, | 
					
						
							|  |  |  |             path: uri0.path, | 
					
						
							|  |  |  |             port: uri0.port, | 
					
						
							|  |  |  |             queryParameters: { | 
					
						
							|  |  |  |               'current': current.toString(), | 
					
						
							|  |  |  |               'pageSize': pageSize.toString(), | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |               'accessible': '', | 
					
						
							|  |  |  |               'status': '1', | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |             }); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |         final resp = await http.get(uri, headers: getHttpHeaders()); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |         _statusCode = resp.statusCode; | 
					
						
							|  |  |  |         Map<String, dynamic> json = | 
					
						
							|  |  |  |             _jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode); | 
					
						
							|  |  |  |         if (json.containsKey('error')) { | 
					
						
							| 
									
										
										
										
											2023-09-18 14:36:55 +08:00
										 |  |  |           if (json['error'] == 'Admin required!' || | 
					
						
							|  |  |  |               json['error'] | 
					
						
							|  |  |  |                   .toString() | 
					
						
							|  |  |  |                   .contains('ambiguous column name: status')) { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |             throw translate('upgrade_rustdesk_server_pro_to_{1.1.10}_tip'); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |           } else { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |             throw json['error']; | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (resp.statusCode != 200) { | 
					
						
							|  |  |  |           throw 'HTTP ${resp.statusCode}'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (json.containsKey('total')) { | 
					
						
							|  |  |  |           if (total == 0) total = json['total']; | 
					
						
							|  |  |  |           if (json.containsKey('data')) { | 
					
						
							|  |  |  |             final data = json['data']; | 
					
						
							|  |  |  |             if (data is List) { | 
					
						
							|  |  |  |               for (final user in data) { | 
					
						
							|  |  |  |                 final u = UserPayload.fromJson(user); | 
					
						
							|  |  |  |                 int index = tmpUsers.indexWhere((e) => e.name == u.name); | 
					
						
							|  |  |  |                 if (index < 0) { | 
					
						
							|  |  |  |                   tmpUsers.add(u); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                   tmpUsers[index] = u; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |                 } | 
					
						
							|  |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |       } while (current * pageSize < total); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     } catch (err) { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       debugPrint('get accessible users: $err'); | 
					
						
							| 
									
										
										
										
											2023-09-24 08:36:53 +08:00
										 |  |  |       groupLoadError.value = | 
					
						
							|  |  |  |           '${translate('pull_group_failed_tip')}: ${translate(err.toString())}'; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     } | 
					
						
							| 
									
										
										
										
											2023-06-17 20:48:58 +08:00
										 |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |   Future<bool> _getPeers(List<Peer> tmpPeers) async { | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     try { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       final api = "${await bind.mainGetApiServer()}/api/peers"; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       var uri0 = Uri.parse(api); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       final pageSize = 100; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       var total = 0; | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |       int current = 0; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |       do { | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |         current += 1; | 
					
						
							| 
									
										
										
										
											2023-09-19 12:03:45 +08:00
										 |  |  |         var queryParameters = { | 
					
						
							|  |  |  |           'current': current.toString(), | 
					
						
							|  |  |  |           'pageSize': pageSize.toString(), | 
					
						
							|  |  |  |           'accessible': '', | 
					
						
							|  |  |  |           'status': '1', | 
					
						
							|  |  |  |         }; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |         var uri = Uri( | 
					
						
							|  |  |  |             scheme: uri0.scheme, | 
					
						
							|  |  |  |             host: uri0.host, | 
					
						
							|  |  |  |             path: uri0.path, | 
					
						
							|  |  |  |             port: uri0.port, | 
					
						
							| 
									
										
										
										
											2023-06-21 09:30:32 +08:00
										 |  |  |             queryParameters: queryParameters); | 
					
						
							| 
									
										
										
										
											2023-01-06 19:26:19 +09:00
										 |  |  |         final resp = await http.get(uri, headers: getHttpHeaders()); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |         _statusCode = resp.statusCode; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |         Map<String, dynamic> json = | 
					
						
							|  |  |  |             _jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode); | 
					
						
							|  |  |  |         if (json.containsKey('error')) { | 
					
						
							|  |  |  |           throw json['error']; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (resp.statusCode != 200) { | 
					
						
							|  |  |  |           throw 'HTTP ${resp.statusCode}'; | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |         if (json.containsKey('total')) { | 
					
						
							|  |  |  |           if (total == 0) total = json['total']; | 
					
						
							|  |  |  |           if (json.containsKey('data')) { | 
					
						
							|  |  |  |             final data = json['data']; | 
					
						
							|  |  |  |             if (data is List) { | 
					
						
							|  |  |  |               for (final p in data) { | 
					
						
							|  |  |  |                 final peerPayload = PeerPayload.fromJson(p); | 
					
						
							|  |  |  |                 final peer = PeerPayload.toPeer(peerPayload); | 
					
						
							|  |  |  |                 int index = tmpPeers.indexWhere((e) => e.id == peer.id); | 
					
						
							|  |  |  |                 if (index < 0) { | 
					
						
							|  |  |  |                   tmpPeers.add(peer); | 
					
						
							|  |  |  |                 } else { | 
					
						
							|  |  |  |                   tmpPeers[index] = peer; | 
					
						
							|  |  |  |                 } | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |               } | 
					
						
							|  |  |  |             } | 
					
						
							|  |  |  |           } | 
					
						
							|  |  |  |         } | 
					
						
							| 
									
										
										
										
											2022-12-23 10:36:18 +08:00
										 |  |  |       } while (current * pageSize < total); | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       return true; | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |     } catch (err) { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |       debugPrint('get accessible peers: $err'); | 
					
						
							| 
									
										
										
										
											2023-09-24 08:36:53 +08:00
										 |  |  |       groupLoadError.value = | 
					
						
							|  |  |  |           '${translate('pull_group_failed_tip')}: ${translate(err.toString())}'; | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     } | 
					
						
							|  |  |  |     return false; | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   Map<String, dynamic> _jsonDecodeResp(String body, int statusCode) { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       Map<String, dynamic> json = jsonDecode(body); | 
					
						
							|  |  |  |       return json; | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       final err = body.isNotEmpty && body.length < 128 ? body : e.toString(); | 
					
						
							|  |  |  |       if (statusCode != 200) { | 
					
						
							|  |  |  |         throw 'HTTP $statusCode, $err'; | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       throw err; | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   void _saveCache() { | 
					
						
							|  |  |  |     try { | 
					
						
							|  |  |  |       final map = (<String, dynamic>{ | 
					
						
							|  |  |  |         "access_token": bind.mainGetLocalOption(key: 'access_token'), | 
					
						
							|  |  |  |         "users": users.map((e) => e.toGroupCacheJson()).toList(), | 
					
						
							|  |  |  |         'peers': peers.map((e) => e.toGroupCacheJson()).toList() | 
					
						
							|  |  |  |       }); | 
					
						
							|  |  |  |       bind.mainSaveGroup(json: jsonEncode(map)); | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint('group save:$e'); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2023-09-24 17:56:35 +08:00
										 |  |  |   Future<void> loadCache() async { | 
					
						
							| 
									
										
										
										
											2023-09-14 10:17:03 +08:00
										 |  |  |     try { | 
					
						
							|  |  |  |       if (_cacheLoadOnceFlag || groupLoading.value || initialized) return; | 
					
						
							|  |  |  |       _cacheLoadOnceFlag = true; | 
					
						
							|  |  |  |       final access_token = bind.mainGetLocalOption(key: 'access_token'); | 
					
						
							|  |  |  |       if (access_token.isEmpty) return; | 
					
						
							|  |  |  |       final cache = await bind.mainLoadGroup(); | 
					
						
							|  |  |  |       if (groupLoading.value) return; | 
					
						
							|  |  |  |       final data = jsonDecode(cache); | 
					
						
							|  |  |  |       if (data == null || data['access_token'] != access_token) return; | 
					
						
							|  |  |  |       users.clear(); | 
					
						
							|  |  |  |       peers.clear(); | 
					
						
							|  |  |  |       if (data['users'] is List) { | 
					
						
							|  |  |  |         for (var u in data['users']) { | 
					
						
							|  |  |  |           users.add(UserPayload.fromJson(u)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |       if (data['peers'] is List) { | 
					
						
							|  |  |  |         for (final peer in data['peers']) { | 
					
						
							|  |  |  |           peers.add(Peer.fromJson(peer)); | 
					
						
							|  |  |  |         } | 
					
						
							|  |  |  |       } | 
					
						
							|  |  |  |     } catch (e) { | 
					
						
							|  |  |  |       debugPrint("load group cache: $e"); | 
					
						
							|  |  |  |     } | 
					
						
							|  |  |  |   } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |   reset() async { | 
					
						
							|  |  |  |     groupLoadError.value = ''; | 
					
						
							|  |  |  |     users.clear(); | 
					
						
							|  |  |  |     peers.clear(); | 
					
						
							|  |  |  |     selectedUser.value = ''; | 
					
						
							|  |  |  |     await bind.mainClearGroup(); | 
					
						
							| 
									
										
										
										
											2022-12-11 21:40:35 +08:00
										 |  |  |   } | 
					
						
							|  |  |  | } |