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