Comparing version 0.0.4 to 0.0.5
# KS3 命令行文档 | ||
## 说明 | ||
本工具主要是满足用户`上传`和`下载`文件的需求,尤其是大文件情况.在上传和下载过程中都会进行断点续传,节省时间和带宽资源. | ||
## 安装 | ||
@@ -8,3 +12,3 @@ | ||
### 准备条件 | ||
1. 安装[nodejs]以及[npm] | ||
1. 安装[nodejs]以及[npm] | ||
@@ -15,15 +19,15 @@ ### 安装 | ||
``` | ||
npm install -g ks3 | ||
``` | ||
``` | ||
npm install -g ks3 | ||
``` | ||
- 最新版安装 | ||
``` | ||
git clone $gitpath --depth=1 | ||
npm install -g ./ks3-node-sdk | ||
``` | ||
``` | ||
git clone $gitpath --depth=1 | ||
npm install -g ./ks3-node-sdk | ||
``` | ||
## 命令解释 | ||
- ks3 reset | ||
### ks3 reset | ||
重置开发者配置,清空历史记录 | ||
@@ -36,3 +40,3 @@ | ||
- ks3 init | ||
### ks3 init | ||
主要执行初始化操作.在初始化过程中,可以指定开发者的`AK`和`SK`. | ||
@@ -51,3 +55,3 @@ 命令行使用分为两种模式: 直接指定,或者进入交互模式.在`交互模式`下,会指导你填写必须的参数.如果所需参数没有提供完全,也会进入`交互模式`. | ||
- ks3 upload | ||
### ks3 upload | ||
上传文件以及文件夹.程序会根据文件大小进行`简单上传`和`分块上传`. | ||
@@ -59,3 +63,3 @@ | ||
`-p --path` : 开发者制定要上传文件夹或者文件的地址 | ||
`-b --bucket` : 制定上传文件存储的bucket | ||
`-b --bucket` : 指定上传文件存储的bucket | ||
`-k --key` : 如果上传的path为文件,则为文件名,如果上传的path是文件夹,则为文件夹名称 | ||
@@ -85,4 +89,29 @@ `--withsubdir` : 在上传文件夹的过程中,是否上传子文件夹,默认不上传,加上本参数,上传子文件夹内容 | ||
也可以直接输入`ks3 upload`进入交互模式 | ||
也可以直接输入`ks3 upload`进入交互模式 | ||
### ks3 download | ||
下载金山云存储的文件,可以进行断点续传.现在暂时只能下载文件,不能下载文件夹 | ||
``` | ||
ks3 download -b $bucket -k $key -p $localpath | ||
``` | ||
`-b --bucket` : 指定下载文件所在的bucket | ||
`-k --key` : 指定下载文件对应的key,**注意,key不包含bucket名称** | ||
`-p --path` : 下载文件的本地存储地址 | ||
例如: | ||
1. 把`ks3-sdk-test` bucket下的 `test_download.txt` 下载到本地 `D盘` 根目录下,并且重命名为`test.txt` | ||
``` | ||
ks3 download -k test_download.txt -p d:\test.txt | ||
// 由于没有输入bucket名称,会进入交互模式,让你输入bucket名称 | ||
// 或者直接指定bucket名称 | ||
ks3 download -b ks3-sdk-test -k test_download.txt -p d:\test.txt | ||
``` | ||
## 帮助说明 | ||
@@ -89,0 +118,0 @@ |
@@ -77,3 +77,9 @@ var request = require('./../request'); | ||
if(key !== 'Bucket') { | ||
queryString.push(key + '=' + encodeURIComponent(params[key])); | ||
/** | ||
* 在之前的逻辑中,可以传递值为空的 delimiter | ||
* 但是现在后端修改逻辑了,禁止传递这样的delimiter | ||
*/ | ||
if(!(key == 'delimiter' && params[key] =='')){ | ||
queryString.push(key + '=' + encodeURIComponent(params[key])); | ||
} | ||
} | ||
@@ -80,0 +86,0 @@ }); |
@@ -58,3 +58,3 @@ var config = require('../../config'); | ||
// 分块大小 | ||
var range = params.range || 1 * 1024; | ||
var chunk = params.chunk || 1 * 1024 * 10; | ||
var count = 0; | ||
@@ -74,3 +74,3 @@ var index = 0; | ||
if (fs.existsSync(configFile)) { // 之前已经有配置信息了 | ||
range = nconf.get('range'); | ||
chunk = nconf.get('chunk'); | ||
count = nconf.get('count'); | ||
@@ -82,3 +82,3 @@ index = nconf.get('index'); | ||
nconf.set('path', filePath); | ||
nconf.set('range', range); | ||
nconf.set('chunk',chunk); | ||
nconf.set('count', 0); | ||
@@ -102,3 +102,3 @@ nconf.set('index', 0); | ||
var length = res.headers['content-length']; | ||
count = parseInt(length / range) + (length % range == 0 ? 0: 1); | ||
count = parseInt(length / chunk) + (length % chunk== 0 ? 0: 1); | ||
// 后端返回 文件大小为0 | ||
@@ -144,3 +144,3 @@ if (count == 0) { | ||
Key: key, | ||
range: 'bytes=' + index * range + '-' + ((index + 1) * range - 1) | ||
range: 'bytes=' + index * chunk + '-' + ((index + 1) * chunk - 1) | ||
}, | ||
@@ -169,2 +169,3 @@ function(err, data, res, originData) { | ||
} else { | ||
fs.unlinkSync(configFile); | ||
throw err; | ||
@@ -171,0 +172,0 @@ } |
@@ -5,2 +5,3 @@ var request = require('./../request'); | ||
var util = require('../util'); | ||
var mime = require('mime'); | ||
var fs = require('fs'); | ||
@@ -208,3 +209,4 @@ var uploadMaxSize = config.uploadMaxSize; | ||
method: 'PUT', | ||
// TODO: type:require('mime').lookup(key), | ||
// 在上传文件的时候默认一个content-type | ||
type:require('mime').lookup(Key), | ||
date: util.getDate(), | ||
@@ -273,2 +275,3 @@ uri: config.protocol + '://' + bucketName + '.' + config.baseUrl + resource, | ||
var key = util.encodeKey(params.Key)|| null; | ||
var contentType = params.type || ''; | ||
@@ -292,2 +295,3 @@ var partNumber = (typeof params.PartNumber!=='undefined') ?params.PartNumber: ''; | ||
method: 'PUT', | ||
type:contentType, | ||
date: util.getDate(), | ||
@@ -294,0 +298,0 @@ uri: config.protocol + '://' + bucketName + '.' + config.baseUrl + resource, |
@@ -10,2 +10,3 @@ var config = require('../../config'); | ||
var ProgressBar = require('progress'); | ||
var mime = require('mime'); | ||
var bar, barDir; | ||
@@ -150,2 +151,3 @@ var cachePath = config.cachePath; | ||
}); | ||
var contentType = require('mime').lookup(filePath) || ''; | ||
// 分块上传 | ||
@@ -167,3 +169,4 @@ async.auto({ | ||
show: ['init', function(callback) { | ||
bar = new ProgressBar(' 开始上传文件: ' + filePath+' [:bar] :percent', { | ||
console.log(' 开始上传文件: ' + filePath) | ||
bar = new ProgressBar(' [:bar] :percent', { | ||
total: nconf.get('count') | ||
@@ -229,2 +232,3 @@ }); | ||
params.body = body; | ||
params.type = contentType; | ||
debug('正在上传第 ', index, ' 块,总共: ', + count + ' 块'); | ||
@@ -270,3 +274,3 @@ | ||
fs.unlinkSync(configFile); | ||
if(cb){ | ||
if (cb) { | ||
cb(err, results.upload[0], results.upload[1]); | ||
@@ -277,5 +281,10 @@ } | ||
var fileList = util.walkFile(filePath, params.fileSetting); | ||
nconf.file({ | ||
file: configFile | ||
}); | ||
var count = fileList.length; | ||
barDir = new ProgressBar(' 上传文件夹:'+filePath+' [:bar] :percent ', { | ||
total: count | ||
console.log(' 开始上传文件夹:' + filePath); | ||
barDir = new ProgressBar(' ' + ' [:bar] :percent ', { | ||
total: count, | ||
width: 100 | ||
}); | ||
@@ -285,42 +294,80 @@ barDir.tick(); | ||
if (count > 0) { | ||
// 先初始化缓存文件 | ||
if (!fs.existsSync(configFile)) { | ||
nconf.set('name', filePath); | ||
/** | ||
* 缓存中不记录文件个数和完成数 | ||
* 是因为如果中间有文件改动,会增加复杂度 | ||
* 现在只需要判断用户上传的这个文件之前有没有山穿过就好了 | ||
nconf.set('count',count); | ||
nconf.set('index',index); | ||
/**/ | ||
nconf.save(); | ||
} | ||
async.eachSeries(fileList, function(file, callback) { | ||
if (fs.statSync(file).isFile()) { // 碰到文件 | ||
if (fs.statSync(file).size > config.chunkSize) { // 大文件,复杂上传 | ||
var key2 = key + file.replace(filePath, ''); | ||
debug('使用`分块上传`,正在上传第 ' + index + '/' + count + ' 个文件:' + file); | ||
self.upload.start({ | ||
filePath: file, | ||
Key: key2 | ||
}, | ||
function(err, data, res) { | ||
// 需要去掉路径,取得真正文件名 | ||
var key2 = key + file.replace(filePath, ''); | ||
if (!nconf.get('list:' + key2)) { // 之前没有上传过这个文件 | ||
if (fs.statSync(file).isFile()) { // 碰到文件 | ||
if (fs.statSync(file).size > config.chunkSize) { // 大文件,复杂上传 | ||
debug('使用`分块上传`,正在上传第 ' + index + '/' + count + ' 个文件:' + file); | ||
self.upload.start({ | ||
filePath: file, | ||
Key: key2 | ||
}, | ||
function(err, data, res) { | ||
index = index + 1; | ||
barDir.tick(); | ||
if (index > count) { | ||
// 删除缓存文件 | ||
fs.unlinkSync(configFile); | ||
if (cb) cb(err, data, res); | ||
} else { | ||
nconf.set('list:' + key2, true); | ||
nconf.save() | ||
callback(); | ||
} | ||
}) | ||
} else { // 小文件 简单上传 | ||
//debug('\n正在上传文件: ', file); | ||
debug('使用`简单上传` 文件:' + file); | ||
self.object.put({ | ||
filePath: file, | ||
Key: key2 | ||
}, | ||
function(err, data, res) { | ||
debug('index:', index, 'count:', count) | ||
if (index >= count) { | ||
fs.unlinkSync(configFile); | ||
if (cb) cb(err, data, res); | ||
} else { | ||
index = index + 1; | ||
barDir.tick(); | ||
nconf.set('list:' + key2, true); | ||
nconf.save() | ||
callback(); | ||
} | ||
}) | ||
} | ||
} else { // 文件夹 | ||
if (index >= count) { | ||
// 统一回调,所以模拟一个返回状态 | ||
fs.unlinkSync(configFile); | ||
if (cb) cb(null, null, { | ||
statusCode: 200 | ||
}); | ||
} else { | ||
index = index + 1; | ||
nconf.set('list:' + key2, true); | ||
nconf.save() | ||
barDir.tick(); | ||
if (index > count) { | ||
if (cb) cb(err, data, res); | ||
} else { | ||
callback(); | ||
} | ||
}) | ||
} else { // 小文件 简单上传 | ||
var key2 = key + file.replace(filePath, ''); | ||
//debug('\n正在上传文件: ', file); | ||
debug('使用`简单上传` 文件:' + file); | ||
self.object.put({ | ||
filePath: file, | ||
Key: key2 | ||
}, | ||
function(err, data, res) { | ||
debug('index:', index, 'count:', count) | ||
if (index >= count) { | ||
if (cb) cb(err, data, res); | ||
} else { | ||
index = index + 1; | ||
barDir.tick(); | ||
callback(); | ||
} | ||
}) | ||
callback(); | ||
} | ||
} | ||
} else { // 文件夹 | ||
} else { // 之前已经上传成功这个文件了 | ||
if (index >= count) { | ||
// 统一回调,所以模拟一个返回状态 | ||
fs.unlinkSync(configFile); | ||
if (cb) cb(null, null, { | ||
@@ -331,2 +378,4 @@ statusCode: 200 | ||
index = index + 1; | ||
nconf.set('list:' + key2, true); | ||
nconf.save() | ||
barDir.tick(); | ||
@@ -333,0 +382,0 @@ callback(); |
{ | ||
"name": "ks3", | ||
"version": "0.0.4", | ||
"version": "0.0.5", | ||
"description": "", | ||
@@ -23,3 +23,2 @@ "main": "index.js", | ||
"dependencies": { | ||
"debug": "^2.0.0", | ||
"async": "^0.9.0", | ||
@@ -29,2 +28,4 @@ "colorful": "^2.1.0", | ||
"crypto": "0.0.3", | ||
"debug": "^2.0.0", | ||
"mime": "^1.2.11", | ||
"nconf": "^0.6.9", | ||
@@ -31,0 +32,0 @@ "progress": "^1.1.8", |
@@ -49,2 +49,4 @@ # KS3-SDK-Nodejs | ||
以下调用详细信息,可以访问[官方文档](http://ks3.ksyun.com/doc/api/index.html) | ||
`ks3.service.get` : 可以通过该操作来列出客户所有的 Bucket 信息 | ||
@@ -78,3 +80,4 @@ | ||
## KS3 | ||
## KS3 | ||
关于命令行工具,文档请查看 `./bin/readme.md`,或者[查看这里](https://github.com/StoneRen/ks3-node-sdk/tree/master/bin#user-content-ks3-命令行文档) | ||
@@ -81,0 +84,0 @@ |
@@ -55,3 +55,3 @@ var KS3 = require('..'); | ||
}); | ||
it('Put ACL havent params', function() { | ||
it('Put ACL without params', function() { | ||
(function() { | ||
@@ -87,12 +87,5 @@ client.bucket.putACL(function(err, data, res) {}); | ||
}); | ||
describe('bucket name is null', function() { | ||
var client = new KS3(ak, sk); | ||
it('return a error', function() { | ||
(function(){ | ||
client.bucket.getACL(function(err, data, res){}) | ||
}).should.throw('require the bucketName'); | ||
}) | ||
}); | ||
describe('list objects', function() { | ||
it('get objects with havent params', function(done) { | ||
it('get objects without params', function(done) { | ||
client.bucket.get(function(err, data, res) { | ||
@@ -106,7 +99,5 @@ should.not.exist(err); | ||
client.bucket.get({ | ||
'max-keys': 30, | ||
delimiter: '', | ||
'max-keys': 30, | ||
marker: '', | ||
prefix: '', | ||
'encoding-type': 'url' | ||
prefix: '' | ||
}, function(err, data, res) { | ||
@@ -118,2 +109,19 @@ should.not.exist(err); | ||
}); | ||
/** | ||
* 禁止传递空值 delimiter, | ||
* sdk会做处理 | ||
*/ | ||
it('get objects with empty delimiter', function(done) { | ||
client.bucket.get({ | ||
'max-keys': 30, | ||
delimiter:'', | ||
marker: '', | ||
prefix: '' | ||
}, function(err, data, res) { | ||
should.not.exist(err); | ||
res.should.have.status(200); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -128,5 +136,13 @@ describe('head bucket', function() { | ||
}); | ||
}) | ||
}); | ||
describe('bucket name is null', function() { | ||
var client = new KS3(ak, sk); | ||
it('return a error', function() { | ||
(function(){ | ||
client.bucket.getACL(function(err, data, res){}) | ||
}).should.throw('require the bucketName'); | ||
}) | ||
}); | ||
}); | ||
}); |
@@ -17,2 +17,4 @@ var KS3 = require('..'); | ||
var filePath = path.join(__dirname, './assets/'+key); | ||
var downFilePath = path.join(__dirname, './assets/test_download_'+key); | ||
var upFileStat = fs.statSync(filePath); | ||
@@ -27,6 +29,8 @@ client.object.put({ | ||
Key: key, | ||
filePath: path.join(__dirname, './assets/test_download_'+key) | ||
filePath: downFilePath | ||
}, | ||
function(err, data, res) { | ||
if (err) throw err; | ||
var downFileStat = fs.statSync(downFilePath); | ||
(downFileStat.size).should.equal(upFileStat.size); | ||
should.not.exist(err); | ||
@@ -33,0 +37,0 @@ done(); |
@@ -97,2 +97,4 @@ var KS3 = require('..'); | ||
var key = 'test_upload_'+fileName; | ||
var upFileStat = fs.statSync(filePath); | ||
client.object.put({ | ||
@@ -104,2 +106,3 @@ Bucket: bucketName, | ||
function(err, data, res) { | ||
should.not.exist(err); | ||
client.object.get({ | ||
@@ -109,4 +112,7 @@ Bucket:bucketName, | ||
},function(err,data,res,originData){ | ||
should.not.exist(err); | ||
var newFileName = path.join(__dirname,'assets/test_object_get_download_'+fileName); | ||
fs.writeFileSync(newFileName,originData); | ||
var downFileStat = fs.statSync(filePath); | ||
(downFileStat.size).should.equal(upFileStat.size); | ||
done(); | ||
@@ -261,3 +267,3 @@ }); | ||
it('aborts a multipart upload1', function(done) { | ||
it('aborts a multipart upload', function(done) { | ||
var client = new KS3(ak, sk, bucketName); | ||
@@ -264,0 +270,0 @@ client.config({ |
@@ -36,2 +36,23 @@ var KS3 = require('..'); | ||
}); | ||
it('upload a file and set content-type', function(done) { | ||
var client = new KS3(ak, sk, bucketName); | ||
var filePath = path.join(__dirname, './assets/test_content_type.html'); | ||
var fileName = (function(){ | ||
var s = filePath.split('/'); | ||
return s[s.length-1]; | ||
})(); | ||
var key = 'test_upload_file_from_upload_and_set_content_type_'+fileName; | ||
client.upload.start({ | ||
Bucket: bucketName, | ||
filePath: filePath, | ||
Key: key | ||
}, | ||
function(err, data, res) { | ||
should.not.exist(err); | ||
res.should.have.status(200); | ||
done(); | ||
}); | ||
}); | ||
}); | ||
@@ -38,0 +59,0 @@ |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5250379
43
3045
85
10
+ Addedmime@^1.2.11
+ Addedmime@1.6.0(transitive)