From e03b10dfbded8cd62213b20a2ea0507b4873abbd Mon Sep 17 00:00:00 2001 From: longbai Date: Fri, 12 Jul 2013 10:21:26 +0800 Subject: [PATCH 01/41] delete previous version --- CHANGELOG.md | 67 ------ Makefile | 20 -- README.md | 138 ------------ docs/README.md | 519 ---------------------------------------------- index.js | 9 - lib/auth.js | 94 --------- lib/conf.js | 20 -- lib/digestauth.js | 148 ------------- lib/img.js | 35 ---- lib/rs.js | 410 ------------------------------------ lib/util.js | 98 --------- package.json | 55 ----- test/logo.png | Bin 14057 -> 0 bytes test/rs.test.js | 493 ------------------------------------------- 14 files changed, 2106 deletions(-) delete mode 100644 CHANGELOG.md delete mode 100644 Makefile delete mode 100644 README.md delete mode 100644 docs/README.md delete mode 100644 index.js delete mode 100644 lib/auth.js delete mode 100644 lib/conf.js delete mode 100644 lib/digestauth.js delete mode 100644 lib/img.js delete mode 100644 lib/rs.js delete mode 100644 lib/util.js delete mode 100644 package.json delete mode 100644 test/logo.png delete mode 100644 test/rs.test.js diff --git a/CHANGELOG.md b/CHANGELOG.md deleted file mode 100644 index 30aa8d89..00000000 --- a/CHANGELOG.md +++ /dev/null @@ -1,67 +0,0 @@ -#CHANGELOG - -## v2.4.3 - -2013-02-22 - -Issue [#54](https://github.com/qiniu/nodejs-sdk/pull/54): - -- 去除对自定义 generateQueryString() 函数的依赖,使用 querystring 包的 stringify() 函数。 -- auth.PutPolicy 增加对 returnBody 的支持,用户可自定义上传完文件后的返回值。 - -## v2.4.2 - -Issue [#48](https://github.com/qiniu/nodejs-sdk/pull/48): - -- 去除 auth.GetPolicy.scope 的默认值:"*/*" - -Issue [#46](https://github.com/qiniu/nodejs-sdk/pull/46): - -- 更新 v2.4.1 的文档(docs/README.md) - - -## v2.4.1 - -2013-02-09 - -Issue [#43](https://github.com/qiniu/nodejs-sdk/pull/43): - -- imageMogr bugfix: auto-orient -- auth.UploadToken, auth.DownloadToken 改为 auth.PutPolicy, auth.GetPolicy -- auth.UploadToken.generateToken() 改为 auth.PutPolicy.token() -- auth.DownloadToken.generateToken() 改为 auth.GetPolicy.token() -- auth.DownloadToken.pattern 改为 auth.GetPolicy.scope - - -## v2.4.0 - -2013-01-23 - -Issue [#36](https://github.com/qiniu/nodejs-sdk/pull/36): - -- 增加 auth.DownloadToken 类 -- auth.UploadToken 增加:escape、asyncOps 成员,generateSignature 改名为 generateToken -- 增加 rs.copy, rs.move, rs.batchGet, rs.batchStat, rs.batchDelete, rs.batchCopy, rs.batchMove -- 增加 Travis-CI 的支持 - -Issue [#32](https://github.com/qiniu/nodejs-sdk/pull/32): - -- auth.UploadToken.generateSignature 各个参数调整为可选 -- uploadWithToken 非兼容调整: rs.uploadWithToken(uploadToken, stream, key, mimeType, customMeta, callbackParams, crc32, onret) -- generateActionString 非兼容调整: action = util.generateActionString(bucket, key, mimeType, customMeta, crc32) - - -## v2.3.2 - -2012-12-31 - -- 修复crc32编码 -- 修复使用UploadToken方式上传时流式上传bug,流式上传不检查crc32 - - -## v2.3.0 - -2012-11-23 - -- 启用新的 uploadToken(上传凭证)上传方式,可由客户方业务服务器生成上传凭证。上传前无需请求七牛云存储,减少http请求。 - diff --git a/Makefile b/Makefile deleted file mode 100644 index e588dc1a..00000000 --- a/Makefile +++ /dev/null @@ -1,20 +0,0 @@ -TESTS = test/*.test.js -REPORTER = spec -TIMEOUT = 5000 - -test: - @NODE_ENV=test ./node_modules/mocha/bin/mocha \ - --reporter $(REPORTER) \ - --timeout $(TIMEOUT) \ - $(TESTS) - -test-cov: - @rm -rf ./lib-cov - @$(MAKE) lib-cov - @QINIU_COV=1 $(MAKE) test REPORTER=dot - @QINIU_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html - -lib-cov: - @jscoverage lib $@ - -.PHONY: test-cov test lib-cov diff --git a/README.md b/README.md deleted file mode 100644 index 4e45e4bc..00000000 --- a/README.md +++ /dev/null @@ -1,138 +0,0 @@ -# Node wrapper for Qiniu Resource (Cloud) Storage API - -[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) - -![logo](http://qiniutek.com/images/logo-2.png) - -该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 [七牛云存储官方API](/v3/api/) 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 - -jscoverage: [85%](http://fengmk2.github.com/coverage/qiniu.html) - -## 安装 - - npm install qiniu - -### 获取 ACCESS_KEY 和 SECRET_KEY - -要对接七牛云存储服务,您需要七牛云存储服务端颁发给您的 `ACCESS_KEY` 和 `SECRET_KEY`。`ACCESS_KEY` 用于标识客户方的身份,在网络请求中会以某种形式进行传输。`SECRET_KEY` 作为私钥形式存放于客户方本地并不在网络中传递,`SECRET_KEY` 的作用是对于客户方发起的具体请求进行数字签名,用以保证该请求是来自指定的客户方并且请求本身是合法有效的。使用 `ACCESS_KEY` 进行身份识别,加上 `SECRET_KEY` 进行数字签名,即可完成应用接入与认证授权。 - -您可以通过如下步骤获得 `ACCESS_KEY` 和 `SECRET_KEY`: - -1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) -2. [登录七牛开发者自助平台,查看 ACCESS_KEY 和 SECRET_KEY](https://dev.qiniutek.com/account/keys) - -获取到 `ACCESS_KEY` 和 `SECRET_KEY` 之后,您就可以参考下面的示例代码进行接入使用了。 - -## 使用 - -SDK 使用文档参考:[http://docs.qiniutek.com/v3/sdk/nodejs/](http://docs.qiniutek.com/v3/sdk/nodejs/) - -### 示例程序 - - var qiniu = require('qiniu'); - - // 配置密钥 - qiniu.conf.ACCESS_KEY = ''; - qiniu.conf.SECRET_KEY = ''; - - // 实例化带授权的 HTTP Client 对象 - var conn = new qiniu.digestauth.Client(); - - // 创建空间,也可以在开发者自助网站创建 - var bucket = 'yet_another_bucket'; - qiniu.rs.mkbucket(conn, bucket, function(resp) { - console.log("\n===> Make bucket result: ", resp); - if (resp.code != 200) { - return; - } - }); - - // 实例化 Bucket 操作对象 - var rs = new qiniu.rs.Service(conn, bucket); - - // 上传文件第1步 - // 生成上传授权凭证(uploadToken) - var opts = { - scope: "yet_another_bucket", // 可以是 "" 或 ":" - expires: 3600, - callbackUrl: "http://www.example.com/notifications/qiniurs", // 可选 - callbackBodyType: "application/x-www-form-urlencoded", // 可选 - }; - var uploadPolicy = new qiniu.auth.PutPolicy(opts); - var uploadToken = uploadPolicy.token(); - - // 上传文件第2步 - // 组装上传文件所需要的参数 - var key = __filename; - var localFile = key, - customMeta = "", - callbackParams = {"bucket": bucket, "key": key}, - enableCrc32Check = false, - mimeType = mime.lookup(key); - - // 上传文件第3步 - // 上传文件 - rs.uploadFileWithToken(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, function(resp){ - console.log("\n===> Upload File with Token result: ", resp); - if (resp.code != 200) { - // ... - return; - } - - // 查看已上传文件属性信息 - rs.stat(key, function(resp) { - console.log("\n===> Stat result: ", resp); - if (resp.code != 200) { - // ... - return; - } - }); - }); - - - // 获取文件下载链接(含文件属性信息) - var saveAsFriendlyName = key; - rs.get(key, saveAsFriendlyName, function(resp) { - console.log("\n===> Get result: ", resp); - if (resp.code != 200) { - // ... - return; - } - }); - - // 删除已上传文件 - rs.remove(key, function(resp) { - console.log("\n===> Delete result: ", resp); - }); - - // 将bucket的内容作为静态内容发布 - var DEMO_DOMAIN = bucket + '.dn.qbox.me'; - rs.publish(DEMO_DOMAIN, function(resp){ - console.log("\n===> Publish result: ", resp); - if (resp.code != 200){ - clear(rs); - return; - } - }); - - // 删除bucket,慎用! - rs.drop(function(resp){ - console.log("\n===> Drop result: ", resp); - }); - - -## 贡献代码 - -1. Fork -2. 创建您的特性分支 (`git checkout -b my-new-feature`) -3. 提交您的改动 (`git commit -am 'Added some feature'`) -4. 将您的修改记录提交到远程 `git` 仓库 (`git push origin my-new-feature`) -5. 然后到 github 网站的该 `git` 远程仓库的 `my-new-feature` 分支下发起 Pull Request - -## 许可证 - -Copyright (c) 2012 qiniutek.com - -基于 MIT 协议发布: - -* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) diff --git a/docs/README.md b/docs/README.md deleted file mode 100644 index d29375bb..00000000 --- a/docs/README.md +++ /dev/null @@ -1,519 +0,0 @@ ---- -title: NodeJS SDK | 七牛云存储 ---- - -# NodeJS SDK 使用指南 - -该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 [七牛云存储官方API](/v3/api/) 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 - -七牛云存储 NodeJS SDK 开放源代码地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) - -**文档大纲** - -- [安装](#Installation) -- [使用](#Usage) - - [获取 ACCESS_KEY 和 SECRET_KEY](#appkey) - - [应用接入与初始化](#establish_connection!) - - [上传文件](#upload) - - [获取用于上传文件的临时授权凭证](#generate-token) - - [服务端上传文件](#server-side-upload) - - [非断点续传方式](#normal-upload) - - [默认上传方式](#default-upload) - - [针对NotFound处理场景](#upload-file-not-found) - - [客户端上传文件](#client-side-upload) - - [获取文件属性信息](#stat) - - [获取文件下载链接(含文件属性信息)](#get) - - [获取文件下载链接(断点续下载)](#getIfNotModified) - - [创建公开外链](#publish) - - [取消公开外链](#unpublish) - - [删除指定文件](#remove) - - [删除所有文件(指定 bucket)](#drop) - - [图像处理](#fo-image) - - [图像处理(缩略、裁剪、旋转、转化)](#qiniu-img-mogrify) - - [图像处理(缩略、裁剪、旋转、转化)并持久化](#imageMogrifyAs) -- [贡献代码](#Contributing) -- [许可证](#License) - - - -## 安装 - -通过 npm 以 node 模块化的方式安装: - - npm install qiniu - - - -## 使用 - - - -### 获取 ACCESS_KEY 和 SECRET_KEY - -要对接七牛云存储服务,您需要七牛云存储服务端颁发给您的 `ACCESS_KEY` 和 `SECRET_KEY`。`ACCESS_KEY` 用于标识客户方的身份,在网络请求中会以某种形式进行传输。`SECRET_KEY` 作为私钥形式存放于客户方本地并不在网络中传递,`SECRET_KEY` 的作用是对于客户方发起的具体请求进行数字签名,用以保证该请求是来自指定的客户方并且请求本身是合法有效的。使用 `ACCESS_KEY` 进行身份识别,加上 `SECRET_KEY` 进行数字签名,即可完成应用接入与认证授权。 - -您可以通过如下步骤获得 `ACCESS_KEY` 和 `SECRET_KEY`: - -1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) -2. [登录七牛开发者自助平台,查看 ACCESS_KEY 和 SECRET_KEY](https://dev.qiniutek.com/account/keys) - -获取到 `ACCESS_KEY` 和 `SECRET_KEY` 之后,您就可以参考下面将要介绍的用法进行接入使用了。 - - - -### 应用接入与初始化 - -使用 npm 安装成功后,您就可以直接在项目中使用了,如下示例代码: - - var qiniu = require("qiniu"); - - // 配置密钥 - qiniu.conf.ACCESS_KEY = ''; - qiniu.conf.SECRET_KEY = ''; - - // 实例化带授权的 HTTP Client 对象 - var conn = new qiniu.digestauth.Client(); - var bucket = ""; - - // 创建空间,也可以在开发者自助网站创建 - qiniu.rs.mkbucket(conn, bucket, function(resp) { - console.log("\n===> Make bucket result: ", resp); - if (resp.code != 200) { - return; - } - }); - - // 实例化 Bucket 操作对象 - var rs = new qiniu.rs.Service(conn, ""); - - - - -### 上传文件 - - - -#### 获取用于上传文件的临时授权凭证 - -要上传一个文件,首先需要调用 SDK 提供的 `qiniu.auth.PutPolicy(options)`创建一个PutPolicy对象,然后使用它提供的token()方法生成用于临时匿名上传的upload_token——经过数字签名的一组数据信息,该 upload_token 作为文件上传流中 multipart/form-data 的一部分进行传输。 - - - var options = { - scope: , // 可以是 "" 或 ":" - expires: , - callbackUrl: , // 可选 - callbackBodyType: , // 可选 - customer: // 可选 - }; - - var uploadPolicy = new qiniu.auth.PutPolicy(options); - var uploadToken = uploadPolicy.token(); - -**options参数** - -scope -: 必须,字符串类型(String),设定文件要上传到的目标 `bucket`,也可以限定上传的目标必须为 `bucket:key`。 - -expires -: 可选,数字类型,用于设置上传 URL 的有效期,单位:秒,缺省为 3600 秒,即 1 小时后该上传链接不再有效(但该上传URL在其生成之后的59分59秒都是可用的)。 - -:callbackUrl -: 可选,字符串类型(String),用于设置文件上传成功后,七牛云存储服务端要回调客户方的业务服务器地址。 - -callbackBodyType -: 可选,字符串类型(String),用于设置文件上传成功后,七牛云存储服务端向客户方的业务服务器发送回调请求的 `Content-Type`。比如发送POST类型的表单数据回调,可以是 `application/x-www-form-urlencoded`。 - -customer -: 可选,字符串类型(String),客户方终端用户(End User)的ID,该字段可以用来标示一个文件的属主,这在一些特殊场景下(比如给终端用户上传的图片打上名字水印)非常有用。 - -**响应** - -返回一个字符串类型(String)的用于上传文件用的临时授权 `uploadToken`。 - - - - -#### 服务端上传文件 - - - -##### 非断点续上传方式 - -如果您确定客户端上传的东西无需使用断点续上传方式进行上传,可以使用rs.uploadFileWithToken()。 - - rs.uploadFileWithToken(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, function(resp){ - console.log("\n===> Upload File with Token result: ", resp); - if (resp.code != 200) { - return; - } - }); - - -**参数** - -uploadToken -: 必须,字符串类型(String),调用 `PutPolicy.token()` 生成的 [用于上传文件的临时授权凭证](#generate-token) - -localFile -: 必须,字符串类型(String),本地文件可被读取的有效路径 - -key -: 必须,字符串类型(String),类似传统数据库里边某个表的主键ID,给每一个文件一个UUID用于进行标示。 - -mimeType -: 可选,字符串类型(String),文件的 mime-type 值。如若不传入,SDK 会自行计算得出,若计算失败缺省使用 `application/octet-stream` 代替之。 - -customMeta -: 可选,字符串类型(String),为文件添加备注信息。 - -callbackParams -: 可选,String 或者 Hash 类型,文件上传成功后,七牛云存储向客户方业务服务器发送的回调参数。 - -enableCrc32Check -: 可选,Boolean 类型,是否启用文件上传 crc32 校验,缺省为 false 。 - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { - code: 200, - data: { - hash: 'FrOXNat8VhBVmcMF3uGrILpTu8Cs' - } - } - - - -##### 默认上传方式 - -up.Upload()函数封装了以上断点续上传和非断点续上传的方式。如果您上传的文件大于设置的BLOCK大小(该值可以在conf.js配置文件中进行设置),则默认采用断点续上传的方式进行上传。否则,采用普通的方式进行上传。 - - - -##### 针对 NotFound 场景处理 - -您可以上传一个应对 HTTP 404 出错处理的文件,当您 [创建公开外链](#publish) 后,若公开的外链找不到该文件,即可使用您上传的“自定义404文件”代替之。要这么做,您只须使用 `up.Upload()` 函数上传一个 `key` 为固定字符串类型的值 `errno-404` 即可。 - -除了使用 SDK 提供的方法,同样也可以借助七牛云存储提供的命令行辅助工具 [qboxrsctl](https://github.com/qiniu/devtools/tags) 达到同样的目的: - - qboxrsctl put - -将其中的 `` 换作 `errno-404` 即可。 - -注意,每个 `` 里边有且只有一个 `errno-404` 文件,上传多个,最后的那一个会覆盖前面所有的。 - - - -#### 客户端直传文件 - -客户端上传流程和服务端上传类似,差别在于:客户端直传文件所需的 `uploadToken` 可以选择在客户方的业务服务器端生成,也可以选择在客户方的客户端程序里边生成。选择前者,可以和客户方的业务揉合得更紧密和安全些,比如防伪造请求。 - -简单来讲,客户端上传流程也分为两步: - -1. 获取 `uploadToken`([用于上传文件的临时授权凭证](#generate-upload-token)) -2. 将该 `uploadToken` 作为文件上传流 `multipart/form-data` 中的一部分实现上传操作 - -如果您的网络程序是从云端(服务端程序)到终端(手持设备应用)的架构模型,且终端用户有使用您移动端App上传文件(比如照片或视频)的需求,可以把您服务器得到的此 `uploadToken` 返回给手持设备端的App,然后您的移动 App 可以使用 [七牛云存储 Objective-SDK (iOS)](http://docs.qiniutek.com/v3/sdk/objc/) 或 [七牛云存储 Android-SDK](http://docs.qiniutek.com/v3/sdk/android/) 的相关上传函数或参照 [七牛云存储API之文件上传](http://docs.qiniutek.com/v3/api/io/#upload) 直传文件。这样,您的终端用户即可把数据(比如图片或视频)直接上传到七牛云存储服务器上无须经由您的服务端中转,而且在上传之前,七牛云存储做了智能加速,终端用户上传数据始终是离他物理距离最近的存储节点。当终端用户上传成功后,七牛云存储服务端会向您指定的 `callbackUrl` 发送回调数据。如果 `callbackUrl` 所在的服务处理完毕后输出 `JSON` 格式的数据,七牛云存储服务端会将该回调请求所得的响应信息原封不动地返回给终端应用程序。 - - - -### 获取文件属性信息 - - rs.stat(key, function(resp) { - console.log("\n===> Stat result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**参数** - -key -: 资源ID - -callback function -: 请求完成之后执行的回调函数 - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { - code: 200, - data: { - fsize: 1275, // 资源大小 - hash: 'FrOXNat8VhBVmcMF3uGrILpTu8Cs', // 资源摘要值 - mimeType: 'application/octet-stream', // 资源的 MIME 类型 - putTime: 13421490912350790 // 资源最后修改时间,单位:百纳秒 - } - } - - - -### 获取文件下载链接(含文件属性信息) - - rs.get(key, saveAsFriendlyName, function(resp) { - console.log("\n===> Get result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**参数** - -key -: 资源ID - -saveAsFriendlyName -: 指定文件下载下来要保存的文件名称 - -callback function -: 请求完成之后执行的回调函数 - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { - code: 200, - data: { - fsize: 1275, // 资源大小 - hash: 'FrOXNat8VhBVmcMF3uGrILpTu8Cs', // 资源摘要值 - mimeType: 'application/octet-stream', // 资源的 MIME 类型 - expires: 3600 // 缺省3600秒,指定下载链接的有效期 - url: 'http://iovip.qbox.me/file/...' // 文件下载链接 - } - } - - - -### 获取文件下载链接(断点续下载) - - rs.getIfNotModified(key, saveAsFriendlyName, baseVer, function(resp) { - console.log("\n===> Get result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**参数** - -key -: 资源ID - -saveAsFriendlyName -: 指定文件下载下来要保存的文件名称 - -baseVer -: 续传的基版本,一般为上一次请求下载返回的 `hash` 值 - -callback function -: 请求完成之后执行的回调函数 - -**响应** - -同 `rs.get` 返回的结果规格一致。 - - - -### 创建公开外链 - - rs.publish(domain, function(resp) { - console.log("\n===> publish result: ", resp); - if (resp.code != 200) { - return; - } - }); - -调用 `rs.publish` 函数可以将您在七牛云存储中的资源表 `bucket` 发布到某个 `domain` 下,`domain` 需要在 DNS 管理里边 CNAME 到 `iovip.qbox.me` 。 - -这样,用户就可以通过 `http:///` 来访问资源表 `bucket` 中的文件。键值为 `foo/bar/file` 的文件对应访问 URL 为 `http:///foo/bar/file`。 `domain` 可以是一个真实的域名,比如 `www.example.com`,也可以是七牛云存储的二级路径,比如 `io.qbox.me/bucket` 。 - -例如:执行 `rs.publish("cdn.example.com", function(resp){…})` 后,那么键名为 `foo/bar/file` 的文件可以通过 `http://cdn.example.com/foo/bar/file` 公开访问。 - -**参数** - -domain -: 必须,字符串类型(String),资源表发布的目标域名,例如:`cdn.example.com` - -callback function -: 请求完成之后执行的回调函数 - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { code: 200 } - - - -### 取消公开外链 - -取消指定 `bucket` 的在某个 `domain` 域下的所有公开外链访问。 - - rs.unpublish(domain, function(resp) { - console.log("\n===> unpublish result: ", resp); - if (resp.code != 200) { - return; - } - }); - -参数 和 响应的返回值 同 `rs.publish()` 规格一致。 - - - -### 删除指定文件 - -`rs.remove()` 函数提供了从即定的 `bucket` 中删除指定的 `key`,即删除 `key` 索引关联的具体文件。 - - rs.remove(key, function(resp) { - console.log("\n===> remove result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { code: 200 } - - - -### 删除所有文件(指定 bucket) - -`rs.drop()` 提供了删除整个 `bucket` 及其里边的所有 `key`,以及这些 `key` 关联的所有文件都将被删除。 - - rs.drop(function(resp) { - console.log("\n===> drop result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { code: 200 } - - - - -### 图像处理 - - - -### 图像处理(缩略、裁剪、旋转、转化) - -`qiniu.img.mogrify()` 方法支持将一个存储在七牛云存储的图片进行缩略、裁剪、旋转和格式转化处理,该方法返回一个可以直接预览缩略图的URL。 - - var imgMogrPreviewURL = qiniu.img.mogrify(imageDownloadURL, options); - -**参数** - -imageDownloadURL -: 必须,字符串类型(string),指定原始图片的下载链接,可以根据 rs.get() 获取到。 - -options -: 必须,对象型(object),JSON 格式的图像处理参数。 - -`options` 对象具体的规格如下: - - options = { - "thumbnail": , - "gravity": , =NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast - "crop": , - "quality": , - "rotate": , - "format": , =jpg, gif, png, tif, etc. - "auto_orient": - } - -`qiniu.img.mogrify()` 方法是对七牛云存储图像处理高级接口的完整包装,关于 `options` 参数里边的具体含义和使用方式,可以参考文档:[图像处理高级接口](#/v3/api/foimg/#fo-imageMogr)。 - - - -### 图像处理(缩略、裁剪、旋转、转化)并持久化存储处理结果 - -`qiniu.rs` 模块提供的 `imageMogrifyAs()` 方法支持将一个存储在七牛云存储的图片进行缩略、裁剪、旋转和格式转化处理,并且将处理后的缩略图作为一个新文件持久化存储到七牛云存储服务器上,这样就可以供后续直接使用而不用每次都传入参数进行图像处理。 - - var conn = new qiniu.digestauth.Client(); - - var imgrs = new qiniu.rs.Service(conn, thumbnails_bucket); - - imgrs.imageMogrifyAs(key, SourceImageDownloadURL, options, function(resp) { - console.log("\n===> imageMogrifyAs result: ", resp); - if (resp.code != 200) { - return; - } - }); - -**参数** - -imageDownloadURL -: 必须,字符串类型(string),指定原始图片的下载链接,可以根据 rs.get() 获取到。 - -options -: 必须,对象型(object),JSON 格式的图像处理参数。 - -`options` 对象具体的规格如下: - - options = { - "thumbnail": , - "gravity": , =NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast - "crop": , - "quality": , - "rotate": , - "format": , = jpg, gif, png, tif, etc. - "auto_orient": - } - -`imgrs.imageMogrifyAs()` 方法同样是对七牛云存储图像处理高级接口的完整包装,关于 `options` 参数里边的具体含义和使用方式,可以参考文档:[图像处理高级接口](#/v3/api/foimg/#fo-imageMogr)。 - -**注意** - -在上述示例代码中,我们实例化了一个新的 `imgrs` 对象,之所以这么做是因为我们考虑到缩略图也许可以创建公开外链,即缩略图所存放的 `thumbnails_bucket` 可以通过调用 `imgrs.publish()` 方法公开从而提供静态链接直接访问,这样做的好处是限定了作用域仅限于 `thumbnails_bucket`,也使得缩略图不必通过API通道进行请求且使用静态CDN加速访问,同时也保证了原图不受任何操作影响。 - -为了使得调用 `imgrs.imageMogrifyAs()` 方法有实际意义,客户方的业务服务器必须保存 `` 和 `imgrs.imageMogrifyAs` 方法中参数 `` 的值。如此,该缩略图作为一个新文件可以使用 NodeJS SDK 提供的任何方法。 - -callback function -: 请求完成之后执行的回调函数 - -**响应** - -如果操作成功,回调函数的 resp 参数返回如下一段 json 信息: - - { - code: 200, - data: { - hash: 'FrOXNat8VhBVmcMF3uGrILpTu8Cs' - } - } - - - - -## 贡献代码 - -七牛云存储 NodeJS SDK 开放源代码地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) - -1. 登录 [github.com](https://github.com) -2. Fork [https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) -3. 创建您的特性分支 (`git checkout -b my-new-feature`) -4. 提交您的改动 (`git commit -am 'Added some feature'`) -5. 将您的改动记录提交到远程 `git` 仓库 (`git push origin my-new-feature`) -6. 然后到 github 网站的该 `git` 远程仓库的 `my-new-feature` 分支下发起 Pull Request - - - -## 许可证 - -Copyright (c) 2012 qiniutek.com - -基于 MIT 协议发布: - -* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) - diff --git a/index.js b/index.js deleted file mode 100644 index b5c2c61c..00000000 --- a/index.js +++ /dev/null @@ -1,9 +0,0 @@ -var libpath = process.env.QINIU_COV ? './lib-cov' : './lib'; - -module.exports = { - conf: require(libpath + '/conf.js'), - digestauth: require(libpath + '/digestauth.js'), - rs: require(libpath + '/rs.js'), - img: require(libpath + '/img.js'), - auth: require(libpath + '/auth.js'), -}; diff --git a/lib/auth.js b/lib/auth.js deleted file mode 100644 index 7fa9cdde..00000000 --- a/lib/auth.js +++ /dev/null @@ -1,94 +0,0 @@ -var crypto = require('crypto'); -var config = require("./conf.js"); -var util = require('./util.js'); - -exports.PutPolicy = PutPolicy; -exports.GetPolicy = GetPolicy; - -// ------------------------------------------------------------------------------------------ -// func generateSignature - -function generateSignature(params) { - var paramsString = JSON.stringify(params); - return util.encode(paramsString); -} - -// ------------------------------------------------------------------------------------------ -// func generateEncodedDigest - -function generateEncodedDigest(signature) { - var hmac = crypto.createHmac('sha1', config.SECRET_KEY); - hmac.update(signature); - var digest = hmac.digest('base64'); - return util.base64ToUrlsafe(digest); -} - -// ------------------------------------------------------------------------------------------ -// func generateToken - -function generateToken(params) { - var signature = generateSignature(params); - var encodedDigest = generateEncodedDigest(signature); - return config.ACCESS_KEY + ":" + encodedDigest + ":" + signature; -} - -// ------------------------------------------------------------------------------------------ -// type PutPolicy - -function PutPolicy(opts) { - this.scope = opts.scope || null; - this.expires = opts.expires || 3600; - this.callbackUrl = opts.callbackUrl || null; - this.callbackBodyType = opts.callbackBodyType || null; - this.customer = opts.customer || null; - this.escape = opts.escape || 0; - this.asyncOps = opts.asyncOps || null; - this.returnBody = opts.returnBody || null; -} - -PutPolicy.prototype.token = function() { - var params = { - "deadline": this.expires + Math.floor(Date.now() / 1000) - }; - if (this.scope !== null) { - params["scope"] = this.scope; - } - if (this.callbackUrl !== null) { - params["callbackurl"] = this.callbackUrl; - } - if (this.callbackBodyType !== null) { - params["callbackBodyType"] = this.callbackBodyType; - } - if (this.customer !== null) { - params["customer"] = this.customer; - } - if (this.asyncOps !== null) { - params["asyncOps"] = this.asyncOps; - } - if (this.escape) { - params["escape"] = this.excape; - } - if (this.returnBody !== null) { - params["returnBody"] = this.returnBody; - } - return generateToken(params); -}; - -// ------------------------------------------------------------------------------------------ -// type GetPolicy - -function GetPolicy(opts) { - this.expires = opts.expires || 3600; - this.scope = opts.scope; // GetPolicy.scope 没有默认值:用 "*/*" 访问权限太高! -} - -GetPolicy.prototype.token = function() { - var params = { - S: this.scope, - E: this.expires + Math.floor(Date.now() / 1000), - }; - return generateToken(params); -}; - -// ------------------------------------------------------------------------------------------ - diff --git a/lib/conf.js b/lib/conf.js deleted file mode 100644 index b4894610..00000000 --- a/lib/conf.js +++ /dev/null @@ -1,20 +0,0 @@ -// ------------------------------------------------------------------------------------------ -exports.ACCESS_KEY = ''; -exports.SECRET_KEY = ''; - -exports.REDIRECT_URI = ''; -exports.AUTHORIZATION_ENDPOINT = ''; -exports.TOKEN_ENDPOINT = 'https://acc.qbox.me/oauth2/token'; - -exports.PUT_TIMEOUT = 300000; // 300s = 5m -exports.BLOCK_SIZE = 1024*1024*4; // Block Size: 4MB -exports.CHUNK_SIZE = 1024*256; // Chunk Size: 256KB -exports.MAX_RETRY_TIMES = 3; // Max retry times: 3 - -exports.IO_HOST = 'http://iovip.qbox.me'; -//exports.FS_HOST = 'https://fs.qbox.me'; -exports.RS_HOST = 'http://rs.qbox.me'; -exports.UP_HOST = 'http://up.qbox.me'; - -// ------------------------------------------------------------------------------------------ - diff --git a/lib/digestauth.js b/lib/digestauth.js deleted file mode 100644 index 40a85bc7..00000000 --- a/lib/digestauth.js +++ /dev/null @@ -1,148 +0,0 @@ -var crypto = require('crypto'); -var http = require('http'); -var https = require('https'); -var uri = require('url'); -var querystring = require('querystring'); -var conf = require('./conf.js'); -var util = require('./util.js'); - -// ------------------------------------------------------------------------------------------ -// func checksum - -function checksum(opt, body) { - var hmac = crypto.createHmac('sha1', conf.SECRET_KEY); - hmac.update(opt.path + "\n"); - if (body) { - hmac.update(body); - } - var digest = hmac.digest('base64'); - return util.base64ToUrlsafe(digest); -} - -// ------------------------------------------------------------------------------------------ -// type Client - -function Client() { -} - -Client.prototype.execute = function(options, url, params, onresp, onerror) { - var u = uri.parse(url); - var opt = { - headers: {'Accept': 'application/json', 'Accept-Encoding': 'gzip, deflate'}, - host: u.hostname, - port: u.port, - path: u.path, - method: 'POST' - }; - - var proto; - if (u.protocol === 'https:') { - proto = https; - } else { - proto = http; - } - - var body; - var isStream = false; - var isText = true; - var contentLength = 0; - var contentType = 'application/x-www-form-urlencoded'; - if (params) { - if (params instanceof util.Binary) { - contentType = 'application/octet-stream'; - contentLength = params.bytes; - isStream = true; - } else if (params instanceof util.Form) { - contentType = params.contentType; - contentLength = null; - isStream = true; - } else { - if (typeof params === 'string') { - body = params; - } else { - body = querystring.stringify(params); - } - contentLength = body.length; - } - } - - opt.headers['Content-Type'] = contentType; - if (contentLength !== null) { - opt.headers['Content-Length'] = contentLength; - } - - if (options.UploadSignatureToken != undefined && options.UploadSignatureToken != null && options.UploadSignatureToken != "") { - opt.headers['Authorization'] = 'UpToken ' + options.UploadSignatureToken; - } else if (options.AccessToken != undefined && options.AccessToken != null && options.AccessToken != "") { - opt.headers['Authorization'] = 'Bearer ' + options.AccessToken; - } else { - opt.headers['Authorization'] = 'QBox ' + conf.ACCESS_KEY + ':' + checksum(opt, body); - } - - var req = proto.request(opt, onresp); - req.on('error', onerror); - - if (params) { - if (isStream) { - params.stream.pipe(req); - } else { - req.end(params); - } - } else { - req.end(); - } - return req; -}; - -Client.prototype._callWith = function(options, url, params, onret) { - - var onresp = function(res) { - util.readAll(res, function(data) { - var ret; - if (data.length === 0) { - ret = {code: res.statusCode}; - if (res.statusCode !== 200) { - ret.error = 'E' + res.statusCode; - } - onret(ret); - return; - } - try { - ret = JSON.parse(data); - if (res.statusCode === 200) { - ret = {code: 200, data: ret}; - } else { - ret.code = res.statusCode; - } - } catch (e) { - ret = {code: -2, error: e.toString(), detail: e}; - } - onret(ret); - }); - }; - - var onerror = function(e) { - var ret = { - code: -1, - error: e.message, - detail: e - }; - onret(ret); - }; - - return this.execute(options, url, params, onresp, onerror); -}; - -Client.prototype.callWith = function(url, params, onret) { - return this._callWith("", url, params, onret); -} - -Client.prototype.callWithToken = function(uploadToken, url, params, onret){ - var options = { 'UploadSignatureToken': uploadToken }; - return this._callWith(options, url, params, onret); -}; - -exports.Client = Client; - -// ------------------------------------------------------------------------------------------ - diff --git a/lib/img.js b/lib/img.js deleted file mode 100644 index e0dd31ce..00000000 --- a/lib/img.js +++ /dev/null @@ -1,35 +0,0 @@ -/* - * 图像处理接口,生成图像处理的参数 - * func mkMogrifyParams() => string - * opts = { - * "thumbnail": , - * "gravity": , =NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast - * "crop": , - * "quality": , - * "rotate": , - * "format": , =jpg, gif, png, tif, etc. - * "auto_orient": - * } - */ -exports.mkMogrifyParams = function(opts){ - opts = opts || {}; - var keys = ["thumbnail", "gravity", "crop", "quality", "rotate", "format"]; - var params_string = "", key = null, val = null; - if (undefined !== opts.auto_orient && opts.auto_orient === true){ - params_string += "/auto-orient"; - } - for (var i=0; i < keys.length; i++) { - key = keys[i]; - if (undefined !== opts[key]) { - params_string += '/' + key + '/' + opts[key]; - } - } - return 'imageMogr' + params_string; -}; - -/* - * 图像处理接口,生成最终的缩略图预览URL - */ -exports.mogrify = function(source_img_url, opts){ - return source_img_url + '?' + this.mkMogrifyParams(opts); -}; diff --git a/lib/rs.js b/lib/rs.js deleted file mode 100644 index 3c306483..00000000 --- a/lib/rs.js +++ /dev/null @@ -1,410 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var crc32 = require('crc32'); -var mime = require('mime'); -var formstream = require('formstream'); -var querystring = require('querystring'); -var config = require('./conf.js'); -var util = require('./util.js'); -var img = require('./img.js'); - -exports.Service = Service; -exports.mkbucket = function(conn, bucketname, onret) { - var url = config.RS_HOST + '/mkbucket/' + bucketname; - conn.callWith(url, null, onret); -}; - -// ------------------------------------------------------------------------------------------ -// type Service - -function Service(conn, bucket) { - this.conn = conn; - this.bucket = bucket; -} - -Service.prototype.buckets = function(onret) { - var url = config.RS_HOST + '/buckets'; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.putAuth = function(onret) { - /* - * func PutAuth() => PutAuthRet - * 上传授权(生成一个短期有效的可匿名上传URL) - **/ - var url = config.IO_HOST + '/put-auth/'; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.putAuthEx = function(expires, callbackUrl, onret) { - /* - * func PutAuthEx(expires, callbackUrl) => PutAuthRet - * 上传授权(生成一个短期有效的可匿名上传URL) - **/ - var url = config.IO_HOST + '/put-auth/' + expires + '/callback/' + util.encode(callbackUrl); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.put = function(key, mimeType, fp, bytes, onret) { - /* - * func Put(key string, mimeType string, fp File, bytes int64) => (data PutRet, code int, err Error) - * 上传一个流 - **/ - if (!mimeType) { - mimeType = 'application/octet-stream'; - } - var entryURI = this.bucket + ':' + key; - var url = config.IO_HOST + '/rs-put/' + util.encode(entryURI) + '/mimeType/' + util.encode(mimeType); - var binary = new util.Binary(fp, bytes); - return this.conn.callWith(url, binary, onret); -}; - -Service.prototype.putFile = function(key, mimeType, localFile, onret) { - /* - * func PutFile(key string, mimeType string, localFile string) => (data PutRet, code int, err Error) - * 上传文件 - **/ - var self = this; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var fp = fs.createReadStream(localFile); - self.put(key, mimeType, fp, fi.size, onret); - }); -}; - -Service.prototype.upload = function(upToken, key, mimeType, filename, stream, onret) { - /* - * func Upload(upToken string, key string, mimeType string, filename string, stream ReadStream) => (data PutRet, code int, err Error) - * 以multipart/form-data形式上传ReadStream - **/ - var self = this; - if (!mimeType) { - mimeType = "application/octet-stream"; - } - var entryURI = this.bucket + ':' + key; - entryURI = '/rs-put/' + util.encode(entryURI) + '/mimeType/' + util.encode(mimeType); - - var form = formstream(); - form.field('action', entryURI); - form.stream('file', stream, filename, mimeType); - - form = new util.Form(form, form.headers()['Content-Type']); - return this.conn.callWith(upToken, form, onret); -}; - -Service.prototype.uploadFile = function(upToken, key, mimeType, localFile, onret) { - /* - * func UploadFile(upToken string, key string, mimeType string, localFile string) => (data PutRet, code int, err Error) - * 以multipart/form-data形式上传文件 - **/ - var self = this; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var filename = path.basename(localFile); - var stream = fs.createReadStream(localFile); - self.upload(upToken, key, mimeType, filename, stream, onret); - }); -}; - -Service.prototype.uploadWithToken = function(uploadToken, stream, key, mimeType, customMeta, callbackParams, crc32, onret) { - /* - * func UploadWithToken(uploadToken, stream, key, mimeType, customMeta, callbackParams, crc32, onret) => (data PutRet, code int, err Error) - * 使用upload_token以multipart/form-data形式上传ReadStream流 - **/ - var bucket = this.bucket; - if (!mimeType) { - mimeType = "application/octet-stream"; - } - - var actionString = util.generateActionString(bucket, key, mimeType, customMeta, crc32); - if (callbackParams === null) { - callbackParams = { - "bucket": bucket, - "key": key, - "mime_type": mimeType - }; - } - var callbackQueryString = querystring.stringify(callbackParams); - var url = config.UP_HOST + "/upload"; - - var filename = path.basename(key); - var form = formstream(); - form.field('action', actionString); - form.field('params', callbackQueryString); - form.field('multipart', true); - form.field('auth', uploadToken); - form.stream('file', stream, filename, mimeType); - form = new util.Form(form, form.headers()['Content-Type']); - - return this.conn.callWithToken(uploadToken, url, form, onret); -}; - -Service.prototype.uploadFileWithToken = function(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, onret) { - /* - * func UploadFileWithToken(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, onret) => (data PutRet, code int, err Error) - * 使用upload_token以multipart/form-data形式上传文件 - **/ - var self = this - , bucket = self.bucket; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var fileCrc32 = null - , stream = fs.createReadStream(localFile); - - if (enableCrc32Check) { - var fileStat = fs.statSync(localFile) - , fileSize = fileStat.size - , buf = new Buffer(fileSize) - , fd = fs.openSync(localFile, 'r'); - - fs.readSync(fd, buf, 0, fileSize, 0); - fs.closeSync(fd); - fileCrc32 = parseInt("0x" + crc32(buf)).toString(); - } - - self.uploadWithToken(uploadToken, stream, key, mimeType, customMeta, callbackParams, fileCrc32, onret); - }); -}; - -Service.prototype.get = function(key, attName, onret) { - /* - * func Get(key string, attName string) => GetRet - * 下载授权(生成一个短期有效的可匿名下载URL) - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/get/' + util.encode(entryURI) + '/attName/' + util.encode(attName); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.getIfNotModified = function(key, attName, base, onret) { - /* - * func GetIfNotModified(key string, attName string, base string) => GetRet - * 下载授权(生成一个短期有效的可匿名下载URL),如果服务端文件没被人修改的话(用于断点续传) - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/get/' + util.encode(entryURI) + '/attName/' + util.encode(attName) + '/base/' + base; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.stat = function(key, onret) { - /* - * func Stat(key string) => Entry - * 取资源属性 - */ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/stat/' + util.encode(entryURI); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.publish = function(domain, onret) { - /* - * func Publish(domain string) => Bool - * 将本 Table 的内容作为静态资源发布。静态资源的url为:http://domain/key - **/ - var url = config.RS_HOST + '/publish/' + util.encode(domain) + '/from/' + this.bucket; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.unpublish = function(domain, onret) { - /* - * func Unpublish(domain string) => Bool - * 取消发布 - */ - var url = config.RS_HOST + '/unpublish/' + util.encode(domain); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.remove = function(key, onret) { - /* - * func Delete(key string) => Bool - * 删除资源 - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/delete/' + util.encode(entryURI); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.drop = function(onret) { - /* - * func Drop() => Bool - * 删除整个表(慎用!) - **/ - var url = config.RS_HOST + '/drop/' + this.bucket; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.copy = function(sourceBucket, sourceKey, targetBucket, targetKey, onret) { - /* - * func Copy(sourceBucket, sourceKey, targetBucket, targetKey, onret) => Bool - * 拷贝某个资源表中的文件到另一个资源表中的某个文件 - */ - var url = config.RS_HOST + generateMoveOrCopyOpString('copy', sourceBucket, sourceKey, targetBucket, targetKey); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.move = function(sourceBucket, sourceKey, targetBucket, targetKey, onret) { - /* - * func Move(sourceBucket, sourceKey, targetBucket, targetKey, onret) => Bool - * 移动某个资源表中的文件到另一个资源表中的某个文件 - */ - var url = config.RS_HOST + generateMoveOrCopyOpString('move', sourceBucket, sourceKey, targetBucket, targetKey); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.batchGet = function(bucket, keys, onret) { - /* - * func BatchGet(bucket, keys, onret) => GetRet[] - * 为每个key生成一个短期有效的下载地址 - */ - batch(this, "get", bucket, keys, onret); -}; - -Service.prototype.batchStat = function(bucket, keys, onret) { - /* - * func BatchStat(bucket, keys, onret) => Entry[] - * 查看每个key所对应文件的属性 - */ - batch(this, "stat", bucket, keys, onret); -}; - -Service.prototype.batchDelete = function(bucket, keys, onret) { - /* - * func BatchDelete(bucket, keys, onret) => Bool[] - * 批量删除每个key所对应的资源 - */ - batch(this, "delete", bucket, keys, onret); -}; - -Service.prototype.batchCopy = function(entries, onret) { - /* - * func BatchCopy(entries, onret) => Bool[] - * 批量拷贝文件 - */ - batchMoveOrCopy(this, 'copy', entries, onret); -}; - -Service.prototype.batchMove = function(entries, onret) { - /* - * func BatchMove(entries, onret) => Bool[] - * 批量移动文件 - */ - batchMoveOrCopy(this, 'move', entries, onret); -}; - -/* - * 持久化存储一个经过云端服务处理过后的资源 - */ -Service.prototype.saveAs = function(key, source_url, opWithParams, onret) { - var destEntryURI = this.bucket + ':' + key; - var saveAsEntryURI = util.encode(destEntryURI); - var saveAsParam = "/save-as/" + saveAsEntryURI; - var newurl = source_url + '?' + opWithParams + saveAsParam; - this.conn.callWith(newurl, null, onret); -}; - -/* - * 图像处理接口(可持久化存储缩略图) - * func imageMogrifyAs(, , , ) => Entry - * opts = { - * "thumbnail": , - * "gravity": , =NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast - * "crop": , - * "quality": , - * "rotate": , - * "format": , =jpg, gif, png, tif, etc. - * "auto_orient": - * } - */ -Service.prototype.imageMogrifyAs = function(key, source_img_url, opts, onret) { - var mogrifyParams = img.mkMogrifyParams(opts); - this.saveAs(key, source_img_url, mogrifyParams, onret); -}; - -/* - * 水印设置接口 - * setProtected() - 设置原图保护 - * setSeparator() - 设置分隔符 - * setStyle() - 设置图片预览风格别名 - * unsetStyle() - 取消设置图片预览风格别名 -*/ -Service.prototype.setProtected = function(protectedMode, onret){ - var url = config.PUB_HOST + "/accessMode/" + this.bucket + "/mode/" + protectedMode; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.setSeparator = function(sep, onret){ - sep = util.encode(sep); - var url = config.PUB_HOST + "/separator/" + this.bucket + "/sep/" + sep; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.setStyle = function(name, style, onret){ - name = util.encode(name); - style = util.encode(style); - var url = config.PUB_HOST + "/style/" + this.bucket + "/name/" + name + "/style/" + style; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.unsetStyle = function(name, onret){ - name = util.encode(name); - var url = config.PUB_HOST + "/unstyle/" + this.bucket + "/name/" + name; - this.conn.callWith(url, null, onret); -}; - - -// ------------------------------------------------------------------------------------------ -// private functions - -function generateMoveOrCopyOpString(command, sourceBucket, sourceKey, targetBucket, targetKey) { - var sourceEntryURI = sourceBucket + ":" + sourceKey; - var targetEntryURI = targetBucket + ":" + targetKey; - var url = '/' + command + '/' + util.encode(sourceEntryURI) + '/' + util.encode(targetEntryURI); - return url; -}; - -function batch(rs, command, bucket, keys, onret) { - var ops = [] - , length = keys.length - , url = config.RS_HOST + '/batch?'; - - for(var i = 0; i < length; i++) { - console.log("Entry URI is: ", bucket + ":" + keys[i]); - var encodedEntryURI = util.encode(bucket + ":" + keys[i]); - ops.push("op=/" + command + "/" + encodedEntryURI); - } - url += ops.join("&"); - console.log("Batch URL: ", url); - rs.conn.callWith(url, null, onret); -} - -function batchMoveOrCopy(rs, command, entries, onret) { - var ops = [] - , length = ops.length - , url = config.RS_HOST + '/batch?'; - - for(var i = 0; i < length; i++) { - ops.push('op=' + moveOrCopy(command, entries[i][0], entries[i][1], entries[i][2], entries[i][3])); - } - url += ops.join("&"); - rs.conn.callWith(url, null, onret); -} - -// ------------------------------------------------------------------------------------------ diff --git a/lib/util.js b/lib/util.js deleted file mode 100644 index 387c149d..00000000 --- a/lib/util.js +++ /dev/null @@ -1,98 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var mime = require('mime'); -var crypto = require('crypto'); - -// ------------------------------------------------------------------------------------------ -// func encode - -exports.base64ToUrlsafe = function(v) { - return v.replace(/\//g, '_').replace(/\+/g, '-'); -}; - -exports.encode = function(v) { - var encoded = new Buffer(v || '').toString('base64'); - return exports.base64ToUrlsafe(encoded); -}; - -exports.generateActionString = function(bucket, key, mimeType, customMeta, crc32) { - if (!key) { - console.error("Please specify your key!"); - return; - } - var entryUri = bucket + ":" + key; - if (!mimeType) { - mimeType = "application/octet-stream"; - } - var actionParams = '/rs-put/' + this.encode(entryUri) + '/mimeType/' + this.encode(mimeType); - if (customMeta !== "") { - actionParams += '/meta/' + this.encode(customMeta); - } - if ((crc32 !== undefined) && (crc32 !== null) && (crc32 !== "")) { - actionParams += '/crc32/' + crc32; - } - return actionParams; -} - -// ------------------------------------------------------------------------------------------ -// func readAll - -exports.readAll = function(strm, ondata) { - var out = []; - var total = 0; - strm.on('data', function(chunk) { - out.push(chunk); - total += chunk.length; - }); - strm.on('end', function() { - var data; - switch (out.length) { - case 0: - data = new Buffer(0); - break; - case 1: - data = out[0]; - break; - default: - data = new Buffer(total); - var pos = 0; - for (var i = 0; i < out.length; i++) { - var chunk = out[i]; - chunk.copy(data, pos); - pos += chunk.length; - } - } - ondata(data); - }); -}; - -// ------------------------------------------------------------------------------------------ -// type Binary - -function Binary(stream, bytes) { - this.stream = stream; - this.bytes = bytes; -} - -exports.Binary = Binary; - -// type Form - -function Form(stream, contentType) { - this.stream = stream; - this.contentType = contentType; -} - -exports.Form = Form; - -// type Text - -function Text(text, contentType) { - this.text = text; - this.contentType = contentType; -} - -exports.Text = Text; - -// ------------------------------------------------------------------------------------------ - diff --git a/package.json b/package.json deleted file mode 100644 index 290ec119..00000000 --- a/package.json +++ /dev/null @@ -1,55 +0,0 @@ -{ - "name": "qiniu", - "version": "2.4.3", - "description": "Node wrapper for Qiniu Resource (Cloud) Storage API", - "main": "index.js", - "directories": { - "test": "test" - }, - "scripts": { - "test": "make test" - }, - "repository": { - "type": "git", - "url": "git://github.com/qiniu/nodejs-sdk.git" - }, - "bugs": { - "url": "https://github.com/qiniu/nodejs-sdk/issues" - }, - "keywords": [ - "cloud", - "storage", - "s3", - "qiniu", - "web-service" - ], - "author": "qiniutek.com", - "contributors": [ - { - "name": "Xu Shiwei", - "email": "xushiweizh@gmail.com" - }, - { - "name": "why404", - "email": "awhy.xu@gmail.com" - }, - { - "name": "ikbear", - "email": "sunikbear@gmail.com" - } - ], - "engines": [ - "node >= 0.4.7" - ], - "dependencies": { - "mime": "1.2.7", - "formstream": "0.0.2", - "crc32": "0.2.2" - }, - "devDependencies": { - "should": "*", - "pedding": "*", - "mocha": "*" - }, - "license": "MIT" -} diff --git a/test/logo.png b/test/logo.png deleted file mode 100644 index e839c26b177e5f72c5810d22a0459f100ba04e2c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 14057 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 diff --git a/test/rs.test.js b/test/rs.test.js deleted file mode 100644 index d2a793f1..00000000 --- a/test/rs.test.js +++ /dev/null @@ -1,493 +0,0 @@ -/*! - * qiniu - test/rs.test.js - * Copyright(c) 2012 fengmk2 - * MIT Licensed - */ - -"use strict"; - -/** - * Module dependencies. - */ - -var Stream = require('stream'); -var http = require('http'); -var fs = require('fs'); -var should = require('should'); -var qiniu = require('../'); -var path = require('path'); -var pedding = require('pedding'); -var urlparse = require('url').parse; - -qiniu.conf.ACCESS_KEY = process.env.QINIU_ACCESS_KEY; -qiniu.conf.SECRET_KEY = process.env.QINIU_SECRET_KEY; - -var currentTime = new Date().getTime(); -var bucket = "qiniutest" + currentTime, - DEMO_DOMAIN = bucket + '.qiniudn.com', - imagefile = path.join(__dirname, 'logo.png'); - -var conn = new qiniu.digestauth.Client(), - rs = new qiniu.rs.Service(conn, bucket); - -describe('rs.test.js', function () { - var lastHash = null; - - before(function (done) { - qiniu.rs.mkbucket(conn, bucket, function(res){ - res.should.have.property('code', 200); - done(); - }); - }); - - after(function (done) { - rs.drop(function (res) { - res.should.have.property('code', 200); - done(); - }); - }); - - describe('putAuth()', function () { - - it('should return the auth upload url with default expires time 3600 seconds', function (done) { - rs.putAuth(function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.keys(['expiresIn', 'url']); - res.data.expiresIn.should.equal(3600); - res.data.url.should.match(/^http:\/\/iovip\.qbox\.me\/upload\/[\w\-]+$/); - done(); - }); - }); - - }); - - describe('putAuthEx()', function () { - - it('should return the auth upload url with custom expires time 60 seconds and callback url', function (done) { - rs.putAuthEx(60, 'http://127.0.0.1/callback', function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.keys(['expiresIn', 'url']); - res.data.expiresIn.should.equal(60); - res.data.url.should.match(/^http:\/\/iovip\.qbox\.me\/upload\/[\w\-=]+$/); - done(); - }); - }); - - }); - - describe('putFile()', function () { - - it('should upload a file with key', function (done) { - rs.putFile('rs.test.js', null, __filename, function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - done(); - }); - }); - - it('should return error when file not exists', function (done) { - rs.putFile('rs.test.js.not.exists', null, __filename + '123', function (res) { - res.should.have.keys('code', 'error', 'detail'); - res.code.should.equal(-1); - res.error.should.include('ENOENT'); - done(); - }); - }); - - it('should return error when req.abort()', function (done) { - var size = fs.statSync(__filename).size; - var stream = fs.createReadStream(__filename); - - var req = rs.put('rs.test.js.abort', null, stream, size, function (res) { - res.should.have.keys('code', 'detail', 'error'); - res.code.should.equal(-1); - res.error.should.equal('socket hang up'); - res.detail.code.should.equal('ECONNRESET'); - rs.get('rs.test.js.abort', 'test.js', function (res) { - res.should.have.keys('code', 'error'); - res.code.should.equal(612); - res.error.should.equal('no such file or directory'); - done(); - }); - }); - - setTimeout(function () { - req.abort(); - }, 5); - }); - - }); - - describe('uploadFile() && upload()', function () { - - var upToken = null; - beforeEach(function (done) { - rs.putAuth(function (res) { - res.code.should.equal(200); - upToken = res.data.url; - done(); - }); - }); - - it('should upload a file with key using form-data format', function (done) { - rs.uploadFile(upToken, 'test/rs.test.js.uploadFile', null, __filename, function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - var lastHash = res.data.hash; - rs.get('test/rs.test.js.uploadFile', 'foo.js', function (res) { - res.code.should.equal(200); - res.data.hash.should.equal(lastHash); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.fsize.should.equal(fs.statSync(__filename).size); - done(); - }); - }); - }); - - it('should return error when file not exists', function (done) { - rs.uploadFile(upToken, 'rs.test.js.not.exists', null, __filename + '123', function (res) { - res.should.have.keys('code', 'error', 'detail'); - res.code.should.equal(-1); - res.error.should.include('ENOENT'); - done(); - }); - }); - - it('should upload a stream with key using form-data format', function (done) { - var logoStream = fs.createReadStream(imagefile); - rs.upload(upToken, 'test/rs.test.js.upload.logo.png', null, 'logo.png', logoStream, - function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - var lastHash = res.data.hash; - rs.get('test/rs.test.js.upload.logo.png', 'qiniu-logo.png', function (res) { - res.code.should.equal(200); - res.data.hash.should.equal(lastHash); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.fsize.should.equal(fs.statSync(imagefile).size); - done(); - }); - }); - }); - - it('should upload any ReadStream using form-data format', function (done) { - var s = new Stream(); - var count = 0; - var size = 0; - var timer = setInterval(function () { - var text = 'I come from timer stream ' + count + '\n'; - size += text.length; - count++; - if (count >= 5) { - clearInterval(timer); - process.nextTick(function () { - s.emit('end'); - }); - } - s.emit('data', text); - }, 100); - - rs.upload(upToken, 'test/rs.test.js.upload.timer.stream', null, 'stream.txt', s, function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - var lastHash = res.data.hash; - rs.get('test/rs.test.js.upload.timer.stream', 'stream.txt', function (res) { - res.code.should.equal(200); - res.data.hash.should.equal(lastHash); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.fsize.should.equal(size); - done(); - }); - }); - }); - - it('should upload ReadStream and abort() the request', function (done) { - var s = new Stream(); - var count = 0; - var size = 0; - var timer = setInterval(function () { - var text = 'I come from timer stream ' + count + '\n'; - size += text.length; - count++; - if (count >= 5) { - clearInterval(timer); - process.nextTick(function () { - s.emit('end'); - }); - } - s.emit('data', text); - }, 1000); - - var req = rs.upload(upToken, 'test/rs.test.js.upload.timer.stream.abort', null, 'stream.txt', s, function (res) { - res.should.have.keys('code', 'detail', 'error'); - res.code.should.equal(-1); - res.error.should.equal('socket hang up'); - res.detail.code.should.equal('ECONNRESET'); - rs.get('test/rs.test.js.upload.timer.stream.abort', 'stream.txt', function (res) { - res.should.have.keys('code', 'error'); - res.code.should.equal(612); - res.error.should.equal('no such file or directory'); - done(); - }); - }); - - setTimeout(function () { - req.abort(); - }, 1500); - }); - - }); - - describe('uploadWithToken() && uploadFileWithToken()', function () { - var upToken = null; - beforeEach(function (done) { - var opts = { - scope: bucket, - expires: 3600, - callbackUrl: null, - callbackBodyType: null, - customer: null - }; - var policy = new qiniu.auth.PutPolicy(opts); - upToken = policy.token(); - done(); - }); - - it('should upload a stream with key using upToken and form-date format', function (done) { - - var s = new Stream(); - var count = 0; - var size = 0; - var timer = setInterval(function () { - var text = 'I come from timer stream ' + count + '\n'; - size += text.length; - count++; - if (count >= 5) { - clearInterval(timer); - process.nextTick(function () { - s.emit('end'); - }); - } - s.emit('data', text); - }, 100); - - rs.uploadWithToken(upToken, s, "stream.txt", null, null, null, null, function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - var lastHash = res.data.hash; - rs.get('stream.txt', 'stream.txt', function (res) { - res.code.should.equal(200); - res.data.hash.should.equal(lastHash); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.fsize.should.equal(size); - done(); - }); - }); - }); - - it('should upload a file with key using upToken and form-date format', function (done) { - var fstat = fs.statSync(__filename) - , size = fstat.size; - - rs.uploadFileWithToken(upToken, __filename, "uploadfilewithtoken.txt", null, null, {}, false, function(res){ - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - var lastHash = res.data.hash; - rs.get('uploadfilewithtoken.txt', 'uploadfilewithtoken.txt', function (res) { - res.code.should.equal(200); - res.data.hash.should.equal(lastHash); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.fsize.should.equal(size); - done(); - }); - }); - - }); - - }); - - describe('get()', function () { - - var lastHash = null; - - beforeEach(function (done) { - rs.putFile('rs.test.js.get', null, __filename, function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.property('hash').with.match(/^[\w\-=]{28}$/); - lastHash = res.data.hash; - done(); - }); - }); - - it('should return a file download url', function (done) { - rs.get('rs.test.js.get', 'download.js', function (res) { - res.code.should.equal(200); - res.data.should.have.keys('expires', 'fsize', 'hash', 'mimeType', 'url'); - res.data.expires.should.equal(3600); - res.data.fsize.should.be.a('number').with.above(0); - res.data.hash.should.match(/^[\w\-=]{28}$/); - res.data.mimeType.should.equal('application/javascript'); - res.data.url.should.match(/^http:\/\/iovip\.qbox\.me\/file\/[\w\-=]+$/); - - var options = urlparse(res.data.url); - http.get(options, function (downloadRes) { - downloadRes.statusCode.should.equal(200); - downloadRes.should.have.header('content-disposition', 'attachment; filename="download.js"'); - downloadRes.should.have.header('content-length', res.data.fsize + ''); - var size = 0; - downloadRes.on('data', function (chunk) { - size += chunk.length; - }); - downloadRes.on('end', function () { - size.should.equal(res.data.fsize); - done(); - }); - }); - }); - }); - - it('should return "file modified" when hash not match', function (done) { - rs.getIfNotModified('rs.test.js.get', 'getIfNotModified.js', 'nohash', function (res) { - res.should.have.keys('error', 'code'); - res.code.should.equal(608); - res.error.should.equal('file modified'); - done(); - }); - }); - - it('should return download url when hash match', function (done) { - rs.getIfNotModified('rs.test.js.get', 'getIfNotModified.js', lastHash, function (res) { - res.should.have.keys('data', 'code'); - res.code.should.equal(200); - res.data.url.should.match(/^http:\/\/iovip\.qbox\.me\/file\/[\w\-=]+$/); - done(); - }); - }); - - it('should return "no such file or directory" when get the not exists key', function (done) { - done = pedding(2, done); - rs.get('not exists key', 'abc', function (res) { - res.should.eql({ error: 'no such file or directory', code: 612 }); - done(); - }); - rs.getIfNotModified('not exists key', 'abc', 'hash', function (res) { - res.should.eql({ error: 'no such file or directory', code: 612 }); - done(); - }); - }); - - }); - - describe('stat()', function () { - - it('should return key stat info', function (done) { - rs.stat('rs.test.js.get', function (res) { - res.should.have.keys('code', 'data'); - res.code.should.equal(200); - res.data.should.have.keys('fsize', 'hash', 'mimeType', 'putTime'); - done(); - }); - }); - - it('should return "no such file or directory"', function (done) { - rs.stat('not exists file', function (res) { - res.should.eql({ error: 'no such file or directory', code: 612 }); - done(); - }); - }); - - }); - - describe('remove()', function () { - before(function (done) { - rs.putFile('rs.test.js.remove', null, __filename, function (res) { - res.should.have.property('code', 200); - done(); - }); - }); - - it('should remove a file by key', function (done) { - rs.remove('rs.test.js.remove', function (res) { - res.should.eql({ code: 200 }); - // remove a gain will error - rs.remove('rs.test.js.remove', function (res) { - res.should.eql({ error: 'no such file or directory', code: 612 }); - done(); - }); - }); - }); - - it('should return "no such file or directory" when key not exists', function (done) { - rs.remove('not exists file', function (res) { - res.should.eql({ error: 'no such file or directory', code: 612 }); - done(); - }); - }); - - }); - - describe('imageMogrifyAs()', function () { - - var sourceURL = ''; - before(function (done) { - rs.putFile('logo.png', null, imagefile, function (res) { - res.code.should.equal(200); - rs.get('logo.png', 'abc', function (res) { - res.should.have.property('code', 200); - sourceURL = res.data.url; - done(); - }); - }); - }); - - it('should modified a image', function (done) { - rs.imageMogrifyAs('logo.png', sourceURL, { - thumbnail: '50x50^', - auto_orient: true, - format: 'jpg', - }, function (res) { - res.should.have.property('code', 200); - res.should.have.property('data'); - res.data.should.have.property('hash').with.match(/^[\w\-=]+$/); - done(); - }); - }); - - }); - - describe('publish() && unpublish()', function () { - - it('should publish a domain', function (done) { - rs.publish(DEMO_DOMAIN, function (res) { - res.should.have.property('code', 200); - // again will no problem - rs.publish(DEMO_DOMAIN, function (res) { - res.should.have.property('code', 200); - done(); - }); - }); - }); - - it('should unpublish a domain', function (done) { - rs.unpublish(DEMO_DOMAIN, function (res) { - res.should.have.property('code', 200); - // again will error - rs.unpublish(DEMO_DOMAIN, function (res) { - res.should.eql({ error: 'Document not found', code: 599 }); - done(); - }); - }); - }); - - }); - -}); From 377072eb1a11ac85dcd91892a1755ef31daf2c86 Mon Sep 17 00:00:00 2001 From: longbai Date: Fri, 12 Jul 2013 10:29:02 +0800 Subject: [PATCH 02/41] delete demo/* --- .gitignore | 4 ---- 1 file changed, 4 deletions(-) diff --git a/.gitignore b/.gitignore index 217f1b38..72a03e60 100644 --- a/.gitignore +++ b/.gitignore @@ -17,7 +17,3 @@ results node_modules npm-debug.log -demo/*.jpg -demo/rtest.js -demo/itest.js -demo/put.sh From fdf62b68b713b8f23b6ee1eb68cad2295f16132d Mon Sep 17 00:00:00 2001 From: longbai Date: Fri, 12 Jul 2013 10:31:16 +0800 Subject: [PATCH 03/41] create version 6.0.0 --- Makefile | 25 +++++ docs/demo/client.js | 43 ++++++++ docs/demo/fop.js | 22 ++++ docs/demo/rs.js | 58 ++++++++++ docs/demo/rsf.js | 20 ++++ docs/demo/server.js | 26 +++++ index.js | 10 ++ qiniu/auth/digest.js | 39 +++++++ qiniu/conf.js | 9 ++ qiniu/fop.js | 51 +++++++++ qiniu/io.js | 117 ++++++++++++++++++++ qiniu/resumable_io.js | 57 ++++++++++ qiniu/rpc.js | 79 ++++++++++++++ qiniu/rs.js | 246 ++++++++++++++++++++++++++++++++++++++++++ qiniu/rsf.js | 46 ++++++++ qiniu/util.js | 75 +++++++++++++ test-env.sh | 4 + test/fop.test.js | 43 ++++++++ test/io.test.js | 126 ++++++++++++++++++++++ test/logo.png | Bin 0 -> 14057 bytes test/rs.test.js | 166 ++++++++++++++++++++++++++++ 21 files changed, 1262 insertions(+) create mode 100644 Makefile create mode 100644 docs/demo/client.js create mode 100644 docs/demo/fop.js create mode 100644 docs/demo/rs.js create mode 100644 docs/demo/rsf.js create mode 100644 docs/demo/server.js create mode 100644 index.js create mode 100644 qiniu/auth/digest.js create mode 100644 qiniu/conf.js create mode 100644 qiniu/fop.js create mode 100644 qiniu/io.js create mode 100644 qiniu/resumable_io.js create mode 100644 qiniu/rpc.js create mode 100644 qiniu/rs.js create mode 100644 qiniu/rsf.js create mode 100644 qiniu/util.js create mode 100644 test-env.sh create mode 100644 test/fop.test.js create mode 100644 test/io.test.js create mode 100644 test/logo.png create mode 100644 test/rs.test.js diff --git a/Makefile b/Makefile new file mode 100644 index 00000000..20868608 --- /dev/null +++ b/Makefile @@ -0,0 +1,25 @@ +TESTS = test/*.test.js +TIMEOUT = 15000 +REPORTER = spec +MOCHA_OPTS = +test: + @NODE_ENV=test ./node_modules/.bin/mocha \ + --require should \ + --reporter $(REPORTER) \ + --timeout $(TIMEOUT) \ + $(MOCHA_OPTS) \ + $(TESTS) + +test-cov: lib-cov +# @QINIU_COV=1 $(MAKE) test REPORTER=dot + @QINIU_COV=1 $(MAKE) test REPORTER=html-cov > coverage.html + @rm -rf ./lib-cov + + +lib-cov: + @jscoverage --no-highlight qiniu $@ + +clean: + rm -rf ./lib-cov coverage.html + +.PHONY: test-cov lib-cov test diff --git a/docs/demo/client.js b/docs/demo/client.js new file mode 100644 index 00000000..1e482819 --- /dev/null +++ b/docs/demo/client.js @@ -0,0 +1,43 @@ +var qiniu = require('../../'); + +// @gist uploadFile +function uploadFile(localFile, key, uptoken) { + var extra = new qiniu.io.PutExtra(); + //extra.params = params; + //extra.mimeType = mimeType; + //extra.crc32 = crc32; + //extra.checkCrc = checkCrc; + + io.putFile(uptoken, key, localFile, extra, function(ret) { + if(ret.code === 200) { + // 上传成功, 处理返回值 + // ret.data.key & ret.data.hash + } else { + // 上传失败, 处理返回代码 + // ret.code + // http://docs.qiniu.com/api/put.html#error-code + } + }); +} +// @endgist + +// @gist uploadBufDemo +function uploadBufDemo(body, key, uptoken) { + var extra = new qiniu.io.PutExtra(); + //extra.params = params; + //extra.mimeType = mimeType; + //extra.crc32 = crc32; + //extra.checkCrc = checkCrc; + + io.put(uptoken, key, body, extra, function(ret) { + if(ret.code === 200) { + // 上传成功, 处理返回值 + // ret.data.key & ret.data.hash + } else { + // 上传失败, 处理返回代码 + // ret.code + // http://docs.qiniu.com/api/put.html#error-code + } + }); +} +// @endgist diff --git a/docs/demo/fop.js b/docs/demo/fop.js new file mode 100644 index 00000000..584b8e64 --- /dev/null +++ b/docs/demo/fop.js @@ -0,0 +1,22 @@ +var qiniu = require('../../'); + +// @gist makeImageInfoUrl +function makeImageInfoUrl(imageUrl) { + var ii = new qiniu.fop.ImageInfo(); + return ii.makeRequest(imageUrl); +} +// @endgist + +// @gist makeExifUrl +function makeExifUrl(imageUrl) { + var e = new qiniu.fop.Exif(); + return e.makeRequest(imageUrl); +} +// @endgist + +// @gist makeImageViewUrl +function makeImageViewUrl(imageUrl, mode, width, height, quality, format) { + var iv = new qiniu.fop.ImageView(mode, width, height, quality, format); + return iv.makeRequest(imageUrl); +} +// @endgist diff --git a/docs/demo/rs.js b/docs/demo/rs.js new file mode 100644 index 00000000..dd1fba50 --- /dev/null +++ b/docs/demo/rs.js @@ -0,0 +1,58 @@ +var qiniu = require('../../'); + +// @gist init +qiniu.conf.ACCESS_KEY = ''; +qiniu.conf.SECRET_KEY = ''; +// @endgist + + +// @gist stat +var client = new qiniu.rs.Client(); +client.stat(bucketName, key, function(ret) { + if (ret.code === 200) { + // process + // ret.data.hash & ret.data.fsize & ret.data.putTime & ret.data.mimeType + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist + +// @gist move +var client = new qiniu.rs.Client(); +client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist + +// @gist copy +var client = new qiniu.rs.Client(); +client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist + +// @gist remove +var client = new qiniu.rs.Client(); +client.remove(bucketName, key, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}) +// @endgist + + diff --git a/docs/demo/rsf.js b/docs/demo/rsf.js new file mode 100644 index 00000000..9d30b7f8 --- /dev/null +++ b/docs/demo/rsf.js @@ -0,0 +1,20 @@ +var qiniu = require('../../'); + +// @gist init +qiniu.conf.ACCESS_KEY = ''; +qiniu.conf.SECRET_KEY = ''; +// @endgist + +// @gist listPrefix +function qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { + if(ret.code === 200) { + // process ret.data.marker & ret.data.items + } else { + // something error, see ret.code according to + // http://docs.qiniu.com/api/file-handle.html#list + } +}); +// @endgist + + + diff --git a/docs/demo/server.js b/docs/demo/server.js new file mode 100644 index 00000000..03244049 --- /dev/null +++ b/docs/demo/server.js @@ -0,0 +1,26 @@ +var qiniu = require('../..'); + +qiniu.conf.ACCESS_KEY = '' +qiniu.conf.SECRET_KEY = '' + +// @gist uptoken +function uptoken(bucketname) { + var putPolicy = new qiniu.rs.PutPolicy(bucketname); + //putPolicy.callbackUrl = callbackUrl; + //putPolicy.callbackBody = callbackBody; + //putPolicy.returnUrl = returnUrl; + //putPolicy.returnBody = returnBody; + //putPolicy.asyncOps = asyncOps; + //putPolicy.expires = expires; + + return putPolicy.token(); +} +// @endgist + +// @gist downloadUrl +function downloadUrl(domain, key) { + var baseUrl = rs.makeBaseUrl(domain, key); + var policy = new rs.GetPolicy(); + return policy.makeRequest(baseUrl); +} +// @endgist diff --git a/index.js b/index.js new file mode 100644 index 00000000..6b224d3b --- /dev/null +++ b/index.js @@ -0,0 +1,10 @@ + +var libpath = process.env.QINIU_COV ? './lib-cov' : './qiniu'; + +module.exports = { + io: require(libpath + '/io.js'), + rs: require(libpath + '/rs.js'), + rsf: require(libpath + '/rsf.js'), + fop: require(libpath + '/fop.js'), + conf: require(libpath + '/conf.js'), +}; diff --git a/qiniu/auth/digest.js b/qiniu/auth/digest.js new file mode 100644 index 00000000..8db1bae2 --- /dev/null +++ b/qiniu/auth/digest.js @@ -0,0 +1,39 @@ + +var url = require('url'); +var conf = require('../conf'); +var util = require('../util'); + +exports.Mac = Mac; + +function Mac(accessKey, secretKey) { + this.accessKey = accessKey || conf.ACCESS_KEY; + this.secretKey = secretKey || conf.SECRET_KEY; +} + +//Mac.prototype._sign = function(data) { +// return util.hmacSha1(data, this.secretKey); +//} +// +//Mac.prototype.sign = function(data) { +// return this.accessKey + ':' + this._sign(data); +//} +// +//Mac.prototype.signWithData = function(b) { +// var data = util.urlsafeBase64Encode(b); +// var sign = this._sign(data); +// return this.accessKey + ':' + sign + ':' + data; +//} +// +//Mac.prototype.sign_request = function(path, body, content_type) { +// var u = url.parse(path); +// var path = u.path; +// var data = path + '\n'; +// +// if (body) { +// data += body; +// } +// +// return this.access + ':' + this._sign(data); +//} +// + diff --git a/qiniu/conf.js b/qiniu/conf.js new file mode 100644 index 00000000..e009a789 --- /dev/null +++ b/qiniu/conf.js @@ -0,0 +1,9 @@ + +exports.ACCESS_KEY = ''; +exports.SECRET_KEY = ''; + +exports.USER_AGENT = 'qiniu nodejs-sdk v6.0.0'; + +exports.UP_HOST = 'http://up.qbox.me'; +exports.RS_HOST = 'http://rs.qbox.me'; +exports.RSF_HOST = 'http://rsf.qbox.me'; diff --git a/qiniu/fop.js b/qiniu/fop.js new file mode 100644 index 00000000..860c7f54 --- /dev/null +++ b/qiniu/fop.js @@ -0,0 +1,51 @@ + + +exports.ImageView = ImageView; +exports.ImageInfo = ImageInfo; +exports.Exif = Exif; + +function ImageView(mode, width, height, quality, format) { + this.mode = mode || 1; + this.width = width || 0; + this.height = height || 0; + this.quality = quality || 0; + this.format = format || null; +} + +ImageView.prototype.makeRequest = function(url) { + url += '?imageView/' + this.mode; + + if (this.width > 0) { + url += '/w/' + this.width; + } + + if (this.height > 0) { + url += '/h/' + this.height; + } + + if (this.quality > 0) { + url += '/q/' + this.quality; + } + + if (this.format) { + url += '/format/' + this.format; + } + + return url; +} + +function ImageInfo() { +} + +ImageInfo.prototype.makeRequest = function(url) { + return url + '?imageInfo' +} + +function Exif() { +} + +Exif.prototype.makeRequest = function(url) { + return url + '?exif' +} + + diff --git a/qiniu/io.js b/qiniu/io.js new file mode 100644 index 00000000..e7be16bc --- /dev/null +++ b/qiniu/io.js @@ -0,0 +1,117 @@ + +var conf = require('./conf'); +var util = require('./util'); +var rpc = require('./rpc'); +var fs = require('fs'); +var getCrc32 = require('crc32'); +var url = require('url'); +var mime = require('mime'); +var formstream = require('formstream'); + +exports.UNDEFINED_KEY = '?' +exports.PutExtra = PutExtra; +exports.PutRet = PutRet; +exports.put = put; +exports.putWithoutKey = putWithoutKey; +exports.putFile = putFile; +exports.putFileWithoutKey = putFileWithoutKey; + +function PutExtra(params, mimeType, crc32, checkCrc) { + this.paras = params || {}; + this.mimeType = mimeType || null; + this.crc32 = crc32 || null; + this.checkCrc = checkCrc || 0; +} + +function PutRet(hash, key) { + this.hash = hash || null; + this.key = key || null; +} + +// onret: callback function instead of ret +function put(uptoken, key, body, extra, onret) { + if(!extra) { + extra = new PutExtra(); + } + if (!extra.mimeType) { + extra.mimeType = 'application/octet-stream'; + } + + function parseRet(data) { + var ret = data; + if (ret.code !== 200) { + onret(ret); + return; + } + try { + var dt = JSON.parse(ret.data); + ret.data = dt; + } catch (e) { + ret = {code: -2, error: e.toString()}; + } + onret(ret); + } + + if(!key) { + key = exports.UNDEFINED_KEY; + } + + var form = getMultipart(uptoken, key, body, extra); + + rpc.postMultipart(conf.UP_HOST, form, parseRet); +} + +function putWithoutKey(uptoken, body, extra, onret) { + put(uptoken, null, body, extra, onret); +} + +function getMultipart(uptoken, key, body, extra) { + + var form = formstream(); + + form.field('token', uptoken); + if(key != exports.UNDEFINED_KEY) { + form.field('key', key); + } + + form.buffer('file', new Buffer(body), key, extra.mimeType); + + //extra['checkcrc'] + if (extra.checkCrc == 1) { + var bodyCrc32 = getCrc32(body); + extra.crc32 = '' + parseInt(bodyCrc32, 16); + } + + if(extra.checkCrc) { + form.field('crc32', extra.crc32); + } + + for (k in extra.params) { + form.field(k, extra.params[k]); + } + + return form; +} + +function putFile(uptoken, key, loadFile, extra, onret) { + fs.readFile(loadFile, function(err, data) { + if(err) { + onret({code: -1, error: err.toString(), detail: err}); + return; + } + + if(!extra) { + extra = new PutExtra(); + } + + if(!extra.mimeType) { + extra.mimeType = mime.lookup(loadFile); + } + put(uptoken, key, data, extra, onret); + }); +} + +function putFileWithoutKey(uptoken, loadFile, extra, onret) { + putFile(uptoken, null, loadFile, extra, onret); +} + diff --git a/qiniu/resumable_io.js b/qiniu/resumable_io.js new file mode 100644 index 00000000..c48e3dc4 --- /dev/null +++ b/qiniu/resumable_io.js @@ -0,0 +1,57 @@ + + +exports.UNDEDINED_KEY = '?'; +exports.BlkputRet = BlkputRet; +exports.PutExtra = PutExtra; +exports.PutRet = PutRet; +exports.put = put; +exports.putFile = putFile; +exports.blockCount = blockCount; +exports.Settings = Settings; +exports.setSettings = setSettings; + +function BlkputRet(ctx, checksum, crc32, offset) { + this.ctx = ctx || null; + this.checksum = checksum || null; + this.crc32 = crc32 || null; + this.offset = offset || null; +} + +function PutExtra(params, mimeType, chunkSize, tryTimes, + progresses, notify, notifyErr){ + this.params = params || {}; + this.mimeType = mimeType || null; + this.chunkSize = chunkSize || null; + this.tryTimes = tryTimes || null; + this.progresses = progresses || []; + this.notify = notify || null; + this.notifyErr = notifyErr || null; +} + +function PutRet(hash, key) { + this.hash = hash || null; + this.key = key || null; +} + +function put(ret, uptoken, key, f, fsize, extra) { + +} + +function putFile(ret, uptoken, key, localFile, extra) { + +} + +function blockCount(fsize) { + +} + +function Settings(taskQsize, workers, chunkSize, tryTimes) { + this.taskQsize = taskQsize || null; + this.workers = workers || null; + this.chunkSize = chunkSize || 256; // 256k + this.tryTimes = tryTimes || 3; +} + +function setSettings(settings) { + +} diff --git a/qiniu/rpc.js b/qiniu/rpc.js new file mode 100644 index 00000000..2b9f3db0 --- /dev/null +++ b/qiniu/rpc.js @@ -0,0 +1,79 @@ +var url = require('url'); +var util = require('./util'); +var conf = require('./conf'); + +exports.postMultipart = postMultipart; +exports.postWithForm = postWithForm; +exports.postWithoutForm = postWithoutForm; + +function postMultipart(uri, form, onret) { + post(uri, form, form.headers(), getResp(onret)); +} + +function postWithForm(uri, form, token, onret) { + var headers = { + 'Content-Type': 'application/x-www-form-urlencoded' + } + if (token) { + headers['Authorization'] = token; + } + post(uri, form, headers, getResp(onret)); +} + +function postWithoutForm(uri, token, onret) { + var headers = { + 'Content-Type': 'application/x-www-form-urlencoded', + } + if (token) { + headers['Authorization'] = token; + } + post(uri, null, headers, getResp(onret)); +} + +function getResp(onret) { + var onresp = function(res) { + util.readAll(res, function(data) { + var ret = {}; + if (data.length === 0) { + ret = {code: res.statusCode}; + onret(ret); + return; + } + ret = {code: res.statusCode, data: data.toString()}; + onret(ret); + }); + }; + return onresp; +} + +function post(uri, form, headers, onresp) { + + var u = url.parse(uri); + var options = { + headers: headers, + method: 'POST', + host: u.hostname, + port: u.port, + path: u.path, + 'User-Agent': conf.USER_AGENT, + } + + var proto; + if (u.protocol == 'https') { + proto = require('https'); + } else { + proto = require('http'); + } + + var req = proto.request(options, onresp); + if(form) { + if (typeof form === 'string') { + req.end(form); + } else { + form.pipe(req); + } + } else { + req.end(); + } +} + diff --git a/qiniu/rs.js b/qiniu/rs.js new file mode 100644 index 00000000..3ba91cd4 --- /dev/null +++ b/qiniu/rs.js @@ -0,0 +1,246 @@ + +var url = require('url'); +var crypto = require('crypto'); +var formstream = require('formstream'); +var querystring = require('querystring'); +var rpc = require('./rpc'); +var conf = require('./conf'); +var util = require('./util'); +var Mac = require('./auth/digest').Mac; + + +exports.Client = Client; +exports.Entry = Entry; +exports.EntryPath = EntryPath; +exports.EntryPathPair = EntryPathPair; +exports.BatchItemRet = BatchItemRet; +exports.BatchStatItemRet = BatchStatItemRet; + +exports.PutPolicy = PutPolicy; +exports.GetPolicy = GetPolicy; +exports.makeBaseUrl = makeBaseUrl; + +function Client(client) { + this.client = client || null; +} + +Client.prototype.stat = function(bucket, key, onret) { + var encodedEntryUri = getEncodedEntryUri(bucket, key); + var uri = conf.RS_HOST + '/stat/' + encodedEntryUri; + var digest = util.generateAccessToken(uri, null); + + function parseRet(ret) { + if (ret.code != 200 || !ret.data) { + onret(ret); + return; + } + try { + var dt = JSON.parse(ret.data); + ret.data = dt; + } catch (e) { + ret = {code: -2, error: e.toString()}; + } + onret(ret); + } + + rpc.postWithoutForm(uri, digest, parseRet); +} + +Client.prototype.remove = function(bucket, key, onret) { + /* + * func (this Client) Delete(bucket, key string) (err error) + * */ + var encodedEntryUri = getEncodedEntryUri(bucket, key); + var uri = conf.RS_HOST + '/delete/' + encodedEntryUri; + var digest = util.generateAccessToken(uri, null); + rpc.postWithoutForm(uri, digest, onret); +} + +Client.prototype.move = function(bucketSrc, keySrc, bucketDest, keyDest, onret) { + var encodedEntryURISrc = getEncodedEntryUri(bucketSrc, keySrc); + var encodedEntryURIDest = getEncodedEntryUri(bucketDest, keyDest); + var uri = conf.RS_HOST + '/move/' + encodedEntryURISrc + '/' + encodedEntryURIDest; + var digest = util.generateAccessToken(uri, null); + rpc.postWithoutForm(uri, digest, onret); +} + +Client.prototype.copy = function(bucketSrc, keySrc, bucketDest, keyDest, onret) { + var encodedEntryURISrc = getEncodedEntryUri(bucketSrc, keySrc); + var encodedEntryURIDest = getEncodedEntryUri(bucketDest, keyDest); + var uri = conf.RS_HOST + '/copy/' + encodedEntryURISrc + '/' + encodedEntryURIDest; + var digest = util.generateAccessToken(uri, null); + rpc.postWithoutForm(uri, digest, onret); +} + + +function Entry(hash, fsize, putTime, mimeType, endUser) { + this.hash = hash || null; + this.fsize = fsize || null; + this.putTime = putTime || null; + this.mimeType = mimeType || null; + this.endUser = endUser || null; +} + +// ----- batch ------- + +function EntryPath(bucket, key) { + this.bucket = bucket || null; + this.key = key || null; +} + +EntryPath.prototype.encode = function() { + return getEncodedEntryUri(this.bucket, this.key); +} + +EntryPath.prototype.toStr = function(op) { + return 'op=/' + op + '/' + getEncodedEntryUri(this.bucket, this.key) + '&'; +} + +function EntryPathPair(src, dest) { + this.src = src || null; + this.dest = dest || null; +} + +EntryPathPair.prototype.toStr = function(op) { + return 'op=/' + op + '/' + this.src.encode() + '/' + this.dest.encode() + '&'; +} + +function BatchItemRet(error, code) { + this.error = error || null; + this.code = code || null; +} + +function BatchStatItemRet(data, error, code) { + this.data = data; + this.error = error; + this.code = code; +} + +Client.prototype.batchStat = function(entries, onret) { + fileHandle('stat', entries, batchRet(onret)); +} + +Client.prototype.batchDelete = function(entries, onret) { + fileHandle('delete', entries, batchRet(onret)); +} + +Client.prototype.batchMove = function(entries, onret) { + fileHandle('move', entries, batchRet(onret)); +} + +Client.prototype.batchCopy = function(entries, onret) { + fileHandle('copy', entries, batchRet(onret)); +} + +function batchRet(onret) { + return function(ret){ + if (ret.data) { + try { + ret.data = JSON.parse(ret.data); + } catch (e) { + ret = {code: -2, error: e.toString()}; + } + } + onret(ret); + } +} + +function fileHandle(op, entries, onret) { + var body = ''; + for (i in entries) { + body += entries[i].toStr(op); + } + + var uri = conf.RS_HOST + '/batch'; + var digest = util.generateAccessToken(uri, body); + rpc.postWithForm(uri, body, digest, onret); +} + +function getEncodedEntryUri(bucket, key) { + return util.urlsafeBase64Encode(bucket + ':' + key); +} + + +// ----- token -------- + +function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, + asyncOps, endUser, expires) { + this.scope = scope || null; + this.callbackUrl = callbackUrl || null; + this.callbackBody = callbackBody || null; + this.returnUrl = returnUrl || null; + this.returnBody = returnBody || null; + this.asyncOps = asyncOps || null; + this.endUser = endUser || null; + this.expires = expires || 3600; +} + +PutPolicy.prototype.token = function(mac) { + if (mac == null) { + mac = new Mac(conf.ACCESS_KEY, conf.SECRET_KEY); + } + var flags = this.getFlags(); + var encodedFlags = util.urlsafeBase64Encode(JSON.stringify(flags)); + var encoded = util.hmacSha1(encodedFlags, mac.secretKey); + var encodedSign = util.base64ToUrlSafe(encoded); + var uploadToken = mac.accessKey + ':' + encodedSign + ':' + encodedFlags; + return uploadToken; +} + +PutPolicy.prototype.getFlags = function(putPolicy) { + var flags = {}; + if (this.scope != null) { + flags['scope'] = this.scope; + } + if (this.callbackUrl != null) { + flags['callbackUrl'] = this.scope; + } + if (this.callbackBody != null) { + flags['callbackBody'] = this.callbackBody; + } + if (this.returnUrl != null) { + flags['returnUrl'] = this.returnUrl; + } + if (this.returnBody != null) { + flags['returnBody'] = this.returnBody; + } + if (this.asyncOps != null) { + flags['asyncOps'] = this.asyncOps; + } + if (this.endUser != null) { + flags['endUser'] = this.endUser; + } + flags['deadline'] = this.expires + Math.floor(Date.now() / 1000); + return flags; +} + + +function GetPolicy(expires) { + this.expires = expires || 3600; +} + +GetPolicy.prototype.makeRequest = function(baseUrl, mac) { + if (!mac) { + mac = new Mac(conf.ACCESS_KEY, conf.SECRET_KEY); + } + + var deadline = this.expires + Math.floor(Date.now() / 1000); + + if (baseUrl.indexOf('?') >= 0) { + baseUrl += '&e='; + } else { + baseUrl += '?e='; + } + baseUrl += deadline; + + var signature = util.hmacSha1(baseUrl, mac.secretKey); + var encodedSign = util.base64ToUrlSafe(signature); + var downloadToken = mac.accessKey + ':' + encodedSign; + + return baseUrl + '&token=' + downloadToken; +} + +function makeBaseUrl(domain, key) { + key = new Buffer(key); + return 'http://' + domain + '/' + querystring.escape(key); +} diff --git a/qiniu/rsf.js b/qiniu/rsf.js new file mode 100644 index 00000000..00c34014 --- /dev/null +++ b/qiniu/rsf.js @@ -0,0 +1,46 @@ +var rpc = require('./rpc'); +var conf = require('./conf'); +var util = require('./util'); + +exports.listPrefix = function(bucket, prefix, marker, limit, onret) { + var uri = getPrefixUri(bucket, prefix, marker, limit); + var digest = util.generateAccessToken(uri, null); + + function parseRet(ret) { + if (ret.code === 200 && ret.data) { + try { + ret.data = JSON.parse(ret.data); + } catch (e) { + ret['error'] = e.toString(); + } + } + onret(ret); + } + + rpc.postWithoutForm(uri, digest, parseRet); +} + +function getPrefixUri(bucket, prefix, marker, limit) { + var uri = conf.RSF_HOST + '/' + 'list?' + 'bucket=' + bucket; + if (marker) { + uri += '&' + 'marker=' + marker; + } + + if (limit) { + uri += '&' + 'limit=' + limit; + } + + if (prefix) { + uri += '&' + 'prefix=' + prefix; + } + return uri; +} + +function ListItem(key, hash, fsize, putTime, mimeType, endUser) { + this.key = key || null; + this.hash = hash || null; + this.fsize = fsize || null; + this.putTime = putTime || null; + this.mimeType = mimeType || null; + this.endUser = endUser || null; +} diff --git a/qiniu/util.js b/qiniu/util.js new file mode 100644 index 00000000..b8a51a09 --- /dev/null +++ b/qiniu/util.js @@ -0,0 +1,75 @@ +var fs = require('fs'); +var url = require('url'); +var path = require('path'); +var crypto = require('crypto'); +var conf = require('./conf'); + +// ------------------------------------------------------------------------------------------ +// func encode + +exports.urlsafeBase64Encode = function(jsonFlags) { + var encoded = new Buffer(jsonFlags).toString('base64'); + return exports.base64ToUrlSafe(encoded); +} + +exports.base64ToUrlSafe = function(v) { + return v.replace(/\//g, '_').replace(/\+/g, '-'); +} + +exports.hmacSha1 = function(encodedFlags, secretKey) { + /* + *return value already encoded with base64 + * */ + var hmac = crypto.createHmac('sha1', secretKey); + hmac.update(encodedFlags); + return hmac.digest('base64'); +} + +// ------------------------------------------------------------------------------------------ +// func readAll + +exports.readAll = function(strm, ondata) { + var out = []; + var total = 0; + strm.on('data', function(chunk) { + out.push(chunk); + total += chunk.length; + }); + strm.on('end', function() { + var data; + switch (out.length) { + case 0: + data = new Buffer(0); + break; + case 1: + data = out[0]; + break; + default: + data = new Buffer(total); + var pos = 0; + for (var i = 0; i < out.length; i++) { + var chunk = out[i]; + chunk.copy(data, pos); + pos += chunk.length; + } + } + ondata(data); + }); +}; + +// ------------------------------------------------------------------------------------------ +// func generateAccessToken + +exports.generateAccessToken = function(uri, body) { + var u = url.parse(uri); + var path = u.path; + var access = path + '\n'; + + if (body) { + access += body; + } + + var digest = exports.hmacSha1(access, conf.SECRET_KEY); + var safeDigest = exports.base64ToUrlSafe(digest); + return 'QBox ' + conf.ACCESS_KEY + ':' + safeDigest; +} diff --git a/test-env.sh b/test-env.sh new file mode 100644 index 00000000..a7d28969 --- /dev/null +++ b/test-env.sh @@ -0,0 +1,4 @@ +export QINIU_ACCESS_KEY="8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc" +export QINIU_SECRET_KEY="1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN" +export QINIU_TEST_BUCKET="test963" +export QINIU_TEST_DOMAIN="test963.qiniudn.com" diff --git a/test/fop.test.js b/test/fop.test.js new file mode 100644 index 00000000..65e685d6 --- /dev/null +++ b/test/fop.test.js @@ -0,0 +1,43 @@ +var fop = require('../').fop; + +describe('test start step 0', function() { + describe('fop.js', function() { + var pic = 'http://test963.qiniudn.com/logo.png'; + + describe('fop.Exif#makeRequest()', function() { + it('test makeRequest', function(done) { + var exif = new fop.Exif(); + var returl = exif.makeRequest(pic); + returl.should.equal(pic + '?exif'); + done(); + }); + }); + + describe('fop.ImageView#makeRequest()', function() { + it('test makeRequest of ImageView', function(done) { + var iv = new fop.ImageView(); + iv.height = 100; + iv.width = 40; + var returl = iv.makeRequest(pic); + returl.should.equal(pic + '?imageView/1/w/40/h/100'); + + iv.quality = 20; + iv.format = 'jpg'; + returl = iv.makeRequest(pic); + returl.should.equal(pic + '?imageView/1/w/40/h/100/q/20/format/jpg'); + done(); + }); + }); + + describe('fop.ImageInfo#makeRequest()', function() { + it('test makeRequest of ImageInfo', function(done) { + var ii = new fop.ImageInfo(); + var returl = ii.makeRequest(pic); + returl.should.equal(pic + '?imageInfo'); + done(); + }); + }); + + }); +}); + diff --git a/test/io.test.js b/test/io.test.js new file mode 100644 index 00000000..934c354e --- /dev/null +++ b/test/io.test.js @@ -0,0 +1,126 @@ +var qiniu = require('../'); +var should = require('should'); +var path = require('path'); + +qiniu.conf.ACCESS_KEY = process.env.QINIU_ACCESS_KEY; +qiniu.conf.SECRET_KEY = process.env.QINIU_SECRET_KEY; + +var TEST_BUCKET = process.env.QINIU_TEST_BUCKET; +var TEST_DOMAIN = process.env.QINIU_TEST_DOMAIN; + +var imageFile = path.join(__dirname, 'logo.png'); + +before(function(done) { + if(!process.env.QINIU_ACCESS_KEY) { + console.log('should run command `source test-env.sh` first\n'); + process.exit(0); + } + done(); +}); + +describe('test start step1:', function() { + + var keys = []; + + after(function(done) { + entries = []; + for (i in keys) { + entries.push(new qiniu.rs.EntryPath(TEST_BUCKET, keys[i])); + } + + var client = new qiniu.rs.Client(); + client.batchDelete(entries, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + + describe('io.js', function() { + describe('upload#', function() { + var uptoken = null; + beforeEach(function(done) { + var putPolicy = new qiniu.rs.PutPolicy(TEST_BUCKET); + uptoken = putPolicy.token(); + done(); + }); + + describe('io.put()', function() { + it('test upload from memory', function(done) { + qiniu.io.put(uptoken, 'filename', 'content', null, function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('hash', 'key'); + ret.data.key.should.equal('filename'); + keys.push(ret.data.key); + done(); + }); + }); + }); + + describe('io.putWithoutKey()', function() { + it('test upload from memory without key', function(done) { + qiniu.io.putWithoutKey(uptoken, 'content', null, function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('hash', 'key'); + ret.data.key.should.equal(ret.data.hash); + keys.push(ret.data.key); + done(); + }); + }); + }); + + describe('io.putFile()', function() { + it('test upload from a file', function(done) { + qiniu.io.putFile(uptoken, 'logo.png', imageFile, null, function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('key', 'hash'); + ret.data.key.should.equal('logo.png'); + keys.push(ret.data.key); + done(); + }); + }); + + it('test upload from a file with checkCrc32=1', function(done) { + var extra = new qiniu.io.PutExtra(); + extra.checkCrc = 1; + qiniu.io.putFile(uptoken, 'logo_crc32.png', imageFile, extra, function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('key', 'hash'); + ret.data.key.should.equal('logo_crc32.png'); + keys.push(ret.data.key); + done(); + }); + }); + }); + + describe('io.putFileWithoutKey()', function() { + it('test upload from a file without key', function(done) { + qiniu.io.putFileWithoutKey(uptoken, imageFile, null, function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('key', 'hash'); + ret.data.key.should.equal(ret.data.hash); + keys.push(ret.data.key); + done(); + }); + }); + }); + }); + }); + + describe('rsf.js', function() { + describe('file handle', function() { + describe('rsf.listPrefix()', function() { + it('list all file in test bucket', function(done) { + qiniu.rsf.listPrefix(TEST_BUCKET, null, null, null, function(ret) { + ret.code.should.equal(200); + ret.data.items.length.should.equal(keys.length); + for (i in ret.items) { + ret.data.items[i].should.has.keys('key', 'time', 'hash', 'fsize', 'mimeType', 'customer'); + keys.indexOf(ret.data.items[i].key).should.above(-1); + } + done(); + }); + }); + }); + }); + }); +}); diff --git a/test/logo.png b/test/logo.png new file mode 100644 index 0000000000000000000000000000000000000000..e839c26b177e5f72c5810d22a0459f100ba04e2c GIT binary patch literal 14057 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 literal 0 HcmV?d00001 diff --git a/test/rs.test.js b/test/rs.test.js new file mode 100644 index 00000000..efea0916 --- /dev/null +++ b/test/rs.test.js @@ -0,0 +1,166 @@ +var qiniu = require('../'); +var should = require('should'); +var path = require('path'); + +qiniu.conf.ACCESS_KEY = process.env.QINIU_ACCESS_KEY; +qiniu.conf.SECRET_KEY = process.env.QINIU_SECRET_KEY; + +var TEST_BUCKET = process.env.QINIU_TEST_BUCKET; +var TEST_DOMAIN = process.env.QINIU_TEST_DOMAIN; +var imageFile = path.join(__dirname, 'logo.png'); + +describe('test start step2:', function() { + + describe('rs.test.js', function() { + + var client = new qiniu.rs.Client(); + + var EntryPath = qiniu.rs.EntryPath; + var EntryPathPair = qiniu.rs.EntryPathPair; + + describe('single file handle', function() { + + before(function(done) { + var putPolicy = new qiniu.rs.PutPolicy(TEST_BUCKET); + var uptoken = putPolicy.token(); + qiniu.io.putFile(uptoken, 'logo2.png', imageFile, null, function(ret) { + ret.code.should.equal(200); + }); + qiniu.io.putFile(uptoken, 'logo.png', imageFile, null, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + + describe('rs.Client#stat()', function() { + it('get the stat of a file', function(done) { + client.stat(TEST_BUCKET, 'logo.png', function(ret) { + ret.code.should.equal(200); + ret.data.should.have.keys('hash', 'fsize', 'putTime', 'mimeType'); + done(); + }); + }); + }); + + describe('rs.Client#copy()', function() { + it('copy logo.png to logo1.png', function(done) { + client.copy(TEST_BUCKET, 'logo.png', TEST_BUCKET, 'logo1.png', function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + + describe('rs.Client#remove()', function() { + it('remove logo.png', function(done) { + client.remove(TEST_BUCKET, 'logo.png', function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + + describe('rs.Client#move()', function() { + it('move logo1.png to logo.png', function(done) { + client.move(TEST_BUCKET, 'logo1.png', TEST_BUCKET, 'logo.png', function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + }); + + describe('batch file handle', function() { + + after(function(done) { + var entries = [new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo2.png')]; + + client.batchDelete(entries, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + + describe('rs.Client#batchStat()', function() { + it('get the stat of logo.png and logo2.png', function(done) { + var entries = [ + new EntryPath(TEST_BUCKET, 'logo.png'), + new EntryPath(TEST_BUCKET, 'logo2.png')]; + + client.batchStat(entries, function(ret) { + ret.code.should.equal(200); + ret.data.length.should.equal(2); + for (i in ret.data) { + ret.data[i].code.should.equal(200); + ret.data[i].data.should.have.keys('fsize', 'hash', 'mimeType', 'putTime'); + } + done(); + }); + }); + + it('should return code 298 when partial ok', function(done) { + + var entries = [ + new EntryPath(TEST_BUCKET, 'logo.png'), + new EntryPath(TEST_BUCKET, 'not exist file')]; + + client.batchStat(entries, function(ret) { + + ret.code.should.equal(298); + ret.data.length.should.equal(2); + + for (i in ret.data) { + if (ret.data[i].code !== 200) { + ret.data[i].code.should.equal(612); + ret.data[i].data.should.have.keys('error'); + } + } + + done(); + }); + }); + + }); + + describe('rs.Client#batchCopy', function() { + var entries = []; + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo1.png'))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo2.png'), new EntryPath(TEST_BUCKET, 'logo3.png'))); + + it('copy from logo, logo2 to logo1, logo3', function(done) { + client.batchCopy(entries, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + + describe('rs.Client#batchDelete', function() { + var entries = [new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo2.png')]; + + it('delete logo.png, logo2.png', function(done) { + client.batchDelete(entries, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + + describe('rs.Client#batchMove', function() { + var entries = []; + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo1.png'), new EntryPath(TEST_BUCKET, 'logo.png'))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo3.png'), new EntryPath(TEST_BUCKET, 'logo2.png'))); + + it('move from logo1.png, logo3.png to logo.png, logo2.png', function(done) { + client.batchMove(entries, function(ret) { + ret.code.should.equal(200); + done(); + }); + }); + }); + }); + + // rs.GetPolicy#makeRequest() + + }); +}); From 404ed880f3d4a40e36c257ca1bed0573863f5134 Mon Sep 17 00:00:00 2001 From: longbai Date: Fri, 12 Jul 2013 10:34:06 +0800 Subject: [PATCH 04/41] add test-env.sh --- .npmignore | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.npmignore b/.npmignore index c68978b7..3867aec4 100644 --- a/.npmignore +++ b/.npmignore @@ -1,7 +1,7 @@ test/ +test-env.sh .travis.yml coverage.html lib-cov/ Makefile docs/ -demo/ From 5b9a4a0f6f414c5c3e9da8169db45df5e8ad5255 Mon Sep 17 00:00:00 2001 From: longbai Date: Fri, 12 Jul 2013 11:18:51 +0800 Subject: [PATCH 05/41] filename docs/demo -> docs/gist --- docs/{demo => gist}/client.js | 0 docs/{demo => gist}/fop.js | 0 docs/{demo => gist}/rs.js | 0 docs/{demo => gist}/rsf.js | 0 docs/{demo => gist}/server.js | 0 5 files changed, 0 insertions(+), 0 deletions(-) rename docs/{demo => gist}/client.js (100%) rename docs/{demo => gist}/fop.js (100%) rename docs/{demo => gist}/rs.js (100%) rename docs/{demo => gist}/rsf.js (100%) rename docs/{demo => gist}/server.js (100%) diff --git a/docs/demo/client.js b/docs/gist/client.js similarity index 100% rename from docs/demo/client.js rename to docs/gist/client.js diff --git a/docs/demo/fop.js b/docs/gist/fop.js similarity index 100% rename from docs/demo/fop.js rename to docs/gist/fop.js diff --git a/docs/demo/rs.js b/docs/gist/rs.js similarity index 100% rename from docs/demo/rs.js rename to docs/gist/rs.js diff --git a/docs/demo/rsf.js b/docs/gist/rsf.js similarity index 100% rename from docs/demo/rsf.js rename to docs/gist/rsf.js diff --git a/docs/demo/server.js b/docs/gist/server.js similarity index 100% rename from docs/demo/server.js rename to docs/gist/server.js From ded0ecab17ce22501871530baca5e00261d9a5ba Mon Sep 17 00:00:00 2001 From: longbai Date: Mon, 15 Jul 2013 13:48:28 +0800 Subject: [PATCH 06/41] docs --- docs/README.gist.md | 342 ++++++++++++++++++++++++++++ docs/README.md | 543 ++++++++++++++++++++++++++++++++++++++++++++ docs/gist.py | 138 +++++++++++ docs/gist/client.js | 4 +- docs/gist/fop.js | 58 ++++- docs/gist/rs.js | 72 +++++- docs/gist/rsf.js | 6 +- docs/gist/server.js | 2 + 8 files changed, 1146 insertions(+), 19 deletions(-) create mode 100644 docs/README.gist.md create mode 100644 docs/README.md create mode 100755 docs/gist.py diff --git a/docs/README.gist.md b/docs/README.gist.md new file mode 100644 index 00000000..14eeeb8d --- /dev/null +++ b/docs/README.gist.md @@ -0,0 +1,342 @@ +--- +title: Node.js SDK 使用指南 | 七牛云存储 +--- + +# Node.js SDK 使用指南 + + + +SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) + +**文档大纲** + +- [概述](#overview) +- [准备开发环境](#prepare) + - [环境依赖](#dependences) + - [安装](#install) + - [ACCESS_KEY 和 SECRET_KEY](#appkey) +- [使用SDK](#sdk-usage) + - [初始化环境与清理](#init) + - [上传文件](#io-put) + - [上传流程](#io-put-flow) + - [上传策略](#io-put-policy) + - [上传凭证](#upload-token) + - [PutExtra](#put-extra) + - [下载文件](#io-get) + - [下载公有文件](#io-get-public) + - [下载私有文件](#io-get-private) + - [HTTPS 支持](#io-https-get) + - [断点续下载](#resumable-io-get) + - [资源操作](#rs) + - [获取文件信息](#rs-stat) + - [删除文件](#rs-delete) + - [复制/移动文件](#rs-copy-move) + - [批量操作](#rs-batch) + - [云处理](#fop) + + +## 概述 + + +该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 + + +Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](https://github.com/qiniu/sdkspec) +涉及到以下几个方面: + +- 服务端操作,生成上传授权(uptoken),私有bucket下载URL(downloadUrl),文件操作授权 +- 客户端操作,上传文件(qiniu/io.js) +- 文件管理(qiniu/rs.js) +- 数据处理(qiniu/fop.js) +- 公共库(qiniu/rpc.js, qiniu/util.js) + + + +## 准备开发环境 + + + + + +### 环境依赖 + +适用于 NodeJS 0.4.7 及其以上版本 + + + +### 安装 + + +通过 npm 以 node 模块化的方式安装: +`npm node qiniu` + + + +### ACCESS_KEY 和 SECRET_KEY + +在使用SDK 前,您需要拥有一对有效的 AccessKey 和 SecretKey 用来进行签名授权。 + +可以通过如下步骤获得: + +1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) +2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://dev.qiniutek.com/account/keys) 。 + + + +## 使用SDK + + + +### 初始化环境 + +对于服务端而言,常规程序流程是: + +``` +@gist(gist/server.js#init) +``` + + +*服务端操作时请务必初始化这两个变量* + + + +### 上传文件 + +为了尽可能地改善终端用户的上传体验,七牛云存储首创了客户端直传功能。一般云存储的上传流程是: + + 客户端(终端用户) => 业务服务器 => 云存储服务 + +这样多了一次上传的流程,和本地存储相比,会相对慢一些。但七牛引入了客户端直传,将整个上传过程调整为: + + 客户端(终端用户) => 七牛 => 业务服务器 + +客户端(终端用户)直接上传到七牛的服务器,通过DNS智能解析,七牛会选择到离终端用户最近的ISP服务商节点,速度会比本地存储快很多。文件上传成功以后,七牛的服务器使用回调功能,只需要将非常少的数据(比如Key)传给应用服务器,应用服务器进行保存即可。 + + + +#### 上传流程 + +在七牛云存储中,整个上传流程大体分为这样几步: + +1. 业务服务器颁发 [uptoken(上传授权凭证)](http://docs.qiniu.com/api/put.html#uploadToken)给客户端(终端用户) +2. 客户端凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 在七牛获得完整数据后,发起一个 HTTP 请求回调到业务服务器 +4. 业务服务器保存相关信息,并返回一些信息给七牛 +5. 七牛原封不动地将这些信息转发给客户端(终端用户) + +需要注意的是,回调到业务服务器的过程是可选的,它取决于业务服务器颁发的 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。如果没有回调,七牛会返回一些标准的信息(比如文件的 hash)给客户端。如果上传发生在业务服务器,以上流程可以自然简化为: + +1. 业务服务器生成 uptoken(不设置回调,自己回调到自己这里没有意义) +2. 凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 善后工作,比如保存相关的一些信息 + + + +##### 上传策略 + +[uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 实际上是用 AccessKey/SecretKey 进行数字签名的上传策略(`rs.PutPolicy`),它控制则整个上传流程的行为。让我们快速过一遍你都能够决策啥: + +``` +@gist(../qiniu/rs.js#PutPolicy) +``` + +* `scope` 限定客户端的权限。如果 `scope` 是 bucket,则客户端只能新增文件到指定的 bucket,不能修改文件。如果 `scope` 为 bucket:key,则客户端可以修改指定的文件。 +* `callbackUrl` 设定业务服务器的回调地址,这样业务服务器才能感知到上传行为的发生。 +* `callbackBody` 设定业务服务器的回调信息。文件上传成功后,七牛向业务服务器的callbackUrl发送的POST请求携带的数据。支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。 +* `returnUrl` 设置用于浏览器端文件上传成功后,浏览器执行301跳转的URL,一般为 HTML Form 上传时使用。文件上传成功后浏览器会自动跳转到 `returnUrl?upload_ret=returnBody`。 +* `returnBody` 可调整返回给客户端的数据包,支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。`returnBody` 只在没有 `callbackUrl` 时有效(否则直接返回 `callbackUrl` 返回的结果)。不同情形下默认返回的 `returnBody` 并不相同。在一般情况下返回的是文件内容的 `hash`,也就是下载该文件时的 `etag`;但指定 `returnUrl` 时默认的 `returnBody` 会带上更多的信息。 +* `asyncOps` 可指定上传完成后,需要自动执行哪些数据处理。这是因为有些数据处理操作(比如音视频转码)比较慢,如果不进行预转可能第一次访问的时候效果不理想,预转可以很大程度改善这一点。 +* `expires`指定`uptoken`的过期时间,默认3600s + +关于上传策略更完整的说明,请参考 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。 + + + +##### 生成上传凭证 + +服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: + +``` +@gist(gist/server.js#uptoken) +``` + + + +##### PutExtra + + + + +PutExtra是上传时的可选信息,默认为null +``` +@gist(../qiniu/io.js#PutExtra) +``` + +* `params` 是一个字典。[自定义变量](http://docs.qiniu.com/api/put.html#xVariables),key必须以 x: 开头命名,不限个数。可以在 uploadToken 的 callbackBody 选项中求值。 +* `mime_type` 表示数据的MimeType,当不指定时七牛服务器会自动检测。 +* `crc32` 待检查的crc32值 +* `check_crc` 可选值为0, 1, 2。 + `check_crc == 0`: 表示不进行 crc32 校验。 + `check_crc == 1`: 上传二进制数据时等同于 `check_crc=2`;上传本地文件时会自动计算 crc32 值。 + `check_crc == 2`: 表示进行 crc32 校验,且 crc32 值就是上面的 `crc32` 变量 + +##### 上传文件 + +上传文件到七牛(通常是客户端完成,但也可以发生在服务端): + +直接上传二进制流: +``` +@gist(gist/client.js#uploadBuf) +``` + +上传本地文件: + +``` +@gist(gist/client.js#uploadFile) +``` + + + +#### 下载文件 + + + +##### 下载公有文件 + +每个 bucket 都会绑定一个或多个域名(domain)。如果这个 bucket 是公开的,那么该 bucket 中的所有文件可以通过一个公开的下载 url 可以访问到: + + http:/// + +假设某个 bucket 既绑定了七牛的二级域名,如 hello.qiniudn.com,也绑定了自定义域名(需要备案),如 hello.com。那么该 bucket 中 key 为 a/b/c.htm 的文件可以通过 http://hello.qiniudn.com/a/b/c.htm 或 http://hello.com/a/b/c.htm 中任意一个 url 进行访问。 + + + +##### 下载私有文件 + +如果某个 bucket 是私有的,那么这个 bucket 中的所有文件只能通过一个的临时有效的 downloadUrl 访问: + + http:///?e=&token= + +其中 dntoken 是由业务服务器签发的一个[临时下载授权凭证](http://docs.qiniu.com/api/get.html#download-token),deadline 是 dntoken 的有效期。dntoken不需要单独生成,SDK 提供了生成完整 downloadUrl 的方法(包含了 dntoken),示例代码如下: + +``` +@gist(gist/server.js#downloadUrl) +``` + +生成 downloadUrl 后,服务端下发 downloadUrl 给客户端。客户端收到 downloadUrl 后,和公有资源类似,直接用任意的 HTTP 客户端就可以下载该资源了。唯一需要注意的是,在 downloadUrl 失效却还没有完成下载时,需要重新向服务器申请授权。 + +无论公有资源还是私有资源,下载过程中客户端并不需要七牛 SDK 参与其中。 + + + +##### 断点续下载 + + +无论是公有资源还是私有资源,获得的下载 url 支持标准的 HTTP 断点续传协议。考虑到多数语言都有相应的断点续下载支持的成熟方法,七牛 Nodejs-SDK 并不提供断点续下载相关代码。 + + +### 资源操作 + +资源操作限在服务端操作,先进行初始化 +``` +@gist(gist/rs.js#init) +``` + + + +#### 获取文件信息 + + +``` +@gist(gist/rs.js#stat) +``` + + + +#### 删除文件 + + +``` +@gist(gist/rs.js#remove) +``` + + + +#### 复制/移动文件 + + +``` +@gist(gist/rs.js#copy) +``` + +``` +@gist(gist/rs.js#move) +``` + + + +#### 批量操作 + + +当您需要一次性进行多个操作时, 可以使用批量操作。 + +####批量获取文件信息 +``` +@gist(gist/rs.js#batchStat) +``` +####批量复制文件 +``` +@gist(gist/rs.js#batchCopy) +``` +####批量移动文件 +``` +@gist(gist/rs.js#batchMove) +``` +####批量删除文件 +``` +@gist(gist/rs.js#batchDelete) +``` + + + +### 高级管理操作 + + +####列出文件 +请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 +``` +@gist(gist/rsf.js#listPrefix) +``` + + +### 云处理 + + +####查看图像信息 +``` +@gist(gist/fop.js#makeImageInfoUrl) +``` +####查看图像Exif +``` +@gist(gist/fop.js#makeExifUrl) +``` +####生成缩略图 +``` +@gist(gist/fop.js#makeImageViewUrl) +``` + +## 贡献代码 + ++ Fork ++ 创建您的特性分支 (git checkout -b my-new-feature) ++ 提交您的改动 (git commit -am 'Added some feature') ++ 将您的修改记录提交到远程 git 仓库 (git push origin my-new-feature) ++ 然后到 github 网站的该 git 远程仓库的 my-new-feature 分支下发起 Pull Request + +## 许可证 + +> Copyright (c) 2013 qiniu.com + +## 基于 MIT 协议发布: + +> [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) diff --git a/docs/README.md b/docs/README.md new file mode 100644 index 00000000..f4901f52 --- /dev/null +++ b/docs/README.md @@ -0,0 +1,543 @@ +--- +title: Node.js SDK 使用指南 | 七牛云存储 +--- + +# Node.js SDK 使用指南 + + + +SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) + +**文档大纲** + +- [概述](#overview) +- [准备开发环境](#prepare) + - [环境依赖](#dependences) + - [安装](#install) + - [ACCESS_KEY 和 SECRET_KEY](#appkey) +- [使用SDK](#sdk-usage) + - [初始化环境与清理](#init) + - [上传文件](#io-put) + - [上传流程](#io-put-flow) + - [上传策略](#io-put-policy) + - [上传凭证](#upload-token) + - [PutExtra](#put-extra) + - [下载文件](#io-get) + - [下载公有文件](#io-get-public) + - [下载私有文件](#io-get-private) + - [HTTPS 支持](#io-https-get) + - [断点续下载](#resumable-io-get) + - [资源操作](#rs) + - [获取文件信息](#rs-stat) + - [删除文件](#rs-delete) + - [复制/移动文件](#rs-copy-move) + - [批量操作](#rs-batch) + - [云处理](#fop) + + +## 概述 + + +该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 + + +Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](https://github.com/qiniu/sdkspec) +涉及到以下几个方面: + +- 服务端操作,生成上传授权(uptoken),私有bucket下载URL(downloadUrl),文件操作授权 +- 客户端操作,上传文件(qiniu/io.js) +- 文件管理(qiniu/rs.js) +- 数据处理(qiniu/fop.js) +- 公共库(qiniu/rpc.js, qiniu/util.js) + + + +## 准备开发环境 + + + + + +### 环境依赖 + +适用于 NodeJS 0.4.7 及其以上版本 + + + +### 安装 + + +通过 npm 以 node 模块化的方式安装: +`npm node qiniu` + + + +### ACCESS_KEY 和 SECRET_KEY + +在使用SDK 前,您需要拥有一对有效的 AccessKey 和 SecretKey 用来进行签名授权。 + +可以通过如下步骤获得: + +1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) +2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://dev.qiniutek.com/account/keys) 。 + + + +## 使用SDK + + + +### 初始化环境 + +对于服务端而言,常规程序流程是: + +``` +qiniu.conf.ACCESS_KEY = '' +qiniu.conf.SECRET_KEY = '' +``` + + +*服务端操作时请务必初始化这两个变量* + + + +### 上传文件 + +为了尽可能地改善终端用户的上传体验,七牛云存储首创了客户端直传功能。一般云存储的上传流程是: + + 客户端(终端用户) => 业务服务器 => 云存储服务 + +这样多了一次上传的流程,和本地存储相比,会相对慢一些。但七牛引入了客户端直传,将整个上传过程调整为: + + 客户端(终端用户) => 七牛 => 业务服务器 + +客户端(终端用户)直接上传到七牛的服务器,通过DNS智能解析,七牛会选择到离终端用户最近的ISP服务商节点,速度会比本地存储快很多。文件上传成功以后,七牛的服务器使用回调功能,只需要将非常少的数据(比如Key)传给应用服务器,应用服务器进行保存即可。 + + + +#### 上传流程 + +在七牛云存储中,整个上传流程大体分为这样几步: + +1. 业务服务器颁发 [uptoken(上传授权凭证)](http://docs.qiniu.com/api/put.html#uploadToken)给客户端(终端用户) +2. 客户端凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 在七牛获得完整数据后,发起一个 HTTP 请求回调到业务服务器 +4. 业务服务器保存相关信息,并返回一些信息给七牛 +5. 七牛原封不动地将这些信息转发给客户端(终端用户) + +需要注意的是,回调到业务服务器的过程是可选的,它取决于业务服务器颁发的 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。如果没有回调,七牛会返回一些标准的信息(比如文件的 hash)给客户端。如果上传发生在业务服务器,以上流程可以自然简化为: + +1. 业务服务器生成 uptoken(不设置回调,自己回调到自己这里没有意义) +2. 凭借 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 上传文件到七牛 +3. 善后工作,比如保存相关的一些信息 + + + +##### 上传策略 + +[uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 实际上是用 AccessKey/SecretKey 进行数字签名的上传策略(`rs.PutPolicy`),它控制则整个上传流程的行为。让我们快速过一遍你都能够决策啥: + +``` +function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, + asyncOps, endUser, expires) { + this.scope = scope || null; // 必须 + this.callbackUrl = callbackUrl || null; + this.callbackBody = callbackBody || null; + this.returnUrl = returnUrl || null; + this.returnBody = returnBody || null; + this.asyncOps = asyncOps || null; + this.endUser = endUser || null; + this.expires = expires || 3600; +} +``` + +* `scope` 限定客户端的权限。如果 `scope` 是 bucket,则客户端只能新增文件到指定的 bucket,不能修改文件。如果 `scope` 为 bucket:key,则客户端可以修改指定的文件。 +* `callbackUrl` 设定业务服务器的回调地址,这样业务服务器才能感知到上传行为的发生。 +* `callbackBody` 设定业务服务器的回调信息。文件上传成功后,七牛向业务服务器的callbackUrl发送的POST请求携带的数据。支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。 +* `returnUrl` 设置用于浏览器端文件上传成功后,浏览器执行301跳转的URL,一般为 HTML Form 上传时使用。文件上传成功后浏览器会自动跳转到 `returnUrl?upload_ret=returnBody`。 +* `returnBody` 可调整返回给客户端的数据包,支持 [魔法变量](http://docs.qiniu.com/api/put.html#MagicVariables) 和 [自定义变量](http://docs.qiniu.com/api/put.html#xVariables)。`returnBody` 只在没有 `callbackUrl` 时有效(否则直接返回 `callbackUrl` 返回的结果)。不同情形下默认返回的 `returnBody` 并不相同。在一般情况下返回的是文件内容的 `hash`,也就是下载该文件时的 `etag`;但指定 `returnUrl` 时默认的 `returnBody` 会带上更多的信息。 +* `asyncOps` 可指定上传完成后,需要自动执行哪些数据处理。这是因为有些数据处理操作(比如音视频转码)比较慢,如果不进行预转可能第一次访问的时候效果不理想,预转可以很大程度改善这一点。 +* `expires`指定`uptoken`的过期时间,默认3600s + +关于上传策略更完整的说明,请参考 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken)。 + + + +##### 生成上传凭证 + +服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: + +``` +function uptoken(bucketname) { + var putPolicy = new qiniu.rs.PutPolicy(bucketname); + //putPolicy.callbackUrl = callbackUrl; + //putPolicy.callbackBody = callbackBody; + //putPolicy.returnUrl = returnUrl; + //putPolicy.returnBody = returnBody; + //putPolicy.asyncOps = asyncOps; + //putPolicy.expires = expires; + + return putPolicy.token(); +} +``` + + + +##### PutExtra + + + + +PutExtra是上传时的可选信息,默认为null +``` +function PutExtra(params, mimeType, crc32, checkCrc) { + this.paras = params || {}; + this.mimeType = mimeType || null; + this.crc32 = crc32 || null; + this.checkCrc = checkCrc || 0; +} +``` + +* `params` 是一个字典。[自定义变量](http://docs.qiniu.com/api/put.html#xVariables),key必须以 x: 开头命名,不限个数。可以在 uploadToken 的 callbackBody 选项中求值。 +* `mime_type` 表示数据的MimeType,当不指定时七牛服务器会自动检测。 +* `crc32` 待检查的crc32值 +* `check_crc` 可选值为0, 1, 2。 + `check_crc == 0`: 表示不进行 crc32 校验。 + `check_crc == 1`: 上传二进制数据时等同于 `check_crc=2`;上传本地文件时会自动计算 crc32 值。 + `check_crc == 2`: 表示进行 crc32 校验,且 crc32 值就是上面的 `crc32` 变量 + +##### 上传文件 + +上传文件到七牛(通常是客户端完成,但也可以发生在服务端): + +直接上传二进制流: +``` +function uploadBuf(body, key, uptoken) { + var extra = new qiniu.io.PutExtra(); + //extra.params = params; + //extra.mimeType = mimeType; + //extra.crc32 = crc32; + //extra.checkCrc = checkCrc; + + io.put(uptoken, key, body, extra, function(ret) { + if(ret.code === 200) { + // 上传成功, 处理返回值 + // ret.data.key & ret.data.hash + } else { + // 上传失败, 处理返回代码 + // ret.code + // http://docs.qiniu.com/api/put.html#error-code + } + }); +} +``` + +上传本地文件: + +``` +function uploadFile(localFile, key, uptoken) { + var extra = new qiniu.io.PutExtra(); + //extra.params = params; + //extra.mimeType = mimeType; + //extra.crc32 = crc32; + //extra.checkCrc = checkCrc; + + io.putFile(uptoken, key, localFile, extra, function(ret) { + if(ret.code === 200) { + // 上传成功, 处理返回值 + // ret.data.key & ret.data.hash + } else { + // 上传失败, 处理返回代码 + // ret.code + // http://docs.qiniu.com/api/put.html#error-code + } + }); +} +``` + + + +#### 下载文件 + + + +##### 下载公有文件 + +每个 bucket 都会绑定一个或多个域名(domain)。如果这个 bucket 是公开的,那么该 bucket 中的所有文件可以通过一个公开的下载 url 可以访问到: + + http:/// + +假设某个 bucket 既绑定了七牛的二级域名,如 hello.qiniudn.com,也绑定了自定义域名(需要备案),如 hello.com。那么该 bucket 中 key 为 a/b/c.htm 的文件可以通过 http://hello.qiniudn.com/a/b/c.htm 或 http://hello.com/a/b/c.htm 中任意一个 url 进行访问。 + + + +##### 下载私有文件 + +如果某个 bucket 是私有的,那么这个 bucket 中的所有文件只能通过一个的临时有效的 downloadUrl 访问: + + http:///?e=&token= + +其中 dntoken 是由业务服务器签发的一个[临时下载授权凭证](http://docs.qiniu.com/api/get.html#download-token),deadline 是 dntoken 的有效期。dntoken不需要单独生成,SDK 提供了生成完整 downloadUrl 的方法(包含了 dntoken),示例代码如下: + +``` +function downloadUrl(domain, key) { + var baseUrl = rs.makeBaseUrl(domain, key); + var policy = new rs.GetPolicy(); + return policy.makeRequest(baseUrl); +} +``` + +生成 downloadUrl 后,服务端下发 downloadUrl 给客户端。客户端收到 downloadUrl 后,和公有资源类似,直接用任意的 HTTP 客户端就可以下载该资源了。唯一需要注意的是,在 downloadUrl 失效却还没有完成下载时,需要重新向服务器申请授权。 + +无论公有资源还是私有资源,下载过程中客户端并不需要七牛 SDK 参与其中。 + + + +##### 断点续下载 + + +无论是公有资源还是私有资源,获得的下载 url 支持标准的 HTTP 断点续传协议。考虑到多数语言都有相应的断点续下载支持的成熟方法,七牛 Nodejs-SDK 并不提供断点续下载相关代码。 + + +### 资源操作 + +资源操作限在服务端操作,先进行初始化 +``` +qiniu.conf.ACCESS_KEY = ''; +qiniu.conf.SECRET_KEY = ''; +``` + + + +#### 获取文件信息 + + +``` +var client = new qiniu.rs.Client(); +client.stat(bucketName, key, function(ret) { + if (ret.code === 200) { + // process + // ret.data has keys (hash, fsize, putTime, mimeType) + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` + + + +#### 删除文件 + + +``` +var client = new qiniu.rs.Client(); +client.remove(bucketName, key, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}) +``` + + + +#### 复制/移动文件 + + +``` +var client = new qiniu.rs.Client(); +client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` + +``` +var client = new qiniu.rs.Client(); +client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` + + + +#### 批量操作 + + +当您需要一次性进行多个操作时, 可以使用批量操作。 + +####批量获取文件信息 +``` +var path0 = new qiniu.rs.EntryPath(bucketName, key0); +var path1 = new qiniu.rs.EntryPath(bucketName, key1); +var path2 = new qiniu.rs.EntryPath(bucketName, key2); +var client = new qiniu.rs.Client(); +client.batchStat([path0, path1, path2], function(ret) { + if (ret.code === 200) { + // ok, parse ret.data + // each item in ret.data has keys (code, data) + // ret.data[i].data has keys (hash, fsize, putTime, mimeType) + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` +####批量复制文件 +``` +var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); +var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); +var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); +var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); +var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); +var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); +var client = new qiniu.rs.Client(); + +client.batchCopy([pair0, pair1], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` +####批量移动文件 +``` +var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); +var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); +var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); +var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); +var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); +var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); +var client = new qiniu.rs.Client(); + +client.batchMove([pair0, pair1], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` +####批量删除文件 +``` +var path0 = new qiniu.rs.EntryPath(bucketName, key0); +var path1 = new qiniu.rs.EntryPath(bucketName, key1); +var path2 = new qiniu.rs.EntryPath(bucketName, key2); +var client = new qiniu.rs.Client(); + +client.batchDelete([path0, path1, path2], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +``` + + + +### 高级管理操作 + + +####列出文件 +请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 +``` +qiniu.conf.ACCESS_KEY = ''; +qiniu.conf.SECRET_KEY = ''; + +qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { + if(ret.code === 200) { + // process ret.data.marker & ret.data.items + } else { + // something error, see ret.code according to + // http://docs.qiniu.com/api/file-handle.html#list + } +}); +``` + + +### 云处理 + + +####查看图像信息 +``` +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var ii = new qiniu.fop.ImageInfo(); +url = ii.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); +``` +####查看图像Exif +``` +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var exif = new qiniu.fop.Exif(); +url = exif.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); +``` +####生成缩略图 +``` +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var iv = new qiniu.fop.ImageView(); +iv.width = 100; +url = iv.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); +``` + +## 贡献代码 + ++ Fork ++ 创建您的特性分支 (git checkout -b my-new-feature) ++ 提交您的改动 (git commit -am 'Added some feature') ++ 将您的修改记录提交到远程 git 仓库 (git push origin my-new-feature) ++ 然后到 github 网站的该 git 远程仓库的 my-new-feature 分支下发起 Pull Request + +## 许可证 + +> Copyright (c) 2013 qiniu.com + +## 基于 MIT 协议发布: + +> [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) + diff --git a/docs/gist.py b/docs/gist.py new file mode 100755 index 00000000..939a779a --- /dev/null +++ b/docs/gist.py @@ -0,0 +1,138 @@ +#!/usr/bin/env python +# -*- coding: utf-8 -*- + +import sys +import os +import re + +re_md_gist = re.compile(r"@gist\(([^\)]+)\)") +re_strip = re.compile(r"^\n*(.*)\n\t*$", re.S) +re_indent = re.compile(r"^(\t*)[^\t\s\n\r]") +line_start = r"(?:^|\n)\s*" +re_gist_comment = dict( + c = dict( + start = re.compile(r"%s\/\*\s*@gist\s+([\w\-_]+)\s*\*/.*?\n+" % line_start), + end = re.compile(r"%s\/\*\s*@endgist\s*\*/" % line_start), + ), + bash = dict( + start = re.compile(r"%s#\s*@gist\s+([\w\-_]+).*?\n+" % line_start), + end = re.compile(r"%s#\s*@endgist" % line_start), + ), + cpp = dict( + start = re.compile(r"%s//\s*@gist\s+([\w\-_]+).*?\n+" % line_start), + end = re.compile(r"%s//\s*@endgist" % line_start) + ), + html = dict( + start = re.compile(r"%s.*?\n+" % line_start), + end = re.compile(r"%s" % line_start), + ), +) +cpath = sys.path[0] + +def openfile(path): + if not os.path.exists(path): + return None + f = open(path, "r") + body = f.read() + f.close() + return body + +def get_gist_block(path): + gists = dict() + body = openfile(path) + if body is None: + return gists + start = 0 + while True: + a = search_one_block(body[start:]) + if a is None: + break + name, content, new_start = a + start += new_start + if not name in gists: + gists[name] = content + else: + gists[name].extend(["", "...", ""]) + gists[name].extend(content) + gists[""] = body.split("\n") + return gists + +def search_one_block(body): + if len(body) == 0: + return None + for n, regs in re_gist_comment.iteritems(): + a = regs["start"].search(body) + if a is None: + continue + start = a.span()[1] + b = regs["end"].search(body[start:]) + if b is None: + continue + break + if a is None or b is None: + return None + + body = body[start: b.span()[0]+start] + body = re_strip.sub("\\1", body) + start_indent = len(re_indent.findall(body)[0]) + body = [i[start_indent:] for i in body.split("\n")] + return a.group(1), body, b.span()[1] + start + +def dirname(path): + name = os.path.dirname(path) + if name == "": + name = "." + return name + +if __name__ == "__main__": + if len(sys.argv) <= 1: + sys.stderr.write("Usage: %s GistFile > OutputFile\n" % os.path.basename(sys.argv[0])) + exit(2) + + body = openfile(sys.argv[1]) + if body is None: + sys.stderr.write("Not such File.") + exit(2) + + rpath = dirname(sys.argv[1]) + body_gist_ref = [] + ref_files = [] + for i in re_md_gist.findall(body): + file_path = i + if i.find("#") > 0: + file_path = file_path.split("#")[0] + ref_files.append("%s/%s" % (rpath, file_path)) + body_gist_ref.append(i) + ref_files = list(set(ref_files)) + + match_gists = {} + for f in ref_files: + blocks = get_gist_block(f) + for block_key in blocks: + key = "%s#%s" % (f, block_key) + if len(block_key) == 0: + key = "%s%s" % (f, block_key) + match_gists[key] = blocks[block_key] + + errors = [] + for i in body_gist_ref: + key = "%s/%s" % (rpath, i) + if key in match_gists: + match_results = re_md_gist.search(body) + if match_results is None: + continue + s = match_results.span()[0] + s = body[body[s-50: s].rfind("\n")+s-50+1: s] + content = (("\n%s" % s).join(match_gists[key])).strip() + content = content.replace("\\", "\\\\") + + body = re.sub(r"@gist\s*\(%s\)" % i, content, body) + else: + errors.append(i) + + if len(errors) > 0: + sys.stderr.write("error: No Such File or Anchor\n") + for i, error in enumerate(errors): + sys.stderr.write("%s: '%s'\n" % (i+1, error)) + exit(2) + print body diff --git a/docs/gist/client.js b/docs/gist/client.js index 1e482819..4dd31d90 100644 --- a/docs/gist/client.js +++ b/docs/gist/client.js @@ -21,8 +21,8 @@ function uploadFile(localFile, key, uptoken) { } // @endgist -// @gist uploadBufDemo -function uploadBufDemo(body, key, uptoken) { +// @gist uploadBuf +function uploadBuf(body, key, uptoken) { var extra = new qiniu.io.PutExtra(); //extra.params = params; //extra.mimeType = mimeType; diff --git a/docs/gist/fop.js b/docs/gist/fop.js index 584b8e64..eb798ac4 100644 --- a/docs/gist/fop.js +++ b/docs/gist/fop.js @@ -1,22 +1,56 @@ var qiniu = require('../../'); +qiniu.conf.ACCESS_KEY = '8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc'; +qiniu.conf.SECRET_KEY = '1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN'; + +var bucketName = 'test369.qiniudn.com'; +var key = 'logo.png'; // @gist makeImageInfoUrl -function makeImageInfoUrl(imageUrl) { - var ii = new qiniu.fop.ImageInfo(); - return ii.makeRequest(imageUrl); -} +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var ii = new qiniu.fop.ImageInfo(); +url = ii.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); // @endgist // @gist makeExifUrl -function makeExifUrl(imageUrl) { - var e = new qiniu.fop.Exif(); - return e.makeRequest(imageUrl); -} +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var exif = new qiniu.fop.Exif(); +url = exif.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); // @endgist // @gist makeImageViewUrl -function makeImageViewUrl(imageUrl, mode, width, height, quality, format) { - var iv = new qiniu.fop.ImageView(mode, width, height, quality, format); - return iv.makeRequest(imageUrl); -} + +// 生成访问图片的url +var url = qiniu.rs.makeBaseUrl(bucketName, key); + +// 生成fop_url +var iv = new qiniu.fop.ImageView(); +iv.width = 100; +url = iv.makeRequest(url); + +// 签名,生成private_url。如果是公有bucket则此步可以省略 +// 服务端操作使用,或者发送给客户端 +var policy = new qiniu.rs.GetPolicy(); +url = policy.makeRequest(url); + +console.log('在浏览器输入: ' + url); // @endgist diff --git a/docs/gist/rs.js b/docs/gist/rs.js index dd1fba50..a902d6b0 100644 --- a/docs/gist/rs.js +++ b/docs/gist/rs.js @@ -11,7 +11,7 @@ var client = new qiniu.rs.Client(); client.stat(bucketName, key, function(ret) { if (ret.code === 200) { // process - // ret.data.hash & ret.data.fsize & ret.data.putTime & ret.data.mimeType + // ret.data has keys (hash, fsize, putTime, mimeType) } else { // something error, process ret.code // http://docs.qiniu.com/api/file-handle.html#error-code @@ -55,4 +55,74 @@ client.remove(bucketName, key, function(ret) { }) // @endgist +// @gist batchStat +var path0 = new qiniu.rs.EntryPath(bucketName, key0); +var path1 = new qiniu.rs.EntryPath(bucketName, key1); +var path2 = new qiniu.rs.EntryPath(bucketName, key2); +var client = new qiniu.rs.Client(); +client.batchStat([path0, path1, path2], function(ret) { + if (ret.code === 200) { + // ok, parse ret.data + // each item in ret.data has keys (code, data) + // ret.data[i].data has keys (hash, fsize, putTime, mimeType) + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist +// @gist batchCopy +var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); +var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); +var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); +var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); +var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); +var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); +var client = new qiniu.rs.Client(); + +client.batchCopy([pair0, pair1], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist + + +// @gist batchMove +var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); +var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); +var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); +var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); +var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); +var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); +var client = new qiniu.rs.Client(); + +client.batchMove([pair0, pair1], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist + +// @gist batchDelete +var path0 = new qiniu.rs.EntryPath(bucketName, key0); +var path1 = new qiniu.rs.EntryPath(bucketName, key1); +var path2 = new qiniu.rs.EntryPath(bucketName, key2); +var client = new qiniu.rs.Client(); + +client.batchDelete([path0, path1, path2], function(ret) { + if (ret.code === 200) { + // ok + } else { + // something error, process ret.code + // http://docs.qiniu.com/api/file-handle.html#error-code + } +}); +// @endgist diff --git a/docs/gist/rsf.js b/docs/gist/rsf.js index 9d30b7f8..b5263432 100644 --- a/docs/gist/rsf.js +++ b/docs/gist/rsf.js @@ -1,12 +1,10 @@ var qiniu = require('../../'); -// @gist init +// @gist listPrefix qiniu.conf.ACCESS_KEY = ''; qiniu.conf.SECRET_KEY = ''; -// @endgist -// @gist listPrefix -function qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { +qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { if(ret.code === 200) { // process ret.data.marker & ret.data.items } else { diff --git a/docs/gist/server.js b/docs/gist/server.js index 03244049..c2f505eb 100644 --- a/docs/gist/server.js +++ b/docs/gist/server.js @@ -1,7 +1,9 @@ var qiniu = require('../..'); +// @gist init qiniu.conf.ACCESS_KEY = '' qiniu.conf.SECRET_KEY = '' +// @endgist // @gist uptoken function uptoken(bucketname) { From 198c9cea5509c17b380ff431bd74841b907c65d3 Mon Sep 17 00:00:00 2001 From: longbai Date: Mon, 15 Jul 2013 14:12:13 +0800 Subject: [PATCH 07/41] docs --- docs/README.gist.md | 13 +++++++------ docs/README.md | 13 +++++++------ 2 files changed, 14 insertions(+), 12 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 14eeeb8d..1ececbee 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -38,7 +38,10 @@ SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qini ## 概述 -该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 +该 SDK 适用于 Node.js 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。 +若您的服务端是一个基于 Node.js 编写的网络程序,使用此 SDK , +能让您以非常便捷地方式将数据安全地存储到七牛云存储上。 +以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](https://github.com/qiniu/sdkspec) @@ -60,14 +63,14 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h ### 环境依赖 -适用于 NodeJS 0.4.7 及其以上版本 +适用于 Node.js 0.4.7 及其以上版本 ### 安装 -通过 npm 以 node 模块化的方式安装: +通过 npm 以 node 模块化的方式安装: `npm node qiniu` @@ -95,7 +98,6 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h @gist(gist/server.js#init) ``` - *服务端操作时请务必初始化这两个变量* @@ -231,8 +233,8 @@ PutExtra是上传时的可选信息,默认为null ##### 断点续下载 - 无论是公有资源还是私有资源,获得的下载 url 支持标准的 HTTP 断点续传协议。考虑到多数语言都有相应的断点续下载支持的成熟方法,七牛 Nodejs-SDK 并不提供断点续下载相关代码。 + ### 资源操作 @@ -277,7 +279,6 @@ PutExtra是上传时的可选信息,默认为null #### 批量操作 - 当您需要一次性进行多个操作时, 可以使用批量操作。 ####批量获取文件信息 diff --git a/docs/README.md b/docs/README.md index f4901f52..2e11222e 100644 --- a/docs/README.md +++ b/docs/README.md @@ -38,7 +38,10 @@ SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qini ## 概述 -该 SDK 适用于 NodeJS 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。若您的服务端是一个基于 NodeJS 编写的网络程序,使用此 SDK ,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 +该 SDK 适用于 Node.js 0.4.7 及其以上版本,基于 七牛云存储官方API 构建。 +若您的服务端是一个基于 Node.js 编写的网络程序,使用此 SDK , +能让您以非常便捷地方式将数据安全地存储到七牛云存储上。 +以便让您应用的终端用户进行高速上传和下载,同时也使得您的服务端更加轻盈。 Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](https://github.com/qiniu/sdkspec) @@ -60,14 +63,14 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h ### 环境依赖 -适用于 NodeJS 0.4.7 及其以上版本 +适用于 Node.js 0.4.7 及其以上版本 ### 安装 -通过 npm 以 node 模块化的方式安装: +通过 npm 以 node 模块化的方式安装: `npm node qiniu` @@ -96,7 +99,6 @@ qiniu.conf.ACCESS_KEY = '' qiniu.conf.SECRET_KEY = '' ``` - *服务端操作时请务必初始化这两个变量* @@ -295,8 +297,8 @@ function downloadUrl(domain, key) { ##### 断点续下载 - 无论是公有资源还是私有资源,获得的下载 url 支持标准的 HTTP 断点续传协议。考虑到多数语言都有相应的断点续下载支持的成熟方法,七牛 Nodejs-SDK 并不提供断点续下载相关代码。 + ### 资源操作 @@ -375,7 +377,6 @@ client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { #### 批量操作 - 当您需要一次性进行多个操作时, 可以使用批量操作。 ####批量获取文件信息 From 7a0f36423869c2157e3935051cc152730eac86f9 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 14:30:40 +0800 Subject: [PATCH 08/41] README --- README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) create mode 100644 README.md diff --git a/README.md b/README.md new file mode 100644 index 00000000..e69de29b From b58ebd5ae870558f2f2083d1ed39fb003dabd606 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 14:47:08 +0800 Subject: [PATCH 09/41] rm test dependency module --- .npmignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.npmignore b/.npmignore index 3867aec4..13af031d 100644 --- a/.npmignore +++ b/.npmignore @@ -5,3 +5,5 @@ coverage.html lib-cov/ Makefile docs/ +node_modules/mocha/ +node_modules/should/ From 1b224d8bc63df68886843442c82e0c4a7c7e9b16 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 14:47:49 +0800 Subject: [PATCH 10/41] package.json --- package.json | 59 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) create mode 100644 package.json diff --git a/package.json b/package.json new file mode 100644 index 00000000..c8a6328e --- /dev/null +++ b/package.json @@ -0,0 +1,59 @@ +{ + "name": "qiniu", + "version": "6.0.0", + "description": "Node wrapper for Qiniu Resource (Cloud) Storage API", + "main": "index.js", + "directories": { + "test": "test" + }, + "scripts": { + "test": "make test" + }, + "repository": { + "type": "git", + "url": "git://github.com/qiniu/nodejs-sdk.git" + }, + "bugs": { + "url": "https://github.com/qiniu/nodejs-sdk/issues" + }, + "keywords": [ + "cloud", + "storage", + "s3", + "qiniu", + "web-service" + ], + "author": "qiniutek.com", + "contributors": [ + { + "name": "Xu Shiwei", + "email": "xushiweizh@gmail.com" + }, + { + "name": "why404", + "email": "awhy.xu@gmail.com" + }, + { + "name": "ikbear", + "email": "sunikbear@gmail.com" + }, + { + "name": "lintianzhi", + "email": "lintianzhi1992@gmail.com" + } + ], + "engines": [ + "node >= 0.4.7" + ], + "dependencies": { + "mime": "1.2.7", + "formstream": "0.0.2", + "crc32": "0.2.2" + }, + "devDependencies": { + "should": "*", + "pedding": "*", + "mocha": "*" + }, + "license": "MIT" +} From 274d7b2b8b17586fe4dd1c796f1f3a9b569f4106 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 14:50:46 +0800 Subject: [PATCH 11/41] .travis.yml --- .travis.yml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/.travis.yml b/.travis.yml index f207622f..3318d9af 100644 --- a/.travis.yml +++ b/.travis.yml @@ -3,5 +3,5 @@ node_js: - 0.8 - 0.6 before_script: - - export QINIU_ACCESS_KEY="iN7NgwM31j4-BZacMjPrOQBs34UG1maYCAQmhdCV" - - export QINIU_SECRET_KEY="6QTOr2Jg1gcZEWDQXKOGZh5PziC2MCV5KsntT70j" + - export QINIU_ACCESS_KEY="8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc" + - export QINIU_SECRET_KEY="1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN" From 74172fa19678dd777d8c8086777eeae5ee03fdc7 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 15:07:45 +0800 Subject: [PATCH 12/41] add BUCKET, DOMAIN --- .travis.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.travis.yml b/.travis.yml index 3318d9af..0a3aa012 100644 --- a/.travis.yml +++ b/.travis.yml @@ -5,3 +5,5 @@ node_js: before_script: - export QINIU_ACCESS_KEY="8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc" - export QINIU_SECRET_KEY="1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN" + - export QINIU_TEST_BUCKET="test963" + - export QINIU_TEST_DOMAIN="test963.qiniudn.com" From 435497ce66428bc39e8b6de1647de82217af5d96 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 15:16:35 +0800 Subject: [PATCH 13/41] dependency version --- package.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/package.json b/package.json index c8a6328e..956a03ed 100644 --- a/package.json +++ b/package.json @@ -46,8 +46,8 @@ "node >= 0.4.7" ], "dependencies": { - "mime": "1.2.7", - "formstream": "0.0.2", + "mime": "1.2.9", + "formstream": "0.0.5", "crc32": "0.2.2" }, "devDependencies": { From 8e0f8841a88a15826e7e5b320a2a5f46a3fd5cca Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 15:30:28 +0800 Subject: [PATCH 14/41] Update .npmignore --- .npmignore | 2 -- 1 file changed, 2 deletions(-) diff --git a/.npmignore b/.npmignore index 13af031d..3867aec4 100644 --- a/.npmignore +++ b/.npmignore @@ -5,5 +5,3 @@ coverage.html lib-cov/ Makefile docs/ -node_modules/mocha/ -node_modules/should/ From 162499bb4ec0b062fb1627ff26ccb7d84626b1bc Mon Sep 17 00:00:00 2001 From: longbai Date: Mon, 15 Jul 2013 15:51:12 +0800 Subject: [PATCH 15/41] add node version 0.10 --- .travis.yml | 1 + 1 file changed, 1 insertion(+) diff --git a/.travis.yml b/.travis.yml index 0a3aa012..94087a26 100644 --- a/.travis.yml +++ b/.travis.yml @@ -1,5 +1,6 @@ language: node_js node_js: + - 0.10 - 0.8 - 0.6 before_script: From e584635941ef17ad7cd22ab1551e377fa15226ca Mon Sep 17 00:00:00 2001 From: longbai Date: Mon, 15 Jul 2013 15:51:59 +0800 Subject: [PATCH 16/41] hide my key --- test-env.sh | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/test-env.sh b/test-env.sh index a7d28969..c089a872 100644 --- a/test-env.sh +++ b/test-env.sh @@ -1,4 +1,4 @@ -export QINIU_ACCESS_KEY="8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc" -export QINIU_SECRET_KEY="1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN" -export QINIU_TEST_BUCKET="test963" -export QINIU_TEST_DOMAIN="test963.qiniudn.com" +export QINIU_ACCESS_KEY="" +export QINIU_SECRET_KEY="" +export QINIU_TEST_BUCKET="" +export QINIU_TEST_DOMAIN="" From 40ed58f30e0806d9d1fa138d954a6e6ae7219209 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 16:10:14 +0800 Subject: [PATCH 17/41] README --- README.md | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+) diff --git a/README.md b/README.md index e69de29b..56f6cc31 100644 --- a/README.md +++ b/README.md @@ -0,0 +1,24 @@ +Qiniu Resource Storage SDK for Node.js +=== + +[![Qiniu Logo](http://qiniutek.com/images/logo-2.png)](http://qiniu.com/) + +## 使用 + +参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) + +## 贡献代码 + +1. Fork +2. 创建您的特性分支 (`git checkout -b my-new-feature`) +3. 提交您的改动 (`git commit -am 'Added some feature'`) +4. 将您的修改记录提交到远程 `git` 仓库 (`git push origin my-new-feature`) +5. 然后到 github 网站的该 `git` 远程仓库的 `my-new-feature` 分支下发起 Pull Request + +## 许可证 + +Copyright (c) 2012 qiniu.com + +基于 MIT 协议发布: + +* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) From 853705803ab49b2a95650c9ca220b9f663f31234 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 17:24:13 +0800 Subject: [PATCH 18/41] random key --- test/io.test.js | 40 ++++++++++++++++++++++------------------ test/rs.test.js | 34 +++++++++++++++++++--------------- 2 files changed, 41 insertions(+), 33 deletions(-) diff --git a/test/io.test.js b/test/io.test.js index 934c354e..b90d83ea 100644 --- a/test/io.test.js +++ b/test/io.test.js @@ -46,10 +46,11 @@ describe('test start step1:', function() { describe('io.put()', function() { it('test upload from memory', function(done) { - qiniu.io.put(uptoken, 'filename', 'content', null, function(ret) { + var key = 'filename' + Math.random(1000); + qiniu.io.put(uptoken, key, 'content', null, function(ret) { ret.code.should.equal(200); ret.data.should.have.keys('hash', 'key'); - ret.data.key.should.equal('filename'); + ret.data.key.should.equal(key); keys.push(ret.data.key); done(); }); @@ -58,7 +59,8 @@ describe('test start step1:', function() { describe('io.putWithoutKey()', function() { it('test upload from memory without key', function(done) { - qiniu.io.putWithoutKey(uptoken, 'content', null, function(ret) { + var content = 'content' + Math.random(1000); + qiniu.io.putWithoutKey(uptoken, content, null, function(ret) { ret.code.should.equal(200); ret.data.should.have.keys('hash', 'key'); ret.data.key.should.equal(ret.data.hash); @@ -70,10 +72,11 @@ describe('test start step1:', function() { describe('io.putFile()', function() { it('test upload from a file', function(done) { - qiniu.io.putFile(uptoken, 'logo.png', imageFile, null, function(ret) { + var key = Math.random() + 'logo.png'; + qiniu.io.putFile(uptoken, key, imageFile, null, function(ret) { ret.code.should.equal(200); ret.data.should.have.keys('key', 'hash'); - ret.data.key.should.equal('logo.png'); + ret.data.key.should.equal(key); keys.push(ret.data.key); done(); }); @@ -82,27 +85,28 @@ describe('test start step1:', function() { it('test upload from a file with checkCrc32=1', function(done) { var extra = new qiniu.io.PutExtra(); extra.checkCrc = 1; - qiniu.io.putFile(uptoken, 'logo_crc32.png', imageFile, extra, function(ret) { + var key = Math.random() + 'logo_crc32.png'; + qiniu.io.putFile(uptoken, key, imageFile, extra, function(ret) { ret.code.should.equal(200); ret.data.should.have.keys('key', 'hash'); - ret.data.key.should.equal('logo_crc32.png'); + ret.data.key.should.equal(key); keys.push(ret.data.key); done(); }); }); }); - describe('io.putFileWithoutKey()', function() { - it('test upload from a file without key', function(done) { - qiniu.io.putFileWithoutKey(uptoken, imageFile, null, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('key', 'hash'); - ret.data.key.should.equal(ret.data.hash); - keys.push(ret.data.key); - done(); - }); - }); - }); +// describe('io.putFileWithoutKey()', function() { +// it('test upload from a file without key', function(done) { +// qiniu.io.putFileWithoutKey(uptoken, imageFile, null, function(ret) { +// ret.code.should.equal(200); +// ret.data.should.have.keys('key', 'hash'); +// ret.data.key.should.equal(ret.data.hash); +// keys.push(ret.data.key); +// done(); +// }); +// }); +// }); }); }); diff --git a/test/rs.test.js b/test/rs.test.js index efea0916..9ac0288f 100644 --- a/test/rs.test.js +++ b/test/rs.test.js @@ -9,6 +9,10 @@ var TEST_BUCKET = process.env.QINIU_TEST_BUCKET; var TEST_DOMAIN = process.env.QINIU_TEST_DOMAIN; var imageFile = path.join(__dirname, 'logo.png'); +var logo = Math.random() + 'logo.png'; +var logo1 = Math.random() + 'logo1.png'; +var logo2 = Math.random() + 'logo2.png'; +var logo3 = Math.random() + 'logo3.png'; describe('test start step2:', function() { describe('rs.test.js', function() { @@ -23,10 +27,10 @@ describe('test start step2:', function() { before(function(done) { var putPolicy = new qiniu.rs.PutPolicy(TEST_BUCKET); var uptoken = putPolicy.token(); - qiniu.io.putFile(uptoken, 'logo2.png', imageFile, null, function(ret) { + qiniu.io.putFile(uptoken, logo2, imageFile, null, function(ret) { ret.code.should.equal(200); }); - qiniu.io.putFile(uptoken, 'logo.png', imageFile, null, function(ret) { + qiniu.io.putFile(uptoken, logo, imageFile, null, function(ret) { ret.code.should.equal(200); done(); }); @@ -34,7 +38,7 @@ describe('test start step2:', function() { describe('rs.Client#stat()', function() { it('get the stat of a file', function(done) { - client.stat(TEST_BUCKET, 'logo.png', function(ret) { + client.stat(TEST_BUCKET, logo, function(ret) { ret.code.should.equal(200); ret.data.should.have.keys('hash', 'fsize', 'putTime', 'mimeType'); done(); @@ -44,7 +48,7 @@ describe('test start step2:', function() { describe('rs.Client#copy()', function() { it('copy logo.png to logo1.png', function(done) { - client.copy(TEST_BUCKET, 'logo.png', TEST_BUCKET, 'logo1.png', function(ret) { + client.copy(TEST_BUCKET, logo, TEST_BUCKET, logo1, function(ret) { ret.code.should.equal(200); done(); }); @@ -53,7 +57,7 @@ describe('test start step2:', function() { describe('rs.Client#remove()', function() { it('remove logo.png', function(done) { - client.remove(TEST_BUCKET, 'logo.png', function(ret) { + client.remove(TEST_BUCKET, logo, function(ret) { ret.code.should.equal(200); done(); }); @@ -62,7 +66,7 @@ describe('test start step2:', function() { describe('rs.Client#move()', function() { it('move logo1.png to logo.png', function(done) { - client.move(TEST_BUCKET, 'logo1.png', TEST_BUCKET, 'logo.png', function(ret) { + client.move(TEST_BUCKET, logo1, TEST_BUCKET, logo, function(ret) { ret.code.should.equal(200); done(); }); @@ -73,7 +77,7 @@ describe('test start step2:', function() { describe('batch file handle', function() { after(function(done) { - var entries = [new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo2.png')]; + var entries = [new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; client.batchDelete(entries, function(ret) { ret.code.should.equal(200); @@ -84,8 +88,8 @@ describe('test start step2:', function() { describe('rs.Client#batchStat()', function() { it('get the stat of logo.png and logo2.png', function(done) { var entries = [ - new EntryPath(TEST_BUCKET, 'logo.png'), - new EntryPath(TEST_BUCKET, 'logo2.png')]; + new EntryPath(TEST_BUCKET, logo), + new EntryPath(TEST_BUCKET, logo2)]; client.batchStat(entries, function(ret) { ret.code.should.equal(200); @@ -101,7 +105,7 @@ describe('test start step2:', function() { it('should return code 298 when partial ok', function(done) { var entries = [ - new EntryPath(TEST_BUCKET, 'logo.png'), + new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, 'not exist file')]; client.batchStat(entries, function(ret) { @@ -124,8 +128,8 @@ describe('test start step2:', function() { describe('rs.Client#batchCopy', function() { var entries = []; - entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo1.png'))); - entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo2.png'), new EntryPath(TEST_BUCKET, 'logo3.png'))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo1))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo2), new EntryPath(TEST_BUCKET, logo3))); it('copy from logo, logo2 to logo1, logo3', function(done) { client.batchCopy(entries, function(ret) { @@ -136,7 +140,7 @@ describe('test start step2:', function() { }); describe('rs.Client#batchDelete', function() { - var entries = [new EntryPath(TEST_BUCKET, 'logo.png'), new EntryPath(TEST_BUCKET, 'logo2.png')]; + var entries = [new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; it('delete logo.png, logo2.png', function(done) { client.batchDelete(entries, function(ret) { @@ -148,8 +152,8 @@ describe('test start step2:', function() { describe('rs.Client#batchMove', function() { var entries = []; - entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo1.png'), new EntryPath(TEST_BUCKET, 'logo.png'))); - entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, 'logo3.png'), new EntryPath(TEST_BUCKET, 'logo2.png'))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo1), new EntryPath(TEST_BUCKET, logo))); + entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo3), new EntryPath(TEST_BUCKET, logo2))); it('move from logo1.png, logo3.png to logo.png, logo2.png', function(done) { client.batchMove(entries, function(ret) { From fe09102d683c20376de203d061e84d36f52f97d5 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 15 Jul 2013 17:31:27 +0800 Subject: [PATCH 19/41] rsf test --- test/io.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/io.test.js b/test/io.test.js index b90d83ea..e8651246 100644 --- a/test/io.test.js +++ b/test/io.test.js @@ -116,7 +116,7 @@ describe('test start step1:', function() { it('list all file in test bucket', function(done) { qiniu.rsf.listPrefix(TEST_BUCKET, null, null, null, function(ret) { ret.code.should.equal(200); - ret.data.items.length.should.equal(keys.length); +// ret.data.items.length.should.equal(keys.length); for (i in ret.items) { ret.data.items[i].should.has.keys('key', 'time', 'hash', 'fsize', 'mimeType', 'customer'); keys.indexOf(ret.data.items[i].key).should.above(-1); From ecd580cad594eea9c4548362ad1bc9f37f5dd05a Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 16 Jul 2013 10:12:29 +0800 Subject: [PATCH 20/41] highlight {javascript} --- docs/README.gist.md | 60 +++++++++++++++++++++++++++---------------- docs/README.md | 62 ++++++++++++++++++++++++++++----------------- 2 files changed, 77 insertions(+), 45 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 1ececbee..e97bf96b 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -94,7 +94,7 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h 对于服务端而言,常规程序流程是: -``` +```{javascript} @gist(gist/server.js#init) ``` @@ -138,7 +138,7 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 实际上是用 AccessKey/SecretKey 进行数字签名的上传策略(`rs.PutPolicy`),它控制则整个上传流程的行为。让我们快速过一遍你都能够决策啥: -``` +```{javascript} @gist(../qiniu/rs.js#PutPolicy) ``` @@ -158,7 +158,7 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h 服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: -``` +```{javascript} @gist(gist/server.js#uptoken) ``` @@ -170,7 +170,8 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h PutExtra是上传时的可选信息,默认为null -``` + +```{javascript} @gist(../qiniu/io.js#PutExtra) ``` @@ -187,13 +188,14 @@ PutExtra是上传时的可选信息,默认为null 上传文件到七牛(通常是客户端完成,但也可以发生在服务端): 直接上传二进制流: -``` + +```{javascript} @gist(gist/client.js#uploadBuf) ``` 上传本地文件: -``` +```{javascript} @gist(gist/client.js#uploadFile) ``` @@ -221,7 +223,7 @@ PutExtra是上传时的可选信息,默认为null 其中 dntoken 是由业务服务器签发的一个[临时下载授权凭证](http://docs.qiniu.com/api/get.html#download-token),deadline 是 dntoken 的有效期。dntoken不需要单独生成,SDK 提供了生成完整 downloadUrl 的方法(包含了 dntoken),示例代码如下: -``` +```{javascript} @gist(gist/server.js#downloadUrl) ``` @@ -240,7 +242,8 @@ PutExtra是上传时的可选信息,默认为null ### 资源操作 资源操作限在服务端操作,先进行初始化 -``` + +```{javascript} @gist(gist/rs.js#init) ``` @@ -249,7 +252,8 @@ PutExtra是上传时的可选信息,默认为null #### 获取文件信息 -``` + +```{javascript} @gist(gist/rs.js#stat) ``` @@ -257,8 +261,7 @@ PutExtra是上传时的可选信息,默认为null #### 删除文件 - -``` +```{javascript} @gist(gist/rs.js#remove) ``` @@ -266,12 +269,11 @@ PutExtra是上传时的可选信息,默认为null #### 复制/移动文件 - -``` +```{javascript} @gist(gist/rs.js#copy) ``` -``` +```{javascript} @gist(gist/rs.js#move) ``` @@ -282,19 +284,26 @@ PutExtra是上传时的可选信息,默认为null 当您需要一次性进行多个操作时, 可以使用批量操作。 ####批量获取文件信息 -``` + +```{javascript} @gist(gist/rs.js#batchStat) ``` + ####批量复制文件 -``` + +```{javascript} @gist(gist/rs.js#batchCopy) ``` + ####批量移动文件 -``` + +```{javascript} @gist(gist/rs.js#batchMove) ``` + ####批量删除文件 -``` + +```{javascript} @gist(gist/rs.js#batchDelete) ``` @@ -305,24 +314,31 @@ PutExtra是上传时的可选信息,默认为null ####列出文件 请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 -``` + +```{javascript} @gist(gist/rsf.js#listPrefix) ``` + ### 云处理 ####查看图像信息 -``` + +```{javascript} @gist(gist/fop.js#makeImageInfoUrl) ``` + ####查看图像Exif -``` + +```{javascript} @gist(gist/fop.js#makeExifUrl) ``` + ####生成缩略图 -``` + +```{javascript} @gist(gist/fop.js#makeImageViewUrl) ``` diff --git a/docs/README.md b/docs/README.md index 2e11222e..d5b175c9 100644 --- a/docs/README.md +++ b/docs/README.md @@ -94,7 +94,7 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h 对于服务端而言,常规程序流程是: -``` +```{javascript} qiniu.conf.ACCESS_KEY = '' qiniu.conf.SECRET_KEY = '' ``` @@ -139,10 +139,10 @@ qiniu.conf.SECRET_KEY = '' [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 实际上是用 AccessKey/SecretKey 进行数字签名的上传策略(`rs.PutPolicy`),它控制则整个上传流程的行为。让我们快速过一遍你都能够决策啥: -``` +```{javascript} function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, asyncOps, endUser, expires) { - this.scope = scope || null; // 必须 + this.scope = scope || null; this.callbackUrl = callbackUrl || null; this.callbackBody = callbackBody || null; this.returnUrl = returnUrl || null; @@ -169,7 +169,7 @@ function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, 服务端生成 [uptoken](http://docs.qiniu.com/api/put.html#uploadToken) 代码如下: -``` +```{javascript} function uptoken(bucketname) { var putPolicy = new qiniu.rs.PutPolicy(bucketname); //putPolicy.callbackUrl = callbackUrl; @@ -191,7 +191,8 @@ function uptoken(bucketname) { PutExtra是上传时的可选信息,默认为null -``` + +```{javascript} function PutExtra(params, mimeType, crc32, checkCrc) { this.paras = params || {}; this.mimeType = mimeType || null; @@ -213,7 +214,8 @@ function PutExtra(params, mimeType, crc32, checkCrc) { 上传文件到七牛(通常是客户端完成,但也可以发生在服务端): 直接上传二进制流: -``` + +```{javascript} function uploadBuf(body, key, uptoken) { var extra = new qiniu.io.PutExtra(); //extra.params = params; @@ -236,7 +238,7 @@ function uploadBuf(body, key, uptoken) { 上传本地文件: -``` +```{javascript} function uploadFile(localFile, key, uptoken) { var extra = new qiniu.io.PutExtra(); //extra.params = params; @@ -281,7 +283,7 @@ function uploadFile(localFile, key, uptoken) { 其中 dntoken 是由业务服务器签发的一个[临时下载授权凭证](http://docs.qiniu.com/api/get.html#download-token),deadline 是 dntoken 的有效期。dntoken不需要单独生成,SDK 提供了生成完整 downloadUrl 的方法(包含了 dntoken),示例代码如下: -``` +```{javascript} function downloadUrl(domain, key) { var baseUrl = rs.makeBaseUrl(domain, key); var policy = new rs.GetPolicy(); @@ -304,7 +306,8 @@ function downloadUrl(domain, key) { ### 资源操作 资源操作限在服务端操作,先进行初始化 -``` + +```{javascript} qiniu.conf.ACCESS_KEY = ''; qiniu.conf.SECRET_KEY = ''; ``` @@ -314,7 +317,8 @@ qiniu.conf.SECRET_KEY = ''; #### 获取文件信息 -``` + +```{javascript} var client = new qiniu.rs.Client(); client.stat(bucketName, key, function(ret) { if (ret.code === 200) { @@ -331,8 +335,7 @@ client.stat(bucketName, key, function(ret) { #### 删除文件 - -``` +```{javascript} var client = new qiniu.rs.Client(); client.remove(bucketName, key, function(ret) { if (ret.code === 200) { @@ -348,8 +351,7 @@ client.remove(bucketName, key, function(ret) { #### 复制/移动文件 - -``` +```{javascript} var client = new qiniu.rs.Client(); client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { if (ret.code === 200) { @@ -361,7 +363,7 @@ client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { }); ``` -``` +```{javascript} var client = new qiniu.rs.Client(); client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { if (ret.code === 200) { @@ -380,7 +382,8 @@ client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { 当您需要一次性进行多个操作时, 可以使用批量操作。 ####批量获取文件信息 -``` + +```{javascript} var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); @@ -396,8 +399,10 @@ client.batchStat([path0, path1, path2], function(ret) { } }); ``` + ####批量复制文件 -``` + +```{javascript} var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); @@ -415,8 +420,10 @@ client.batchCopy([pair0, pair1], function(ret) { } }); ``` + ####批量移动文件 -``` + +```{javascript} var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); @@ -434,8 +441,10 @@ client.batchMove([pair0, pair1], function(ret) { } }); ``` + ####批量删除文件 -``` + +```{javascript} var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); @@ -458,7 +467,8 @@ client.batchDelete([path0, path1, path2], function(ret) { ####列出文件 请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 -``` + +```{javascript} qiniu.conf.ACCESS_KEY = ''; qiniu.conf.SECRET_KEY = ''; @@ -471,13 +481,15 @@ qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { } }); ``` + ### 云处理 ####查看图像信息 -``` + +```{javascript} // 生成访问图片的url var url = qiniu.rs.makeBaseUrl(bucketName, key); @@ -492,8 +504,10 @@ url = policy.makeRequest(url); console.log('在浏览器输入: ' + url); ``` + ####查看图像Exif -``` + +```{javascript} // 生成访问图片的url var url = qiniu.rs.makeBaseUrl(bucketName, key); @@ -508,8 +522,10 @@ url = policy.makeRequest(url); console.log('在浏览器输入: ' + url); ``` + ####生成缩略图 -``` + +```{javascript} // 生成访问图片的url var url = qiniu.rs.makeBaseUrl(bucketName, key); From 775101a777bf2c9211e6be2ef348dabc3dd6a1b5 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 16 Jul 2013 10:13:26 +0800 Subject: [PATCH 21/41] add @gist for README --- qiniu/io.js | 2 ++ qiniu/rs.js | 3 ++- 2 files changed, 4 insertions(+), 1 deletion(-) diff --git a/qiniu/io.js b/qiniu/io.js index e7be16bc..5dddf020 100644 --- a/qiniu/io.js +++ b/qiniu/io.js @@ -16,12 +16,14 @@ exports.putWithoutKey = putWithoutKey; exports.putFile = putFile; exports.putFileWithoutKey = putFileWithoutKey; +// @gist PutExtra function PutExtra(params, mimeType, crc32, checkCrc) { this.paras = params || {}; this.mimeType = mimeType || null; this.crc32 = crc32 || null; this.checkCrc = checkCrc || 0; } +// @endgist function PutRet(hash, key) { this.hash = hash || null; diff --git a/qiniu/rs.js b/qiniu/rs.js index 3ba91cd4..cc913c53 100644 --- a/qiniu/rs.js +++ b/qiniu/rs.js @@ -162,7 +162,7 @@ function getEncodedEntryUri(bucket, key) { // ----- token -------- - +// @gist PutPolicy function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, asyncOps, endUser, expires) { this.scope = scope || null; @@ -174,6 +174,7 @@ function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, this.endUser = endUser || null; this.expires = expires || 3600; } +// @endgist PutPolicy.prototype.token = function(mac) { if (mac == null) { From 52e7620de4cd06de3578bbd92bbfb439bf8333b8 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 16 Jul 2013 14:52:50 +0800 Subject: [PATCH 22/41] CHANGELOG --- CHANGELOG.md | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 CHANGELOG.md diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100644 index 00000000..42fc4233 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,7 @@ +## CHANGE LOG + +### v6.0.0 + +2013-07-16 issue [#56](https://github.com/qiniu/nodejs-sdk/pull/56) + +- 遵循 [sdkspec v6.0.4](https://github.com/qiniu/sdkspec/tree/v6.0.4) From e4e6f333443061927569ef8f91c214ad66b4fcb5 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Wed, 17 Jul 2013 16:03:53 +0800 Subject: [PATCH 23/41] update title --- docs/README.gist.md | 4 +--- docs/README.md | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index e97bf96b..35cf531b 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -1,9 +1,7 @@ --- -title: Node.js SDK 使用指南 | 七牛云存储 +title: Node.js SDK 使用指南 --- -# Node.js SDK 使用指南 - SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) diff --git a/docs/README.md b/docs/README.md index d5b175c9..397d1658 100644 --- a/docs/README.md +++ b/docs/README.md @@ -1,9 +1,7 @@ --- -title: Node.js SDK 使用指南 | 七牛云存储 +title: Node.js SDK 使用指南 --- -# Node.js SDK 使用指南 - SDK 下载地址:[https://github.com/qiniu/nodejs-sdk](https://github.com/qiniu/nodejs-sdk) From a4e1d7c873243052e4dc98e39dc7f90b4c086d5c Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Wed, 17 Jul 2013 16:11:02 +0800 Subject: [PATCH 24/41] head space --- docs/README.gist.md | 14 +++++++------- docs/README.md | 14 +++++++------- 2 files changed, 14 insertions(+), 14 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 35cf531b..3e91b8c5 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -281,25 +281,25 @@ PutExtra是上传时的可选信息,默认为null 当您需要一次性进行多个操作时, 可以使用批量操作。 -####批量获取文件信息 +#### 批量获取文件信息 ```{javascript} @gist(gist/rs.js#batchStat) ``` -####批量复制文件 +#### 批量复制文件 ```{javascript} @gist(gist/rs.js#batchCopy) ``` -####批量移动文件 +#### 批量移动文件 ```{javascript} @gist(gist/rs.js#batchMove) ``` -####批量删除文件 +#### 批量删除文件 ```{javascript} @gist(gist/rs.js#batchDelete) @@ -322,19 +322,19 @@ PutExtra是上传时的可选信息,默认为null ### 云处理 -####查看图像信息 +#### 查看图像信息 ```{javascript} @gist(gist/fop.js#makeImageInfoUrl) ``` -####查看图像Exif +#### 查看图像Exif ```{javascript} @gist(gist/fop.js#makeExifUrl) ``` -####生成缩略图 +#### 生成缩略图 ```{javascript} @gist(gist/fop.js#makeImageViewUrl) diff --git a/docs/README.md b/docs/README.md index 397d1658..c7a78a63 100644 --- a/docs/README.md +++ b/docs/README.md @@ -379,7 +379,7 @@ client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { 当您需要一次性进行多个操作时, 可以使用批量操作。 -####批量获取文件信息 +#### 批量获取文件信息 ```{javascript} var path0 = new qiniu.rs.EntryPath(bucketName, key0); @@ -398,7 +398,7 @@ client.batchStat([path0, path1, path2], function(ret) { }); ``` -####批量复制文件 +#### 批量复制文件 ```{javascript} var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); @@ -419,7 +419,7 @@ client.batchCopy([pair0, pair1], function(ret) { }); ``` -####批量移动文件 +#### 批量移动文件 ```{javascript} var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); @@ -440,7 +440,7 @@ client.batchMove([pair0, pair1], function(ret) { }); ``` -####批量删除文件 +#### 批量删除文件 ```{javascript} var path0 = new qiniu.rs.EntryPath(bucketName, key0); @@ -485,7 +485,7 @@ qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { ### 云处理 -####查看图像信息 +#### 查看图像信息 ```{javascript} // 生成访问图片的url @@ -503,7 +503,7 @@ url = policy.makeRequest(url); console.log('在浏览器输入: ' + url); ``` -####查看图像Exif +#### 查看图像Exif ```{javascript} // 生成访问图片的url @@ -521,7 +521,7 @@ url = policy.makeRequest(url); console.log('在浏览器输入: ' + url); ``` -####生成缩略图 +#### 生成缩略图 ```{javascript} // 生成访问图片的url From 7e16c363d81ef575a1c8633e1985bb6ff11e9774 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Wed, 17 Jul 2013 16:17:52 +0800 Subject: [PATCH 25/41] head space --- docs/README.gist.md | 2 +- docs/README.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 3e91b8c5..2cd99a92 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -310,7 +310,7 @@ PutExtra是上传时的可选信息,默认为null ### 高级管理操作 -####列出文件 +#### 列出文件 请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 ```{javascript} diff --git a/docs/README.md b/docs/README.md index c7a78a63..a645bb84 100644 --- a/docs/README.md +++ b/docs/README.md @@ -463,7 +463,7 @@ client.batchDelete([path0, path1, path2], function(ret) { ### 高级管理操作 -####列出文件 +#### 列出文件 请求某个存储空间(bucket)下的文件列表,如果有前缀,可以按前缀(prefix)进行过滤;第一次调用时置marker为null,之后的调用填上服务器返回的marker(如果有),则列出刚刚为列完的文件 ```{javascript} From 42c6e9ff143c227eb789555710aadaefa7b3a35e Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Wed, 24 Jul 2013 18:05:51 +0800 Subject: [PATCH 26/41] update key --- .travis.yml | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.travis.yml b/.travis.yml index 94087a26..a0331ae1 100644 --- a/.travis.yml +++ b/.travis.yml @@ -4,7 +4,7 @@ node_js: - 0.8 - 0.6 before_script: - - export QINIU_ACCESS_KEY="8Y7uZY0cqHxAyGK27V_B2Bxf8IhAkqEPOHr6iwwc" - - export QINIU_SECRET_KEY="1uvFVvk9IqFRQ6t4TCr-DdeXybTbSS0gauJrYiJN" - - export QINIU_TEST_BUCKET="test963" - - export QINIU_TEST_DOMAIN="test963.qiniudn.com" + - export QINIU_ACCESS_KEY="nnwjTeUgpQdfZp9cb4-iHK0EUlebKCNk4kXwoStq" + - export QINIU_SECRET_KEY="Ia9pXC-XEcGF6hvu1V5fdRhwFLpeUkCbt0Gxk5NW" + - export QINIU_TEST_BUCKET="test741" + - export QINIU_TEST_DOMAIN="test741.qiniudn.com" From c2ac60cb509e1c3c9483aac31401b7730e9c73d7 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Wed, 24 Jul 2013 18:09:54 +0800 Subject: [PATCH 27/41] qiniutek.com -> qiniu.com --- docs/README.gist.md | 4 ++-- docs/README.md | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 2cd99a92..1a6b61f2 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -79,8 +79,8 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h 可以通过如下步骤获得: -1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) -2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://dev.qiniutek.com/account/keys) 。 +1. [开通七牛开发者帐号](https://portal.qiniu.com/signup) +2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://portal.qiniu.com/setting/key) 。 diff --git a/docs/README.md b/docs/README.md index a645bb84..cb16ac82 100644 --- a/docs/README.md +++ b/docs/README.md @@ -79,8 +79,8 @@ Node.js SDK 主要包含对七牛云存储API的包装,遵循[qiniu sdkspec](h 可以通过如下步骤获得: -1. [开通七牛开发者帐号](https://dev.qiniutek.com/signup) -2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://dev.qiniutek.com/account/keys) 。 +1. [开通七牛开发者帐号](https://portal.qiniu.com/signup) +2. [登录七牛开发者自助平台,查看 AccessKey 和 SecretKey](https://portal.qiniu.com/setting/key) 。 From d96376ed43b4145ccddc9f1fb4518b348c13ef46 Mon Sep 17 00:00:00 2001 From: paul-2012 Date: Fri, 26 Jul 2013 15:18:15 +0800 Subject: [PATCH 28/41] get Error: 'First argument needs to be a number, array or string' with mime@1.2.10 buffer.js:238 throw new Error('First argument needs to be a number, ' + ^ Error: First argument needs to be a number, array or string. at new Buffer (buffer.js:238:15) at FormStream.field (./formstream/lib/formstream.js:135:16) at Service.uploadWithToken (./lib/rs.js:146:8) at Object.oncomplete (./lib/rs.js:183:10) --- lib/rs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/rs.js b/lib/rs.js index 3c306483..9f64c0c1 100644 --- a/lib/rs.js +++ b/lib/rs.js @@ -143,7 +143,7 @@ Service.prototype.uploadWithToken = function(uploadToken, stream, key, mimeType, var form = formstream(); form.field('action', actionString); form.field('params', callbackQueryString); - form.field('multipart', true); + form.field('multipart', 'true'); form.field('auth', uploadToken); form.stream('file', stream, filename, mimeType); form = new util.Form(form, form.headers()['Content-Type']); From 5f6d4a603976be4f85301ce521e0d2eb18d5ddc9 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 29 Jul 2013 15:05:55 +0800 Subject: [PATCH 29/41] add travis-ci status image --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 56f6cc31..72673aa8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ Qiniu Resource Storage SDK for Node.js === +[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) [![Qiniu Logo](http://qiniutek.com/images/logo-2.png)](http://qiniu.com/) ## 使用 @@ -17,7 +18,7 @@ Qiniu Resource Storage SDK for Node.js ## 许可证 -Copyright (c) 2012 qiniu.com +Copyright (c) 2013 qiniu.com 基于 MIT 协议发布: From 411ee49856991efa0f0af62cc9a9eee8614e2a31 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 29 Jul 2013 15:13:25 +0800 Subject: [PATCH 30/41] add travis-ci status image --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 72673aa8..292e0494 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,7 @@ Qiniu Resource Storage SDK for Node.js === -[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) +[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) [![Qiniu Logo](http://qiniutek.com/images/logo-2.png)](http://qiniu.com/) ## 使用 From 0b6a8a3eb9a63581270a4961ea722d4da7bb924d Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 30 Jul 2013 13:29:02 +0800 Subject: [PATCH 31/41] rm resumable_io.js --- qiniu/resumable_io.js | 57 ------------------------------------------- 1 file changed, 57 deletions(-) delete mode 100644 qiniu/resumable_io.js diff --git a/qiniu/resumable_io.js b/qiniu/resumable_io.js deleted file mode 100644 index c48e3dc4..00000000 --- a/qiniu/resumable_io.js +++ /dev/null @@ -1,57 +0,0 @@ - - -exports.UNDEDINED_KEY = '?'; -exports.BlkputRet = BlkputRet; -exports.PutExtra = PutExtra; -exports.PutRet = PutRet; -exports.put = put; -exports.putFile = putFile; -exports.blockCount = blockCount; -exports.Settings = Settings; -exports.setSettings = setSettings; - -function BlkputRet(ctx, checksum, crc32, offset) { - this.ctx = ctx || null; - this.checksum = checksum || null; - this.crc32 = crc32 || null; - this.offset = offset || null; -} - -function PutExtra(params, mimeType, chunkSize, tryTimes, - progresses, notify, notifyErr){ - this.params = params || {}; - this.mimeType = mimeType || null; - this.chunkSize = chunkSize || null; - this.tryTimes = tryTimes || null; - this.progresses = progresses || []; - this.notify = notify || null; - this.notifyErr = notifyErr || null; -} - -function PutRet(hash, key) { - this.hash = hash || null; - this.key = key || null; -} - -function put(ret, uptoken, key, f, fsize, extra) { - -} - -function putFile(ret, uptoken, key, localFile, extra) { - -} - -function blockCount(fsize) { - -} - -function Settings(taskQsize, workers, chunkSize, tryTimes) { - this.taskQsize = taskQsize || null; - this.workers = workers || null; - this.chunkSize = chunkSize || 256; // 256k - this.tryTimes = tryTimes || 3; -} - -function setSettings(settings) { - -} From 6c0a3e926ae6d6381871dcecadeb312eb7ea7635 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 30 Jul 2013 13:30:41 +0800 Subject: [PATCH 32/41] add the link of old sdk doc --- README.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README.md b/README.md index 292e0494..92bdfbd1 100644 --- a/README.md +++ b/README.md @@ -6,7 +6,8 @@ Qiniu Resource Storage SDK for Node.js ## 使用 -参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) +参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) +旧版本的SDK(version < 6.0.0) [戳这里](http://docs.qiniutek.com/v3/sdk/nodejs/) ## 贡献代码 From 02c52b3f0a83179bb79e611e3903dcd48b5194c7 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 30 Jul 2013 13:35:26 +0800 Subject: [PATCH 33/41] onret(ret) -> onret(err, ret) --- docs/README.gist.md | 9 +++- docs/README.md | 128 +++++++++++++++++++++++++++++--------------- docs/gist/client.js | 18 ++++--- docs/gist/rs.js | 95 +++++++++++++++++++++----------- docs/gist/rsf.js | 6 +-- qiniu/io.js | 19 +------ qiniu/rpc.js | 22 ++------ qiniu/rs.js | 38 ++----------- qiniu/rsf.js | 13 +---- qiniu/util.js | 26 +++++++++ test/io.test.js | 52 +++++++++--------- test/rs.test.js | 70 ++++++++++++------------ 12 files changed, 266 insertions(+), 230 deletions(-) diff --git a/docs/README.gist.md b/docs/README.gist.md index 1a6b61f2..d36eb940 100644 --- a/docs/README.gist.md +++ b/docs/README.gist.md @@ -279,7 +279,14 @@ PutExtra是上传时的可选信息,默认为null #### 批量操作 -当您需要一次性进行多个操作时, 可以使用批量操作。 +当您需要一次性进行多个操作时, 可以使用批量操作。 +批量操作的几个函数中,当返回值`err`为`null`的时候,有两种情况: + +1. 批量操作的所有操作都成功 +2. 批量操作仅仅部分成功 + +因此在返回成功的时候还需要检查各个子项目的返回值(详细见各个示例)。 +注意:批量操作不是对单个文件操作的包装,而是有独立的接口。 #### 批量获取文件信息 diff --git a/docs/README.md b/docs/README.md index cb16ac82..105e3d65 100644 --- a/docs/README.md +++ b/docs/README.md @@ -221,13 +221,14 @@ function uploadBuf(body, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.put(uptoken, key, body, extra, function(ret) { - if(ret.code === 200) { + io.put(uptoken, key, body, extra, function(err, ret) { + if (!err) { // 上传成功, 处理返回值 - // ret.data.key & ret.data.hash + console.log(ret.key, ret.hash); + // ret.key & ret.hash } else { // 上传失败, 处理返回代码 - // ret.code + console.log(err) // http://docs.qiniu.com/api/put.html#error-code } }); @@ -244,13 +245,14 @@ function uploadFile(localFile, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.putFile(uptoken, key, localFile, extra, function(ret) { - if(ret.code === 200) { + io.putFile(uptoken, key, localFile, extra, function(err, ret) { + if(!err) { // 上传成功, 处理返回值 - // ret.data.key & ret.data.hash + console.log(ret.key, ret.hash); + // ret.key & ret.hash } else { // 上传失败, 处理返回代码 - // ret.code + console.log(err); // http://docs.qiniu.com/api/put.html#error-code } }); @@ -318,12 +320,12 @@ qiniu.conf.SECRET_KEY = ''; ```{javascript} var client = new qiniu.rs.Client(); -client.stat(bucketName, key, function(ret) { - if (ret.code === 200) { - // process - // ret.data has keys (hash, fsize, putTime, mimeType) +client.stat(bucketName, key, function(err, ret) { + if (!err) { + // ok + // ret has keys (hash, fsize, putTime, mimeType) } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -335,11 +337,11 @@ client.stat(bucketName, key, function(ret) { ```{javascript} var client = new qiniu.rs.Client(); -client.remove(bucketName, key, function(ret) { - if (ret.code === 200) { +client.remove(bucketName, key, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }) @@ -351,11 +353,11 @@ client.remove(bucketName, key, function(ret) { ```{javascript} var client = new qiniu.rs.Client(); -client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { - if (ret.code === 200) { +client.copy(bucketSrc, keySrc, bucketDest, keyDest, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -363,11 +365,11 @@ client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { ```{javascript} var client = new qiniu.rs.Client(); -client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { - if (ret.code === 200) { +client.move(bucketSrc, keySrc, bucketDest, keyDest, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -377,7 +379,14 @@ client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { #### 批量操作 -当您需要一次性进行多个操作时, 可以使用批量操作。 +当您需要一次性进行多个操作时, 可以使用批量操作。 +批量操作的几个函数中,当返回值`err`为`null`的时候,有两种情况: + +1. 批量操作的所有操作都成功 +2. 批量操作仅仅部分成功 + +因此在返回成功的时候还需要检查各个子项目的返回值(详细见各个示例)。 +注意:批量操作不是对单个文件操作的包装,而是有独立的接口。 #### 批量获取文件信息 @@ -386,13 +395,20 @@ var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); var client = new qiniu.rs.Client(); -client.batchStat([path0, path1, path2], function(ret) { - if (ret.code === 200) { - // ok, parse ret.data - // each item in ret.data has keys (code, data) - // ret.data[i].data has keys (hash, fsize, putTime, mimeType) + +client.batchStat([path0, path1, path2], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code === 200) { + //ok, ret[i].data has keys (hash, fsize, putTime, mimeType) + } else { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -405,15 +421,24 @@ var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); + var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); + var client = new qiniu.rs.Client(); -client.batchCopy([pair0, pair1], function(ret) { - if (ret.code === 200) { - // ok +client.batchCopy([pair0, pair1], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } + } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -426,15 +451,23 @@ var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); + var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); + var client = new qiniu.rs.Client(); -client.batchMove([pair0, pair1], function(ret) { - if (ret.code === 200) { - // ok +client.batchMove([pair0, pair1], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i] !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -446,13 +479,20 @@ client.batchMove([pair0, pair1], function(ret) { var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); + var client = new qiniu.rs.Client(); -client.batchDelete([path0, path1, path2], function(ret) { - if (ret.code === 200) { - // ok +client.batchDelete([path0, path1, path2], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -470,11 +510,11 @@ client.batchDelete([path0, path1, path2], function(ret) { qiniu.conf.ACCESS_KEY = ''; qiniu.conf.SECRET_KEY = ''; -qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { - if(ret.code === 200) { +qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(err, ret) { + if (!err) { // process ret.data.marker & ret.data.items } else { - // something error, see ret.code according to + console.log(err) // http://docs.qiniu.com/api/file-handle.html#list } }); diff --git a/docs/gist/client.js b/docs/gist/client.js index 4dd31d90..c484cff4 100644 --- a/docs/gist/client.js +++ b/docs/gist/client.js @@ -8,13 +8,14 @@ function uploadFile(localFile, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.putFile(uptoken, key, localFile, extra, function(ret) { - if(ret.code === 200) { + io.putFile(uptoken, key, localFile, extra, function(err, ret) { + if(!err) { // 上传成功, 处理返回值 - // ret.data.key & ret.data.hash + console.log(ret.key, ret.hash); + // ret.key & ret.hash } else { // 上传失败, 处理返回代码 - // ret.code + console.log(err); // http://docs.qiniu.com/api/put.html#error-code } }); @@ -29,13 +30,14 @@ function uploadBuf(body, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.put(uptoken, key, body, extra, function(ret) { - if(ret.code === 200) { + io.put(uptoken, key, body, extra, function(err, ret) { + if (!err) { // 上传成功, 处理返回值 - // ret.data.key & ret.data.hash + console.log(ret.key, ret.hash); + // ret.key & ret.hash } else { // 上传失败, 处理返回代码 - // ret.code + console.log(err) // http://docs.qiniu.com/api/put.html#error-code } }); diff --git a/docs/gist/rs.js b/docs/gist/rs.js index a902d6b0..99ef52dc 100644 --- a/docs/gist/rs.js +++ b/docs/gist/rs.js @@ -8,12 +8,12 @@ qiniu.conf.SECRET_KEY = ''; // @gist stat var client = new qiniu.rs.Client(); -client.stat(bucketName, key, function(ret) { - if (ret.code === 200) { - // process - // ret.data has keys (hash, fsize, putTime, mimeType) +client.stat(bucketName, key, function(err, ret) { + if (!err) { + // ok + // ret has keys (hash, fsize, putTime, mimeType) } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -21,11 +21,11 @@ client.stat(bucketName, key, function(ret) { // @gist move var client = new qiniu.rs.Client(); -client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { - if (ret.code === 200) { +client.move(bucketSrc, keySrc, bucketDest, keyDest, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -33,11 +33,11 @@ client.move(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { // @gist copy var client = new qiniu.rs.Client(); -client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { - if (ret.code === 200) { +client.copy(bucketSrc, keySrc, bucketDest, keyDest, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -45,11 +45,11 @@ client.copy(bucketSrc, keySrc, bucketDestm keyDest, function(ret) { // @gist remove var client = new qiniu.rs.Client(); -client.remove(bucketName, key, function(ret) { - if (ret.code === 200) { +client.remove(bucketName, key, function(err, ret) { + if (!err) { // ok } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }) @@ -60,13 +60,20 @@ var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); var client = new qiniu.rs.Client(); -client.batchStat([path0, path1, path2], function(ret) { - if (ret.code === 200) { - // ok, parse ret.data - // each item in ret.data has keys (code, data) - // ret.data[i].data has keys (hash, fsize, putTime, mimeType) + +client.batchStat([path0, path1, path2], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code === 200) { + //ok, ret[i].data has keys (hash, fsize, putTime, mimeType) + } else { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -77,15 +84,24 @@ var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); + var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); + var client = new qiniu.rs.Client(); -client.batchCopy([pair0, pair1], function(ret) { - if (ret.code === 200) { - // ok +client.batchCopy([pair0, pair1], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } + } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -97,15 +113,23 @@ var pathSrc0 = new qiniu.rs.EntryPath(bucketName, key0); var pathDest0 = new qiniu.rs.EntryPath(bucketName, key1); var pathSrc1 = new qiniu.rs.EntryPath(bucketName, key2); var pathDest1 = new qiniu.rs.EntryPath(bucketName, key3); + var pair0 = new qiniu.rs.EntryPathPair(pathSrc0, pathDest0); var pair1 = new qiniu.rs.EntryPathPair(pathSrc1, pathDest1); + var client = new qiniu.rs.Client(); -client.batchMove([pair0, pair1], function(ret) { - if (ret.code === 200) { - // ok +client.batchMove([pair0, pair1], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i] !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); @@ -115,13 +139,20 @@ client.batchMove([pair0, pair1], function(ret) { var path0 = new qiniu.rs.EntryPath(bucketName, key0); var path1 = new qiniu.rs.EntryPath(bucketName, key1); var path2 = new qiniu.rs.EntryPath(bucketName, key2); + var client = new qiniu.rs.Client(); -client.batchDelete([path0, path1, path2], function(ret) { - if (ret.code === 200) { - // ok +client.batchDelete([path0, path1, path2], function(err, ret) { + if (!err) { + for (i in ret) { + if (ret[i].code !== 200) { + // parse error code + console.log(ret[i].code, ret[i].data); + // http://docs.qiniu.com/api/file-handle.html#error-code + } + } } else { - // something error, process ret.code + console.log(err); // http://docs.qiniu.com/api/file-handle.html#error-code } }); diff --git a/docs/gist/rsf.js b/docs/gist/rsf.js index b5263432..1af064b9 100644 --- a/docs/gist/rsf.js +++ b/docs/gist/rsf.js @@ -4,11 +4,11 @@ var qiniu = require('../../'); qiniu.conf.ACCESS_KEY = ''; qiniu.conf.SECRET_KEY = ''; -qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(ret) { - if(ret.code === 200) { +qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(err, ret) { + if (!err) { // process ret.data.marker & ret.data.items } else { - // something error, see ret.code according to + console.log(err) // http://docs.qiniu.com/api/file-handle.html#list } }); diff --git a/qiniu/io.js b/qiniu/io.js index 5dddf020..ee8fbf41 100644 --- a/qiniu/io.js +++ b/qiniu/io.js @@ -39,28 +39,13 @@ function put(uptoken, key, body, extra, onret) { extra.mimeType = 'application/octet-stream'; } - function parseRet(data) { - var ret = data; - if (ret.code !== 200) { - onret(ret); - return; - } - try { - var dt = JSON.parse(ret.data); - ret.data = dt; - } catch (e) { - ret = {code: -2, error: e.toString()}; - } - onret(ret); - } - if(!key) { key = exports.UNDEFINED_KEY; } var form = getMultipart(uptoken, key, body, extra); - rpc.postMultipart(conf.UP_HOST, form, parseRet); + rpc.postMultipart(conf.UP_HOST, form, onret); } function putWithoutKey(uptoken, body, extra, onret) { @@ -98,7 +83,7 @@ function getMultipart(uptoken, key, body, extra) { function putFile(uptoken, key, loadFile, extra, onret) { fs.readFile(loadFile, function(err, data) { if(err) { - onret({code: -1, error: err.toString(), detail: err}); + onret({code: -1, error: err.toString()}, {}); return; } diff --git a/qiniu/rpc.js b/qiniu/rpc.js index 2b9f3db0..e1dd41aa 100644 --- a/qiniu/rpc.js +++ b/qiniu/rpc.js @@ -7,7 +7,7 @@ exports.postWithForm = postWithForm; exports.postWithoutForm = postWithoutForm; function postMultipart(uri, form, onret) { - post(uri, form, form.headers(), getResp(onret)); + post(uri, form, form.headers(), util.getResp(onret)); } function postWithForm(uri, form, token, onret) { @@ -17,7 +17,7 @@ function postWithForm(uri, form, token, onret) { if (token) { headers['Authorization'] = token; } - post(uri, form, headers, getResp(onret)); + post(uri, form, headers, util.getResp(onret)); } function postWithoutForm(uri, token, onret) { @@ -27,23 +27,7 @@ function postWithoutForm(uri, token, onret) { if (token) { headers['Authorization'] = token; } - post(uri, null, headers, getResp(onret)); -} - -function getResp(onret) { - var onresp = function(res) { - util.readAll(res, function(data) { - var ret = {}; - if (data.length === 0) { - ret = {code: res.statusCode}; - onret(ret); - return; - } - ret = {code: res.statusCode, data: data.toString()}; - onret(ret); - }); - }; - return onresp; + post(uri, null, headers, util.getResp(onret)); } function post(uri, form, headers, onresp) { diff --git a/qiniu/rs.js b/qiniu/rs.js index cc913c53..d683f5ae 100644 --- a/qiniu/rs.js +++ b/qiniu/rs.js @@ -29,21 +29,7 @@ Client.prototype.stat = function(bucket, key, onret) { var uri = conf.RS_HOST + '/stat/' + encodedEntryUri; var digest = util.generateAccessToken(uri, null); - function parseRet(ret) { - if (ret.code != 200 || !ret.data) { - onret(ret); - return; - } - try { - var dt = JSON.parse(ret.data); - ret.data = dt; - } catch (e) { - ret = {code: -2, error: e.toString()}; - } - onret(ret); - } - - rpc.postWithoutForm(uri, digest, parseRet); + rpc.postWithoutForm(uri, digest, onret); } Client.prototype.remove = function(bucket, key, onret) { @@ -117,32 +103,19 @@ function BatchStatItemRet(data, error, code) { } Client.prototype.batchStat = function(entries, onret) { - fileHandle('stat', entries, batchRet(onret)); + fileHandle('stat', entries, onret); } Client.prototype.batchDelete = function(entries, onret) { - fileHandle('delete', entries, batchRet(onret)); + fileHandle('delete', entries, onret); } Client.prototype.batchMove = function(entries, onret) { - fileHandle('move', entries, batchRet(onret)); + fileHandle('move', entries, onret); } Client.prototype.batchCopy = function(entries, onret) { - fileHandle('copy', entries, batchRet(onret)); -} - -function batchRet(onret) { - return function(ret){ - if (ret.data) { - try { - ret.data = JSON.parse(ret.data); - } catch (e) { - ret = {code: -2, error: e.toString()}; - } - } - onret(ret); - } + fileHandle('copy', entries, onret); } function fileHandle(op, entries, onret) { @@ -160,7 +133,6 @@ function getEncodedEntryUri(bucket, key) { return util.urlsafeBase64Encode(bucket + ':' + key); } - // ----- token -------- // @gist PutPolicy function PutPolicy(scope, callbackUrl, callbackBody, returnUrl, returnBody, diff --git a/qiniu/rsf.js b/qiniu/rsf.js index 00c34014..b8b895a6 100644 --- a/qiniu/rsf.js +++ b/qiniu/rsf.js @@ -6,18 +6,7 @@ exports.listPrefix = function(bucket, prefix, marker, limit, onret) { var uri = getPrefixUri(bucket, prefix, marker, limit); var digest = util.generateAccessToken(uri, null); - function parseRet(ret) { - if (ret.code === 200 && ret.data) { - try { - ret.data = JSON.parse(ret.data); - } catch (e) { - ret['error'] = e.toString(); - } - } - onret(ret); - } - - rpc.postWithoutForm(uri, digest, parseRet); + rpc.postWithoutForm(uri, digest, onret) } function getPrefixUri(bucket, prefix, marker, limit) { diff --git a/qiniu/util.js b/qiniu/util.js index b8a51a09..0d238b84 100644 --- a/qiniu/util.js +++ b/qiniu/util.js @@ -73,3 +73,29 @@ exports.generateAccessToken = function(uri, body) { var safeDigest = exports.base64ToUrlSafe(digest); return 'QBox ' + conf.ACCESS_KEY + ':' + safeDigest; } + +// -------------------- +// getResp + +exports.getResp = function(onret) { + var onresp = function(res) { + exports.readAll(res, function(data) { + var ret = {}; + var err = {}; + + if (Math.floor(res.statusCode/100) === 2) { + if (data.length !== 0) { + try { + ret = JSON.parse(data); + } catch (e) { + } + } + } else { + err = {code: res.statusCode, error: data.toString()}; + } + onret(err, ret); + }) + }; + + return onresp; +} diff --git a/test/io.test.js b/test/io.test.js index e8651246..6f0c0425 100644 --- a/test/io.test.js +++ b/test/io.test.js @@ -29,8 +29,8 @@ describe('test start step1:', function() { } var client = new qiniu.rs.Client(); - client.batchDelete(entries, function(ret) { - ret.code.should.equal(200); + client.batchDelete(entries, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -47,11 +47,11 @@ describe('test start step1:', function() { describe('io.put()', function() { it('test upload from memory', function(done) { var key = 'filename' + Math.random(1000); - qiniu.io.put(uptoken, key, 'content', null, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('hash', 'key'); - ret.data.key.should.equal(key); - keys.push(ret.data.key); + qiniu.io.put(uptoken, key, 'content', null, function(err, ret) { + err.should.eql({}); + ret.should.have.keys('hash', 'key'); + ret.key.should.equal(key); + keys.push(ret.key); done(); }); }); @@ -60,11 +60,11 @@ describe('test start step1:', function() { describe('io.putWithoutKey()', function() { it('test upload from memory without key', function(done) { var content = 'content' + Math.random(1000); - qiniu.io.putWithoutKey(uptoken, content, null, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('hash', 'key'); - ret.data.key.should.equal(ret.data.hash); - keys.push(ret.data.key); + qiniu.io.putWithoutKey(uptoken, content, null, function(err, ret) { + err.should.eql({}); + ret.should.have.keys('hash', 'key'); + ret.key.should.equal(ret.hash); + keys.push(ret.key); done(); }); }); @@ -73,11 +73,11 @@ describe('test start step1:', function() { describe('io.putFile()', function() { it('test upload from a file', function(done) { var key = Math.random() + 'logo.png'; - qiniu.io.putFile(uptoken, key, imageFile, null, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('key', 'hash'); - ret.data.key.should.equal(key); - keys.push(ret.data.key); + qiniu.io.putFile(uptoken, key, imageFile, null, function(err, ret) { + err.should.eql({}); + ret.should.have.keys('key', 'hash'); + ret.key.should.equal(key); + keys.push(ret.key); done(); }); }); @@ -86,11 +86,11 @@ describe('test start step1:', function() { var extra = new qiniu.io.PutExtra(); extra.checkCrc = 1; var key = Math.random() + 'logo_crc32.png'; - qiniu.io.putFile(uptoken, key, imageFile, extra, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('key', 'hash'); - ret.data.key.should.equal(key); - keys.push(ret.data.key); + qiniu.io.putFile(uptoken, key, imageFile, extra, function(err, ret) { + err.should.eql({}); + ret.should.have.keys('key', 'hash'); + ret.key.should.equal(key); + keys.push(ret.key); done(); }); }); @@ -114,12 +114,12 @@ describe('test start step1:', function() { describe('file handle', function() { describe('rsf.listPrefix()', function() { it('list all file in test bucket', function(done) { - qiniu.rsf.listPrefix(TEST_BUCKET, null, null, null, function(ret) { - ret.code.should.equal(200); + qiniu.rsf.listPrefix(TEST_BUCKET, null, null, null, function(err, ret) { + err.should.eql({}); // ret.data.items.length.should.equal(keys.length); for (i in ret.items) { - ret.data.items[i].should.has.keys('key', 'time', 'hash', 'fsize', 'mimeType', 'customer'); - keys.indexOf(ret.data.items[i].key).should.above(-1); + ret.items[i].should.have.keys('key', 'putTime', 'hash', 'fsize', 'mimeType'); + keys.indexOf(ret.items[i].key).should.above(-1); } done(); }); diff --git a/test/rs.test.js b/test/rs.test.js index 9ac0288f..f2579ee1 100644 --- a/test/rs.test.js +++ b/test/rs.test.js @@ -27,20 +27,20 @@ describe('test start step2:', function() { before(function(done) { var putPolicy = new qiniu.rs.PutPolicy(TEST_BUCKET); var uptoken = putPolicy.token(); - qiniu.io.putFile(uptoken, logo2, imageFile, null, function(ret) { - ret.code.should.equal(200); + qiniu.io.putFile(uptoken, logo2, imageFile, null, function(err, ret) { + err.should.eql({}); }); - qiniu.io.putFile(uptoken, logo, imageFile, null, function(ret) { - ret.code.should.equal(200); + qiniu.io.putFile(uptoken, logo, imageFile, null, function(err, ret) { + err.should.eql({}); done(); }); }); describe('rs.Client#stat()', function() { it('get the stat of a file', function(done) { - client.stat(TEST_BUCKET, logo, function(ret) { - ret.code.should.equal(200); - ret.data.should.have.keys('hash', 'fsize', 'putTime', 'mimeType'); + client.stat(TEST_BUCKET, logo, function(err, ret) { + err.should.eql({}); + ret.should.have.keys('hash', 'fsize', 'putTime', 'mimeType'); done(); }); }); @@ -48,8 +48,8 @@ describe('test start step2:', function() { describe('rs.Client#copy()', function() { it('copy logo.png to logo1.png', function(done) { - client.copy(TEST_BUCKET, logo, TEST_BUCKET, logo1, function(ret) { - ret.code.should.equal(200); + client.copy(TEST_BUCKET, logo, TEST_BUCKET, logo1, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -57,8 +57,8 @@ describe('test start step2:', function() { describe('rs.Client#remove()', function() { it('remove logo.png', function(done) { - client.remove(TEST_BUCKET, logo, function(ret) { - ret.code.should.equal(200); + client.remove(TEST_BUCKET, logo, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -66,8 +66,8 @@ describe('test start step2:', function() { describe('rs.Client#move()', function() { it('move logo1.png to logo.png', function(done) { - client.move(TEST_BUCKET, logo1, TEST_BUCKET, logo, function(ret) { - ret.code.should.equal(200); + client.move(TEST_BUCKET, logo1, TEST_BUCKET, logo, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -79,8 +79,8 @@ describe('test start step2:', function() { after(function(done) { var entries = [new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; - client.batchDelete(entries, function(ret) { - ret.code.should.equal(200); + client.batchDelete(entries, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -91,12 +91,12 @@ describe('test start step2:', function() { new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; - client.batchStat(entries, function(ret) { - ret.code.should.equal(200); - ret.data.length.should.equal(2); - for (i in ret.data) { - ret.data[i].code.should.equal(200); - ret.data[i].data.should.have.keys('fsize', 'hash', 'mimeType', 'putTime'); + client.batchStat(entries, function(err, ret) { + err.should.eql({}); + ret.length.should.equal(2); + for (i in ret) { + ret[i].code.should.equal(200); + ret[i].data.should.have.keys('fsize', 'hash', 'mimeType', 'putTime'); } done(); }); @@ -108,15 +108,14 @@ describe('test start step2:', function() { new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, 'not exist file')]; - client.batchStat(entries, function(ret) { + client.batchStat(entries, function(err, ret) { + err.should.eql({}); // 298 + ret.length.should.equal(2); - ret.code.should.equal(298); - ret.data.length.should.equal(2); - - for (i in ret.data) { - if (ret.data[i].code !== 200) { - ret.data[i].code.should.equal(612); - ret.data[i].data.should.have.keys('error'); + for (i in ret) { + if (ret[i].code !== 200) { + ret[i].code.should.equal(612); + ret[i].data.should.have.keys('error'); } } @@ -132,8 +131,9 @@ describe('test start step2:', function() { entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo2), new EntryPath(TEST_BUCKET, logo3))); it('copy from logo, logo2 to logo1, logo3', function(done) { - client.batchCopy(entries, function(ret) { - ret.code.should.equal(200); + client.batchCopy(entries, function(err, ret) { + err.should.eql({}); + console.log(ret); done(); }); }); @@ -143,8 +143,8 @@ describe('test start step2:', function() { var entries = [new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; it('delete logo.png, logo2.png', function(done) { - client.batchDelete(entries, function(ret) { - ret.code.should.equal(200); + client.batchDelete(entries, function(err, ret) { + err.should.eql({}); done(); }); }); @@ -156,8 +156,8 @@ describe('test start step2:', function() { entries.push(new EntryPathPair(new EntryPath(TEST_BUCKET, logo3), new EntryPath(TEST_BUCKET, logo2))); it('move from logo1.png, logo3.png to logo.png, logo2.png', function(done) { - client.batchMove(entries, function(ret) { - ret.code.should.equal(200); + client.batchMove(entries, function(err, ret) { + err.should.eql({}); done(); }); }); From 15afcd06d108e7c6bfb8b8483e6044d733969cc2 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 30 Jul 2013 13:42:15 +0800 Subject: [PATCH 34/41] for travis-ci parallel test --- test/io.test.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/io.test.js b/test/io.test.js index 6f0c0425..0a3ba28a 100644 --- a/test/io.test.js +++ b/test/io.test.js @@ -119,7 +119,7 @@ describe('test start step1:', function() { // ret.data.items.length.should.equal(keys.length); for (i in ret.items) { ret.items[i].should.have.keys('key', 'putTime', 'hash', 'fsize', 'mimeType'); - keys.indexOf(ret.items[i].key).should.above(-1); +// keys.indexOf(ret.items[i].key).should.above(-1); } done(); }); From c6982d5059fc2a61a5bccb0e10b374245282eff4 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 30 Jul 2013 13:53:17 +0800 Subject: [PATCH 35/41] update gist:rsf --- docs/README.md | 2 +- docs/gist/rsf.js | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/docs/README.md b/docs/README.md index 105e3d65..38d52b22 100644 --- a/docs/README.md +++ b/docs/README.md @@ -512,7 +512,7 @@ qiniu.conf.SECRET_KEY = ''; qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(err, ret) { if (!err) { - // process ret.data.marker & ret.data.items + // process ret.marker & ret.items } else { console.log(err) // http://docs.qiniu.com/api/file-handle.html#list diff --git a/docs/gist/rsf.js b/docs/gist/rsf.js index 1af064b9..5ec707e0 100644 --- a/docs/gist/rsf.js +++ b/docs/gist/rsf.js @@ -6,7 +6,7 @@ qiniu.conf.SECRET_KEY = ''; qiniu.rsf.listPrefix(bucketname, prefix, marker, limit, function(err, ret) { if (!err) { - // process ret.data.marker & ret.data.items + // process ret.marker & ret.items } else { console.log(err) // http://docs.qiniu.com/api/file-handle.html#list From 48b149fc6d88f5fb433fbe783ddbd68e57dc0a11 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 6 Aug 2013 13:54:26 +0800 Subject: [PATCH 36/41] update README --- README.md | 28 +++- lib/rs.js | 410 ------------------------------------------------------ 2 files changed, 25 insertions(+), 413 deletions(-) delete mode 100644 lib/rs.js diff --git a/README.md b/README.md index 92bdfbd1..adfac2d5 100644 --- a/README.md +++ b/README.md @@ -1,12 +1,34 @@ -Qiniu Resource Storage SDK for Node.js +# Qiniu Resource Storage SDK for Node.js === -[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) +[![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) + [![Qiniu Logo](http://qiniutek.com/images/logo-2.png)](http://qiniu.com/) +## 下载 + +### 从 npm 安装 + +这是我们建议的方式 + +``` +npm node qiniu +``` + +### 从 release 版本下载 + +下载地址:https://github.com/qiniu/nodejs-sdk/releases + +这里可以下载到旧版本的SDK,release 版本有版本号,有 [CHANGELOG](https://github.com/qiniu/nodejs-sdk/blob/develop/CHANGELOG.md),使用规格也会比较稳定。 + +### 从 git 库下载 + +你可以直接用 git clone 下载源代码来使用。但是请注意非 master 分支的代码在规格上可能承受变更,应谨慎使用。 + ## 使用 -参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) +参考文档:[七牛云存储 Node.js SDK 使用指南](https://github.com/qiniu/nodejs-sdk/tree/develop/docs) + 旧版本的SDK(version < 6.0.0) [戳这里](http://docs.qiniutek.com/v3/sdk/nodejs/) ## 贡献代码 diff --git a/lib/rs.js b/lib/rs.js deleted file mode 100644 index 9f64c0c1..00000000 --- a/lib/rs.js +++ /dev/null @@ -1,410 +0,0 @@ -var fs = require('fs'); -var path = require('path'); -var crc32 = require('crc32'); -var mime = require('mime'); -var formstream = require('formstream'); -var querystring = require('querystring'); -var config = require('./conf.js'); -var util = require('./util.js'); -var img = require('./img.js'); - -exports.Service = Service; -exports.mkbucket = function(conn, bucketname, onret) { - var url = config.RS_HOST + '/mkbucket/' + bucketname; - conn.callWith(url, null, onret); -}; - -// ------------------------------------------------------------------------------------------ -// type Service - -function Service(conn, bucket) { - this.conn = conn; - this.bucket = bucket; -} - -Service.prototype.buckets = function(onret) { - var url = config.RS_HOST + '/buckets'; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.putAuth = function(onret) { - /* - * func PutAuth() => PutAuthRet - * 上传授权(生成一个短期有效的可匿名上传URL) - **/ - var url = config.IO_HOST + '/put-auth/'; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.putAuthEx = function(expires, callbackUrl, onret) { - /* - * func PutAuthEx(expires, callbackUrl) => PutAuthRet - * 上传授权(生成一个短期有效的可匿名上传URL) - **/ - var url = config.IO_HOST + '/put-auth/' + expires + '/callback/' + util.encode(callbackUrl); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.put = function(key, mimeType, fp, bytes, onret) { - /* - * func Put(key string, mimeType string, fp File, bytes int64) => (data PutRet, code int, err Error) - * 上传一个流 - **/ - if (!mimeType) { - mimeType = 'application/octet-stream'; - } - var entryURI = this.bucket + ':' + key; - var url = config.IO_HOST + '/rs-put/' + util.encode(entryURI) + '/mimeType/' + util.encode(mimeType); - var binary = new util.Binary(fp, bytes); - return this.conn.callWith(url, binary, onret); -}; - -Service.prototype.putFile = function(key, mimeType, localFile, onret) { - /* - * func PutFile(key string, mimeType string, localFile string) => (data PutRet, code int, err Error) - * 上传文件 - **/ - var self = this; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var fp = fs.createReadStream(localFile); - self.put(key, mimeType, fp, fi.size, onret); - }); -}; - -Service.prototype.upload = function(upToken, key, mimeType, filename, stream, onret) { - /* - * func Upload(upToken string, key string, mimeType string, filename string, stream ReadStream) => (data PutRet, code int, err Error) - * 以multipart/form-data形式上传ReadStream - **/ - var self = this; - if (!mimeType) { - mimeType = "application/octet-stream"; - } - var entryURI = this.bucket + ':' + key; - entryURI = '/rs-put/' + util.encode(entryURI) + '/mimeType/' + util.encode(mimeType); - - var form = formstream(); - form.field('action', entryURI); - form.stream('file', stream, filename, mimeType); - - form = new util.Form(form, form.headers()['Content-Type']); - return this.conn.callWith(upToken, form, onret); -}; - -Service.prototype.uploadFile = function(upToken, key, mimeType, localFile, onret) { - /* - * func UploadFile(upToken string, key string, mimeType string, localFile string) => (data PutRet, code int, err Error) - * 以multipart/form-data形式上传文件 - **/ - var self = this; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var filename = path.basename(localFile); - var stream = fs.createReadStream(localFile); - self.upload(upToken, key, mimeType, filename, stream, onret); - }); -}; - -Service.prototype.uploadWithToken = function(uploadToken, stream, key, mimeType, customMeta, callbackParams, crc32, onret) { - /* - * func UploadWithToken(uploadToken, stream, key, mimeType, customMeta, callbackParams, crc32, onret) => (data PutRet, code int, err Error) - * 使用upload_token以multipart/form-data形式上传ReadStream流 - **/ - var bucket = this.bucket; - if (!mimeType) { - mimeType = "application/octet-stream"; - } - - var actionString = util.generateActionString(bucket, key, mimeType, customMeta, crc32); - if (callbackParams === null) { - callbackParams = { - "bucket": bucket, - "key": key, - "mime_type": mimeType - }; - } - var callbackQueryString = querystring.stringify(callbackParams); - var url = config.UP_HOST + "/upload"; - - var filename = path.basename(key); - var form = formstream(); - form.field('action', actionString); - form.field('params', callbackQueryString); - form.field('multipart', 'true'); - form.field('auth', uploadToken); - form.stream('file', stream, filename, mimeType); - form = new util.Form(form, form.headers()['Content-Type']); - - return this.conn.callWithToken(uploadToken, url, form, onret); -}; - -Service.prototype.uploadFileWithToken = function(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, onret) { - /* - * func UploadFileWithToken(uploadToken, localFile, key, mimeType, customMeta, callbackParams, enableCrc32Check, onret) => (data PutRet, code int, err Error) - * 使用upload_token以multipart/form-data形式上传文件 - **/ - var self = this - , bucket = self.bucket; - if (!mimeType) { - mimeType = mime.lookup(localFile); - } - fs.stat(localFile, function(err, fi) { - if (err) { - onret({code: -1, error: err.toString(), detail: err}); - return; - } - var fileCrc32 = null - , stream = fs.createReadStream(localFile); - - if (enableCrc32Check) { - var fileStat = fs.statSync(localFile) - , fileSize = fileStat.size - , buf = new Buffer(fileSize) - , fd = fs.openSync(localFile, 'r'); - - fs.readSync(fd, buf, 0, fileSize, 0); - fs.closeSync(fd); - fileCrc32 = parseInt("0x" + crc32(buf)).toString(); - } - - self.uploadWithToken(uploadToken, stream, key, mimeType, customMeta, callbackParams, fileCrc32, onret); - }); -}; - -Service.prototype.get = function(key, attName, onret) { - /* - * func Get(key string, attName string) => GetRet - * 下载授权(生成一个短期有效的可匿名下载URL) - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/get/' + util.encode(entryURI) + '/attName/' + util.encode(attName); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.getIfNotModified = function(key, attName, base, onret) { - /* - * func GetIfNotModified(key string, attName string, base string) => GetRet - * 下载授权(生成一个短期有效的可匿名下载URL),如果服务端文件没被人修改的话(用于断点续传) - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/get/' + util.encode(entryURI) + '/attName/' + util.encode(attName) + '/base/' + base; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.stat = function(key, onret) { - /* - * func Stat(key string) => Entry - * 取资源属性 - */ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/stat/' + util.encode(entryURI); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.publish = function(domain, onret) { - /* - * func Publish(domain string) => Bool - * 将本 Table 的内容作为静态资源发布。静态资源的url为:http://domain/key - **/ - var url = config.RS_HOST + '/publish/' + util.encode(domain) + '/from/' + this.bucket; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.unpublish = function(domain, onret) { - /* - * func Unpublish(domain string) => Bool - * 取消发布 - */ - var url = config.RS_HOST + '/unpublish/' + util.encode(domain); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.remove = function(key, onret) { - /* - * func Delete(key string) => Bool - * 删除资源 - **/ - var entryURI = this.bucket + ':' + key; - var url = config.RS_HOST + '/delete/' + util.encode(entryURI); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.drop = function(onret) { - /* - * func Drop() => Bool - * 删除整个表(慎用!) - **/ - var url = config.RS_HOST + '/drop/' + this.bucket; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.copy = function(sourceBucket, sourceKey, targetBucket, targetKey, onret) { - /* - * func Copy(sourceBucket, sourceKey, targetBucket, targetKey, onret) => Bool - * 拷贝某个资源表中的文件到另一个资源表中的某个文件 - */ - var url = config.RS_HOST + generateMoveOrCopyOpString('copy', sourceBucket, sourceKey, targetBucket, targetKey); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.move = function(sourceBucket, sourceKey, targetBucket, targetKey, onret) { - /* - * func Move(sourceBucket, sourceKey, targetBucket, targetKey, onret) => Bool - * 移动某个资源表中的文件到另一个资源表中的某个文件 - */ - var url = config.RS_HOST + generateMoveOrCopyOpString('move', sourceBucket, sourceKey, targetBucket, targetKey); - this.conn.callWith(url, null, onret); -}; - -Service.prototype.batchGet = function(bucket, keys, onret) { - /* - * func BatchGet(bucket, keys, onret) => GetRet[] - * 为每个key生成一个短期有效的下载地址 - */ - batch(this, "get", bucket, keys, onret); -}; - -Service.prototype.batchStat = function(bucket, keys, onret) { - /* - * func BatchStat(bucket, keys, onret) => Entry[] - * 查看每个key所对应文件的属性 - */ - batch(this, "stat", bucket, keys, onret); -}; - -Service.prototype.batchDelete = function(bucket, keys, onret) { - /* - * func BatchDelete(bucket, keys, onret) => Bool[] - * 批量删除每个key所对应的资源 - */ - batch(this, "delete", bucket, keys, onret); -}; - -Service.prototype.batchCopy = function(entries, onret) { - /* - * func BatchCopy(entries, onret) => Bool[] - * 批量拷贝文件 - */ - batchMoveOrCopy(this, 'copy', entries, onret); -}; - -Service.prototype.batchMove = function(entries, onret) { - /* - * func BatchMove(entries, onret) => Bool[] - * 批量移动文件 - */ - batchMoveOrCopy(this, 'move', entries, onret); -}; - -/* - * 持久化存储一个经过云端服务处理过后的资源 - */ -Service.prototype.saveAs = function(key, source_url, opWithParams, onret) { - var destEntryURI = this.bucket + ':' + key; - var saveAsEntryURI = util.encode(destEntryURI); - var saveAsParam = "/save-as/" + saveAsEntryURI; - var newurl = source_url + '?' + opWithParams + saveAsParam; - this.conn.callWith(newurl, null, onret); -}; - -/* - * 图像处理接口(可持久化存储缩略图) - * func imageMogrifyAs(, , , ) => Entry - * opts = { - * "thumbnail": , - * "gravity": , =NorthWest, North, NorthEast, West, Center, East, SouthWest, South, SouthEast - * "crop": , - * "quality": , - * "rotate": , - * "format": , =jpg, gif, png, tif, etc. - * "auto_orient": - * } - */ -Service.prototype.imageMogrifyAs = function(key, source_img_url, opts, onret) { - var mogrifyParams = img.mkMogrifyParams(opts); - this.saveAs(key, source_img_url, mogrifyParams, onret); -}; - -/* - * 水印设置接口 - * setProtected() - 设置原图保护 - * setSeparator() - 设置分隔符 - * setStyle() - 设置图片预览风格别名 - * unsetStyle() - 取消设置图片预览风格别名 -*/ -Service.prototype.setProtected = function(protectedMode, onret){ - var url = config.PUB_HOST + "/accessMode/" + this.bucket + "/mode/" + protectedMode; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.setSeparator = function(sep, onret){ - sep = util.encode(sep); - var url = config.PUB_HOST + "/separator/" + this.bucket + "/sep/" + sep; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.setStyle = function(name, style, onret){ - name = util.encode(name); - style = util.encode(style); - var url = config.PUB_HOST + "/style/" + this.bucket + "/name/" + name + "/style/" + style; - this.conn.callWith(url, null, onret); -}; - -Service.prototype.unsetStyle = function(name, onret){ - name = util.encode(name); - var url = config.PUB_HOST + "/unstyle/" + this.bucket + "/name/" + name; - this.conn.callWith(url, null, onret); -}; - - -// ------------------------------------------------------------------------------------------ -// private functions - -function generateMoveOrCopyOpString(command, sourceBucket, sourceKey, targetBucket, targetKey) { - var sourceEntryURI = sourceBucket + ":" + sourceKey; - var targetEntryURI = targetBucket + ":" + targetKey; - var url = '/' + command + '/' + util.encode(sourceEntryURI) + '/' + util.encode(targetEntryURI); - return url; -}; - -function batch(rs, command, bucket, keys, onret) { - var ops = [] - , length = keys.length - , url = config.RS_HOST + '/batch?'; - - for(var i = 0; i < length; i++) { - console.log("Entry URI is: ", bucket + ":" + keys[i]); - var encodedEntryURI = util.encode(bucket + ":" + keys[i]); - ops.push("op=/" + command + "/" + encodedEntryURI); - } - url += ops.join("&"); - console.log("Batch URL: ", url); - rs.conn.callWith(url, null, onret); -} - -function batchMoveOrCopy(rs, command, entries, onret) { - var ops = [] - , length = ops.length - , url = config.RS_HOST + '/batch?'; - - for(var i = 0; i < length; i++) { - ops.push('op=' + moveOrCopy(command, entries[i][0], entries[i][1], entries[i][2], entries[i][3])); - } - url += ops.join("&"); - rs.conn.callWith(url, null, onret); -} - -// ------------------------------------------------------------------------------------------ From 8ff631815e4783de28551a2d979f144ebcb86851 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 6 Aug 2013 13:58:55 +0800 Subject: [PATCH 37/41] update --- README.md | 1 - 1 file changed, 1 deletion(-) diff --git a/README.md b/README.md index adfac2d5..fff3b86d 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,4 @@ # Qiniu Resource Storage SDK for Node.js -=== [![Build Status](https://travis-ci.org/qiniu/nodejs-sdk.png?branch=master)](https://travis-ci.org/qiniu/nodejs-sdk) From f4c73cd32871b95f854f3eb28b8c8834047d86b4 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Tue, 6 Aug 2013 14:09:52 +0800 Subject: [PATCH 38/41] update --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index fff3b86d..0ac540a0 100644 --- a/README.md +++ b/README.md @@ -11,7 +11,7 @@ 这是我们建议的方式 ``` -npm node qiniu +npm install qiniu ``` ### 从 release 版本下载 From 7c2b7e8b2cb4c8fc0ffe518e2c343ad2032fd84a Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Thu, 8 Aug 2013 17:21:55 +0800 Subject: [PATCH 39/41] update --- docs/README.md | 8 ++++---- docs/gist/client.js | 4 ++-- docs/gist/server.js | 6 +++--- 3 files changed, 9 insertions(+), 9 deletions(-) diff --git a/docs/README.md b/docs/README.md index 38d52b22..ff18a924 100644 --- a/docs/README.md +++ b/docs/README.md @@ -221,7 +221,7 @@ function uploadBuf(body, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.put(uptoken, key, body, extra, function(err, ret) { + qiniu.io.put(uptoken, key, body, extra, function(err, ret) { if (!err) { // 上传成功, 处理返回值 console.log(ret.key, ret.hash); @@ -245,7 +245,7 @@ function uploadFile(localFile, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.putFile(uptoken, key, localFile, extra, function(err, ret) { + qiniu.io.putFile(uptoken, key, localFile, extra, function(err, ret) { if(!err) { // 上传成功, 处理返回值 console.log(ret.key, ret.hash); @@ -285,8 +285,8 @@ function uploadFile(localFile, key, uptoken) { ```{javascript} function downloadUrl(domain, key) { - var baseUrl = rs.makeBaseUrl(domain, key); - var policy = new rs.GetPolicy(); + var baseUrl = qiniu.rs.makeBaseUrl(domain, key); + var policy = new qiniu.rs.GetPolicy(); return policy.makeRequest(baseUrl); } ``` diff --git a/docs/gist/client.js b/docs/gist/client.js index c484cff4..c9e9e220 100644 --- a/docs/gist/client.js +++ b/docs/gist/client.js @@ -8,7 +8,7 @@ function uploadFile(localFile, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.putFile(uptoken, key, localFile, extra, function(err, ret) { + qiniu.io.putFile(uptoken, key, localFile, extra, function(err, ret) { if(!err) { // 上传成功, 处理返回值 console.log(ret.key, ret.hash); @@ -30,7 +30,7 @@ function uploadBuf(body, key, uptoken) { //extra.crc32 = crc32; //extra.checkCrc = checkCrc; - io.put(uptoken, key, body, extra, function(err, ret) { + qiniu.io.put(uptoken, key, body, extra, function(err, ret) { if (!err) { // 上传成功, 处理返回值 console.log(ret.key, ret.hash); diff --git a/docs/gist/server.js b/docs/gist/server.js index c2f505eb..02905930 100644 --- a/docs/gist/server.js +++ b/docs/gist/server.js @@ -1,4 +1,4 @@ -var qiniu = require('../..'); +var qiniu = require('../../'); // @gist init qiniu.conf.ACCESS_KEY = '' @@ -21,8 +21,8 @@ function uptoken(bucketname) { // @gist downloadUrl function downloadUrl(domain, key) { - var baseUrl = rs.makeBaseUrl(domain, key); - var policy = new rs.GetPolicy(); + var baseUrl = qiniu.rs.makeBaseUrl(domain, key); + var policy = new qiniu.rs.GetPolicy(); return policy.makeRequest(baseUrl); } // @endgist From db45cc9d8b3b9a240ee87cdd0cc8e1cc427206a9 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Sat, 10 Aug 2013 13:52:26 +0800 Subject: [PATCH 40/41] {} -> nil --- qiniu/util.js | 3 +-- test/io.test.js | 12 ++++++------ test/rs.test.js | 24 ++++++++++++------------ 3 files changed, 19 insertions(+), 20 deletions(-) diff --git a/qiniu/util.js b/qiniu/util.js index 0d238b84..a26a9e8d 100644 --- a/qiniu/util.js +++ b/qiniu/util.js @@ -80,8 +80,7 @@ exports.generateAccessToken = function(uri, body) { exports.getResp = function(onret) { var onresp = function(res) { exports.readAll(res, function(data) { - var ret = {}; - var err = {}; + var err, ret; if (Math.floor(res.statusCode/100) === 2) { if (data.length !== 0) { diff --git a/test/io.test.js b/test/io.test.js index 0a3ba28a..1d77bd5d 100644 --- a/test/io.test.js +++ b/test/io.test.js @@ -30,7 +30,7 @@ describe('test start step1:', function() { var client = new qiniu.rs.Client(); client.batchDelete(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -48,7 +48,7 @@ describe('test start step1:', function() { it('test upload from memory', function(done) { var key = 'filename' + Math.random(1000); qiniu.io.put(uptoken, key, 'content', null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.should.have.keys('hash', 'key'); ret.key.should.equal(key); keys.push(ret.key); @@ -61,7 +61,7 @@ describe('test start step1:', function() { it('test upload from memory without key', function(done) { var content = 'content' + Math.random(1000); qiniu.io.putWithoutKey(uptoken, content, null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.should.have.keys('hash', 'key'); ret.key.should.equal(ret.hash); keys.push(ret.key); @@ -74,7 +74,7 @@ describe('test start step1:', function() { it('test upload from a file', function(done) { var key = Math.random() + 'logo.png'; qiniu.io.putFile(uptoken, key, imageFile, null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.should.have.keys('key', 'hash'); ret.key.should.equal(key); keys.push(ret.key); @@ -87,7 +87,7 @@ describe('test start step1:', function() { extra.checkCrc = 1; var key = Math.random() + 'logo_crc32.png'; qiniu.io.putFile(uptoken, key, imageFile, extra, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.should.have.keys('key', 'hash'); ret.key.should.equal(key); keys.push(ret.key); @@ -115,7 +115,7 @@ describe('test start step1:', function() { describe('rsf.listPrefix()', function() { it('list all file in test bucket', function(done) { qiniu.rsf.listPrefix(TEST_BUCKET, null, null, null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); // ret.data.items.length.should.equal(keys.length); for (i in ret.items) { ret.items[i].should.have.keys('key', 'putTime', 'hash', 'fsize', 'mimeType'); diff --git a/test/rs.test.js b/test/rs.test.js index f2579ee1..75024600 100644 --- a/test/rs.test.js +++ b/test/rs.test.js @@ -28,10 +28,10 @@ describe('test start step2:', function() { var putPolicy = new qiniu.rs.PutPolicy(TEST_BUCKET); var uptoken = putPolicy.token(); qiniu.io.putFile(uptoken, logo2, imageFile, null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); }); qiniu.io.putFile(uptoken, logo, imageFile, null, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -39,7 +39,7 @@ describe('test start step2:', function() { describe('rs.Client#stat()', function() { it('get the stat of a file', function(done) { client.stat(TEST_BUCKET, logo, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.should.have.keys('hash', 'fsize', 'putTime', 'mimeType'); done(); }); @@ -49,7 +49,7 @@ describe('test start step2:', function() { describe('rs.Client#copy()', function() { it('copy logo.png to logo1.png', function(done) { client.copy(TEST_BUCKET, logo, TEST_BUCKET, logo1, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -58,7 +58,7 @@ describe('test start step2:', function() { describe('rs.Client#remove()', function() { it('remove logo.png', function(done) { client.remove(TEST_BUCKET, logo, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -67,7 +67,7 @@ describe('test start step2:', function() { describe('rs.Client#move()', function() { it('move logo1.png to logo.png', function(done) { client.move(TEST_BUCKET, logo1, TEST_BUCKET, logo, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -80,7 +80,7 @@ describe('test start step2:', function() { var entries = [new EntryPath(TEST_BUCKET, logo), new EntryPath(TEST_BUCKET, logo2)]; client.batchDelete(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -92,7 +92,7 @@ describe('test start step2:', function() { new EntryPath(TEST_BUCKET, logo2)]; client.batchStat(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); ret.length.should.equal(2); for (i in ret) { ret[i].code.should.equal(200); @@ -109,7 +109,7 @@ describe('test start step2:', function() { new EntryPath(TEST_BUCKET, 'not exist file')]; client.batchStat(entries, function(err, ret) { - err.should.eql({}); // 298 + should.not.exist(err); // 298 ret.length.should.equal(2); for (i in ret) { @@ -132,7 +132,7 @@ describe('test start step2:', function() { it('copy from logo, logo2 to logo1, logo3', function(done) { client.batchCopy(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); console.log(ret); done(); }); @@ -144,7 +144,7 @@ describe('test start step2:', function() { it('delete logo.png, logo2.png', function(done) { client.batchDelete(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); @@ -157,7 +157,7 @@ describe('test start step2:', function() { it('move from logo1.png, logo3.png to logo.png, logo2.png', function(done) { client.batchMove(entries, function(err, ret) { - err.should.eql({}); + should.not.exist(err); done(); }); }); From 5399e17411767dbc8de23fcdebc6f5aa608b54f6 Mon Sep 17 00:00:00 2001 From: lintianzhi Date: Mon, 12 Aug 2013 11:37:44 +0800 Subject: [PATCH 41/41] fix catch return empty --- qiniu/util.js | 1 + 1 file changed, 1 insertion(+) diff --git a/qiniu/util.js b/qiniu/util.js index a26a9e8d..b8e99569 100644 --- a/qiniu/util.js +++ b/qiniu/util.js @@ -87,6 +87,7 @@ exports.getResp = function(onret) { try { ret = JSON.parse(data); } catch (e) { + err = {code: res.statusCode, err: e.toString()}; } } } else {