From 2917b2b68dd50152905781d1633de16cf8573fae Mon Sep 17 00:00:00 2001 From: xuty <xty50337@hotmail.com> Date: Sun, 29 Mar 2020 14:50:07 +0800 Subject: [PATCH] finish removeObject --- example/minio_example.dart | 29 +++++++++++++---- lib/src/minio.dart | 50 +++++++++++++++++++++++++---- lib/src/minio_models_generated.dart | 29 ++++++++++------- lib/src/utils.dart | 19 ++++++++++- 4 files changed, 101 insertions(+), 26 deletions(-) diff --git a/example/minio_example.dart b/example/minio_example.dart index 4e2329a..c26829b 100644 --- a/example/minio_example.dart +++ b/example/minio_example.dart @@ -6,13 +6,16 @@ import 'package:minio/models.dart'; void main() async { final minio = Minio( endPoint: 'play.min.io', - useSSL: false, accessKey: 'Q3AM3UQ867SPQQA43P2F', secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG', + useSSL: false, + enableTrace: true, ); final bucket = '00test'; final object = 'teaweb.png'; + final copy1 = '$object.copy'; + final copy2 = '$object.copy2'; if (!await minio.bucketExists(bucket)) { await minio.makeBucket(bucket); @@ -42,14 +45,18 @@ void main() async { final file = File('example/$object'); final size = await file.length(); final etag = await minio.putObject(bucket, object, file.openRead(), size); + print('---'); + print('etag:'); print(etag); - final copyResult = await minio.copyObject( - bucket, - '$object.copy', - '$bucket/$object', - ); - print(copyResult.eTag); + final copyResult1 = await minio.copyObject(bucket, copy1, '$bucket/$object'); + final copyResult2 = await minio.copyObject(bucket, copy2, '$bucket/$object'); + print('---'); + print('Copy1 etag:'); + print(copyResult1.eTag); + print('---'); + print('Copy2 etag:'); + print(copyResult2.eTag); final stat = await minio.statObject(bucket, object); print('Stat:'); @@ -57,4 +64,12 @@ void main() async { print(stat.size); print(stat.lastModified); print(stat.metaData); + + await minio.removeObject(bucket, object); + print('---'); + print('Removed'); + + await minio.removeObjects(bucket, [copy1, copy2]); + print('---'); + print('Copy removed'); } diff --git a/lib/src/minio.dart b/lib/src/minio.dart index d1c3043..74120b4 100644 --- a/lib/src/minio.dart +++ b/lib/src/minio.dart @@ -169,10 +169,8 @@ class MinioClient { ); } - static var enableTrace = true; - - static void logRequest(MinioRequest request) { - if (!enableTrace) return; + void logRequest(MinioRequest request) { + if (!minio.enableTrace) return; final buffer = StringBuffer(); buffer.writeln('REQUEST: ${request.method} ${request.url}'); @@ -189,8 +187,8 @@ class MinioClient { print(buffer.toString()); } - static void logResponse(BaseResponse response) { - if (!enableTrace) return; + void logResponse(BaseResponse response) { + if (!minio.enableTrace) return; final buffer = StringBuffer(); buffer.writeln('RESPONSE: ${response.statusCode} ${response.reasonPhrase}'); @@ -217,6 +215,7 @@ class Minio { this.secretKey = '', this.sessionToken, this.region, + this.enableTrace = false, }) : assert(isValidEndpoint(endPoint)), assert(port == null || isValidPort(port)), assert(useSSL != null), @@ -236,6 +235,7 @@ class Minio { final String secretKey; final String sessionToken; final String region; + final bool enableTrace; MinioClient _client; final _regionMap = <String, String>{}; @@ -734,6 +734,44 @@ class Minio { _regionMap.remove(bucket); } + Future<void> removeObject(String bucket, String object) async { + MinioInvalidBucketNameError.check(bucket); + MinioInvalidObjectNameError.check(object); + + final resp = await _client.request( + method: 'DELETE', + bucket: bucket, + object: object, + ); + + validate(resp, expect: 204); + } + + Future<void> removeObjects(String bucket, List<String> objects) async { + MinioInvalidBucketNameError.check(bucket); + + final bunches = groupList(objects, 1000); + + for (var bunch in bunches) { + final payload = Delete( + bunch.map((key) => ObjectIdentifier(key, null)).toList(), + true, + ).toXml().toString(); + + final headers = { + 'Content-MD5': md5Base64(payload) + }; + + await _client.request( + method: 'POST', + bucket: bucket, + resource: 'delete', + headers: headers, + payload: payload + ); + } + } + Future<StatObjectResult> statObject(String bucket, String object) async { MinioInvalidBucketNameError.check(bucket); MinioInvalidObjectNameError.check(object); diff --git a/lib/src/minio_models_generated.dart b/lib/src/minio_models_generated.dart index e76ab16..36a67a6 100644 --- a/lib/src/minio_models_generated.dart +++ b/lib/src/minio_models_generated.dart @@ -442,7 +442,7 @@ class CompletedPart { builder.element('ETag', nest: eTag); builder.element('PartNumber', nest: partNumber.toString()); }); - return builder.build(); + return (builder.build() as XmlDocument).rootElement; } /// Entity tag returned when the part was uploaded. @@ -789,22 +789,24 @@ class Delete { this.quiet, ); - Delete.fromXml(XmlElement xml) { - objects = ObjectIdentifier.fromXml(getProp(xml, 'Objects')); - quiet = getProp(xml, 'Quiet')?.text?.toUpperCase() == 'TRUE'; - } + // Delete.fromXml(XmlElement xml) { + // objects = ObjectIdentifier.fromXml(getProp(xml, 'Objects')); + // quiet = getProp(xml, 'Quiet')?.text?.toUpperCase() == 'TRUE'; + // } XmlNode toXml() { final builder = XmlBuilder(); builder.element('Delete', nest: () { - builder.element('Objects', nest: objects.toXml()); + for (var object in objects) { + builder.element('Object', nest: object.toXml().children); + } builder.element('Quiet', nest: quiet ? 'TRUE' : 'FALSE'); }); return builder.build(); } /// The objects to delete. - ObjectIdentifier objects; + List<ObjectIdentifier> objects; /// Element to enable quiet mode for the request. When you add this element, you must set its value to true. bool quiet; @@ -1664,7 +1666,8 @@ class LifecycleExpiration { date = DateTime.parse(getProp(xml, 'Date')?.text); days = int.tryParse(getProp(xml, 'Days')?.text); expiredObjectDeleteMarker = - getProp(xml, 'ExpiredObjectDeleteMarker')?.text?.toUpperCase() == 'TRUE'; + getProp(xml, 'ExpiredObjectDeleteMarker')?.text?.toUpperCase() == + 'TRUE'; } XmlNode toXml() { @@ -2271,13 +2274,15 @@ class ObjectIdentifier { versionId = getProp(xml, 'VersionId')?.text; } - XmlNode toXml() { + XmlElement toXml() { final builder = XmlBuilder(); - builder.element('ObjectIdentifier', nest: () { + builder.element('Object', nest: () { builder.element('Key', nest: key); - builder.element('VersionId', nest: versionId); + if (versionId != null) { + builder.element('VersionId', nest: versionId); + } }); - return builder.build(); + return (builder.build() as XmlDocument).rootElement; } /// Key name of the object to delete. diff --git a/lib/src/utils.dart b/lib/src/utils.dart index e0be398..1f20c22 100644 --- a/lib/src/utils.dart +++ b/lib/src/utils.dart @@ -1,5 +1,6 @@ import 'dart:async'; import 'dart:convert'; +import 'dart:math' as math; import 'package:buffer/buffer.dart'; import 'package:convert/convert.dart'; @@ -19,6 +20,11 @@ String sha256Hex(Object data) { return hex.encode(sha256.convert(data).bytes); } +String md5Base64(String source) { + final md5digest = md5.convert(utf8.encode(source)).bytes; + return base64.encode(md5digest); +} + XmlElement getNodeProp(XmlElement xml, String name) { final result = xml.findElements(name); return result.isNotEmpty ? result.first : null; @@ -73,4 +79,15 @@ String trimDoubleQuote(String str) { DateTime parseRfc7231Time(String time) { final format = DateFormat('EEE, dd MMM yyyy hh:mm:ss zzz'); return format.parse(time); -} \ No newline at end of file +} + +List<List<T>> groupList<T>(List<T> list, int maxMembers) { + final groups = (list.length / maxMembers).ceil(); + final result = <List<T>>[]; + for (var i = 0; i < groups; i++) { + final start = i * maxMembers; + final end = math.min(start + maxMembers, list.length); + result.add(list.sublist(start, end)); + } + return result; +} -- GitLab