import 'dart:async'; import 'dart:convert'; import 'dart:io'; import 'dart:typed_data'; import 'package:fis_common/logger/logger.dart'; import 'package:fis_jsonrpc/rpc.dart'; import 'package:http/http.dart' as http; import 'package:image_picker/image_picker.dart'; import 'package:path_provider/path_provider.dart'; import 'package:vitalapp/architecture/utils/prompt_box.dart'; import 'package:vitalapp/rpc.dart'; import 'package:vitalapp/store/store.dart'; import 'package:universal_html/html.dart' as html; /// 部分分段返回的结果 class PartFileResultInfo { /// 分片上传的文件地址 String fileUrl; /// 分片上传的eTag String eTag; /// 分块的uploadId String uploadId; /// 分块的下标 int partNumber; PartFileResultInfo({ required this.fileUrl, required this.eTag, required this.uploadId, required this.partNumber, }); } /// 分段上传文件 class PartUploadFileInfo { /// 分片的下标 int partNumber; /// 初始化生成的uploadId String uploadId; /// 分片文件的二进制数据 Uint8List fileBytes; PartUploadFileInfo({ required this.partNumber, required this.uploadId, required this.fileBytes, }); } ///存储上传文件基本信息 class StorageUploadFileInfo { ///文件token String fileToken; ///文件的二进制数据 Uint8List fileBytes; ///文件名 String fileName; ///文件模拟类型 String? mimeType; /// 文件大小 int? fileSize; StorageUploadFileInfo({ required this.fileToken, required this.fileBytes, required this.fileName, this.mimeType, this.fileSize, }); } ///存储上传请求 class StorageUploadRequest { StorageUploadFileInfo fileInfo; StorageUploadRequest({ required this.fileInfo, }); } ///web的存储API class StorageWebApi { Future testApi() async => false; } ///存储服务扩展类 extension StorageServiceExt on StorageService { ///鉴权 TODO: fileName 为空则接口报错,所以此处设置一个默认值 Future getAuth({ String? fileName, bool? isRechristen, List? urlParams, List? headerParams, String? requestMethod, }) async { try { final result = await rpc.storage.getAuthorizationAsync(FileServiceRequest( token: Store.user.token, fileName: fileName ?? "dat", isRechristen: isRechristen ?? true, urlParams: urlParams, headerParams: headerParams, requestMethod: requestMethod, )); return result; } catch (e) { return StorageServiceSettingDTO(); } } /// 图片上传 Future upload(XFile xfile, {String? fileType}) async { try { final auth = await getAuth(fileName: fileType); final bytes = await xfile.readAsBytes(); Map params = {}; params['Authorization'] = auth.authorization!; params['ContentType'] = auth.contentType!; final response = await http .put( Uri.parse(auth.storageUrl!), body: bytes, headers: params, ) .timeout( const Duration(seconds: 30), ); if (response.statusCode == 200) { return auth.storageUrl!; } } catch (e) { PromptBox.toast('上传失败'); logger.e("file upload error", e); return null; } return null; } /// web 端图片上传 Future webUpload(html.File file, {String? fileType}) async { try { final auth = await getAuth(fileName: fileType); final bytes = await readBytesFromHtmlFile(file); Map params = {}; params['Authorization'] = auth.authorization!; params['ContentType'] = auth.contentType!; final response = await http .put( Uri.parse(auth.storageUrl!), body: bytes, headers: params, ) .timeout( const Duration(seconds: 30), ); if (response.statusCode == 200) { return auth.storageUrl!; } } catch (e) { PromptBox.toast('上传失败'); logger.e("file upload error", e); return null; } return null; } Future> readBytesFromHtmlFile(html.File file) async { final completer = Completer>(); final reader = html.FileReader(); reader.onLoadEnd.listen((html.ProgressEvent event) { final result = reader.result; completer.complete(result as FutureOr>?); }); reader.onError.listen((html.ProgressEvent event) { completer.completeError('Error reading file'); }); reader.readAsArrayBuffer(file); return completer.future; } // 将字符串写入文件 Future writeStringToFile(String content) async { final tempDir = await getTemporaryDirectory(); final tempFile = File('${tempDir.path}/temp.txt'); await tempFile.writeAsString(content); return tempFile; } // 文件上传 Future uploadFile(File file) async { try { final auth = await getAuth(); final bytes = await file.readAsBytes(); Map params = {}; params['Authorization'] = auth.authorization!; params['ContentType'] = auth.contentType!; final response = await http .put( Uri.parse(auth.storageUrl!), body: bytes, headers: params, ) .timeout( const Duration(seconds: 30), ); if (response.statusCode == 200) { return auth.storageUrl!; } } catch (e) { PromptBox.toast('上传失败'); logger.e("file upload error", e); return null; } return null; } ///文件上传(base64) Future uploadBase64File(String base64Str, String name) async { try { var buffer = base64.decode(base64Str); return uploadUint8List(buffer, name); } catch (e) { logger.e("file upload error", e); } return null; } ///文件上传(UInt8List) Future uploadUint8List(Uint8List buffer, String name, [bool? isRechristen]) async { try { var nameInfos = name.split('.'); final auth = await getAuth( fileName: nameInfos.last, isRechristen: isRechristen, ); Map params = {}; params['Authorization'] = auth.authorization!; params['ContentType'] = auth.contentType!; final response = await http .put( Uri.parse(auth.storageUrl!), body: buffer, headers: params, ) .timeout( const Duration(seconds: 30), ); if (response.statusCode == 200) { return auth.storageUrl; } } catch (e) { logger.e('StorageServiceExt uploadUint8List ex:$e'); } return null; } }