You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

343 lines
11 KiB

/*
* ====================================================
* package : manager
* author : Created by nansi.
* time : 2019/5/20 10:23 AM
* remark :
* ====================================================
*/
import 'dart:async';
import 'dart:collection';
import 'dart:convert';
import 'dart:io';
import 'package:async/async.dart';
import 'package:dio/adapter.dart';
import 'package:dio/dio.dart';
import 'package:path/path.dart';
import 'package:power_logger/power_logger.dart';
import 'package:recook/constants/api.dart';
import 'package:recook/constants/config.dart';
import 'package:recook/manager/user_manager.dart';
import 'package:recook/models/image_upload_model.dart';
import 'package:recook/models/media_model.dart';
import 'package:recook/utils/image_utils.dart';
import 'package:recook/utils/print_util.dart';
import 'package:recook/utils/sc_encrypt_util.dart';
typedef OnSuccess<T> = Function(T data, String code, String msg);
typedef OnFailure = Function(String code, String msg);
class HttpCode {
static const SUCCESS = 1000;
static const FAILURE = 999;
static const ERROR = -1;
}
class HttpStatus {
static const SUCCESS = "SUCCESS";
static const FAILURE = "FAIL";
static const UNAUTHORIZED = "UNAUTHORIZED"; //登录失效
static const ERROR = "ERROR";
}
class HttpManager {
static const CONTENT_TYPE_JSON = "application/json";
static const CONTENT_TYPE_FORM = "application/x-www-form-urlencoded";
static Map optionParams = {
"timeoutMs": 15000,
"token": null,
"authorizationCode": null,
};
static Future<Null> uploadFiles(
{url = CommonApi.upload, List<MediaModel> medias, key = "photo"}) async {
FutureGroup group = FutureGroup();
medias.forEach((media) {
group.add(uploadFile(url: url, file: media.file, key: key).then((result) {
media.result = result;
}));
});
group.close();
await group.future;
return null;
}
static Future<UploadResult> uploadFile({url, File file, key}) async {
Map<String, dynamic> header = Map();
if (UserManager.instance.user.auth != null) {
header.putIfAbsent(
"X-Recook-ID", () => UserManager.instance.user.auth.id.toString());
header.putIfAbsent(
"X-Recook-Token", () => UserManager.instance.user.auth.token);
}
Dio dio = new Dio();
dio.options.baseUrl = Api.host;
dio.options.headers = header;
var result = await ImageUtils.compressImageWithBytes(
file.absolute.path,
quality: 60,
);
print("原大小: " +
file.lengthSync().toString() +
"------- 压缩后大小: " +
result.length.toString());
// FormData formData =
// new FormData.from({key: new UploadFileInfo.fromBytes(result, basename(file.path))});
FormData formData = new FormData.fromMap({
key: new MultipartFile.fromBytes(result, filename: basename(file.path))
});
Response response = await dio.post(url, data: formData);
DPrint.printf("上传返回 ==== ${response.toString()}");
ResultData resultData = _handleResponse(response.toString());
if (!resultData.result) {
return UploadResult(false, resultData.msg, "");
}
ImageUploadModel model = ImageUploadModel.fromJson(resultData.data);
if (model.code != HttpStatus.SUCCESS) {
return UploadResult(false, model.msg, "");
}
return UploadResult(true, resultData.msg, model.data.url);
}
static Future<ResultData> post(url, params,
{Map<String, String> header, Options option, noTip = false}) async {
if (option != null) {
option.method = "post";
} else {
// option = new Options(method: "post", connectTimeout: 5000);
option =
new Options(method: "post", sendTimeout: 5000, receiveTimeout: 5000);
}
if (header == null) {
header = Map<String, String>();
}
header.putIfAbsent(
"X-Recook-System", () => Platform.isIOS ? "ios" : "android");
header.putIfAbsent("X-Recook-version", () => "${AppConfig.versionNumber}");
if (UserManager.instance.user.auth != null) {
header.putIfAbsent(
"X-Recook-ID", () => UserManager.instance.user.auth.id.toString());
header.putIfAbsent(
"X-Recook-Token", () => UserManager.instance.user.auth.token);
}
header.putIfAbsent('Device-Type', () => Platform.isIOS ? "ios" : "android");
DPrint.printf(header);
return await netFetch(url, params, header, option);
}
///发起网络请求
///[ url] 请求url
///[ params] 请求参数
///[ header] 外加头
///[ option] 配置
static Future<ResultData> netFetch(
url, params, Map<String, String> header, Options option,
{noTip = false}) async {
Map<String, String> headers = new HashMap();
if (header != null) {
headers.addAll(header);
}
if (option != null) {
option.headers = headers;
} else {
option = new Options(
method: "post",
receiveTimeout: 5000,
sendTimeout: 5000,
);
option.headers = headers;
}
Dio dio = new Dio();
dio.options.baseUrl = Api.host;
dio.options.connectTimeout = 10000;
dio.options.receiveTimeout = 5000;
dio.options.method = "POST";
// https 关闭证书验证
(dio.httpClientAdapter as DefaultHttpClientAdapter).onHttpClientCreate =
(HttpClient client) {
client.badCertificateCallback =
(X509Certificate cert, String host, int port) => true;
};
Response response;
Map encryptParams = params;
// if (AppConfig.needEncrypt) {
encryptParams = await paramsEncrypt(params: params);
// }
DPrint.printf(params);
DPrint.printf(encryptParams);
try {
response =
await dio.request<String>(url, data: encryptParams, options: option);
} on DioError catch (e) {
LoggerData.addData(e..requestOptions.data = params);
Response errorResponse;
if (e.response != null) {
errorResponse = e.response;
} else {
errorResponse = new Response(
statusCode: 666, requestOptions: RequestOptions(path: ''));
}
if (e.type == DioErrorType.connectTimeout) {
errorResponse.statusCode = HttpCode.ERROR;
}
if (AppConfig.debug) {
print('❌❌❌❌请求异常: ' + e.toString());
print('请求异常url: ' + Api.host + url);
}
return new ResultData(null, false, HttpStatus.ERROR, "您的网络出小差了,\n请稍后再试");
// return new ResultData(null, false, HttpStatus.ERROR, "网络崩溃了");
// return new ResultData(null, false, HttpStatus.ERROR, "请求出错,请稍后再试");
}
LoggerData.addData((response)..requestOptions.data = params);
String responseStr = response.data;
if (AppConfig.needEncrypt) {
responseStr = await responseDecrypt(response.data);
}
if (AppConfig.debug) {
DPrint.printf('请求url: ---- ' + Api.host + url);
DPrint.printf('请求头: ---- ' + option.headers.toString());
if (params != null) {
DPrint.printf('请求参数: ' + json.encode(params));
DPrint.printf('请求加密参数: ' + json.encode(encryptParams));
}
if (response != null) {
DPrint.printf('返回reponse: ---- ' + response.data);
if (AppConfig.needEncrypt) {
DPrint.printLongJson('解密返回reponse: ---- ' + responseStr);
}
}
if (optionParams["authorizationCode"] != null) {
DPrint.printf(
'authorizationCode: ' + optionParams["authorizationCode"]);
}
}
return _handleResponse(responseStr);
}
static ResultData _handleResponse(String responseStr) {
Map<String, dynamic> map = json.decode(responseStr);
if (map != null) {
if (map["code"] == HttpStatus.SUCCESS) {
DPrint.printf("🍎🍎🍎🍎 data --- ${json.encode(map["data"])}");
return new ResultData(map["data"], true, map["code"], map["msg"]);
} else if (map["code"] == HttpStatus.UNAUTHORIZED) {
Future.delayed(Duration(milliseconds: 300), () {
UserManager.logout();
});
return new ResultData(map["data"], false, map["code"], "登录失效,请重新登录");
} else {
print("❎❎❎❎ --- 服务器错误 --- ${map["msg"]}");
return new ResultData(map["data"], false, map["code"], "${map["msg"]}");
}
}
return new ResultData(responseStr, true, map["code"], map["msg"]);
}
///发起网络请求
///[ url] 请求url
///[ params] 请求参数
///[ header] 外加头
///[ option] 配置
static Future<Response> netFetchNormal(
url, params, Map<String, String> header, Options option,
{noTip = false}) async {
Map<String, String> headers = new HashMap();
if (header != null) {
headers.addAll(header);
}
if (option != null) {
option.headers = headers;
} else {
option = new Options(method: "get");
option.headers = headers;
}
Dio dio = new Dio();
Response response;
try {
response = await dio.request<String>(url, data: params, options: option);
} on DioError catch (e) {
Response errorResponse;
if (e.response != null) {
errorResponse = e.response;
} else {
errorResponse = new Response(
statusCode: 666, requestOptions: RequestOptions(path: ''));
}
if (e.type == DioErrorType.connectTimeout) {
errorResponse.statusCode = HttpCode.ERROR;
}
if (AppConfig.debug) {
print('请求异常: ' + e.toString());
print('请求异常url: ' + url);
}
return response;
}
if (AppConfig.debug) {
print('请求url: ' + Api.host + url);
print('请求头: ' + option.headers.toString());
if (params != null) {
print('请求参数: ' + params.toString());
}
if (response != null) {
print('返回参数: ' + response.toString());
}
if (optionParams["authorizationCode"] != null) {
print('authorizationCode: ' + optionParams["authorizationCode"]);
}
}
return response;
}
/// 参数加密
static paramsEncrypt({Map params}) async {
int timestamp = DateTime.now().second;
String md5Str = SCEncryptUtil.md5Encrypt(timestamp.toString());
String aesEncryptStr = await SCEncryptUtil.aesEncrypt(
key: md5Str, encryptString: json.encode(params));
String rsaKey = await SCEncryptUtil.rsaEncrypt(encryptString: md5Str);
return {"key": rsaKey, "body": aesEncryptStr};
}
/// response 解密
static responseDecrypt(String responseJson) async {
Map response = json.decode(responseJson);
String rsaDecryptKey =
await SCEncryptUtil.rsaDecrypt(decryptString: response["key"]);
String decryptStr = await SCEncryptUtil.aesDecrypt(
key: rsaDecryptKey, decryptString: response["body"]);
return decryptStr;
}
}
class ResultData {
var data;
/// 网络请求错误或者服务器返回错误时 为false
bool result;
String code;
var headers;
String msg;
ResultData(this.data, this.result, this.code, this.msg, {this.headers});
}