group_model.dart 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272
  1. import 'package:flutter/widgets.dart';
  2. import 'package:flutter_hbb/common.dart';
  3. import 'package:flutter_hbb/common/hbbs/hbbs.dart';
  4. import 'package:flutter_hbb/common/widgets/peers_view.dart';
  5. import 'package:flutter_hbb/models/model.dart';
  6. import 'package:flutter_hbb/models/peer_model.dart';
  7. import 'package:flutter_hbb/models/platform_model.dart';
  8. import 'package:get/get.dart';
  9. import 'dart:convert';
  10. import '../utils/http_service.dart' as http;
  11. class GroupModel {
  12. final RxBool groupLoading = false.obs;
  13. final RxString groupLoadError = "".obs;
  14. final RxList<UserPayload> users = RxList.empty(growable: true);
  15. final RxList<Peer> peers = RxList.empty(growable: true);
  16. final RxString selectedUser = ''.obs;
  17. final RxString searchUserText = ''.obs;
  18. WeakReference<FFI> parent;
  19. var initialized = false;
  20. var _cacheLoadOnceFlag = false;
  21. var _statusCode = 200;
  22. bool get emtpy => users.isEmpty && peers.isEmpty;
  23. late final Peers peersModel;
  24. GroupModel(this.parent) {
  25. peersModel = Peers(
  26. name: PeersModelName.group,
  27. getInitPeers: () => peers,
  28. loadEvent: LoadEvent.group);
  29. }
  30. Future<void> pull({force = true, quiet = false}) async {
  31. if (bind.isDisableGroupPanel()) return;
  32. if (!gFFI.userModel.isLogin || groupLoading.value) return;
  33. if (gFFI.userModel.networkError.isNotEmpty) return;
  34. if (!force && initialized) return;
  35. if (!quiet) {
  36. groupLoading.value = true;
  37. groupLoadError.value = "";
  38. }
  39. try {
  40. await _pull();
  41. } catch (_) {}
  42. groupLoading.value = false;
  43. initialized = true;
  44. platformFFI.tryHandle({'name': LoadEvent.group});
  45. if (_statusCode == 401) {
  46. gFFI.userModel.reset(resetOther: true);
  47. } else {
  48. _saveCache();
  49. }
  50. }
  51. Future<void> _pull() async {
  52. List<UserPayload> tmpUsers = List.empty(growable: true);
  53. if (!await _getUsers(tmpUsers)) {
  54. return;
  55. }
  56. List<Peer> tmpPeers = List.empty(growable: true);
  57. if (!await _getPeers(tmpPeers)) {
  58. return;
  59. }
  60. // me first
  61. var index = tmpUsers
  62. .indexWhere((user) => user.name == gFFI.userModel.userName.value);
  63. if (index != -1) {
  64. var user = tmpUsers.removeAt(index);
  65. tmpUsers.insert(0, user);
  66. }
  67. users.value = tmpUsers;
  68. if (!users.any((u) => u.name == selectedUser.value)) {
  69. selectedUser.value = '';
  70. }
  71. // recover online
  72. final oldOnlineIDs = peers.where((e) => e.online).map((e) => e.id).toList();
  73. peers.value = tmpPeers;
  74. peers
  75. .where((e) => oldOnlineIDs.contains(e.id))
  76. .map((e) => e.online = true)
  77. .toList();
  78. groupLoadError.value = '';
  79. }
  80. Future<bool> _getUsers(List<UserPayload> tmpUsers) async {
  81. final api = "${await bind.mainGetApiServer()}/api/users";
  82. try {
  83. var uri0 = Uri.parse(api);
  84. final pageSize = 100;
  85. var total = 0;
  86. int current = 0;
  87. do {
  88. current += 1;
  89. var uri = Uri(
  90. scheme: uri0.scheme,
  91. host: uri0.host,
  92. path: uri0.path,
  93. port: uri0.port,
  94. queryParameters: {
  95. 'current': current.toString(),
  96. 'pageSize': pageSize.toString(),
  97. 'accessible': '',
  98. 'status': '1',
  99. });
  100. final resp = await http.get(uri, headers: getHttpHeaders());
  101. _statusCode = resp.statusCode;
  102. Map<String, dynamic> json =
  103. _jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode);
  104. if (json.containsKey('error')) {
  105. if (json['error'] == 'Admin required!' ||
  106. json['error']
  107. .toString()
  108. .contains('ambiguous column name: status')) {
  109. throw translate('upgrade_rustdesk_server_pro_to_{1.1.10}_tip');
  110. } else {
  111. throw json['error'];
  112. }
  113. }
  114. if (resp.statusCode != 200) {
  115. throw 'HTTP ${resp.statusCode}';
  116. }
  117. if (json.containsKey('total')) {
  118. if (total == 0) total = json['total'];
  119. if (json.containsKey('data')) {
  120. final data = json['data'];
  121. if (data is List) {
  122. for (final user in data) {
  123. final u = UserPayload.fromJson(user);
  124. int index = tmpUsers.indexWhere((e) => e.name == u.name);
  125. if (index < 0) {
  126. tmpUsers.add(u);
  127. } else {
  128. tmpUsers[index] = u;
  129. }
  130. }
  131. }
  132. }
  133. }
  134. } while (current * pageSize < total);
  135. return true;
  136. } catch (err) {
  137. debugPrint('get accessible users: $err');
  138. groupLoadError.value =
  139. '${translate('pull_group_failed_tip')}: ${translate(err.toString())}';
  140. }
  141. return false;
  142. }
  143. Future<bool> _getPeers(List<Peer> tmpPeers) async {
  144. try {
  145. final api = "${await bind.mainGetApiServer()}/api/peers";
  146. var uri0 = Uri.parse(api);
  147. final pageSize = 100;
  148. var total = 0;
  149. int current = 0;
  150. do {
  151. current += 1;
  152. var queryParameters = {
  153. 'current': current.toString(),
  154. 'pageSize': pageSize.toString(),
  155. 'accessible': '',
  156. 'status': '1',
  157. };
  158. var uri = Uri(
  159. scheme: uri0.scheme,
  160. host: uri0.host,
  161. path: uri0.path,
  162. port: uri0.port,
  163. queryParameters: queryParameters);
  164. final resp = await http.get(uri, headers: getHttpHeaders());
  165. _statusCode = resp.statusCode;
  166. Map<String, dynamic> json =
  167. _jsonDecodeResp(utf8.decode(resp.bodyBytes), resp.statusCode);
  168. if (json.containsKey('error')) {
  169. throw json['error'];
  170. }
  171. if (resp.statusCode != 200) {
  172. throw 'HTTP ${resp.statusCode}';
  173. }
  174. if (json.containsKey('total')) {
  175. if (total == 0) total = json['total'];
  176. if (json.containsKey('data')) {
  177. final data = json['data'];
  178. if (data is List) {
  179. for (final p in data) {
  180. final peerPayload = PeerPayload.fromJson(p);
  181. final peer = PeerPayload.toPeer(peerPayload);
  182. int index = tmpPeers.indexWhere((e) => e.id == peer.id);
  183. if (index < 0) {
  184. tmpPeers.add(peer);
  185. } else {
  186. tmpPeers[index] = peer;
  187. }
  188. }
  189. }
  190. }
  191. }
  192. } while (current * pageSize < total);
  193. return true;
  194. } catch (err) {
  195. debugPrint('get accessible peers: $err');
  196. groupLoadError.value =
  197. '${translate('pull_group_failed_tip')}: ${translate(err.toString())}';
  198. }
  199. return false;
  200. }
  201. Map<String, dynamic> _jsonDecodeResp(String body, int statusCode) {
  202. try {
  203. Map<String, dynamic> json = jsonDecode(body);
  204. return json;
  205. } catch (e) {
  206. final err = body.isNotEmpty && body.length < 128 ? body : e.toString();
  207. if (statusCode != 200) {
  208. throw 'HTTP $statusCode, $err';
  209. }
  210. throw err;
  211. }
  212. }
  213. void _saveCache() {
  214. try {
  215. final map = (<String, dynamic>{
  216. "access_token": bind.mainGetLocalOption(key: 'access_token'),
  217. "users": users.map((e) => e.toGroupCacheJson()).toList(),
  218. 'peers': peers.map((e) => e.toGroupCacheJson()).toList()
  219. });
  220. bind.mainSaveGroup(json: jsonEncode(map));
  221. } catch (e) {
  222. debugPrint('group save:$e');
  223. }
  224. }
  225. Future<void> loadCache() async {
  226. try {
  227. if (_cacheLoadOnceFlag || groupLoading.value || initialized) return;
  228. _cacheLoadOnceFlag = true;
  229. final access_token = bind.mainGetLocalOption(key: 'access_token');
  230. if (access_token.isEmpty) return;
  231. final cache = await bind.mainLoadGroup();
  232. if (groupLoading.value) return;
  233. final data = jsonDecode(cache);
  234. if (data == null || data['access_token'] != access_token) return;
  235. users.clear();
  236. peers.clear();
  237. if (data['users'] is List) {
  238. for (var u in data['users']) {
  239. users.add(UserPayload.fromJson(u));
  240. }
  241. }
  242. if (data['peers'] is List) {
  243. for (final peer in data['peers']) {
  244. peers.add(Peer.fromJson(peer));
  245. }
  246. }
  247. } catch (e) {
  248. debugPrint("load group cache: $e");
  249. }
  250. }
  251. reset() async {
  252. groupLoadError.value = '';
  253. users.clear();
  254. peers.clear();
  255. selectedUser.value = '';
  256. await bind.mainClearGroup();
  257. }
  258. }