bkblz 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +9 -0
- data/.rspec +2 -0
- data/.travis.yml +5 -0
- data/Gemfile +4 -0
- data/LICENSE.txt +21 -0
- data/README.rb +141 -0
- data/Rakefile +11 -0
- data/bkblz.gemspec +25 -0
- data/lib/all.rb +6 -0
- data/lib/bkblz.rb +35 -0
- data/lib/bkblz/config.rb +35 -0
- data/lib/bkblz/core_ext.rb +22 -0
- data/lib/bkblz/logger.rb +139 -0
- data/lib/bkblz/map_key_formatter.rb +21 -0
- data/lib/bkblz/v1/all.rb +16 -0
- data/lib/bkblz/v1/authorize_account.rb +24 -0
- data/lib/bkblz/v1/create_bucket.rb +22 -0
- data/lib/bkblz/v1/delete_bucket.rb +23 -0
- data/lib/bkblz/v1/delete_file_version.rb +23 -0
- data/lib/bkblz/v1/error_response.rb +24 -0
- data/lib/bkblz/v1/get_upload_url.rb +22 -0
- data/lib/bkblz/v1/list_buckets.rb +18 -0
- data/lib/bkblz/v1/list_file_versions.rb +43 -0
- data/lib/bkblz/v1/model_base.rb +37 -0
- data/lib/bkblz/v1/models.rb +29 -0
- data/lib/bkblz/v1/request.rb +81 -0
- data/lib/bkblz/v1/response.rb +114 -0
- data/lib/bkblz/v1/session.rb +72 -0
- data/lib/bkblz/v1/upload_file.rb +50 -0
- data/lib/bkblz/version.rb +3 -0
- metadata +116 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 7636a95e10db31242f5b3e666734c62e16f870da
|
4
|
+
data.tar.gz: 54425688a09f9dcec3d598ad9b9fc312e1cb8c42
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: 73aa799368884833b533d5ae3e8f23f7dd3b4c0a8aa0126c69509420520b290bb631721860b788a66ab0d2b13839b27fcb68e064ad07adb635285234ac932eca
|
7
|
+
data.tar.gz: ba3359e74fc5b8e49da7f21ebd60a8f5e59d4ee421633a22dbd0d71428455120f16b294b72e7d012c467eac147832dddc1cbefca3e4287e9024f25fad22e5c54
|
data/.gitignore
ADDED
data/.rspec
ADDED
data/.travis.yml
ADDED
data/Gemfile
ADDED
data/LICENSE.txt
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
The MIT License (MIT)
|
2
|
+
|
3
|
+
Copyright (c) 2016 Erick Johnson
|
4
|
+
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
7
|
+
in the Software without restriction, including without limitation the rights
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
10
|
+
furnished to do so, subject to the following conditions:
|
11
|
+
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
13
|
+
all copies or substantial portions of the Software.
|
14
|
+
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
21
|
+
THE SOFTWARE.
|
data/README.rb
ADDED
@@ -0,0 +1,141 @@
|
|
1
|
+
$: << 'lib'
|
2
|
+
require 'all'
|
3
|
+
|
4
|
+
# Run `ruby README.rb` for a working demo, but first add your
|
5
|
+
# applicatoin key and account id in the slots below.
|
6
|
+
Bkblz.configure do |config_map|
|
7
|
+
config_map.merge!(
|
8
|
+
:application_key => "!!! APP KEY !!!",
|
9
|
+
:account_id => "!!! ACCOUNT ID !!!",
|
10
|
+
:debug_http => false,
|
11
|
+
:log_level => :info # change this to :debug for more info
|
12
|
+
)
|
13
|
+
end
|
14
|
+
|
15
|
+
Bkblz.log.info do <<EOS
|
16
|
+
# Step 1, the block above configures some defaults (including the
|
17
|
+
# logger, which is why this is after the configure block), see
|
18
|
+
# Bkblz::Config for details. This is where to set the account_id
|
19
|
+
# and application_key.
|
20
|
+
EOS
|
21
|
+
end
|
22
|
+
|
23
|
+
if Bkblz.config.account_id.match /!!!/
|
24
|
+
Bkblz.log.error "you didn't fill in your credentials, read the comments"
|
25
|
+
exit 1
|
26
|
+
end
|
27
|
+
|
28
|
+
Bkblz.log.info do <<EOS
|
29
|
+
# Step 2, using the config above, create an authorized session. All
|
30
|
+
# requests will run in the context of this session. See
|
31
|
+
# +Bkblz::V1::Session#authorize+.
|
32
|
+
EOS
|
33
|
+
end
|
34
|
+
Bkblz::V1::Session.authorize Bkblz.config do |api_session|
|
35
|
+
Bkblz.log.info "API session => #{api_session}"
|
36
|
+
|
37
|
+
Bkblz.log.info do <<EOS
|
38
|
+
# Step 3, first try to find an existing bucket named my-test-bucket,
|
39
|
+
# we'll use that if it exists. All requests in a session are sent
|
40
|
+
# through the session so that the request object gets access to the
|
41
|
+
# auth credentials.
|
42
|
+
EOS
|
43
|
+
end
|
44
|
+
buckets = api_session.send(Bkblz::V1::ListBucketsRequest.new).buckets
|
45
|
+
bucket = buckets.select { |b| b.bucket_name == "my-test-bucket" }.first
|
46
|
+
Bkblz.log.info "bucket list => #{buckets}"
|
47
|
+
|
48
|
+
Bkblz.log.info do <<EOS
|
49
|
+
# Step 4, otherwise create a new my-test-bucket
|
50
|
+
EOS
|
51
|
+
end
|
52
|
+
unless bucket
|
53
|
+
bucket = Bkblz::V1::Model::Bucket.new \
|
54
|
+
:bucket_name => "my-test-bucket",
|
55
|
+
:bucket_type => "allPrivate",
|
56
|
+
:account_id => api_session.account_id
|
57
|
+
|
58
|
+
Bkblz.log.info do <<EOS
|
59
|
+
# Step 5, pass a model to the CreateBucketRequest,
|
60
|
+
# models are just named wrappers with dynamic methods
|
61
|
+
# around the JSON responses provided back from the Bkblz
|
62
|
+
# API. See lib/bkblz/v1/models.rb for a list of defined API
|
63
|
+
# objects. See Bkblz::V1::Model::Base for how it work.
|
64
|
+
EOS
|
65
|
+
end
|
66
|
+
request = Bkblz::V1::CreateBucketRequest.new bucket
|
67
|
+
Bkblz.log.info "bucket model => #{bucket}"
|
68
|
+
|
69
|
+
# Bkblz::V1::Response objects are returned from +send+. Some
|
70
|
+
# provide a to_model method if they declare the +response_model+
|
71
|
+
# in the class definition.
|
72
|
+
bucket = api_session.send(request).to_model
|
73
|
+
Bkblz.log.info "created bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
74
|
+
end
|
75
|
+
|
76
|
+
Bkblz.log.info do <<EOS
|
77
|
+
# Step 6, uploading a file begins with getting a dynamic URL from the API.
|
78
|
+
EOS
|
79
|
+
end
|
80
|
+
upload_auth = api_session.send(
|
81
|
+
Bkblz::V1::GetUploadUrlRequest.new bucket.bucket_id).to_model
|
82
|
+
Bkblz.log.info "upload file URL => #{upload_auth.upload_url}"
|
83
|
+
|
84
|
+
|
85
|
+
Bkblz.log.info do <<EOS
|
86
|
+
# Step 7, use the upload_auth model (a
|
87
|
+
# Bkblz::V1::Model::UploadAuth) to upload some files.
|
88
|
+
EOS
|
89
|
+
end
|
90
|
+
5.times do |i|
|
91
|
+
body = "some text #{i}"
|
92
|
+
file_name = "some_text_#{i}.txt"
|
93
|
+
content_type = nil
|
94
|
+
|
95
|
+
upload_file_info = api_session.send(
|
96
|
+
Bkblz::V1::UploadFileRequest.new upload_auth, body, file_name,
|
97
|
+
content_type, Time.now.to_i * 1000).to_model
|
98
|
+
Bkblz.log.info "uploaded file => #{upload_file_info.file_name}"
|
99
|
+
end
|
100
|
+
|
101
|
+
Bkblz.log.info do <<EOS
|
102
|
+
# Step 8, we uploaded 5 files above, here we'll read back out
|
103
|
+
# metadata from the first 2 files in the bucket.
|
104
|
+
EOS
|
105
|
+
end
|
106
|
+
list_files_response = api_session.send(
|
107
|
+
Bkblz::V1::ListFileVersionsRequest.new bucket, 2)
|
108
|
+
bucket_files_info = list_files_response.files
|
109
|
+
Bkblz.log.info "first 2 files => #{bucket_files_info.map(&:file_name).join "\n"}"
|
110
|
+
|
111
|
+
Bkblz.log.info do <<EOS
|
112
|
+
# Step 9, the response object returned object is a
|
113
|
+
# Bkblz::Api::PaginatedResponse. Use its +has_more?+ and
|
114
|
+
# +next_request+ methods to page through more results.
|
115
|
+
EOS
|
116
|
+
end
|
117
|
+
while list_files_response.has_more?
|
118
|
+
list_files_response = api_session.send list_files_response.next_request 100
|
119
|
+
bucket_files_info.concat list_files_response.files
|
120
|
+
Bkblz.log.info "next N files => #{list_files_response.files.map(&:file_name).join "\n"}"
|
121
|
+
end
|
122
|
+
|
123
|
+
Bkblz.log.info do <<EOS
|
124
|
+
# Step 10, delete all the files in the bucket that we added. This is
|
125
|
+
# a service requirement to deleting a bucket.
|
126
|
+
EOS
|
127
|
+
end
|
128
|
+
bucket_files_info.each do |file_info|
|
129
|
+
request = Bkblz::V1::DeleteFileVersionRequest.new file_info
|
130
|
+
delete_file_version_response = api_session.send request
|
131
|
+
Bkblz.log.info "deleted file => #{delete_file_version_response.to_model.file_name}"
|
132
|
+
end
|
133
|
+
|
134
|
+
Bkblz.log.info do <<EOS
|
135
|
+
# Step 11, delete the bucket.
|
136
|
+
EOS
|
137
|
+
end
|
138
|
+
request = Bkblz::V1::DeleteBucketRequest.new bucket
|
139
|
+
delete_bucket_response = api_session.send request
|
140
|
+
Bkblz.log.info "deleted bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
141
|
+
end
|
data/Rakefile
ADDED
data/bkblz.gemspec
ADDED
@@ -0,0 +1,25 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'bkblz/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "bkblz"
|
8
|
+
spec.version = Bkblz::VERSION
|
9
|
+
spec.authors = ["Erick Johnson"]
|
10
|
+
spec.email = ["erick@vos.io"]
|
11
|
+
|
12
|
+
spec.summary = "Bkblz GEM for the Backblaze B2 API. https://www.backblaze.com/b2/docs/"
|
13
|
+
spec.description = spec.description
|
14
|
+
spec.homepage = "https://github.com/erickj/bkblz"
|
15
|
+
spec.license = "MIT"
|
16
|
+
|
17
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
18
|
+
f.match(%r{^(test|spec|features)/})
|
19
|
+
end
|
20
|
+
spec.require_paths = ["lib"]
|
21
|
+
|
22
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
23
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
24
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
25
|
+
end
|
data/lib/all.rb
ADDED
data/lib/bkblz.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
require "bkblz/config"
|
2
|
+
require "bkblz/logger"
|
3
|
+
|
4
|
+
module Bkblz
|
5
|
+
|
6
|
+
BaseError = Class.new ::StandardError
|
7
|
+
|
8
|
+
class << self
|
9
|
+
def configure(&block)
|
10
|
+
@config = Bkblz::Config.configure @config, &block
|
11
|
+
config_changed
|
12
|
+
end
|
13
|
+
|
14
|
+
def config
|
15
|
+
unless @config
|
16
|
+
@config = Bkblz::Config.configure
|
17
|
+
config_changed
|
18
|
+
end
|
19
|
+
@config
|
20
|
+
end
|
21
|
+
|
22
|
+
def log
|
23
|
+
@logger ||= config_logger
|
24
|
+
end
|
25
|
+
|
26
|
+
private
|
27
|
+
def config_changed
|
28
|
+
@logger = nil
|
29
|
+
end
|
30
|
+
|
31
|
+
def config_logger
|
32
|
+
@logger = Bkblz::Logger.configure config
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
data/lib/bkblz/config.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
module Bkblz
|
2
|
+
|
3
|
+
class Config
|
4
|
+
|
5
|
+
CONFIG_VARS = {
|
6
|
+
:application_key => '',
|
7
|
+
:account_id => '',
|
8
|
+
:debug_http => false,
|
9
|
+
|
10
|
+
:log_device => :stderr, # [:stdout, :stderr, :devnull, path, fd]
|
11
|
+
:log_level => :warn, # [:debug, :info, :warn, :error, :fatal, (-6..-1)]
|
12
|
+
:log_colorize => true
|
13
|
+
}.freeze
|
14
|
+
|
15
|
+
attr_reader *CONFIG_VARS.keys, :config_map
|
16
|
+
|
17
|
+
def initialize(**config_map)
|
18
|
+
config_map.each do |k,v|
|
19
|
+
# allows attr_reader methods from CONFIG_VAR to work
|
20
|
+
instance_variable_set :"@#{k}", v
|
21
|
+
end
|
22
|
+
|
23
|
+
@config_map = config_map
|
24
|
+
end
|
25
|
+
|
26
|
+
class << self
|
27
|
+
def configure(config=nil, &block)
|
28
|
+
map = config ? config.config_map : CONFIG_VARS.dup
|
29
|
+
yield map if block_given?
|
30
|
+
Config.new map
|
31
|
+
end
|
32
|
+
end
|
33
|
+
|
34
|
+
end
|
35
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module CoreExt
|
3
|
+
refine String do
|
4
|
+
def underscore
|
5
|
+
uncamelify = self.gsub /[a-z\W][A-Z]/ do |m|
|
6
|
+
m.gsub /(^.)/, '\1_'
|
7
|
+
end
|
8
|
+
uncamelify.downcase.gsub(/[^a-z0-9]+/, '_')
|
9
|
+
end
|
10
|
+
|
11
|
+
def demodulize
|
12
|
+
self.split('::').last
|
13
|
+
end
|
14
|
+
|
15
|
+
def camelcase
|
16
|
+
self.gsub /_(.)/ do |match|
|
17
|
+
match[1].upcase
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
data/lib/bkblz/logger.rb
ADDED
@@ -0,0 +1,139 @@
|
|
1
|
+
require 'logger'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
class Logger
|
5
|
+
COLOR_MAP = {
|
6
|
+
:d => :green,
|
7
|
+
:i => :blue,
|
8
|
+
:w => :yellow,
|
9
|
+
:e => :red,
|
10
|
+
:f => :pink
|
11
|
+
}
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def configure(config)
|
15
|
+
device = configure_device config.log_device
|
16
|
+
|
17
|
+
logger = ::Logger.new device
|
18
|
+
class << logger
|
19
|
+
include LoggerDebugLevels
|
20
|
+
end
|
21
|
+
raise "missing logger debug methods" unless logger.respond_to? :debug1
|
22
|
+
|
23
|
+
logger.level = case config.log_level
|
24
|
+
when Symbol, String
|
25
|
+
::Logger.const_get config.log_level.to_s.upcase
|
26
|
+
when Integer
|
27
|
+
# Negative numbers can be used for detailed debug levels
|
28
|
+
config.log_level
|
29
|
+
end
|
30
|
+
|
31
|
+
colorize = config.log_colorize && device.tty?
|
32
|
+
logger.formatter = default_formatter colorize
|
33
|
+
|
34
|
+
if config.log_colorize && !device.tty?
|
35
|
+
logger.warn "disabled log colorization for non-tty"
|
36
|
+
end
|
37
|
+
|
38
|
+
logger
|
39
|
+
end
|
40
|
+
|
41
|
+
private
|
42
|
+
def configure_device(device_value)
|
43
|
+
case device_value
|
44
|
+
when :stderr
|
45
|
+
STDERR
|
46
|
+
when :stdout
|
47
|
+
STDOUT
|
48
|
+
when :devnull
|
49
|
+
File.open File::NULL, "w"
|
50
|
+
when Integer
|
51
|
+
IO.new device_value, 'a'
|
52
|
+
when String
|
53
|
+
File.new device_value 'a'
|
54
|
+
else
|
55
|
+
raise ConfigError, "log_device => #{device_value}"
|
56
|
+
end
|
57
|
+
end
|
58
|
+
|
59
|
+
def default_formatter(colorize)
|
60
|
+
lambda do |severity, datetime, progname, msg|
|
61
|
+
s_key = severity[0].downcase.to_sym
|
62
|
+
if colorize && COLOR_MAP[s_key]
|
63
|
+
severity = Styleizer.apply severity, COLOR_MAP[s_key]
|
64
|
+
progname = Styleizer.apply progname, :bold, :dark_gray
|
65
|
+
end
|
66
|
+
|
67
|
+
if progname
|
68
|
+
"[%s] (%s): %s\n" % [severity, progname, msg]
|
69
|
+
else
|
70
|
+
"[%s] %s\n" % [severity, msg]
|
71
|
+
end
|
72
|
+
end
|
73
|
+
end
|
74
|
+
end
|
75
|
+
|
76
|
+
module LoggerDebugLevels
|
77
|
+
NUM_DEBUG_LEVELS = 6
|
78
|
+
|
79
|
+
##
|
80
|
+
# Adds methods debug1, debug2, ... debug6 for more detailed
|
81
|
+
# debug levels. Set a negative index +logger.level+ to enable
|
82
|
+
# lower levels, e.g. logger.level = -6 for debug6 messages.
|
83
|
+
(1..NUM_DEBUG_LEVELS).to_a.each do |debug_level|
|
84
|
+
debug_method_name = "debug#{debug_level}"
|
85
|
+
|
86
|
+
define_method debug_method_name do |*args, &block|
|
87
|
+
severity = debug_level * -1
|
88
|
+
return if severity < self.level
|
89
|
+
|
90
|
+
debug_at_level severity, *args, &block
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
def format_severity(severity)
|
95
|
+
if severity < ::Logger::DEBUG
|
96
|
+
return "D" + severity.abs.to_s
|
97
|
+
else
|
98
|
+
super(severity)[0]
|
99
|
+
end
|
100
|
+
end
|
101
|
+
|
102
|
+
private
|
103
|
+
def debug_at_level(severity, progname=nil, &block)
|
104
|
+
raise 'block required for super debug loggers' unless block_given?
|
105
|
+
raise 'progname required for super debug loggers' unless progname
|
106
|
+
|
107
|
+
add severity, nil, progname, &block
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
class Styleizer
|
112
|
+
class << self
|
113
|
+
|
114
|
+
STYLE_CODES = {
|
115
|
+
:bold => 1,
|
116
|
+
:red => 31,
|
117
|
+
:green => 32,
|
118
|
+
:yellow => 33,
|
119
|
+
:blue => 34,
|
120
|
+
:pink => 35,
|
121
|
+
:light_blue => 36,
|
122
|
+
:light_gray => 37,
|
123
|
+
:dark_gray => 90
|
124
|
+
}
|
125
|
+
|
126
|
+
def apply(str, *styles)
|
127
|
+
return str unless str
|
128
|
+
styles.reduce(str) { |str, style| styleize STYLE_CODES[style], str }
|
129
|
+
end
|
130
|
+
|
131
|
+
private
|
132
|
+
def styleize(color_code, str)
|
133
|
+
"\e[#{color_code}m#{str}\e[0m"
|
134
|
+
end
|
135
|
+
end
|
136
|
+
end
|
137
|
+
|
138
|
+
end
|
139
|
+
end
|
@@ -0,0 +1,21 @@
|
|
1
|
+
module Bkblz
|
2
|
+
class MapKeyFormatter
|
3
|
+
using Bkblz::CoreExt
|
4
|
+
|
5
|
+
def self.underscore_keys(map)
|
6
|
+
modified_map = {}
|
7
|
+
map.each do |k,v|
|
8
|
+
modified_map[k.to_s.underscore.to_sym] = v
|
9
|
+
end
|
10
|
+
modified_map
|
11
|
+
end
|
12
|
+
|
13
|
+
def self.camelcase_keys(map)
|
14
|
+
modified_map = {}
|
15
|
+
map.each do |k,v|
|
16
|
+
modified_map[k.to_s.camelcase.to_sym] = v
|
17
|
+
end
|
18
|
+
modified_map
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
data/lib/bkblz/v1/all.rb
ADDED
@@ -0,0 +1,16 @@
|
|
1
|
+
require_relative "model_base"
|
2
|
+
require_relative "models"
|
3
|
+
|
4
|
+
require_relative "session"
|
5
|
+
require_relative "response"
|
6
|
+
require_relative "request"
|
7
|
+
require_relative "error_response"
|
8
|
+
|
9
|
+
require_relative "authorize_account"
|
10
|
+
require_relative "list_buckets"
|
11
|
+
require_relative "create_bucket"
|
12
|
+
require_relative "delete_bucket"
|
13
|
+
require_relative "get_upload_url"
|
14
|
+
require_relative "upload_file"
|
15
|
+
require_relative "list_file_versions"
|
16
|
+
require_relative "delete_file_version"
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
class AuthorizeAccountResponse < Response
|
4
|
+
response_accessors :account_id,
|
5
|
+
:api_url,
|
6
|
+
:authorization_token,
|
7
|
+
:download_url,
|
8
|
+
:minimum_part_size
|
9
|
+
end
|
10
|
+
|
11
|
+
class AuthorizeAccountRequest < Request
|
12
|
+
|
13
|
+
API_URL = "https://api.backblaze.com/b2api/v1/b2_authorize_account"
|
14
|
+
|
15
|
+
response_class AuthorizeAccountResponse
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
req = Net::HTTP::Get.new URI(API_URL)
|
19
|
+
req.basic_auth(session.config.account_id, session.config.application_key)
|
20
|
+
req
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class CreateBucketResponse < Response
|
5
|
+
response_model Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class CreateBucketRequest < Request
|
9
|
+
|
10
|
+
response_class CreateBucketResponse
|
11
|
+
url_suffix "/b2api/v1/b2_create_bucket"
|
12
|
+
|
13
|
+
def initialize(bucket_model)
|
14
|
+
@body = bucket_model.to_map
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
session.create_post url(session), @body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class DeleteBucketResponse < Response
|
5
|
+
response_model Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class DeleteBucketRequest < Request
|
9
|
+
|
10
|
+
response_class DeleteBucketResponse
|
11
|
+
url_suffix "/b2api/v1/b2_delete_bucket"
|
12
|
+
|
13
|
+
def initialize(bucket_model)
|
14
|
+
@body = {:bucket_id => bucket_model.bucket_id,
|
15
|
+
:account_id => bucket_model.account_id}
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_request(session)
|
19
|
+
session.create_post url(session), @body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,23 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class DeleteFileVersionResponse < Response
|
5
|
+
response_model Model::PartialFileInfo
|
6
|
+
end
|
7
|
+
|
8
|
+
class DeleteFileVersionRequest < Request
|
9
|
+
|
10
|
+
response_class DeleteFileVersionResponse
|
11
|
+
url_suffix "/b2api/v1/b2_delete_file_version"
|
12
|
+
|
13
|
+
def initialize(short_file_info)
|
14
|
+
@body = {:file_name => short_file_info.file_name,
|
15
|
+
:file_id => short_file_info.file_id}
|
16
|
+
end
|
17
|
+
|
18
|
+
def build_request(session)
|
19
|
+
session.create_post url(session), @body
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
@@ -0,0 +1,24 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
class ErrorResponse < Response
|
4
|
+
|
5
|
+
response_model V1::Model::Error
|
6
|
+
|
7
|
+
ERROR_TYPE = {
|
8
|
+
400 => :BAD_REQUEST,
|
9
|
+
401 => :UNAUTHORIZED,
|
10
|
+
403 => :FORBIDDEN,
|
11
|
+
408 => :REQUEST_TIMEOUT,
|
12
|
+
429 => :TOO_MANY_REQUESTS,
|
13
|
+
500 => :INTERNAL_ERROR,
|
14
|
+
503 => :SERVICE_UNAVAILABLE
|
15
|
+
}
|
16
|
+
|
17
|
+
def message
|
18
|
+
model = self.to_model
|
19
|
+
error_type = ERROR_TYPE[model.status]
|
20
|
+
"[#{model.status}:#{error_type}:#{model.code}] #{model.message}"
|
21
|
+
end
|
22
|
+
end
|
23
|
+
end
|
24
|
+
end
|
@@ -0,0 +1,22 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class GetUploadUrlResponse < Response
|
5
|
+
response_model Model::UploadAuth
|
6
|
+
end
|
7
|
+
|
8
|
+
class GetUploadUrlRequest < Request
|
9
|
+
|
10
|
+
response_class GetUploadUrlResponse
|
11
|
+
url_suffix "/b2api/v1/b2_get_upload_url"
|
12
|
+
|
13
|
+
def initialize(bucket_id)
|
14
|
+
@body = {:bucket_id => bucket_id}
|
15
|
+
end
|
16
|
+
|
17
|
+
def build_request(session)
|
18
|
+
session.create_post url(session), @body
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
end
|
@@ -0,0 +1,18 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class ListBucketsResponse < Response
|
5
|
+
response_accessor :buckets, Model::Bucket
|
6
|
+
end
|
7
|
+
|
8
|
+
class ListBucketsRequest < Request
|
9
|
+
|
10
|
+
response_class ListBucketsResponse
|
11
|
+
url_suffix "/b2api/v1/b2_list_buckets"
|
12
|
+
|
13
|
+
def build_request(session)
|
14
|
+
session.create_post url(session), :account_id => session.account_id
|
15
|
+
end
|
16
|
+
end
|
17
|
+
end
|
18
|
+
end
|
@@ -0,0 +1,43 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class ListFileVersionsResponse < PaginatedResponse
|
5
|
+
response_accessor :files, Model::FileInfo
|
6
|
+
pagination_accessors :next_file_name, :next_file_id
|
7
|
+
|
8
|
+
def build_next_request(limit)
|
9
|
+
bucket = original_request.bucket
|
10
|
+
ListFileVersionsRequest.new bucket, limit, self
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ListFileVersionsRequest < Request
|
15
|
+
|
16
|
+
response_class ListFileVersionsResponse
|
17
|
+
url_suffix "/b2api/v1/b2_list_file_versions"
|
18
|
+
|
19
|
+
attr_reader :bucket
|
20
|
+
|
21
|
+
def initialize(bucket, max_file_count=1000, paginate_from=nil)
|
22
|
+
@bucket = bucket
|
23
|
+
@body = {}
|
24
|
+
@body[:bucket_id] = bucket.bucket_id
|
25
|
+
@body[:max_file_count] = max_file_count
|
26
|
+
|
27
|
+
if paginate_from
|
28
|
+
raise 'invalid paginator' unless paginate_from.is_a? ListFileVersionsResponse
|
29
|
+
|
30
|
+
next_file_name = paginate_from.next_file_name
|
31
|
+
next_file_id = paginate_from.next_file_id
|
32
|
+
|
33
|
+
@body[:start_file_name] = next_file_name if next_file_name
|
34
|
+
@body[:start_file_id] = next_file_id if next_file_id
|
35
|
+
end
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_request(session)
|
39
|
+
session.create_post url(session), @body
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
43
|
+
end
|
@@ -0,0 +1,37 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
module Model
|
4
|
+
|
5
|
+
def self.define(*fields)
|
6
|
+
model_klass = Class.new BaseModel
|
7
|
+
model_klass.field_accessors *fields
|
8
|
+
model_klass
|
9
|
+
end
|
10
|
+
|
11
|
+
class BaseModel
|
12
|
+
|
13
|
+
class << self
|
14
|
+
def field_accessors(*fields)
|
15
|
+
fields.each do |field|
|
16
|
+
define_method field do |*args|
|
17
|
+
@map[field]
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
end
|
22
|
+
|
23
|
+
def initialize(map)
|
24
|
+
@map = map
|
25
|
+
end
|
26
|
+
|
27
|
+
def to_map
|
28
|
+
@map.dup
|
29
|
+
end
|
30
|
+
|
31
|
+
def to_s
|
32
|
+
"#<%s:%d %s>" % [self.class.name, __id__, @map]
|
33
|
+
end
|
34
|
+
end
|
35
|
+
end
|
36
|
+
end
|
37
|
+
end
|
@@ -0,0 +1,29 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
module Model
|
4
|
+
|
5
|
+
# Returned by list_buckets, create_bucket, delete_bucket
|
6
|
+
Bucket = Model.define :account_id, :bucket_id, :bucket_name, :bucket_type
|
7
|
+
|
8
|
+
# Returned by list_file_versions
|
9
|
+
File = Model.define *[
|
10
|
+
:action, :content_length, :file_id, :file_name, :size, :upload_timestamp
|
11
|
+
]
|
12
|
+
|
13
|
+
# Returned by upload_file
|
14
|
+
FileInfo = Model.define *[
|
15
|
+
:account_id, :bucket_id, :content_length, :content_sha1, :content_type,
|
16
|
+
:file_id, :file_info, :file_name
|
17
|
+
]
|
18
|
+
|
19
|
+
# Returned by delete_file_version
|
20
|
+
PartialFileInfo = Model.define :file_id, :file_name
|
21
|
+
|
22
|
+
# Returned by get_upload_url
|
23
|
+
UploadAuth = Model.define :bucket_id, :upload_url, :authorization_token
|
24
|
+
|
25
|
+
# Possibly returned by any request
|
26
|
+
Error = Model.define :status, :code, :message
|
27
|
+
end
|
28
|
+
end
|
29
|
+
end
|
@@ -0,0 +1,81 @@
|
|
1
|
+
require 'net/http'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
TooManyRedirectError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class RequestError < Bkblz::BaseError
|
9
|
+
def initialize(error_response)
|
10
|
+
super error_response.message
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class Request
|
15
|
+
|
16
|
+
class << self
|
17
|
+
def response_class(klass=nil)
|
18
|
+
@response_class = klass unless klass.nil?
|
19
|
+
@response_class
|
20
|
+
end
|
21
|
+
|
22
|
+
def url_suffix(suffix=nil)
|
23
|
+
@url_suffix = suffix unless suffix.nil?
|
24
|
+
@url_suffix
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
def send(session)
|
29
|
+
request = build_request session
|
30
|
+
Bkblz.log.debug { "sending request => #{request} to URI => #{request.uri}" }
|
31
|
+
http = Net::HTTP.new(request.uri.host, request.uri.port)
|
32
|
+
http.use_ssl = true
|
33
|
+
http.set_debug_output(STDERR) if session.config.debug_http
|
34
|
+
|
35
|
+
build_response fetch(http, request)
|
36
|
+
end
|
37
|
+
|
38
|
+
protected
|
39
|
+
|
40
|
+
def build_request(session)
|
41
|
+
raise 'not implemented'
|
42
|
+
end
|
43
|
+
|
44
|
+
def build_response(response)
|
45
|
+
unless response.kind_of? Net::HTTPSuccess
|
46
|
+
error_response = ErrorResponse.new response, self
|
47
|
+
raise RequestError.new error_response
|
48
|
+
end
|
49
|
+
Bkblz.log.debug { "#build_response => #{response}" }
|
50
|
+
|
51
|
+
response_class = self.class.response_class || Response
|
52
|
+
response_class.new response, self
|
53
|
+
end
|
54
|
+
|
55
|
+
def url(session)
|
56
|
+
raise "no URL suffix for #{self.class}" unless self.class.url_suffix
|
57
|
+
session.create_url(self.class.url_suffix)
|
58
|
+
end
|
59
|
+
|
60
|
+
private
|
61
|
+
|
62
|
+
def fetch(http, request, limit=10)
|
63
|
+
# You should choose a better exception.
|
64
|
+
raise TooManyRedirectError, 'too many HTTP redirects' if limit == 0
|
65
|
+
|
66
|
+
response = http.start { |http| http.request(request) }
|
67
|
+
|
68
|
+
case response
|
69
|
+
when Net::HTTPSuccess then
|
70
|
+
response
|
71
|
+
when Net::HTTPRedirection then
|
72
|
+
location = response['location']
|
73
|
+
Bkblz.log.warn "redirected to #{location}"
|
74
|
+
fetch http, location, limit - 1
|
75
|
+
else
|
76
|
+
response
|
77
|
+
end
|
78
|
+
end
|
79
|
+
end
|
80
|
+
end
|
81
|
+
end
|
@@ -0,0 +1,114 @@
|
|
1
|
+
require 'json'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
class Response
|
6
|
+
|
7
|
+
MissingResponseError = Class.new Bkblz::BaseError
|
8
|
+
|
9
|
+
attr_reader :parsed_body, :http_response
|
10
|
+
|
11
|
+
class << self
|
12
|
+
|
13
|
+
def response_model(klass=nil)
|
14
|
+
@response_model = klass unless klass.nil?
|
15
|
+
@response_model
|
16
|
+
end
|
17
|
+
|
18
|
+
def response_accessors(*response_fields)
|
19
|
+
response_fields.each do |response_field|
|
20
|
+
response_accessor response_field
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
def response_accessor(response_field, model_klass=nil, &block)
|
25
|
+
api_map_key_converter = lambda do |map|
|
26
|
+
raise "not a Hash" unless map.is_a? Hash
|
27
|
+
Bkblz::MapKeyFormatter.underscore_keys map
|
28
|
+
end
|
29
|
+
api_value_transformer = lambda do |value|
|
30
|
+
return value unless model_klass || block_given?
|
31
|
+
return yield value if block_given?
|
32
|
+
|
33
|
+
if value.is_a? Array
|
34
|
+
value.map do |v|
|
35
|
+
model_klass.new api_map_key_converter.call(v)
|
36
|
+
end
|
37
|
+
else
|
38
|
+
model_klass.new api_map_key_converter.call(value)
|
39
|
+
end
|
40
|
+
end
|
41
|
+
|
42
|
+
define_method response_field do |*args|
|
43
|
+
raise MissingResponseError unless @parsed_response
|
44
|
+
return @cache[response_field] if @cache.key? response_field
|
45
|
+
|
46
|
+
value = @parsed_response[response_field]
|
47
|
+
@cache[response_field] = api_value_transformer.call value
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
51
|
+
|
52
|
+
def initialize(http_response, original_request)
|
53
|
+
@http_response = http_response
|
54
|
+
@original_request = original_request
|
55
|
+
|
56
|
+
@parsed_response = parse http_response
|
57
|
+
@cache = {}
|
58
|
+
Bkblz.log.debug { "parsed response => #{@parsed_response}" }
|
59
|
+
end
|
60
|
+
|
61
|
+
attr_reader :original_request
|
62
|
+
protected :original_request
|
63
|
+
|
64
|
+
def [](key)
|
65
|
+
@parsed_response[key]
|
66
|
+
end
|
67
|
+
|
68
|
+
def to_model
|
69
|
+
raise 'no response model defined' unless self.class.response_model
|
70
|
+
self.class.response_model.new @parsed_response.dup
|
71
|
+
end
|
72
|
+
|
73
|
+
private
|
74
|
+
def parse(http_response)
|
75
|
+
parsed_json = JSON.parse http_response.body, {
|
76
|
+
:allow_nan => true,
|
77
|
+
:symbolize_names => true,
|
78
|
+
:max_nesting => 4
|
79
|
+
}
|
80
|
+
Bkblz::MapKeyFormatter.underscore_keys parsed_json
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class PaginatedResponse < Response
|
85
|
+
|
86
|
+
NoMorePagesError = Class.new Bkblz::BaseError
|
87
|
+
|
88
|
+
class << self
|
89
|
+
|
90
|
+
attr_reader :pagination_fields
|
91
|
+
def pagination_accessors(*pagination_fields)
|
92
|
+
response_accessors *pagination_fields
|
93
|
+
|
94
|
+
@pagination_fields ||= []
|
95
|
+
@pagination_fields.concat pagination_fields
|
96
|
+
end
|
97
|
+
end
|
98
|
+
|
99
|
+
def has_more?
|
100
|
+
self.class.pagination_fields.any? { |f| !self[f].nil? }
|
101
|
+
end
|
102
|
+
|
103
|
+
def next_request(limit=nil)
|
104
|
+
raise NoMorePagesError unless has_more?
|
105
|
+
build_next_request(limit)
|
106
|
+
end
|
107
|
+
|
108
|
+
private
|
109
|
+
def build_next_request(limit)
|
110
|
+
raise "not implemented"
|
111
|
+
end
|
112
|
+
end
|
113
|
+
end
|
114
|
+
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
require 'uri'
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
SessionNotAuthorizedError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class Session
|
9
|
+
|
10
|
+
class << self
|
11
|
+
def authorize(config, &block)
|
12
|
+
session = Session.new config
|
13
|
+
session.auth_response =
|
14
|
+
session.send Bkblz::V1::AuthorizeAccountRequest.new
|
15
|
+
|
16
|
+
yield(session) if block_given?
|
17
|
+
session
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
attr_accessor :config, :auth_response
|
22
|
+
|
23
|
+
def initialize(config)
|
24
|
+
@config = config
|
25
|
+
end
|
26
|
+
|
27
|
+
def send(request)
|
28
|
+
request.send self
|
29
|
+
end
|
30
|
+
|
31
|
+
def account_id
|
32
|
+
check_authorized
|
33
|
+
auth_response.account_id
|
34
|
+
end
|
35
|
+
|
36
|
+
def authorized?
|
37
|
+
!!auth_response && !!auth_response.authorization_token
|
38
|
+
end
|
39
|
+
|
40
|
+
def create_url(url_suffix)
|
41
|
+
check_authorized
|
42
|
+
URI.join auth_response.api_url, url_suffix
|
43
|
+
end
|
44
|
+
|
45
|
+
def create_post(url, body=nil, addl_headers={})
|
46
|
+
Bkblz.log.debug { "creating post for request => #{url}" }
|
47
|
+
check_authorized
|
48
|
+
|
49
|
+
uri = url.is_a?(URI) ? url : URI(url)
|
50
|
+
request = Net::HTTP::Post.new uri
|
51
|
+
|
52
|
+
if body.is_a? Hash
|
53
|
+
body = Bkblz::MapKeyFormatter.camelcase_keys(body).to_json
|
54
|
+
end
|
55
|
+
request.body = body if body
|
56
|
+
|
57
|
+
headers = {:"Authorization" => auth_response.authorization_token}
|
58
|
+
headers.merge(addl_headers).each do |k,v|
|
59
|
+
Bkblz.log.debug2 { "adding request header => #{k}:#{v}" }
|
60
|
+
request.add_field k.to_s, v unless v.nil?
|
61
|
+
end
|
62
|
+
|
63
|
+
request
|
64
|
+
end
|
65
|
+
|
66
|
+
private
|
67
|
+
def check_authorized
|
68
|
+
raise SessionNotAuthorizedError unless authorized?
|
69
|
+
end
|
70
|
+
end
|
71
|
+
end
|
72
|
+
end
|
@@ -0,0 +1,50 @@
|
|
1
|
+
require "digest/sha1"
|
2
|
+
|
3
|
+
module Bkblz
|
4
|
+
module V1
|
5
|
+
|
6
|
+
TooManyBzInfoHeadersError = Class.new Bkblz::BaseError
|
7
|
+
|
8
|
+
class UploadFileResponse < Response
|
9
|
+
response_model Model::FileInfo
|
10
|
+
end
|
11
|
+
|
12
|
+
class UploadFileRequest < Request
|
13
|
+
|
14
|
+
response_class UploadFileResponse
|
15
|
+
|
16
|
+
REQUIRED_HEADERS = {
|
17
|
+
:"Authorization" => nil,
|
18
|
+
:"X-Bz-File-Name" => nil,
|
19
|
+
:"Content-Type" => "b2/x-auto",
|
20
|
+
:"Content-Length" => nil,
|
21
|
+
:"X-Bz-Content-Sha1" => nil
|
22
|
+
}
|
23
|
+
|
24
|
+
def initialize(upload_auth, body, file_name, content_type=nil,
|
25
|
+
last_modified_millis=nil, **bz_info)
|
26
|
+
unless last_modified_millis
|
27
|
+
# Recommended https://www.backblaze.com/b2/docs/b2_upload_file.html
|
28
|
+
bz_info["src_last_modified_millis"] = last_modified_millis
|
29
|
+
end
|
30
|
+
raise TooManyBzInfoHeadersError, bz_info_headers if bz_info.size > 10
|
31
|
+
|
32
|
+
@upload_url = upload_auth.upload_url
|
33
|
+
@body = body.is_a?(IO) ? body.read : body
|
34
|
+
@headers = REQUIRED_HEADERS.dup
|
35
|
+
bz_info.each do |k,v|
|
36
|
+
@headers["X-Bz-Info-#{k.to-s}".to_sym] = v
|
37
|
+
end
|
38
|
+
|
39
|
+
@headers[:"Authorization"] = upload_auth.authorization_token
|
40
|
+
@headers[:"X-Bz-File-Name"] = file_name
|
41
|
+
@headers[:"Content-Length"] = @body.size
|
42
|
+
@headers[:"X-Bz-Content-Sha1"] = Digest::SHA1.hexdigest @body
|
43
|
+
end
|
44
|
+
|
45
|
+
def build_request(session)
|
46
|
+
session.create_post @upload_url, @body, @headers
|
47
|
+
end
|
48
|
+
end
|
49
|
+
end
|
50
|
+
end
|
metadata
ADDED
@@ -0,0 +1,116 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bkblz
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.1.0
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Erick Johnson
|
8
|
+
autorequire:
|
9
|
+
bindir: bin
|
10
|
+
cert_chain: []
|
11
|
+
date: 2016-11-06 00:00:00.000000000 Z
|
12
|
+
dependencies:
|
13
|
+
- !ruby/object:Gem::Dependency
|
14
|
+
name: bundler
|
15
|
+
requirement: !ruby/object:Gem::Requirement
|
16
|
+
requirements:
|
17
|
+
- - "~>"
|
18
|
+
- !ruby/object:Gem::Version
|
19
|
+
version: '1.13'
|
20
|
+
type: :development
|
21
|
+
prerelease: false
|
22
|
+
version_requirements: !ruby/object:Gem::Requirement
|
23
|
+
requirements:
|
24
|
+
- - "~>"
|
25
|
+
- !ruby/object:Gem::Version
|
26
|
+
version: '1.13'
|
27
|
+
- !ruby/object:Gem::Dependency
|
28
|
+
name: rake
|
29
|
+
requirement: !ruby/object:Gem::Requirement
|
30
|
+
requirements:
|
31
|
+
- - "~>"
|
32
|
+
- !ruby/object:Gem::Version
|
33
|
+
version: '10.0'
|
34
|
+
type: :development
|
35
|
+
prerelease: false
|
36
|
+
version_requirements: !ruby/object:Gem::Requirement
|
37
|
+
requirements:
|
38
|
+
- - "~>"
|
39
|
+
- !ruby/object:Gem::Version
|
40
|
+
version: '10.0'
|
41
|
+
- !ruby/object:Gem::Dependency
|
42
|
+
name: rspec
|
43
|
+
requirement: !ruby/object:Gem::Requirement
|
44
|
+
requirements:
|
45
|
+
- - "~>"
|
46
|
+
- !ruby/object:Gem::Version
|
47
|
+
version: '3.0'
|
48
|
+
type: :development
|
49
|
+
prerelease: false
|
50
|
+
version_requirements: !ruby/object:Gem::Requirement
|
51
|
+
requirements:
|
52
|
+
- - "~>"
|
53
|
+
- !ruby/object:Gem::Version
|
54
|
+
version: '3.0'
|
55
|
+
description: ''
|
56
|
+
email:
|
57
|
+
- erick@vos.io
|
58
|
+
executables: []
|
59
|
+
extensions: []
|
60
|
+
extra_rdoc_files: []
|
61
|
+
files:
|
62
|
+
- ".gitignore"
|
63
|
+
- ".rspec"
|
64
|
+
- ".travis.yml"
|
65
|
+
- Gemfile
|
66
|
+
- LICENSE.txt
|
67
|
+
- README.rb
|
68
|
+
- Rakefile
|
69
|
+
- bkblz.gemspec
|
70
|
+
- lib/all.rb
|
71
|
+
- lib/bkblz.rb
|
72
|
+
- lib/bkblz/config.rb
|
73
|
+
- lib/bkblz/core_ext.rb
|
74
|
+
- lib/bkblz/logger.rb
|
75
|
+
- lib/bkblz/map_key_formatter.rb
|
76
|
+
- lib/bkblz/v1/all.rb
|
77
|
+
- lib/bkblz/v1/authorize_account.rb
|
78
|
+
- lib/bkblz/v1/create_bucket.rb
|
79
|
+
- lib/bkblz/v1/delete_bucket.rb
|
80
|
+
- lib/bkblz/v1/delete_file_version.rb
|
81
|
+
- lib/bkblz/v1/error_response.rb
|
82
|
+
- lib/bkblz/v1/get_upload_url.rb
|
83
|
+
- lib/bkblz/v1/list_buckets.rb
|
84
|
+
- lib/bkblz/v1/list_file_versions.rb
|
85
|
+
- lib/bkblz/v1/model_base.rb
|
86
|
+
- lib/bkblz/v1/models.rb
|
87
|
+
- lib/bkblz/v1/request.rb
|
88
|
+
- lib/bkblz/v1/response.rb
|
89
|
+
- lib/bkblz/v1/session.rb
|
90
|
+
- lib/bkblz/v1/upload_file.rb
|
91
|
+
- lib/bkblz/version.rb
|
92
|
+
homepage: https://github.com/erickj/bkblz
|
93
|
+
licenses:
|
94
|
+
- MIT
|
95
|
+
metadata: {}
|
96
|
+
post_install_message:
|
97
|
+
rdoc_options: []
|
98
|
+
require_paths:
|
99
|
+
- lib
|
100
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
101
|
+
requirements:
|
102
|
+
- - ">="
|
103
|
+
- !ruby/object:Gem::Version
|
104
|
+
version: '0'
|
105
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
106
|
+
requirements:
|
107
|
+
- - ">="
|
108
|
+
- !ruby/object:Gem::Version
|
109
|
+
version: '0'
|
110
|
+
requirements: []
|
111
|
+
rubyforge_project:
|
112
|
+
rubygems_version: 2.5.1
|
113
|
+
signing_key:
|
114
|
+
specification_version: 4
|
115
|
+
summary: Bkblz GEM for the Backblaze B2 API. https://www.backblaze.com/b2/docs/
|
116
|
+
test_files: []
|