Hibok
Nevar pievienot vairāk kā 25 tēmas Tēmai ir jāsākas ar burtu vai ciparu, tā var saturēt domu zīmes ('-') un var būt līdz 35 simboliem gara.
 
 
 
 
 
 

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