From 290c0db7dc8a909c2dfcb4e3ae95c7e632bcf889 Mon Sep 17 00:00:00 2001
From: xuty <xty50337@hotmail.com>
Date: Sat, 28 Mar 2020 22:20:46 +0800
Subject: [PATCH] refinement

---
 example/minio_example.dart  |  17 ++++++++++++++-
 example/teaweb.png          | Bin 0 -> 1707 bytes
 lib/src/minio.dart          |  40 ++++++++++++++++++++++++------------
 lib/src/minio_uploader.dart |  35 ++++++++++++-------------------
 lib/src/utils.dart          |  12 +++++++++--
 5 files changed, 66 insertions(+), 38 deletions(-)
 create mode 100644 example/teaweb.png

diff --git a/example/minio_example.dart b/example/minio_example.dart
index 4b19f38..fc7faf2 100644
--- a/example/minio_example.dart
+++ b/example/minio_example.dart
@@ -11,8 +11,17 @@ void main() async {
     secretKey: 'zuf+tfteSlswRu7BJ86wekitnifILbZam1KYY3TG',
   );
 
+  final bucket = '00test';
+
+  if (!await minio.bucketExists(bucket)) {
+    await minio.makeBucket(bucket);
+    print('bucket $bucket created');
+  } else {
+    print('bucket $bucket already exists');
+  }
+
   // print(await minio.bucketExists('02test'));
-  // await minio.makeBucket('05test');
+  // await minio.makeBucket('00test');
   // await minio.removeBucket('05test');
   // print(await minio.getBucketRegion('00test'));
   // print(await minio.getBucketRegion('00test'));
@@ -28,4 +37,10 @@ void main() async {
 
   // final object = await minio.getObject('00test', 'sys8_captcha.png');
   // await File('sys8_captcha.png').openWrite().addStream(object);
+
+  final file = File('example/teaweb.png');
+  final size = await file.length();
+  final etag =
+      await minio.putObject(bucket, 'teaweb.png', file.openRead(), size);
+  print(etag);
 }
diff --git a/example/teaweb.png b/example/teaweb.png
new file mode 100644
index 0000000000000000000000000000000000000000..84746b3b671c92a99bfe0bb17c9abd2a66b24ac6
GIT binary patch
literal 1707
zcmaJ?Yfuws6b-LdXc=p<R<z0*R769v3C6HnB9A0Uv_ZsB6Rd@hEFnU&F<H!phdeB{
zf@qnxP8fBlVim*@G!CLop%xW^3REbs5uXS}r4*2t7}E^``lEDbcE88mbMCqKJKya7
z(2xzzPK%sKB$6{fm>Win4C_0`miXrGaO)-pSBxjZwxThZPNG3b0Wvfi0r*OZ90@}t
zGX1U^#Fs>}Td5F=Fp=OhSc)pC5^D?<SE>m#iR9~tt0mGn1OuWGxkAMz_y1f;1{5+j
zc^gvz3e+4VRuP=2LAEA_2&IW}Qb<PjTMzi+FhQV1FbRMw<5gN1XOky+VPbCGrjdck
z5G;;Oel1EQ2n9H(1_7AVbzV}Cz7}9XR627V3t~|K2C=4rJ~RgC1wt^>8wMG`)I%n+
zX=E{Q7&mAt7qMcKV=+t((`Y)Kj;iyfq8d4k4nYtNWY8E4FCxNAt5;zX+)Jf(pJw19
zTB$~%#uTUuurf-b(FBZ5CX~J|L8+dhRcWW%L^O<sOVl(v6||N#9Vig|f2dM96RpL<
zkT-h&lUOU%s}WilqD2!lQsUrZ+^wn9Fh_$(FjON%(fH{uhQ^{8s*Od}0EaW#H9#Pd
zDpc0JNsK@M^Ho|*qLLzfE}KlSP!$Rp9LV&hdk3+&;JQFAoz8<GI+w)>gdos|K?fo3
z+G#8ol_n?=6*i5Py}|Nk#aiv4R1=xGh(@s+kp*c`B`{ewte9O(;H-R8SlR4aIJ07D
zgczFjaNj!Y=`F%R*6ECOiN%ch5f$Nh4PkBDf$sUljakg+1_<$vXki_E0~{l{RQ+gQ
zP`@alrO+63jQQm37I_YweYZYZCc7_lZ-E!QD6a{RTy<5PwKua!+G%dmt)H75d;UDQ
z65iO2*A1#cV=1`OhyMrdqA1T5YBz`tu8=6NO>FRKGmMoR9LmMbKV5eI9?#T^AFM{W
zJ|{EV@+&6zYveY2uWs4U$jyulILbMYpM&Rg?@WFgVmeh}#32Jahi4LeMSyD>sqWVT
z%)!lvAA8O{+|xt$GmKvr7e1rt?2cnP*O-`~jUPVDue22PQrx7uLY<;^sJiY@WnnkP
z(WVUd;6Kw?T>q{Z+x=wZ^rpEL$>Rf~qxlv;%gc%3o=8){$s@<X1@e?JK2we))m}J%
z;$uza9?N!p*W>iM{(H&e&RtpmlsXMu7}PRsygff%>{1H+x-`PAaDK!-C*Q;@-`I?8
zZhP`B^wk(g{r+5W*>oUNAROzu4mmCw9%`+8y18OYwfM~KJF9X>ES5W+4P{4Ds_L$W
zJ@i0}-Tjk)>qzSDY|T$CdPG^#9A&uF)86fko^2j)V$1By`8U`4TjJs2eLH_Rl(Fyx
z=??yI_*4@b&m7-mJAYv?W!1qQma(JXJP(NvH;=kqJP9TCRlPJfV2Iu+`7uACsjBtf
zX;o_At&x`O(MFT@uZ|>#dG%*P9iq0UEoc2Q{=8U!JtaEqBgb64yWYbkd_7P=3APb!
z%#El`ofx>JxNatdxs+s<8q3=ZeG+|6-u|wgJ%f82n#%kf4!bY!CEuqkTiS93<nbIs
z-nng4dM&biwEbLm|INm_jLKcD3yLY8bG*)8I;OXaZ_GP0NT28A9o3uK)$uj&-7ig+
z7e~@5X$|7C2wOGFW@zO19h;Xuke7Hx6?g(3wdtQPF`FkWH@+*GC^7l%e&jw-bVMfa
z)W2FHA~6_@iiyFbj*;pQ0)QlQO{>5Cvzj>?W7d$-aj?{68SELZjzlY8y|Uz|uTGn1
z`IcIG#bICjx%c|-ri|b6-{23_*iG23IcWN%FZ>W3*DRj4ewvYF`#y>Hg?({0i}%#}
O`{46JxaR_+GX4d<)xGQh

literal 0
HcmV?d00001

diff --git a/lib/src/minio.dart b/lib/src/minio.dart
index 752f456..e57a8ec 100644
--- a/lib/src/minio.dart
+++ b/lib/src/minio.dart
@@ -156,8 +156,8 @@ class MinioClient {
       if (object != null) path = '/${bucket}/${object}';
     }
 
-    final resourcePart = resource != null ? '$resource&' : '';
-    final queryPart = encodeQueries(queries);
+    final resourcePart = resource == null ? '' : '$resource&';
+    final queryPart = queries == null ? '' : encodeQueries(queries);
     final query = resourcePart + queryPart;
 
     return Uri(
@@ -179,7 +179,12 @@ class MinioClient {
     for (var header in request.headers.entries) {
       buffer.writeln('${header.key}: ${header.value}');
     }
-    buffer.writeln(request.body);
+
+    if (request.body is List<int>) {
+      buffer.writeln('List<int> of size ${request.body.length}');
+    } else {
+      buffer.writeln(request.body);
+    }
 
     print(buffer.toString());
   }
@@ -237,11 +242,14 @@ class Minio {
 
   Future<bool> bucketExists(String bucket) async {
     MinioInvalidBucketNameError.check(bucket);
-    final resp = await _client.request(method: 'HEAD', bucket: bucket);
-    if (resp.statusCode != 200 && resp.statusCode != 404) {
-      throw MinioS3Error('bucketExists failed.');
+    try {
+      await _client.request(method: 'HEAD', bucket: bucket);
+    } on MinioS3Error catch (e) {
+      final code = e.error.code;
+      if (code == 'NoSuchBucket' || code == 'NotFound') return false;
+      rethrow;
     }
-    return resp.statusCode == 200;
+    return true;
   }
 
   int calculatePartSize(int size) {
@@ -349,7 +357,7 @@ class Minio {
     final node = xml.parse(resp.body);
     final location = node.findAllElements('LocationConstraint').first.text;
 
-    _regionMap[bucket] = location;
+    _regionMap[bucket] = location ?? 'us-east-1';
     return location;
   }
 
@@ -645,7 +653,7 @@ class Minio {
     Stream<List<int>> data,
     int size, {
     Map<String, String> metadata,
-  }) {
+  }) async {
     MinioInvalidBucketNameError.check(bucket);
     MinioInvalidObjectNameError.check(object);
 
@@ -653,15 +661,21 @@ class Minio {
     assert(size >= 0 || size == null);
 
     metadata = prependXAMZMeta(metadata ?? {});
-    // Stream.
 
     size ??= maxObjectSize;
     size = calculatePartSize(size);
 
     final chunker = BlockStream(size);
-    final uploader =
-        MinioUploader(this, _client, bucket, object, size, metadata);
-    return data.transform(chunker).pipe(uploader);
+    final uploader = MinioUploader(
+      this,
+      _client,
+      bucket,
+      object,
+      size,
+      metadata,
+    );
+    final etag = await data.transform(chunker).pipe(uploader);
+    return etag.toString();
   }
 
   Future<void> removeBucket(String bucket) async {
diff --git a/lib/src/minio_uploader.dart b/lib/src/minio_uploader.dart
index 38d0e85..f8d115a 100644
--- a/lib/src/minio_uploader.dart
+++ b/lib/src/minio_uploader.dart
@@ -42,7 +42,8 @@ class MinioUploader implements StreamConsumer<List<int>> {
       }
 
       if (this.partNumber == 1 && chunk.length < partSize) {
-        return uploadInOneGo(chunk, headers);
+        this.etag = await upload(chunk, headers, null);
+        return;
       }
 
       if (uploadId == null) {
@@ -68,20 +69,7 @@ class MinioUploader implements StreamConsumer<List<int>> {
         'uploadId': uploadId,
       };
 
-      final resp = await client.request(
-        method: 'PUT',
-        queries: queries,
-        headers: headers,
-        bucket: bucket,
-        object: object,
-      );
-
-      validate(resp);
-
-      var etag = resp.headers['etag'];
-      if (etag != null) {
-        etag = etag.replaceAll(RegExp('^"'), '').replaceAll(RegExp(r'"$'), '');
-      }
+      final etag = await upload(chunk, headers, queries);
       final part = CompletedPart(etag, partNumber);
       parts.add(part);
     }
@@ -89,10 +77,7 @@ class MinioUploader implements StreamConsumer<List<int>> {
 
   @override
   Future<String> close() async {
-    if (uploadId == null) {
-      return etag;
-    }
-
+    if (uploadId == null) return etag;
     return minio.completeMultipartUpload(bucket, object, uploadId, parts);
   }
 
@@ -107,11 +92,15 @@ class MinioUploader implements StreamConsumer<List<int>> {
     return headers;
   }
 
-  Future<void> uploadInOneGo(
-      List<int> chunk, Map<String, String> headers) async {
+  Future<String> upload(
+    List<int> chunk,
+    Map<String, String> headers,
+    Map<String, String> queries,
+  ) async {
     final resp = await client.request(
       method: 'PUT',
       headers: headers,
+      queries: queries,
       bucket: bucket,
       object: object,
       payload: chunk,
@@ -119,10 +108,12 @@ class MinioUploader implements StreamConsumer<List<int>> {
 
     validate(resp);
 
-    etag = resp.headers['etag'];
+    var etag = resp.headers['etag'];
     if (etag != null) {
       etag = etag.replaceAll(RegExp('^"'), '').replaceAll(RegExp(r'"$'), '');
     }
+
+    return etag;
   }
 
   Future<void> initMultipartUpload() async {
diff --git a/lib/src/utils.dart b/lib/src/utils.dart
index 36ecc57..774a07d 100644
--- a/lib/src/utils.dart
+++ b/lib/src/utils.dart
@@ -7,8 +7,16 @@ import 'package:convert/convert.dart';
 import 'package:crypto/crypto.dart';
 import 'package:xml/xml.dart';
 
-String sha256Hex(String data) {
-  return hex.encode(sha256.convert(utf8.encode(data)).bytes);
+String sha256Hex(Object data) {
+  if (data is String) {
+    data = utf8.encode(data);
+  } else if (data is List<int>) {
+    data = data;
+  } else {
+    throw ArgumentError('unsupported data type: ${data.runtimeType}');
+  }
+
+  return hex.encode(sha256.convert(data).bytes);
 }
 
 XmlElement getNodeProp(XmlElement xml, String name) {
-- 
GitLab