From 8a1540593b8f7e20db0cb347ca9e4144adc1ff56 Mon Sep 17 00:00:00 2001 From: 404 Date: Wed, 23 May 2012 20:59:03 +0800 Subject: [PATCH] first commit --- .gitignore | 19 +++++ .rspec | 1 + Gemfile | 6 ++ LICENSE | 22 +++++ README.md | 38 +++++++++ Rakefile | 2 + lib/qiniu-rs.rb | 2 + lib/qiniu/rs.rb | 114 ++++++++++++++++++++++++++ lib/qiniu/rs/auth.rb | 74 +++++++++++++++++ lib/qiniu/rs/config.rb | 54 +++++++++++++ lib/qiniu/rs/exceptions.rb | 88 ++++++++++++++++++++ lib/qiniu/rs/image.rb | 20 +++++ lib/qiniu/rs/io.rb | 41 ++++++++++ lib/qiniu/rs/log.rb | 17 ++++ lib/qiniu/rs/rs.rb | 63 +++++++++++++++ lib/qiniu/rs/utils.rb | 124 ++++++++++++++++++++++++++++ lib/qiniu/rs/version.rb | 7 ++ qiniu-rs.gemspec | 24 ++++++ spec/qiniu/rs/auth_spec.rb | 58 ++++++++++++++ spec/qiniu/rs/image_spec.rb | 41 ++++++++++ spec/qiniu/rs/io_spec.rb | 42 ++++++++++ spec/qiniu/rs/rs_spec.rb | 116 +++++++++++++++++++++++++++ spec/qiniu/rs/utils_spec.rb | 49 ++++++++++++ spec/qiniu/rs/version_spec.rb | 10 +++ spec/qiniu/rs_spec.rb | 147 ++++++++++++++++++++++++++++++++++ spec/spec_helper.rb | 12 +++ 26 files changed, 1191 insertions(+) create mode 100755 .gitignore create mode 100755 .rspec create mode 100755 Gemfile create mode 100755 LICENSE create mode 100755 README.md create mode 100755 Rakefile create mode 100755 lib/qiniu-rs.rb create mode 100755 lib/qiniu/rs.rb create mode 100755 lib/qiniu/rs/auth.rb create mode 100755 lib/qiniu/rs/config.rb create mode 100755 lib/qiniu/rs/exceptions.rb create mode 100755 lib/qiniu/rs/image.rb create mode 100755 lib/qiniu/rs/io.rb create mode 100755 lib/qiniu/rs/log.rb create mode 100755 lib/qiniu/rs/rs.rb create mode 100755 lib/qiniu/rs/utils.rb create mode 100755 lib/qiniu/rs/version.rb create mode 100755 qiniu-rs.gemspec create mode 100755 spec/qiniu/rs/auth_spec.rb create mode 100755 spec/qiniu/rs/image_spec.rb create mode 100755 spec/qiniu/rs/io_spec.rb create mode 100755 spec/qiniu/rs/rs_spec.rb create mode 100755 spec/qiniu/rs/utils_spec.rb create mode 100755 spec/qiniu/rs/version_spec.rb create mode 100755 spec/qiniu/rs_spec.rb create mode 100755 spec/spec_helper.rb diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..ed4e0c2 --- /dev/null +++ b/.gitignore @@ -0,0 +1,19 @@ +*.gem +*.rbc +*.swp +.DS_Store +.bundle +.config +.yardoc +Gemfile.lock +InstalledFiles +_yardoc +coverage +doc/ +lib/bundler/man +pkg +rdoc +spec/reports +test/tmp +test/version_tmp +tmp diff --git a/.rspec b/.rspec new file mode 100755 index 0000000..84b61ea --- /dev/null +++ b/.rspec @@ -0,0 +1 @@ +--colour -f nested diff --git a/Gemfile b/Gemfile new file mode 100755 index 0000000..ee7ed45 --- /dev/null +++ b/Gemfile @@ -0,0 +1,6 @@ +source 'https://rubygems.org' + +# Specify your gem's dependencies in qiniu-s3.gemspec +gemspec + +gem "rake", "~> 0.9" diff --git a/LICENSE b/LICENSE new file mode 100755 index 0000000..ef215d7 --- /dev/null +++ b/LICENSE @@ -0,0 +1,22 @@ +Copyright (c) 2012 why404 + +MIT License + +Permission is hereby granted, free of charge, to any person obtaining +a copy of this software and associated documentation files (the +"Software"), to deal in the Software without restriction, including +without limitation the rights to use, copy, modify, merge, publish, +distribute, sublicense, and/or sell copies of the Software, and to +permit persons to whom the Software is furnished to do so, subject to +the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE +LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION +OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION +WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. diff --git a/README.md b/README.md new file mode 100755 index 0000000..70bccc0 --- /dev/null +++ b/README.md @@ -0,0 +1,38 @@ +# 关于 + +此 Ruby SDK 适用于 Ruby 1.8.x, 1.9.x 版本,基于 [七牛云存储官方API](http://docs.qiniutek.com/v1/api/) 构建。使用此 SDK 构建您的网络应用程序,能让您以非常便捷地方式将数据安全地存储到七牛云存储上。无论您的网络应用是一个网站程序,还是包括从云端(服务端程序)到终端(手持设备应用)的架构的服务或应用,通过七牛云存储及其 SDK,都能让您应用程序的终端用户高速上传和下载,同时也让您的服务端更加轻盈。 + +## 安装 + +在您 Ruby 应用程序的 `Gemfile` 文件中,添加如下一行代码: + + gem 'qiniu-rs' + +然后,在应用程序所在的目录下,可以运行 `bundle` 安装依赖包: + + $ bundle + +或者,可以使用 Ruby 的包管理器 `gem` 进行安装: + + $ gem install qiniu-rs + +## 使用 + +参考文档:[七牛云存储 Ruby SDK 使用指南](http://docs.qiniutek.com/v1/sdk/ruby/) + +## 贡献代码 + +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 why404 + +基于 MIT 协议发布: + +* [www.opensource.org/licenses/MIT](http://www.opensource.org/licenses/MIT) + diff --git a/Rakefile b/Rakefile new file mode 100755 index 0000000..f57ae68 --- /dev/null +++ b/Rakefile @@ -0,0 +1,2 @@ +#!/usr/bin/env rake +require "bundler/gem_tasks" diff --git a/lib/qiniu-rs.rb b/lib/qiniu-rs.rb new file mode 100755 index 0000000..75057b3 --- /dev/null +++ b/lib/qiniu-rs.rb @@ -0,0 +1,2 @@ +# More logical way to require 'qiniu-rs' +require File.join(File.dirname(__FILE__), 'qiniu', 'rs') diff --git a/lib/qiniu/rs.rb b/lib/qiniu/rs.rb new file mode 100755 index 0000000..ae5e433 --- /dev/null +++ b/lib/qiniu/rs.rb @@ -0,0 +1,114 @@ +# -*- encoding: utf-8 -*- + +require 'qiniu/rs/version' + +module Qiniu + module RS + autoload :Config, 'qiniu/rs/config' + autoload :Log, 'qiniu/rs/log' + autoload :Exception, 'qiniu/rs/exceptions' + autoload :Utils, 'qiniu/rs/utils' + autoload :Auth, 'qiniu/rs/auth' + autoload :IO, 'qiniu/rs/io' + autoload :RS, 'qiniu/rs/rs' + autoload :Image, 'qiniu/rs/image' + + class << self + + StatusOK = 200 + + def establish_connection!(opts = {}) + Config.initialize_connect opts + end + + def login!(user, pwd) + code, data = Auth.exchange_by_password!(user, pwd) + code == StatusOK + end + + def put_auth(expires_in = nil, callback_url = nil) + code, data = IO.put_auth(expires_in, callback_url) + code == StatusOK ? data["url"] : false + end + + def upload(url, local_file, bucket = '', key = '', mime_type = '', custom_meta = '', callback_params = {}) + code, data = IO.put_file(url, local_file, bucket, key, mime_type, custom_meta, callback_params) + code == StatusOK + end + + def stat(bucket, key) + code, data = RS.stat(bucket, key) + code == StatusOK ? data : false + end + + def get(bucket, key, save_as = nil, expires_in = nil, version = nil) + code, data = RS.get(bucket, key, save_as, expires_in, version) + code == StatusOK ? data : false + end + + def download(bucket, key, save_as = nil, expires_in = nil, version = nil) + code, data = RS.get(bucket, key, save_as, expires_in, version) + code == StatusOK ? data["url"] : false + end + + def delete(bucket, key) + code, data = RS.delete(bucket, key) + code == StatusOK + end + + def batch(command, bucket, keys) + code, data = RS.batch(command, bucket, keys) + code == StatusOK ? data : false + end + + def batch_stat(bucket, keys) + code, data = RS.batch_stat(bucket, keys) + code == StatusOK ? data : false + end + + def batch_get(bucket, keys) + code, data = RS.batch_get(bucket, keys) + code == StatusOK ? data : false + end + + def batch_download(bucket, keys) + code, data = RS.batch_get(bucket, keys) + return false unless code == StatusOK + links = [] + data.each { |e| links << e["data"]["url"] } + links + end + + def batch_delete(bucket, keys) + code, data = RS.batch_delete(bucket, keys) + code == StatusOK ? data : false + end + + def publish(domain, bucket) + code, data = RS.publish(domain, bucket) + code == StatusOK + end + + def unpublish(domain) + code, data = RS.unpublish(domain) + code == StatusOK + end + + def drop(bucket) + code, data = RS.drop(bucket) + code == StatusOK + end + + def image_info(url) + code, data = Image.info(url) + code == StatusOK ? data : false + end + + def image_preview_url(url, spec) + Image.preivew_url(url, spec) + end + + end + + end +end diff --git a/lib/qiniu/rs/auth.rb b/lib/qiniu/rs/auth.rb new file mode 100755 index 0000000..e7b2ca9 --- /dev/null +++ b/lib/qiniu/rs/auth.rb @@ -0,0 +1,74 @@ +# -*- encoding: utf-8 -*- + +require 'qiniu/rs/exceptions' + +module Qiniu + module RS + module Auth + class << self + include Utils + + def exchange_by_password!(username, password) + @username = username + @password = password + post_data = { + :client_id => Config.settings[:client_id], + :grant_type => "password", + :username => username, + :password => password + } + code, data = http_request Config.settings[:auth_url], post_data + reset_token(data["access_token"], data["refresh_token"]) if code == 200 + [code, data] + end + + def exchange_by_refresh_token!(refresh_token) + post_data = { + :client_id => Config.settings[:client_id], + :grant_type => "refresh_token", + :refresh_token => refresh_token + } + code, data = http_request Config.settings[:auth_url], post_data + reset_token(data["access_token"], data["refresh_token"]) if code == 200 + [code, data] + end + + def reset_token(access_token, refresh_token) + @access_token = access_token + @refresh_token = refresh_token + end + + def call(url, data, retry_times = 0) + raise MissingAccessToken if @access_token.nil? + code, data = http_request url, data, {:access_token => @access_token} + if code == 401 + raise MissingRefreshToken if @refresh_token.nil? + code, data = exchange_by_refresh_token!(@refresh_token) + if code == 401 + raise MissingUsernameOrPassword if (@username.nil? || @password.nil?) + code, data = exchange_by_password!(@username, @password) + end + if code == 200 + retry_times += 1 + if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times] + return call(url, data, retry_times) + end + end + end + [code, data] + end + + def request(url, data = nil) + begin + code, data = Auth.call(url, data) + rescue [MissingAccessToken, MissingRefreshToken, MissingUsernameOrPassword] => e + Log.logger.error e + code, data = 401, {} + end + [code, data] + end + + end + end + end +end diff --git a/lib/qiniu/rs/config.rb b/lib/qiniu/rs/config.rb new file mode 100755 index 0000000..077ab0d --- /dev/null +++ b/lib/qiniu/rs/config.rb @@ -0,0 +1,54 @@ +# -*- encoding: utf-8 -*- +# +# USAGE WAY 1: +# Qbox::Config.initialize_connect :client_id => "", +# :client_secret => "" +# +# USAGE WAY 2: +# Qbox::Config.load "path/to/your_project/config/qiniu.yml" +# + +require "qiniu/rs/version" + +module Qiniu + module RS + module Config + class << self + + DEFAULT_OPTIONS = { + :user_agent => 'Qiniu-RS-Ruby-SDK-' + VERSION + '()', + :method => :post, + :content_type => 'application/x-www-form-urlencoded', + :auth_url => "https://acc.qbox.me/oauth2/token", + :rs_host => "http://rs.qbox.me:10100", + :io_host => "http://io.qbox.me", + :client_id => "", + :client_secret => "", + :auto_reconnect => true, + :max_retry_times => 5 + } + + REQUIRED_OPTION_KEYS = [:client_id, :client_secret, :auth_url, :rs_host, :io_host] + + attr_reader :settings, :default_params + + def load config_file + if File.exist?(config_file) + config_options = YAML.load_file(config_file) + initialize_connect(config_options) + else + raise MissingConfError, config_file + end + end + + def initialize_connect options = {} + @settings = DEFAULT_OPTIONS.merge(options) + REQUIRED_OPTION_KEYS.each do |opt| + raise MissingArgsError, [opt] unless @settings.has_key?(opt) + end + end + + end + end + end +end diff --git a/lib/qiniu/rs/exceptions.rb b/lib/qiniu/rs/exceptions.rb new file mode 100755 index 0000000..2c282df --- /dev/null +++ b/lib/qiniu/rs/exceptions.rb @@ -0,0 +1,88 @@ +# -*- encoding: utf-8 -*- + +module Qiniu + module RS + + class Exception < RuntimeError + def to_s + inspect + end + end + + class ResponseError < Exception + attr_reader :response + + def initialize(message, response = nil) + @response = response + super(message) + end + + def http_code + @response.code.to_i if @response + end + + def http_body + @response.body if @response + end + + def inspect + "#{message}: #{http_body}" + end + end + + class RequestFailed < ResponseError + def message + "HTTP status code #{http_code}" + end + + def to_s + message + end + end + + class MissingArgsError < Exception + def initialize(missing_keys) + key_list = missing_keys.map {|key| key.to_s}.join(' and the ') + super("You did not provide both required args. Please provide the #{key_list}.") + end + end + + class MissingAccessToken < MissingArgsError + def initialize + super([:access_token]) + end + end + + class MissingRefreshToken < MissingArgsError + def initialize + super([:refresh_token]) + end + end + + class MissingUsernameOrPassword < MissingArgsError + def initialize + super([:username, :password]) + end + end + + class InvalidArgsError < Exception + def initialize(invalid_keys) + key_list = invalid_keys.map {|key| key.to_s}.join(' and the ') + super("#{key_list} should not be empty.") + end + end + + class MissingConfError < Exception + def initialize(missing_conf_file) + super("Error, missing #{missing_conf_file}. You must have #{missing_conf_file} to configure your client id and secret.") + end + end + + class NoSuchFileError < Exception + def initialize(missing_file) + super("Error, no such file #{missing_file}.") + end + end + + end +end diff --git a/lib/qiniu/rs/image.rb b/lib/qiniu/rs/image.rb new file mode 100755 index 0000000..86a25d4 --- /dev/null +++ b/lib/qiniu/rs/image.rb @@ -0,0 +1,20 @@ +# -*- encoding: utf-8 -*- + +module Qiniu + module RS + module Image + class << self + include Utils + + def info(url) + Utils.http_request url + '/imageInfo', nil, {:method => :get} + end + + def preivew_url(url, spec) + url + '/imagePreview/' + spec.to_s + end + + end + end + end +end diff --git a/lib/qiniu/rs/io.rb b/lib/qiniu/rs/io.rb new file mode 100755 index 0000000..9790979 --- /dev/null +++ b/lib/qiniu/rs/io.rb @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- + +require 'mime/types' +require 'digest/sha1' +require 'qiniu/rs/exceptions' + +module Qiniu + module RS + module IO + class << self + include Utils + + def put_auth(expires_in = nil, callback_url = nil) + url = Config.settings[:io_host] + "/put-auth/" + url += "#{expires_in}" if !expires_in.nil? && expires_in > 0 + if !callback_url.nil? && !callback_url.empty? + encoded_callback_url = Utils.urlsafe_base64_encode(callback_url) + url += "/callback/#{encoded_callback_url}" + end + Auth.request(url) + end + + def put_file(url, local_file, bucket = '', key = '', mime_type = '', custom_meta = '', callback_params = '') + raise NoSuchFileError unless File.exist?(local_file) + key = Digest::SHA1.hexdigest(local_file + Time.now.to_s) if key.empty? + entry_uri = bucket + ':' + key + if mime_type.empty? + mime = MIME::Types.type_for local_file + mime_type = mime.empty? ? 'application/octet-stream' : mime[0].content_type + end + action_params = '/rs-put/' + Utils.urlsafe_base64_encode(entry_uri) + '/mimeType/' + Utils.urlsafe_base64_encode(mime_type) + action_params += '/meta/' + Utils.urlsafe_base64_encode(custom_meta) unless custom_meta.empty? + callback_params = {:bucket => bucket, :key => key, :mime_type => mime_type} if callback_params.empty? + callback_query_string = Utils.generate_query_string(callback_params) + Utils.upload_multipart_data(url, local_file, action_params, callback_query_string) + end + + end + end + end +end diff --git a/lib/qiniu/rs/log.rb b/lib/qiniu/rs/log.rb new file mode 100755 index 0000000..0a3c8a0 --- /dev/null +++ b/lib/qiniu/rs/log.rb @@ -0,0 +1,17 @@ +# -*- encoding: utf-8 -*- + +require 'logger' + +module Qiniu + module RS + module Log + class << self + attr_accessor :logger + + def logger + @logger ||= Logger.new(STDERR) + end + end + end + end +end diff --git a/lib/qiniu/rs/rs.rb b/lib/qiniu/rs/rs.rb new file mode 100755 index 0000000..b45f197 --- /dev/null +++ b/lib/qiniu/rs/rs.rb @@ -0,0 +1,63 @@ +# -*- encoding: utf-8 -*- + +module Qiniu + module RS + module RS + class << self + include Utils + + def stat(bucket, key) + Auth.request Config.settings[:rs_host] + '/stat/' + encode_entry_uri(bucket, key) + end + + def get(bucket, key, save_as = nil, expires_in = nil, version = nil) + url = Config.settings[:rs_host] + '/get/' + encode_entry_uri(bucket, key) + url += '/base/' + version unless version.nil? + url += '/attName/' + Utils.urlsafe_base64_encode(save_as) unless save_as.nil? + url += '/expires/' + expires_in.to_s if !expires_in.nil? && expires_in > 0 + Auth.request url + end + + def delete(bucket, key) + Auth.request Config.settings[:rs_host] + '/delete/' + encode_entry_uri(bucket, key) + end + + def publish(domain, bucket) + encoded_domain = Utils.urlsafe_base64_encode(domain) + Auth.request Config.settings[:rs_host] + "/publish/#{encoded_domain}/from/#{bucket}" + end + + def unpublish(domain) + encoded_domain = Utils.urlsafe_base64_encode(domain) + Auth.request Config.settings[:rs_host] + "/unpublish/#{encoded_domain}" + end + + def drop(bucket) + Auth.request Config.settings[:rs_host] + "/drop/#{bucket}" + end + + def batch(command, bucket, keys) + execs = [] + keys.each do |key| + encoded_uri = encode_entry_uri(bucket, key) + execs << "op=/#{command}/#{encoded_uri}" + end + Auth.request Config.settings[:rs_host] + "/batch?" + execs.join("&") + end + + def batch_get(bucket, keys) + batch("get", bucket, keys) + end + + def batch_stat(bucket, keys) + batch("stat", bucket, keys) + end + + def batch_delete(bucket, keys) + batch("delete", bucket, keys) + end + + end + end + end +end diff --git a/lib/qiniu/rs/utils.rb b/lib/qiniu/rs/utils.rb new file mode 100755 index 0000000..bc58aad --- /dev/null +++ b/lib/qiniu/rs/utils.rb @@ -0,0 +1,124 @@ +# -*- encoding: utf-8 -*- + +require 'uri' +require 'json' +require 'base64' +require 'rest_client' +require 'qiniu/rs/exceptions' + +module Qiniu + module RS + module Utils extend self + + def urlsafe_base64_encode content + Base64.encode64(content).strip.gsub('+', '-').gsub('/','_').gsub(/\r?\n/, '') + end + + def urlsafe_base64_decode encoded_content + Base64.decode64 encoded_content.gsub('_','/').gsub('-', '+') + end + + def encode_entry_uri(bucket, key) + entry_uri = bucket + ':' + key + urlsafe_base64_encode(entry_uri) + end + + def safe_json_parse(data) + JSON.parse(data) + rescue JSON::ParserError + {} + end + + def send_request_with url, data = nil, options = {} + options[:method] = Config.settings[:method] unless options[:method] + options[:content_type] = Config.settings[:content_type] unless options[:content_type] + header_options = { + :accept => :json, + :user_agent => Config.settings[:user_agent] + } + header_options.merge!('Authorization' => "Bearer #{options[:access_token]}") if options[:access_token] + case options[:method] + when :get + response = RestClient.get url, header_options + when :post + header_options.merge!(:content_type => options[:content_type]) + response = RestClient.post url, data, header_options + end + code = response.respond_to?(:code) ? response.code.to_i : 0 + if code != 200 + raise RequestFailed.new(response) + else + data = {} + body = response.respond_to?(:body) ? response.body : {} + data = safe_json_parse(body) unless body.empty? + end + [code, data] + end + + def http_request url, data = nil, options = {} + retry_times = 0 + begin + retry_times += 1 + send_request_with url, data, options + rescue Errno::ECONNRESET => err + if Config.settings[:auto_reconnect] && retry_times < Config.settings[:max_retry_times] + retry + else + Log.logger.error err + end + rescue => e + Log.logger.warn "#{e.message} => Utils.http_request('#{url}')" + code = 0 + data = {} + body = {} + if e.respond_to? :response + res = e.response + code = res.code.to_i if res.respond_to? :code + body = res.respond_to?(:body) ? res.body : "" + data = safe_json_parse(body) unless body.empty? + end + [code, data] + end + end + + def upload_multipart_data(url, filepath, action_string, callback_query_string = '') + code, data = 0, {} + begin + header_options = { + :accept => :json, + :user_agent => Config.settings[:user_agent] + } + post_data = { + :file => File.new(filepath, 'rb'), + :params => callback_query_string, + :action => action_string, + :multipart => true + } + response = RestClient.post url, post_data, header_options + body = response.respond_to?(:body) ? response.body : "" + data = safe_json_parse(body) unless body.empty? + code = response.code.to_i if response.respond_to?(:code) + rescue Errno::ECONNRESET => err + Log.logger.error err + rescue => e + Log.logger.warn "#{e.message} => Utils.http_request('#{url}')" + res = e.response + if e.respond_to? :response + res = e.response + code = res.code.to_i if res.respond_to? :code + body = res.respond_to?(:body) ? res.body : "" + data = safe_json_parse(body) unless body.empty? + end + end + [code, data] + end + + def generate_query_string(params) + return params if params.is_a?(String) + total_param = params.map { |key, value| key.to_s+"="+value.to_s } + URI.escape(total_param.join("&")) + end + + end + end +end diff --git a/lib/qiniu/rs/version.rb b/lib/qiniu/rs/version.rb new file mode 100755 index 0000000..e6a96e8 --- /dev/null +++ b/lib/qiniu/rs/version.rb @@ -0,0 +1,7 @@ +# -*- encoding: utf-8 -*- + +module Qiniu + module RS + VERSION = "1.0.0" + end +end diff --git a/qiniu-rs.gemspec b/qiniu-rs.gemspec new file mode 100755 index 0000000..cb3b144 --- /dev/null +++ b/qiniu-rs.gemspec @@ -0,0 +1,24 @@ +# -*- encoding: utf-8 -*- + +require File.expand_path('../lib/qiniu/rs/version', __FILE__) + +Gem::Specification.new do |gem| + gem.authors = ["why404"] + gem.email = ["why404@gmail.com"] + gem.description = %q{Qiniu Cloud Storage SDK for Ruby. See: http://docs.qiniutek.com/v1/sdk/ruby/} + gem.summary = %q{Qiniu Cloud Storage SDK for Ruby} + gem.homepage = "https://github.com/why404/qiniu-rs-sdk-for-ruby" + + gem.files = `git ls-files`.split($\) + gem.executables = gem.files.grep(%r{^bin/}).map{ |f| File.basename(f) } + gem.test_files = gem.files.grep(%r{^(test|spec|features)/}) + gem.name = "qiniu-rs" + gem.require_paths = ["lib"] + gem.version = Qiniu::RS::VERSION + + # specify any dependencies here; for example: + gem.add_development_dependency "rspec" + gem.add_development_dependency "fakeweb" + gem.add_runtime_dependency "rest-client" + gem.add_runtime_dependency "mime-types" +end diff --git a/spec/qiniu/rs/auth_spec.rb b/spec/qiniu/rs/auth_spec.rb new file mode 100755 index 0000000..b4b4efe --- /dev/null +++ b/spec/qiniu/rs/auth_spec.rb @@ -0,0 +1,58 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'qiniu/rs/auth' + +module Qiniu + module RS + describe Auth do + + before :all do + @username = "test@qbox.net" + @password = "test" + + code, data = Qiniu::RS::Auth.exchange_by_password!(@username, @password) + code.should == 200 + data.should be_an_instance_of(Hash) + data["access_token"].should_not be_empty + data["refresh_token"].should_not be_empty + data["refresh_token"].should_not be_empty + + @access_token = data["access_token"] + @refresh_token = data["refresh_token"] + puts data.inspect + end + + context ".exchange_by_password" do + it "should sign in failed when pass a non-existent username" do + code, data = Qiniu::RS::Auth.exchange_by_password!("a_non_existent_user@example.com", "password") + code.should == 401 + data["error_code"].should == 11 + data["error"].should == "failed_authentication" + puts data.inspect + end + + it "should sign in failed when pass a wrong password" do + code, data = Qiniu::RS::Auth.exchange_by_password!(@username, "a-wrong-password") + code.should == 401 + data["error_code"].should == 11 + data["error"].should == "failed_authentication" + puts data.inspect + end + end + + context ".exchange_by_refresh_token" do + it "should works" do + @refresh_token.should_not be_empty + code, data = Qiniu::RS::Auth.exchange_by_refresh_token!(@refresh_token) + code.should == 200 + data["access_token"].should_not be_empty + data["refresh_token"].should_not be_empty + data["expires_in"].should_not be_zero + puts data.inspect + end + end + + end + end +end diff --git a/spec/qiniu/rs/image_spec.rb b/spec/qiniu/rs/image_spec.rb new file mode 100755 index 0000000..dc96723 --- /dev/null +++ b/spec/qiniu/rs/image_spec.rb @@ -0,0 +1,41 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'qiniu/rs/auth' +require 'qiniu/rs/rs' +require 'qiniu/rs/image' + +module Qiniu + module RS + describe Image do + + before :all do + code, data = Qiniu::RS::Auth.exchange_by_password!("test@qbox.net", "test") + code.should == 200 + data.should be_an_instance_of(Hash) + data["access_token"].should_not be_empty + data["refresh_token"].should_not be_empty + data["refresh_token"].should_not be_empty + puts data.inspect + + @bucket = "test_images" + @key = "test_image.jpg" + code2, data2 = Qiniu::RS::RS.get(@bucket, @key) + code2.should == 200 + data2["url"].should_not be_empty + puts data2.inspect + + @download_url = data2["url"] + end + + context ".info" do + it "should works" do + code, data = Qiniu::RS::Image.info(@download_url) + code.should == 200 + puts data.inspect + end + end + + end + end +end diff --git a/spec/qiniu/rs/io_spec.rb b/spec/qiniu/rs/io_spec.rb new file mode 100755 index 0000000..7e4b042 --- /dev/null +++ b/spec/qiniu/rs/io_spec.rb @@ -0,0 +1,42 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'qiniu/rs/auth' +require 'qiniu/rs/io' +require 'digest/sha1' + +module Qiniu + module RS + describe IO do + + before :all do + code, data = Qiniu::RS::Auth.exchange_by_password!("test@qbox.net", "test") + code.should == 200 + data.should be_an_instance_of(Hash) + data["access_token"].should_not be_empty + data["refresh_token"].should_not be_empty + data["refresh_token"].should_not be_empty + puts data.inspect + + code2, data2 = Qiniu::RS::IO.put_auth() + code2.should == 200 + data2["url"].should_not be_empty + data2["expiresIn"].should_not be_zero + puts data2.inspect + + @put_url = data2["url"] + @bucket = "test" + @key = Digest::SHA1.hexdigest (Time.now.to_i+rand(100)).to_s + end + + context ".put_file" do + it "should works" do + code, data = Qiniu::RS::IO.put_file(@put_url, __FILE__, @bucket, @key) + code.should == 200 + puts data.inspect + end + end + + end + end +end diff --git a/spec/qiniu/rs/rs_spec.rb b/spec/qiniu/rs/rs_spec.rb new file mode 100755 index 0000000..f48ba29 --- /dev/null +++ b/spec/qiniu/rs/rs_spec.rb @@ -0,0 +1,116 @@ +# -*- encoding: utf-8 -*- + +require 'digest/sha1' +require 'spec_helper' +require 'qiniu/rs/auth' +require 'qiniu/rs/io' +require 'qiniu/rs/rs' + +module Qiniu + module RS + describe RS do + + before :all do + code, data = Qiniu::RS::Auth.exchange_by_password!("test@qbox.net", "test") + code.should == 200 + data.should be_an_instance_of(Hash) + data["access_token"].should_not be_empty + data["refresh_token"].should_not be_empty + data["refresh_token"].should_not be_empty + puts data.inspect + + code2, data2 = Qiniu::RS::IO.put_auth() + code2.should == 200 + data2["url"].should_not be_empty + data2["expiresIn"].should_not be_zero + puts data2.inspect + + @put_url = data2["url"] + @bucket = "test" + @key = Digest::SHA1.hexdigest (Time.now.to_i+rand(100)).to_s + @domain = 'cdn.example.com' + end + + context "IO.put_file" do + it "should works" do + code, data = Qiniu::RS::IO.put_file(@put_url, __FILE__, @bucket, @key) + code.should == 200 + puts data.inspect + end + end + + context ".stat" do + it "should works" do + code, data = Qiniu::RS::RS.stat(@bucket, @key) + code.should == 200 + puts data.inspect + end + end + + context ".get" do + it "should works" do + code, data = Qiniu::RS::RS.get(@bucket, @key, "rs_spec.rb", 1) + code.should == 200 + puts data.inspect + end + end + + context ".batch" do + it "should works" do + code, data = Qiniu::RS::RS.batch("stat", @bucket, [@key]) + code.should == 200 + puts data.inspect + end + end + + context ".batch_stat" do + it "should works" do + code, data = Qiniu::RS::RS.batch_stat(@bucket, [@key]) + code.should == 200 + puts data.inspect + end + end + + context ".batch_get" do + it "should works" do + code, data = Qiniu::RS::RS.batch_get(@bucket, [@key]) + code.should == 200 + puts data.inspect + end + end + + context ".publish" do + it "should works" do + code, data = Qiniu::RS::RS.publish(@domain, @bucket) + code.should == 200 + puts data.inspect + end + end + + context ".unpublish" do + it "should works" do + code, data = Qiniu::RS::RS.unpublish(@domain) + code.should == 200 + puts data.inspect + end + end + + context ".delete" do + it "should works" do + code, data = Qiniu::RS::RS.delete(@bucket, @key) + code.should == 200 + puts data.inspect + end + end + + context ".drop" do + it "should works" do + code, data = Qiniu::RS::RS.drop(@bucket) + code.should == 200 + puts data.inspect + end + end + + end + end +end diff --git a/spec/qiniu/rs/utils_spec.rb b/spec/qiniu/rs/utils_spec.rb new file mode 100755 index 0000000..74606c8 --- /dev/null +++ b/spec/qiniu/rs/utils_spec.rb @@ -0,0 +1,49 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'fakeweb' +require 'qiniu/rs/utils' + +module Qiniu + module RS + describe Utils do + before :all do + Struct.new("Response", :code, :body) + end + + after :each do + FakeWeb.clean_registry + FakeWeb.allow_net_connect = true + end + + context "safe_json_parse" do + it "should works" do + Utils.safe_json_parse('{"foo": "bar"}').should == {"foo" => "bar"} + Utils.safe_json_parse('{}').should == {} + end + end + + context ".send_request_with" do + it "should works" do + FakeWeb.allow_net_connect = false + FakeWeb.register_uri(:get, "http://docs.qiniutek.com/", :body => {:abc => 123}.to_json) + res = Utils.send_request_with 'http://docs.qiniutek.com/', nil, :method => :get + res.should == [200, {"abc" => 123}] + end + + [400, 500].each do |code| + context "upstream return http #{code}" do + it "should raise RestClient::RequestFailed" do + FakeWeb.allow_net_connect = false + FakeWeb.register_uri(:get, "http://docs.qiniutek.com/", :status => code) + lambda { + res = Utils.send_request_with 'http://docs.qiniutek.com/', nil, :method => :get + }.should raise_error RestClient::RequestFailed + end + end + end + end + + end + end +end diff --git a/spec/qiniu/rs/version_spec.rb b/spec/qiniu/rs/version_spec.rb new file mode 100755 index 0000000..c18adde --- /dev/null +++ b/spec/qiniu/rs/version_spec.rb @@ -0,0 +1,10 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'qiniu/rs/version' + +describe Qiniu::RS do + it "should has a VERSION" do + Qiniu::RS::VERSION.should =~ /^\d+\.\d+\.\d+?$/ + end +end diff --git a/spec/qiniu/rs_spec.rb b/spec/qiniu/rs_spec.rb new file mode 100755 index 0000000..9ae0310 --- /dev/null +++ b/spec/qiniu/rs_spec.rb @@ -0,0 +1,147 @@ +# -*- encoding: utf-8 -*- + +require 'spec_helper' +require 'qiniu/rs' + +module Qiniu + describe RS do + + before :all do + @bucket = 'qiniu_rs_test' + @key = Digest::SHA1.hexdigest Time.now.to_s + @domain = 'cdn.example.com' + end + + context ".login!" do + it "should works" do + result = Qiniu::RS.login!("test@qbox.net", "test") + result.should be_true + end + end + + context ".put_auth" do + it "should works" do + result = Qiniu::RS.put_auth(10) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".upload" do + it "should works" do + put_url = Qiniu::RS.put_auth(10) + put_url.should_not be_false + put_url.should_not be_empty + puts put_url.inspect + result = Qiniu::RS.upload(put_url, __FILE__, @bucket, @key) + result.should be_true + end + end + + context ".stat" do + it "should works" do + result = Qiniu::RS.stat(@bucket, @key) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".get" do + it "should works" do + result = Qiniu::RS.get(@bucket, @key, "rs_spec.rb", 10) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".download" do + it "should works" do + result = Qiniu::RS.download(@bucket, @key, "rs_spec.rb", 10) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".batch" do + it "should works" do + result = Qiniu::RS.batch("stat", @bucket, [@key]) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".batch_stat" do + it "should works" do + result = Qiniu::RS.batch_stat(@bucket, [@key]) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".batch_get" do + it "should works" do + result = Qiniu::RS.batch_get(@bucket, [@key]) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".batch_download" do + it "should works" do + result = Qiniu::RS.batch_download(@bucket, [@key]) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + context ".publish" do + it "should works" do + result = Qiniu::RS.publish(@domain, @bucket) + result.should_not be_false + end + end + + context ".unpublish" do + it "should works" do + result = Qiniu::RS.unpublish(@domain) + result.should_not be_false + end + end + + context ".delete" do + it "should works" do + result = Qiniu::RS.delete(@bucket, @key) + result.should_not be_false + end + end + + context ".drop" do + it "should works" do + result = Qiniu::RS.drop(@bucket) + result.should_not be_false + end + end + + context ".image_info" do + it "should works" do + data = Qiniu::RS.get("test_images", "test_image.jpg") + data.should_not be_false + data.should_not be_empty + puts data.inspect + result = Qiniu::RS.image_info(data["url"]) + result.should_not be_false + result.should_not be_empty + puts result.inspect + end + end + + end +end diff --git a/spec/spec_helper.rb b/spec/spec_helper.rb new file mode 100755 index 0000000..a025c73 --- /dev/null +++ b/spec/spec_helper.rb @@ -0,0 +1,12 @@ +# -*- encoding: utf-8 -*- + +require 'bundler/setup' +require 'qiniu/rs' +require 'rspec' + +RSpec.configure do |config| + config.before :all do + Qiniu::RS.establish_connection! :client_id => "abcd0c7edcdf914228ed8aa7c6cee2f2bc6155e2", + :client_secret => "fc9ef8b171a74e197b17f85ba23799860ddf3b9c" + end +end