Method.dart 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270
  1. import 'dart:convert';
  2. import 'dart:io';
  3. import 'dart:typed_data';
  4. import 'package:dio/dio.dart';
  5. import 'package:flutter/cupertino.dart';
  6. import 'package:flutter_easyloading/flutter_easyloading.dart';
  7. import 'package:flutter_styled_toast/flutter_styled_toast.dart';
  8. import 'package:path_provider/path_provider.dart';
  9. import 'package:permission_handler/permission_handler.dart';
  10. import 'package:prime_chat/basic/Api.dart';
  11. import 'package:shared_preferences/shared_preferences.dart';
  12. import 'package:flutter_chat_types/flutter_chat_types.dart' as types;
  13. import 'Entities.dart';
  14. import 'Global.dart';
  15. class Handler {
  16. Handler(this.name) : value = prefs.getString(name) ?? "";
  17. final String name;
  18. late String value;
  19. Future<bool> set(String value) async {
  20. this.value = value;
  21. return prefs.setString(name, value);
  22. }
  23. }
  24. final method = Method._();
  25. class Method {
  26. Method._();
  27. Future init() async {
  28. _token = Handler("token");
  29. _name = Handler("name");
  30. _password = Handler("password");
  31. _uid = Handler("uid");
  32. return await preLogin();
  33. }
  34. late Handler _token;
  35. late Handler _name;
  36. late Handler _password;
  37. late Handler _uid;
  38. get dio => token.isEmpty
  39. ? Dio()
  40. : Dio(BaseOptions(
  41. headers: {HttpHeaders.authorizationHeader: "Bearer $token"}));
  42. get token => _token.value;
  43. set token(value) => _token.set(value);
  44. get name => _name.value;
  45. set name(value) => _name.set(value);
  46. get password => _password.value;
  47. set password(value) => _password.set(value);
  48. get uid => _uid.value;
  49. set uid(value) => _uid.set(value);
  50. get user => types.User(id: uid);
  51. Future _handleDioError(DioError e, {int retry = 0}) async {
  52. final res = e.response;
  53. final req = e.requestOptions;
  54. final data = jsonDecode(res.toString());
  55. final code = res == null ? -1 : res.statusCode;
  56. debugPrint("api error, path=${req.path} code=$code error=${data['error']}");
  57. switch (code) {
  58. case HttpStatus.unauthorized:
  59. if (await login()) {
  60. final res = await request(req.path,
  61. data: req.data,
  62. queryParameters: req.queryParameters,
  63. options: Options(method: req.method),
  64. retry: retry);
  65. return res;
  66. }
  67. break;
  68. }
  69. }
  70. Future<Response?> request(String path,
  71. {data,
  72. Map<String, dynamic>? queryParameters,
  73. Options? options,
  74. int retry = 0}) async {
  75. if (retry < 0) return null;
  76. try {
  77. final res = await dio.request(
  78. path,
  79. data: data,
  80. queryParameters: queryParameters,
  81. options: options,
  82. );
  83. return res;
  84. } on DioError catch (e) {
  85. final ret = await _handleDioError(e, retry: retry);
  86. if (ret is Response) {
  87. return ret;
  88. }
  89. }
  90. return null;
  91. }
  92. Future<bool> get authorized async {
  93. final res = await request("$server/home", options: Options(method: "get"));
  94. if (res?.statusCode == HttpStatus.ok) {
  95. debugPrint("token=$token authorized");
  96. final data = jsonDecode(res.toString());
  97. debugPrint("authorized: ${data.toString()}");
  98. uid = data["uid"].toString();
  99. return true;
  100. }
  101. return false;
  102. }
  103. Future<bool> login() async {
  104. final name = _name.value, password = _password.value;
  105. debugPrint('login: name=$name password=$password');
  106. if (name.isEmpty || password.isEmpty) return false;
  107. final res = await request("$server/token",
  108. data: {"name": name, "password": password},
  109. options: Options(method: "post"));
  110. if (res?.statusCode == HttpStatus.ok) {
  111. final data = jsonDecode(res.toString());
  112. token = data['token'];
  113. debugPrint('login ok, token=$token');
  114. // Todo: 修改uid的更新方式为:login时获取profile
  115. return authorized;
  116. }
  117. return false;
  118. }
  119. logout() {
  120. token = "";
  121. password = "";
  122. }
  123. Future<bool> preLogin() async {
  124. if (await authorized) return true;
  125. return login();
  126. }
  127. Future<List<Profile>?> getFriends() async {
  128. final res =
  129. await request('$server/friends', options: Options(method: "get"));
  130. if (res?.statusCode == HttpStatus.ok) {
  131. var data = jsonDecode(res.toString());
  132. List<Profile> friends = [];
  133. data["friends"].forEach((v) => friends.add(Profile.fromJson(v)));
  134. // debugPrint(friends.toString());
  135. return friends;
  136. }
  137. return null;
  138. }
  139. Future<Profile?> getProfile({String? name}) async {
  140. name = name ?? _name.value;
  141. debugPrint("get profile of $name");
  142. final res =
  143. await request("$server/profile/$name", options: Options(method: "get"));
  144. if (res?.statusCode == HttpStatus.ok) {
  145. final data = jsonDecode(res.toString());
  146. final profile = Profile.fromJson(data["profile"]);
  147. debugPrint("profile get, name=${profile.name}");
  148. return profile;
  149. }
  150. return null;
  151. }
  152. Future download(
  153. String url,
  154. String savePath, {
  155. Map<String, dynamic>? queryParams,
  156. CancelToken? cancelToken,
  157. dynamic data,
  158. Options? options,
  159. void Function(int, int)? onReceiveProgress,
  160. }) async {
  161. try {
  162. return await dio.download(
  163. url,
  164. savePath,
  165. queryParameters: queryParams,
  166. cancelToken: cancelToken,
  167. onReceiveProgress: onReceiveProgress,
  168. );
  169. } on DioError catch (e) {
  170. print(e);
  171. if (CancelToken.isCancel(e)) {
  172. EasyLoading.showInfo('下载已取消!');
  173. } else {
  174. if (e.response != null) {
  175. // _handleErrorResponse(e.response);
  176. } else {
  177. EasyLoading.showError(e.message);
  178. }
  179. }
  180. } on Exception catch (e) {
  181. // EasyLoading.showError(e.toString());
  182. }
  183. }
  184. Future<String?> downloadImage(String path, String fileServer) async {
  185. Directory dir = await getApplicationDocumentsDirectory();
  186. String dirPath = dir.path;
  187. final savePath = "$dirPath/$path";
  188. File file = File(savePath);
  189. debugPrint("savePath=$savePath");
  190. if (file.existsSync()) return savePath;
  191. try {
  192. final res = await dio.download('$fileServer/$path', savePath);
  193. debugPrint(res.toString());
  194. } on Exception catch (e) {
  195. debugPrint("文件下载失败");
  196. return null;
  197. }
  198. return savePath;
  199. }
  200. Future<bool> updateAvatar(Uint8List buff, String suf) async {
  201. final file = MultipartFile.fromBytes(buff, filename: 'avatar$suf');
  202. final res =
  203. await request("$server/avatar", data: FormData.fromMap({"file": file}));
  204. return res?.statusCode == HttpStatus.ok;
  205. }
  206. Future<List<types.Message>?> getMessages(String roomId) async {
  207. final res = await request("$server/messages/$roomId", options: Options(method: "get"));
  208. if (res?.statusCode != HttpStatus.ok) return null;
  209. final data = jsonDecode(res.toString());
  210. List<types.Message> messages = [];
  211. debugPrint(data.toString());
  212. for (var msg in data["messages"]) {
  213. messages.add(types.TextMessage(
  214. author: types.User(id: msg["authorId"].toString()),
  215. id: msg["id"],
  216. text: msg["content"],
  217. createdAt: msg["createdAt"]*1000 ?? 0
  218. ));
  219. }
  220. messages.sort((a, b) => b.createdAt!.compareTo(a.createdAt!));
  221. debugPrint(messages.toString());
  222. return messages;
  223. }
  224. Future<bool> sendMessage(
  225. String roomId, types.MessageType type, String content,
  226. {int receiverId = 0}) async {
  227. final res = await request("$server/message", data: {
  228. "roomId": roomId,
  229. "type": type.name,
  230. "content": content,
  231. "receiverId": receiverId
  232. }, options: Options(method: "post"));
  233. return res?.statusCode == HttpStatus.ok;
  234. }
  235. String directRoomId(String id) {
  236. String a = uid, b = id;
  237. final res = a.compareTo(b);
  238. switch (res) {
  239. case 0: throw Exception("id equals to current user's id");
  240. case 1: return "direct:$b,$a";
  241. case -1: return "direct:$a,$b";
  242. }
  243. return "";
  244. }
  245. }