Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Develop #900

Merged
merged 20 commits into from
Dec 3, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion .prettierrc
Original file line number Diff line number Diff line change
Expand Up @@ -5,5 +5,6 @@
"useTabs": false,
"printWidth": 120,
"bracketSpacing": true,
"arrowParens": "avoid"
"arrowParens": "avoid",
"trailingComma": "none"
}
83 changes: 81 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -125,6 +125,7 @@ All operation use es7 async/await to implement. All api is async function.

- [Object Operations](#object-operations)
- [.list(query[, options])](#listquery-options)
- [.listV2(query[, options])](#listV2query-options)
- [.getBucketVersions(query[, options])](#getBucketVersionsquery-options)
- [.put(name, file[, options])](#putname-file-options)
- [.putStream(name, stream[, options])](#putstreamname-stream-options)
Expand Down Expand Up @@ -336,6 +337,7 @@ options:
`fetch` mode ,else `XMLHttpRequest`
- [enableProxy] {Boolean}, Enable proxy request, default is false.
- [proxy] {String | Object}, proxy agent uri or options, default is null.
- [retryMax] {Number}, used by auto retry send request count when request error is net error or timeout.

example:

Expand Down Expand Up @@ -2288,6 +2290,83 @@ const result = await store.list({
console.log(result.objects);
```

### .listV2(query[, options])

List objects in the bucket.(recommended)

parameters:

- [query] {Object} query parameters, default is `null`
- [prefix] {String} search object using `prefix` key
- [continuationToken] {String} search start from `continuationToken`, including `continuationToken` key
- [delimiter] {String} delimiter search scope
e.g. `/` only search current dir, not including subdir
- [max-keys] {String|Number} max objects, default is `100`, limit to `1000`
- [start-after] {String} specifies the Start-after value from which to start the list. The names of objects are returned in alphabetical order.
- [fetch-owner] {Boolean} specifies whether to include the owner information in the response.
- [options] {Object} optional parameters
- [timeout] {Number} the operation timeout

Success will return objects list on `objects` properties.

- objects {Array<ObjectMeta>} object meta info list
Each `ObjectMeta` will contains blow properties:
- name {String} object name on oss
- url {String} resource url
- lastModified {String} object last modified GMT date, e.g.: `2015-02-19T08:39:44.000Z`
- etag {String} object etag contains `"`, e.g.: `"5B3C1A2E053D763E1B002CC607C5A0FE"`
- type {String} object type, e.g.: `Normal`
- size {Number} object size, e.g.: `344606`
- storageClass {String} storage class type, e.g.: `Standard`
- owner {Object|null} object owner, including `id` and `displayName`
- prefixes {Array<String>} prefix list
- isTruncated {Boolean} truncate or not
- nextContinuationToken {String} next continuation-token string
- res {Object} response info, including
- status {Number} response status
- headers {Object} response headers
- size {Number} response size
- rt {Number} request total use time (ms)

- List top 10 objects

```js
const result = await store.listV2({
'max-keys': 10
});
console.log(result.objects);
```

- List `fun/` dir including subdirs objects

```js
const result = await store.listV2({
prefix: 'fun/'
});
console.log(result.objects);
```

- List `fun/` dir objects, not including subdirs

```js
const result = await store.listV2({
prefix: 'fun/',
delimiter: '/'
});
console.log(result.objects);
```

- List `a/` dir objects, after `a/b` and include `a/b`

```js
const result = await store.listV2({
delimiter: '/',
prefix: 'a/',
'start-after': 'b'
});
console.log(result.objects);
```

### .getBucketVersions(query[, options])

List the version information of all objects in the bucket, including the delete marker (Delete Marker).
Expand Down Expand Up @@ -2324,8 +2403,8 @@ Success will return objects list on `objects` properties.
- lastModified {String} object last modified GMT date, e.g.: `2015-02-19T08:39:44.000Z`
- versionId {String} object versionId
- isTruncated {Boolean} truncate or not
- nextMarker {String} next marker string
- NextVersionIdMarker {String} next version ID marker string
- nextKeyMarker (nextMarker) {String} next marker string
- nextVersionIdMarker (NextVersionIdMarker) {String} next version ID marker string
- res {Object} response info, including
- status {Number} response status
- headers {Object} response headers
Expand Down
7 changes: 6 additions & 1 deletion browser-build.js
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,12 @@ function build(options, callback) {
basedir: path.resolve(__dirname, '.'),
fullPaths: false,
standalone: 'OSS',
debug: false
debug: false,
builtins: {
...require("browserify/lib/builtins"),
_process: path.join(__dirname, "shims/process.js"),
url: path.join(__dirname, "shims/url/index.js")
}
};
browserify(brOpts).add('./lib/browser.js')
.transform(babelify, {
Expand Down
24 changes: 23 additions & 1 deletion lib/browser/client.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ const { createRequest } = require('../common/utils/createRequest');
const { encoder } = require('../common/utils/encoder');
const { getReqUrl } = require('../common/client/getReqUrl');
const { setSTSToken } = require('../common/utils/setSTSToken');
const { retry } = require('../common/utils/retry');

const globalHttpAgent = new AgentKeepalive();

Expand Down Expand Up @@ -193,7 +194,28 @@ proto.authorization = function authorization(method, resource, subres, headers)
* @api private
*/

proto.request = async function request(params) {
proto.request = async function (params) {
const isAvailableStream = params.stream ? params.stream.readable : true;
if (this.options.retryMax && isAvailableStream) {
this.request = retry(request.bind(this), this.options.retryMax, {
errorHandler: (err) => {
const _errHandle = (_err) => {
const statusErr = [-1, -2].includes(_err.status);
const requestErrorRetryHandle = this.options.requestErrorRetryHandle || (() => true);
return statusErr && requestErrorRetryHandle(_err);
};
if (_errHandle(err)) return true;
return false;
}
});
} else {
this.request = request.bind(this);
}

return await this.request(params);
};

async function request(params) {
const reqParams = createRequest.call(this, params);

if (!this.options.useFetch) {
Expand Down
32 changes: 26 additions & 6 deletions lib/browser/managed-upload.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ const mime = require('mime');
const copy = require('copy-to');
const { isBlob } = require('../common/utils/isBlob');
const { isFile } = require('../common/utils/isFile');
const { isArray } = require('../common/utils/isArray');
const { isBuffer } = require('../common/utils/isBuffer');

const proto = exports;
Expand All @@ -31,9 +32,8 @@ const proto = exports;
* key2: 'value2'
* }
*/
proto.multipartUpload = async function multipartUpload(name, file, options) {
proto.multipartUpload = async function multipartUpload(name, file, options = {}) {
this.resetCancelFlag();
options = options || {};
if (options.checkpoint && options.checkpoint.uploadId) {
if (file && isFile(file)) options.checkpoint.file = file;

Expand All @@ -59,10 +59,8 @@ proto.multipartUpload = async function multipartUpload(name, file, options) {

const fileSize = await this._getFileSize(file);
if (fileSize < minPartSize) {
const stream = this._createStream(file, 0, fileSize);
options.contentLength = fileSize;

const result = await this.putStream(name, stream, options);
const result = await this.put(name, file, options);
if (options && options.progress) {
await options.progress(1);
}
Expand Down Expand Up @@ -140,15 +138,37 @@ proto._resumeMultipart = async function _resumeMultipart(checkpoint, options) {
try {
if (!self.isCancel()) {
const pi = partOffs[partNo - 1];
const stream = self._createStream(file, pi.start, pi.end);
const data = {
stream: self._createStream(file, pi.start, pi.end),
stream,
size: pi.end - pi.start
};

if (isArray(self.multipartUploadStreams)) {
self.multipartUploadStreams.push(stream);
} else {
self.multipartUploadStreams = [stream];
}

const removeStreamFromMultipartUploadStreams = function () {
if (!stream.destroyed) {
stream.destroy();
}
const index = self.multipartUploadStreams.indexOf(stream);
if (index !== -1) {
self.multipartUploadStreams.splice(index, 1);
}
};

stream.on('close', removeStreamFromMultipartUploadStreams);
stream.on('end', removeStreamFromMultipartUploadStreams);
stream.on('error', removeStreamFromMultipartUploadStreams);

let result;
try {
result = await self._uploadPart(name, uploadId, partNo, data);
} catch (error) {
removeStreamFromMultipartUploadStreams();
if (error.status === 404) {
throw self._makeAbortEvent();
}
Expand Down
73 changes: 60 additions & 13 deletions lib/browser/object.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@

// const debug = require('debug')('ali-oss:object');
const fs = require('fs');
const copy = require('copy-to');
Expand All @@ -12,20 +11,19 @@ const { isBuffer } = require('../common/utils/isBuffer');

// var assert = require('assert');


const proto = exports;

/**
* Object operations
*/

/**
* append an object from String(file path)/Buffer/ReadableStream
* @param {String} name the object key
* @param {Mixed} file String(file path)/Buffer/ReadableStream
* @param {Object} options
* @return {Object}
*/
* append an object from String(file path)/Buffer/ReadableStream
* @param {String} name the object key
* @param {Mixed} file String(file path)/Buffer/ReadableStream
* @param {Object} options
* @return {Object}
*/
proto.append = async function append(name, file, options) {
options = options || {};
if (options.position === undefined) options.position = '0';
Expand Down Expand Up @@ -155,7 +153,6 @@ proto.putStream = async function putStream(name, stream, options) {
return ret;
};


merge(proto, require('../common/object/copyObject'));
merge(proto, require('../common/object/getObjectTagging'));
merge(proto, require('../common/object/putObjectTagging'));
Expand Down Expand Up @@ -229,6 +226,56 @@ proto.list = async function list(query, options) {
};
};

proto.listV2 = async function listV2(query, options) {
const params = this._objectRequestParams('GET', '', options);
params.query = {
'list-type': 2,
...query
};
params.xmlResponse = true;
params.successStatuses = [200];

const result = await this.request(params);
let objects = result.data.Contents;
const that = this;
if (objects) {
if (!Array.isArray(objects)) {
objects = [objects];
}
objects = objects.map(obj => ({
name: obj.Key,
url: that._objectUrl(obj.Key),
lastModified: obj.LastModified,
etag: obj.ETag,
type: obj.Type,
size: Number(obj.Size),
storageClass: obj.StorageClass,
owner: obj.Owner
? {
id: obj.Owner.ID,
displayName: obj.Owner.DisplayName
}
: null
}));
}
let prefixes = result.data.CommonPrefixes || null;
if (prefixes) {
if (!Array.isArray(prefixes)) {
prefixes = [prefixes];
}
prefixes = prefixes.map(item => item.Prefix);
}
return {
res: result.res,
objects,
prefixes,
isTruncated: result.data.IsTruncated === 'true',
keyCount: result.data.KeyCount,
continuationToken: result.data.ContinuationToken || null,
nextContinuationToken: result.data.NextContinuationToken || null
};
};

/**
* Restore Object
* @param {String} name the object key
Expand Down Expand Up @@ -294,18 +341,18 @@ proto._convertMetaToHeaders = function _convertMetaToHeaders(meta, headers) {
return;
}

Object.keys(meta).forEach((k) => {
Object.keys(meta).forEach(k => {
headers[`x-oss-meta-${k}`] = meta[k];
});
};

proto._deleteFileSafe = function _deleteFileSafe(filepath) {
return new Promise((resolve) => {
fs.exists(filepath, (exists) => {
return new Promise(resolve => {
fs.exists(filepath, exists => {
if (!exists) {
resolve();
} else {
fs.unlink(filepath, (err) => {
fs.unlink(filepath, err => {
if (err) {
this.debug('unlink %j error: %s', filepath, err, 'error');
}
Expand Down
Loading