Hibok
Du kannst nicht mehr als 25 Themen auswählen Themen müssen entweder mit einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.
 
 
 
 
 
 

404 Zeilen
11 KiB

  1. import 'dart:convert';
  2. import 'package:chat/data/UserData.dart';
  3. import 'package:chat/generated/i18n.dart';
  4. import 'package:chat/models/ChatMsg.dart';
  5. import 'package:chat/models/group_info_model.dart';
  6. import 'package:chat/models/group_info_server_model.dart';
  7. import 'package:chat/proto/all.pbserver.dart';
  8. import 'package:chat/utils/LoadingDialog.dart';
  9. import 'package:chat/utils/file_cache_mgr.dart';
  10. import 'package:convert/convert.dart';
  11. import 'package:dio/dio.dart';
  12. import 'package:crypto/crypto.dart';
  13. import 'dart:async';
  14. import 'package:http_parser/http_parser.dart';
  15. import 'package:chat/utils/MessageMgr.dart';
  16. import 'package:oktoast/oktoast.dart';
  17. import 'package:chat/utils/msgHandler.dart';
  18. import 'package:chat/utils/sql_util.dart';
  19. var signKey = 'O@MlSxWaeAlc5CYu';
  20. class UploadUtil {
  21. // 工厂模式
  22. factory UploadUtil() => _getInstance();
  23. static UploadUtil get instance => _getInstance();
  24. static UploadUtil _instance;
  25. UploadUtil._internal() {
  26. // 初始化
  27. }
  28. static UploadUtil _getInstance() {
  29. if (_instance == null) {
  30. _instance = new UploadUtil._internal();
  31. }
  32. return _instance;
  33. }
  34. Dio dio;
  35. //进度流
  36. Map<String, StreamController<double>> streamMap = {};
  37. //缓存进度,方便快速显示
  38. Map<String, double> streamLastPercentMap = {};
  39. //上传地址
  40. String uploadUrl;
  41. String rootUrl;
  42. void setUploadUrl(url) {
  43. rootUrl = 'http://' + url;
  44. uploadUrl = 'http://' + url + '/chatresfile/';
  45. BaseOptions options = BaseOptions(
  46. baseUrl: uploadUrl,
  47. headers: {},
  48. );
  49. print(uploadUrl);
  50. dio = new Dio(options);
  51. }
  52. // md5 加密
  53. String generateMd5(String data) {
  54. var content = new Utf8Encoder().convert(data);
  55. var digest = md5.convert(content);
  56. // 这里其实就是 digest.toString()
  57. return hex.encode(digest.bytes);
  58. }
  59. String getSign(Map parameter) {
  60. String k = '';
  61. var keyList = [];
  62. for (var key in parameter.keys) {
  63. keyList.add(key);
  64. }
  65. keyList.sort();
  66. for (var key in keyList) {
  67. k += '$key=${parameter[key]}&';
  68. }
  69. k += 'key=O@MlSxWaeAlc5CYu';
  70. return generateMd5(k);
  71. }
  72. String getFileType(String suffix) {
  73. if (suffix == 'png' || suffix == 'jpg' || suffix == 'jpeg') {
  74. return 'image';
  75. } else if (suffix == 'wav') {
  76. return 'audio';
  77. } else {
  78. return 'video';
  79. }
  80. }
  81. bool isImage(String suffix) {
  82. suffix = suffix.toLowerCase();
  83. return suffix == 'png' || suffix == 'jpg' || suffix == 'jpeg';
  84. }
  85. StreamController<double> getStream(String fileId) {
  86. if (streamMap[fileId] == null) {
  87. streamMap[fileId] = StreamController<double>.broadcast();
  88. }
  89. return streamMap[fileId];
  90. }
  91. Future uploadFile(MsgModel msg, {CancelToken cancelToken}) async {
  92. Response response;
  93. var data = {
  94. "upuserid": msg.from,
  95. 'channeltype': msg.channelType,
  96. "targetid": msg.sessionId,
  97. 'fileid': msg.extraFile,
  98. };
  99. print('上传参数$data');
  100. var path = msg.localFile;
  101. var name = path.substring(path.lastIndexOf("/") + 1, path.length);
  102. String suffix = name.substring(name.lastIndexOf(".") + 1, name.length);
  103. var fileType = getFileType(suffix);
  104. print('文件类型 : $fileType $suffix');
  105. data['sign'] = getSign(data);
  106. data['uploadfile'] = await MultipartFile.fromFile(path,
  107. filename: name, contentType: MediaType(fileType, suffix));
  108. FormData formData = new FormData.fromMap(data);
  109. try {
  110. print('开始上传文件${msg.extraFile} url:${uploadUrl + 'uploadchatfile'}');
  111. var streamController = getStream(msg.extraFile);
  112. response = await dio.post(uploadUrl + 'uploadchatfile', data: formData,
  113. onSendProgress: (int progress, int total) {
  114. streamController.sink.add(progress / total);
  115. streamLastPercentMap[msg.extraFile] = progress / total;
  116. }, cancelToken: cancelToken);
  117. streamController.close();
  118. streamMap.remove(msg.extraFile);
  119. print('uploadFile response $response');
  120. if (response.data['code'] == 0) {
  121. var data = response.data['data'];
  122. print('uploadFile 上传成功');
  123. msg.state = MsgState.Uploaded;
  124. MsgHandler.sendChatMsg(msg);
  125. MessageMgr().emit('Update LastMsg', msg.sessionId);
  126. return data;
  127. } else {
  128. print('uploadFile 上传失败');
  129. msg.state = MsgState.UploadFailed;
  130. MessageMgr().emit('Update LastMsg', msg.sessionId);
  131. return null;
  132. }
  133. } on DioError catch (e) {
  134. if (CancelToken.isCancel(e)) {
  135. print('post请求取消! ' + e.message);
  136. }
  137. showToast('上传文件失败');
  138. msg.state = MsgState.UploadFailed;
  139. print('post请求发生错误:$e');
  140. }
  141. MessageMgr().emit('Update LastMsg', msg.sessionId);
  142. return null;
  143. }
  144. void cancelRequests(CancelToken cancelToken) {
  145. print('取消请求$cancelToken');
  146. cancelToken.cancel("cancelled");
  147. }
  148. String getFullUrl(String imgData, int sessionid, int channelType) {
  149. var data = {
  150. "fileid": imgData,
  151. 'targetid': sessionid,
  152. "userid": UserData().basicInfo.userId,
  153. 'channeltype': channelType
  154. };
  155. var sign = getSign(data);
  156. return uploadUrl +
  157. 'downloadchatfile?targetid=$sessionid&channeltype=$channelType&userid=${UserData().basicInfo.userId}&fileid=$imgData&sign=$sign';
  158. }
  159. Future downloadFile(MsgModel msg, {CancelToken cancelToken}) async {
  160. Response response;
  161. var fullUrl = getFullUrl(msg.extraFile, msg.sessionId, msg.channelType);
  162. print('下载文件$fullUrl');
  163. var path = await FileCacheMgr().genFilePath(msg.extraFile);
  164. if (msg.msgType == ChatType.ShortVoiceChatType.value) {
  165. path = path + '.wav';
  166. } else if (msg.msgType == ChatType.FileChatType.value) {
  167. var fileMsg = FileChat.fromBuffer(msg.msgContent);
  168. var fileName = fileMsg.name;
  169. path = await FileCacheMgr().genFilePath(fileName);
  170. }
  171. print('文件保存路径$path');
  172. try {
  173. var streamController = getStream(msg.extraFile);
  174. response = await dio.download(fullUrl, path,
  175. onReceiveProgress: (int progress, int total) {
  176. streamController.sink.add(progress / total);
  177. streamLastPercentMap[msg.extraFile] = progress / total;
  178. }, cancelToken: cancelToken);
  179. streamController.close();
  180. streamMap.remove(msg.extraFile);
  181. if (response.statusCode == 200) {
  182. msg.state = MsgState.DownloadSuccess;
  183. msg.localFile = path;
  184. SqlUtil().updateLocalFile(msg.extraFile, path,
  185. isGroup: msg.channelType == ChatChannelType.Group.value);
  186. return path;
  187. } else {
  188. msg.state = MsgState.DownloadFailed;
  189. showToast(I18n.of(LoadingManage.context).server_error_tips);
  190. return null;
  191. }
  192. } catch (e) {
  193. msg.state = MsgState.DownloadFailed;
  194. showToast(I18n.of(LoadingManage.context).server_error_tips);
  195. print(response.toString());
  196. }
  197. }
  198. //机器人翻译,type 1文字,2语音
  199. Future<String> commitTranslateSource(
  200. int type, int sourceLang, int toLang, dynamic content) async {
  201. Response response;
  202. var myId = UserData().basicInfo.userId;
  203. Map<String, dynamic> data = {
  204. 'userid': myId,
  205. 'cType': type,
  206. 'ulanguage': sourceLang,
  207. 'tlanguage': toLang
  208. };
  209. data['sign'] = getSign(data);
  210. data['content'] = content;
  211. if (type == 2) {
  212. data['content'] = await MultipartFile.fromFile(content);
  213. }
  214. FormData formData = new FormData.fromMap(data);
  215. try {
  216. print('开始请求翻译$data ${uploadUrl + 'translate/transqt'}');
  217. response = await dio.post(rootUrl + '/translate/transqt', data: formData);
  218. Map resData = response.data;
  219. print('翻译结果$resData');
  220. if (resData['code'] == 0) {
  221. return resData['data'];
  222. }
  223. } catch (e) {
  224. print(e);
  225. }
  226. return null;
  227. }
  228. //获取群列表
  229. Future<List<GroupInfoModel>> getGroupList() async {
  230. Response response;
  231. var myId = UserData().basicInfo.userId;
  232. Map<String, dynamic> data = {
  233. 'userid': myId,
  234. };
  235. data['sign'] = getSign(data);
  236. try {
  237. print('开始请求群列表$data}');
  238. response = await dio.post(rootUrl + '/chat/queryusergroups', data: data);
  239. Map resData = response.data;
  240. if (resData['code'] == 0) {
  241. List resList = resData['data'];
  242. List<GroupInfoModel> groupList = [];
  243. for (var i = 0; i < resList.length; i++) {
  244. var info = GroupInfoServerModel.fromJson(resList[i]);
  245. groupList.add(GroupInfoModel.fromServerGroupInfo(info));
  246. }
  247. return groupList;
  248. }
  249. } catch (e) {
  250. print(e);
  251. }
  252. return null;
  253. }
  254. //获取多个群信息
  255. Future<List<GroupInfoModel>> getMoreGroupInfo(List<int> groupIds) async {
  256. Response response;
  257. var myId = UserData().basicInfo.userId;
  258. Map<String, dynamic> data = {
  259. 'userid': myId,
  260. };
  261. data['sign'] = getSign(data);
  262. data['groupids'] = groupIds;
  263. try {
  264. print('开始请求 getMoreGroupInfo $data');
  265. response = await dio.post(rootUrl + '/chat/querygroups', data: data);
  266. Map resData = response.data;
  267. if (resData['code'] == 0) {
  268. List data = resData['data'];
  269. print('群信息$data');
  270. if (data != null && data.length > 0) {
  271. List<GroupInfoModel> res = [];
  272. for (var each in data) {
  273. var info = GroupInfoServerModel.fromJson(each);
  274. res.add(GroupInfoModel.fromServerGroupInfo(info));
  275. }
  276. return res;
  277. }
  278. }
  279. } catch (e) {
  280. print(e);
  281. }
  282. return null;
  283. }
  284. //获取群信息
  285. Future<GroupInfoModel> getGroupInfo(int groupId) async {
  286. Response response;
  287. var myId = UserData().basicInfo.userId;
  288. Map<String, dynamic> data = {
  289. 'userid': myId,
  290. };
  291. data['sign'] = getSign(data);
  292. data['groupids'] = [groupId];
  293. try {
  294. print('开始请求群信息$data');
  295. response = await dio.post(rootUrl + '/chat/querygroups', data: data);
  296. Map resData = response.data;
  297. if (resData['code'] == 0) {
  298. List data = resData['data'];
  299. print('群信息$data');
  300. if (data != null && data.length > 0) {
  301. var info = GroupInfoServerModel.fromJson(data.first);
  302. return GroupInfoModel.fromServerGroupInfo(info);
  303. }
  304. }
  305. } catch (e) {
  306. print(e);
  307. }
  308. return null;
  309. }
  310. //获取群校验信息
  311. Future<Map> getGroupCheckInfo() async {
  312. Response response;
  313. var myId = UserData().basicInfo.userId;
  314. Map<String, dynamic> data = {
  315. 'userid': myId,
  316. };
  317. data['sign'] = getSign(data);
  318. try {
  319. print('请求获取群校验信息$data');
  320. response = await dio.post(rootUrl + '/chat/checkgroup', data: data);
  321. Map resData = response.data;
  322. if (resData['code'] == 0) {
  323. print('群校验信息${resData['data']}');
  324. return resData['data'];
  325. }
  326. } catch (e) {
  327. print(e);
  328. }
  329. return null;
  330. }
  331. }