import 'dart:convert'; import 'package:chat/data/UserData.dart'; import 'package:chat/generated/i18n.dart'; import 'package:chat/models/ChatMsg.dart'; import 'package:chat/models/group_info_model.dart'; import 'package:chat/models/group_info_server_model.dart'; import 'package:chat/proto/all.pbserver.dart'; import 'package:chat/data/constants.dart'; import 'package:chat/utils/file_cache_mgr.dart'; import 'package:convert/convert.dart'; import 'package:dio/dio.dart'; import 'package:crypto/crypto.dart'; import 'dart:async'; import 'package:http_parser/http_parser.dart'; import 'package:chat/utils/MessageMgr.dart'; import 'package:oktoast/oktoast.dart'; import 'package:chat/utils/msgHandler.dart'; import 'package:chat/utils/sql_util.dart'; var signKey = 'O@MlSxWaeAlc5CYu'; class UploadUtil { // 工厂模式 factory UploadUtil() => _getInstance(); static UploadUtil get instance => _getInstance(); static UploadUtil _instance; UploadUtil._internal() { // 初始化 } static UploadUtil _getInstance() { if (_instance == null) { _instance = new UploadUtil._internal(); } return _instance; } Dio dio; //进度流 Map> streamMap = {}; //缓存进度,方便快速显示 Map streamLastPercentMap = {}; //上传地址 String uploadUrl; String rootUrl; void setUploadUrl(url) { rootUrl = 'http://' + url; uploadUrl = 'http://' + url + '/chatresfile/'; BaseOptions options = BaseOptions( baseUrl: uploadUrl, headers: {}, ); print(uploadUrl); dio = new Dio(options); } // md5 加密 String generateMd5(String data) { var content = new Utf8Encoder().convert(data); var digest = md5.convert(content); // 这里其实就是 digest.toString() return hex.encode(digest.bytes); } String getSign(Map parameter) { String k = ''; var keyList = []; for (var key in parameter.keys) { keyList.add(key); } keyList.sort(); for (var key in keyList) { k += '$key=${parameter[key]}&'; } k += 'key=O@MlSxWaeAlc5CYu'; return generateMd5(k); } String getFileType(String suffix) { if (suffix == 'png' || suffix == 'jpg' || suffix == 'jpeg') { return 'image'; } else if (suffix == 'wav') { return 'audio'; } else { return 'video'; } } bool isImage(String suffix) { suffix = suffix.toLowerCase(); return suffix == 'png' || suffix == 'jpg' || suffix == 'jpeg'; } StreamController getStream(String fileId) { if (streamMap[fileId] == null) { streamMap[fileId] = StreamController.broadcast(); } return streamMap[fileId]; } Future uploadFile(MsgModel msg, {CancelToken cancelToken}) async { Response response; var data = { "upuserid": msg.from, 'channeltype': msg.channelType, "targetid": msg.sessionId, 'fileid': msg.extraFile, }; print('上传参数$data'); var path = msg.localFile; var name = path.substring(path.lastIndexOf("/") + 1, path.length); String suffix = name.substring(name.lastIndexOf(".") + 1, name.length); var fileType = getFileType(suffix); print('文件类型 : $fileType $suffix'); data['sign'] = getSign(data); data['uploadfile'] = await MultipartFile.fromFile(path, filename: name, contentType: MediaType(fileType, suffix)); FormData formData = new FormData.fromMap(data); try { print('开始上传文件${msg.extraFile} url:${uploadUrl + 'uploadchatfile'}'); var streamController = getStream(msg.extraFile); response = await dio.post(uploadUrl + 'uploadchatfile', data: formData, onSendProgress: (int progress, int total) { streamController.sink.add(progress / total); streamLastPercentMap[msg.extraFile] = progress / total; }, cancelToken: cancelToken); streamController.close(); streamMap.remove(msg.extraFile); print('uploadFile response $response'); print('###msgContent ${msg.msgContent.length}'); if (response.data['code'] == 0) { var data = response.data['data']; print('uploadFile 上传成功'); msg.state = MsgState.Uploaded; MsgHandler.sendChatMsg(msg); MessageMgr().emit('Update LastMsg', msg.sessionId); return data; } else { print('uploadFile 上传失败'); msg.state = MsgState.UploadFailed; MessageMgr().emit('Update LastMsg', msg.sessionId); return null; } } on DioError catch (e) { if (CancelToken.isCancel(e)) { print('post请求取消! ' + e.message); } showToast('上传文件失败'); msg.state = MsgState.UploadFailed; print('post请求发生错误:$e'); } MessageMgr().emit('Update LastMsg', msg.sessionId); return null; } void cancelRequests(CancelToken cancelToken) { print('取消请求$cancelToken'); cancelToken.cancel("cancelled"); } String getFullUrl(String imgData, int sessionid, int channelType) { var data = { "fileid": imgData, 'targetid': sessionid, "userid": UserData().basicInfo.userId, 'channeltype': channelType }; var sign = getSign(data); return uploadUrl + 'downloadchatfile?targetid=$sessionid&channeltype=$channelType&userid=${UserData().basicInfo.userId}&fileid=$imgData&sign=$sign'; } Future downloadFile(MsgModel msg, {CancelToken cancelToken}) async { Response response; var fullUrl = getFullUrl(msg.extraFile, msg.sessionId, msg.channelType); print('下载文件$fullUrl'); var path = await FileCacheMgr().genFilePath(msg.extraFile); if (msg.msgType == ChatType.ShortVoiceChatType.value) { path = path + '.wav'; } else if (msg.msgType == ChatType.FileChatType.value) { var fileMsg = FileChat.fromBuffer(msg.msgContent); var fileName = fileMsg.name; path = await FileCacheMgr().genFilePath(fileName); } print('文件保存路径$path'); try { var streamController = getStream(msg.extraFile); response = await dio.download(fullUrl, path, onReceiveProgress: (int progress, int total) { streamController.sink.add(progress / total); streamLastPercentMap[msg.extraFile] = progress / total; }, cancelToken: cancelToken); streamController.close(); streamMap.remove(msg.extraFile); if (response.statusCode == 200) { msg.state = MsgState.DownloadSuccess; msg.localFile = path; SqlUtil().updateLocalFile(msg.extraFile, path, isGroup: msg.channelType == ChatChannelType.Group.value); return path; } else { msg.state = MsgState.DownloadFailed; showToast(I18n.of(Constants.getCurrentContext()).server_error_tips); return null; } } catch (e) { msg.state = MsgState.DownloadFailed; showToast(I18n.of(Constants.getCurrentContext()).server_error_tips); print(response.toString()); } } //机器人翻译,type 1文字,2语音 Future commitTranslateSource( int type, int sourceLang, int toLang, dynamic content) async { Response response; var myId = UserData().basicInfo.userId; Map data = { 'userid': myId, 'cType': type, 'ulanguage': sourceLang, 'tlanguage': toLang }; data['sign'] = getSign(data); data['content'] = content; if (type == 2) { data['content'] = await MultipartFile.fromFile(content); } FormData formData = new FormData.fromMap(data); try { print('开始请求翻译$data ${uploadUrl + 'translate/transqt'}'); response = await dio.post(rootUrl + '/translate/transqt', data: formData); Map resData = response.data; print('翻译结果$resData'); if (resData['code'] == 0) { return resData['data']; } } catch (e) { print(e); } return null; } //获取群列表 Future> getGroupList() async { Response response; var myId = UserData().basicInfo.userId; Map data = { 'userid': myId, }; data['sign'] = getSign(data); try { print('开始请求群列表$data}'); response = await dio.post(rootUrl + '/chat/queryusergroups', data: data); Map resData = response.data; if (resData['code'] == 0) { List resList = resData['data']; List groupList = []; for (var i = 0; i < resList.length; i++) { var info = GroupInfoServerModel.fromJson(resList[i]); groupList.add(GroupInfoModel.fromServerGroupInfo(info)); } return groupList; } } catch (e) { print(e); } return null; } //获取多个群信息 Future> getMoreGroupInfo(List groupIds) async { Response response; var myId = UserData().basicInfo.userId; Map data = { 'userid': myId, }; data['sign'] = getSign(data); data['groupids'] = groupIds; try { print('开始请求 getMoreGroupInfo $data'); response = await dio.post(rootUrl + '/chat/querygroups', data: data); Map resData = response.data; if (resData['code'] == 0) { List data = resData['data']; print('群信息$data'); if (data != null && data.length > 0) { List res = []; for (var each in data) { var info = GroupInfoServerModel.fromJson(each); res.add(GroupInfoModel.fromServerGroupInfo(info)); } return res; } } } catch (e) { print(e); } return null; } //获取群信息 Future getGroupInfo(int groupId) async { Response response; var myId = UserData().basicInfo.userId; Map data = { 'userid': myId, }; data['sign'] = getSign(data); data['groupids'] = [groupId]; try { print('开始请求群信息$data'); response = await dio.post(rootUrl + '/chat/querygroups', data: data); Map resData = response.data; if (resData['code'] == 0) { List data = resData['data']; print('群信息$data'); if (data != null && data.length > 0) { var info = GroupInfoServerModel.fromJson(data.first); return GroupInfoModel.fromServerGroupInfo(info); } } } catch (e) { print(e); } return null; } //获取群校验信息 Future getGroupCheckInfo() async { Response response; var myId = UserData().basicInfo.userId; Map data = { 'userid': myId, }; data['sign'] = getSign(data); try { print('请求获取群校验信息$data'); response = await dio.post(rootUrl + '/chat/checkgroup', data: data); Map resData = response.data; if (resData['code'] == 0) { print('群校验信息${resData['data']}'); return resData['data']; } } catch (e) { print(e); } return null; } }