bkblz 0.1.2 → 0.1.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/README.rb +165 -95
- data/bin/bkblz +1 -3
- data/lib/bkblz/v1/all.rb +1 -0
- data/lib/bkblz/v1/download_file.rb +67 -0
- data/lib/bkblz/v1/models.rb +5 -0
- data/lib/bkblz/v1/request.rb +2 -1
- data/lib/bkblz/v1/response.rb +0 -1
- data/lib/bkblz/v1/session.rb +23 -7
- data/lib/bkblz/version.rb +1 -1
- metadata +3 -2
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 4c2440a3e12c3022fbc44a05079430bc77c80a56
|
4
|
+
data.tar.gz: 667e2e0a9a71e6ceaf81aec43eca2f6e1f9c2d51
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 0b2c6b5912e130d96ffab0390e098fd0b35e197f30240a856b21fca701cbe56396d7ecd5bb04fd9e5587725c430322e5f04e867acee8e578a02bcd5a9aae0652
|
7
|
+
data.tar.gz: ea2b13a18d20c29bb5929969137dede83e20782f5ecbe38b791d16c3ea0205576f9b2c5ee53b5fcfb92036a4f11a5f015cbeb3632389db59cf2da740dd189aaf
|
data/README.rb
CHANGED
@@ -1,8 +1,28 @@
|
|
1
|
-
|
2
|
-
# application key and account id in the slots below.
|
1
|
+
=begin
|
3
2
|
|
4
|
-
|
5
|
-
|
3
|
+
This is the bkblz ruby gem, a library for the Backblaze B2 cloud
|
4
|
+
storage API: https://www.backblaze.com/b2/docs/
|
5
|
+
|
6
|
+
Currently the gem supports the following V1 API calls:
|
7
|
+
|
8
|
+
* b2_authorize_account
|
9
|
+
* b2_create_bucket
|
10
|
+
* b2_delete_bucket
|
11
|
+
* b2_delete_file_version
|
12
|
+
* b2_list_buckets
|
13
|
+
* b2_list_file_names
|
14
|
+
* b2_list_file_versions
|
15
|
+
* b2_upload_file
|
16
|
+
* b2_download_file_by_id
|
17
|
+
* b2_download_file_by_name
|
18
|
+
|
19
|
+
Run `ruby README.rb` for a working demo, but first add your
|
20
|
+
application key and account id in the slots below.
|
21
|
+
|
22
|
+
Or `gem install bkblz` to begin. After install try `bkblz -h` to use
|
23
|
+
the CLI
|
24
|
+
|
25
|
+
=end
|
6
26
|
|
7
27
|
$: << 'lib'
|
8
28
|
require 'bkblz'
|
@@ -29,109 +49,157 @@ if Bkblz.config.account_id.match /!!!/
|
|
29
49
|
exit 1
|
30
50
|
end
|
31
51
|
|
32
|
-
|
33
|
-
# Using the config above, create an authorized session. All
|
34
|
-
# requests will run in the context of this session. See
|
35
|
-
# +Bkblz::V1::Session#authorize+.
|
36
|
-
EOS
|
37
|
-
end
|
38
|
-
Bkblz::V1::Session.authorize Bkblz.config do |api_session|
|
39
|
-
Bkblz.log.info "API session => #{api_session}"
|
40
|
-
|
41
|
-
Bkblz.log.info do <<-EOS
|
42
|
-
# First try to find an existing bucket named my-test-bucket,
|
43
|
-
# we'll use that if it exists. All requests in a session are sent
|
44
|
-
# through the session so that the request object gets access to the
|
45
|
-
# auth credentials.
|
46
|
-
EOS
|
47
|
-
end
|
48
|
-
buckets = api_session.send(Bkblz::V1::ListBucketsRequest.new).buckets
|
49
|
-
bucket = buckets.select { |b| b.bucket_name == "my-test-bucket" }.first
|
50
|
-
Bkblz.log.info "bucket list => #{buckets}"
|
51
|
-
|
52
|
+
def run_readme
|
52
53
|
Bkblz.log.info do <<-EOS
|
53
|
-
#
|
54
|
+
# Using the config above, create an authorized session. All
|
55
|
+
# requests will run in the context of this session. See
|
56
|
+
# +Bkblz::V1::Session#authorize+.
|
54
57
|
EOS
|
55
58
|
end
|
56
|
-
|
57
|
-
|
58
|
-
:bucket_name => "my-test-bucket",
|
59
|
-
:bucket_type => "allPrivate",
|
60
|
-
:account_id => api_session.account_id
|
59
|
+
Bkblz::V1::Session.authorize Bkblz.config do |session|
|
60
|
+
Bkblz.log.info "API session => #{session}"
|
61
61
|
|
62
62
|
Bkblz.log.info do <<-EOS
|
63
|
-
#
|
64
|
-
#
|
65
|
-
#
|
66
|
-
#
|
67
|
-
# objects. See Bkblz::V1::Model::Base for how it work.
|
63
|
+
# First try to find an existing bucket named my-test-bucket,
|
64
|
+
# we'll use that if it exists. All requests in a session are sent
|
65
|
+
# through the session so that the request object gets access to the
|
66
|
+
# auth credentials.
|
68
67
|
EOS
|
69
68
|
end
|
70
|
-
|
71
|
-
Bkblz.log.info "bucket
|
72
|
-
|
73
|
-
# Bkblz::V1::Response objects are returned from +send+. Some
|
74
|
-
# provide a to_model method if they declare the +response_model+
|
75
|
-
# in the class definition.
|
76
|
-
bucket = api_session.send(request).to_model
|
77
|
-
Bkblz.log.info "created bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
78
|
-
end
|
79
|
-
|
80
|
-
Bkblz.log.info do <<-EOS
|
81
|
-
# Uploading a file begins with getting a dynamic URL from the API.
|
82
|
-
EOS
|
83
|
-
end
|
84
|
-
upload_auth = api_session.send(
|
85
|
-
Bkblz::V1::GetUploadUrlRequest.new bucket.bucket_id).to_model
|
86
|
-
Bkblz.log.info "upload file URL => #{upload_auth.upload_url}"
|
69
|
+
buckets = session.send(Bkblz::V1::ListBucketsRequest.new).buckets
|
70
|
+
Bkblz.log.info "bucket list => #{buckets}"
|
87
71
|
|
72
|
+
new_bucket_name = "bkblz-readme-bucket"
|
73
|
+
bucket = buckets.find { |b| b.bucket_name == new_bucket_name }
|
88
74
|
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
end
|
94
|
-
5.times do |i|
|
95
|
-
body = "some text #{i}"
|
96
|
-
file_name = "some_text_#{i}.txt"
|
97
|
-
content_type = nil
|
75
|
+
Bkblz.log.info do <<-EOS
|
76
|
+
# Otherwise create a new my-test-bucket
|
77
|
+
EOS
|
78
|
+
end
|
98
79
|
|
99
|
-
|
100
|
-
|
80
|
+
begin
|
81
|
+
unless bucket
|
82
|
+
bucket = Bkblz::V1::Model::Bucket.new \
|
83
|
+
:bucket_name => new_bucket_name,
|
84
|
+
:bucket_type => "allPrivate",
|
85
|
+
:account_id => session.account_id
|
86
|
+
|
87
|
+
Bkblz.log.info do <<-EOS
|
88
|
+
# Pass a model to the CreateBucketRequest,
|
89
|
+
# models are just named wrappers with dynamic methods
|
90
|
+
# around the JSON responses provided back from the Bkblz
|
91
|
+
# API. See lib/bkblz/v1/models.rb for a list of defined API
|
92
|
+
# objects. See Bkblz::V1::Model::Base for how it work.
|
93
|
+
EOS
|
94
|
+
end
|
95
|
+
request = Bkblz::V1::CreateBucketRequest.new bucket
|
96
|
+
Bkblz.log.info "bucket model => #{bucket}"
|
97
|
+
|
98
|
+
# Bkblz::V1::Response objects are returned from +send+. Some
|
99
|
+
# provide a to_model method if they declare the +response_model+
|
100
|
+
# in the class definition.
|
101
|
+
bucket = session.send(request).to_model
|
102
|
+
Bkblz.log.info "created bucket => #{bucket}"
|
103
|
+
end
|
104
|
+
|
105
|
+
Bkblz.log.info do <<-EOS
|
106
|
+
# Uploading a file begins with getting a dynamic URL from the API.
|
107
|
+
EOS
|
108
|
+
end
|
109
|
+
upload_auth = session.send(
|
110
|
+
Bkblz::V1::GetUploadUrlRequest.new bucket.bucket_id).to_model
|
111
|
+
Bkblz.log.info "upload file URL => #{upload_auth.upload_url}"
|
112
|
+
|
113
|
+
|
114
|
+
Bkblz.log.info do <<-EOS
|
115
|
+
# Use the upload_auth model (a
|
116
|
+
# Bkblz::V1::Model::UploadAuth) to upload some files.
|
117
|
+
EOS
|
118
|
+
end
|
119
|
+
5.times do |i|
|
120
|
+
body = "some text #{i}"
|
121
|
+
file_name = "some_text_#{i}.txt"
|
122
|
+
content_type = nil
|
123
|
+
|
124
|
+
upload_file_info = session.send(
|
125
|
+
Bkblz::V1::UploadFileRequest.new upload_auth, body, file_name,
|
101
126
|
content_type, Time.now.to_i * 1000).to_model
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
127
|
+
Bkblz.log.info "uploaded file => #{upload_file_info.file_name}"
|
128
|
+
end
|
129
|
+
|
130
|
+
Bkblz.log.info do <<-EOS
|
131
|
+
# We uploaded 5 files above, here we'll read back out
|
132
|
+
# metadata from the first 2 files in the bucket.
|
133
|
+
EOS
|
134
|
+
end
|
135
|
+
list_files_response = session.send(
|
136
|
+
Bkblz::V1::ListFileVersionsRequest.new bucket, 2)
|
137
|
+
bucket_files_info = list_files_response.files
|
138
|
+
Bkblz.log.info "first 2 files => #{bucket_files_info.map(&:file_name).join "\n"}"
|
139
|
+
|
140
|
+
Bkblz.log.info do <<-EOS
|
141
|
+
# The response object returned object is a
|
142
|
+
# Bkblz::Api::PaginatedResponse. Use its +has_more?+ and
|
143
|
+
# +next_request+ methods to page through more results.
|
144
|
+
EOS
|
145
|
+
end
|
146
|
+
while list_files_response.has_more?
|
147
|
+
list_files_response = session.send list_files_response.next_request 100
|
148
|
+
bucket_files_info.concat list_files_response.files
|
149
|
+
Bkblz.log.info "next N files => #{list_files_response.files.map(&:file_name).join "\n"}"
|
150
|
+
end
|
151
|
+
|
152
|
+
Bkblz.log.info do <<-EOS
|
153
|
+
# Files can also be listed by name.
|
154
|
+
EOS
|
155
|
+
end
|
156
|
+
list_files_response = session.send(
|
157
|
+
Bkblz::V1::ListFileNamesRequest.new bucket, 10)
|
158
|
+
bucket_files_info = list_files_response.files
|
159
|
+
Bkblz.log.info "files by name => #{bucket_files_info.map(&:file_name).join "\n"}"
|
160
|
+
|
161
|
+
Bkblz.log.info do <<-EOS
|
162
|
+
# Files can be downloaded by file name
|
163
|
+
EOS
|
164
|
+
end
|
165
|
+
file_name = bucket_files_info.first.file_name
|
166
|
+
file_name_download = session.send(
|
167
|
+
Bkblz::V1::DownloadFileByNameRequest.new bucket, file_name).to_model
|
168
|
+
Bkblz.log.info file_name_download
|
169
|
+
Bkblz.log.info "file body: #{file_name_download.body}"
|
170
|
+
|
171
|
+
Bkblz.log.info do <<-EOS
|
172
|
+
# Files can also be downloaded by file id
|
173
|
+
EOS
|
174
|
+
end
|
175
|
+
file_info = bucket_files_info[1]
|
176
|
+
file_id_download = session.send(
|
177
|
+
Bkblz::V1::DownloadFileByIdRequest.new file_info).to_model
|
178
|
+
Bkblz.log.info file_id_download
|
179
|
+
Bkblz.log.info "file body: #{file_id_download.body}"
|
180
|
+
|
181
|
+
Bkblz.log.info do <<-EOS
|
182
|
+
# File byte ranges can also be downloaded
|
183
|
+
EOS
|
184
|
+
end
|
185
|
+
bytes = (2..8)
|
186
|
+
byte_range_download = session.send(
|
187
|
+
Bkblz::V1::DownloadFileByNameRequest.new bucket, file_name, bytes).to_model
|
188
|
+
Bkblz.log.info "file bytes: #{byte_range_download.body}"
|
189
|
+
rescue => e
|
190
|
+
Bkblz.log.error "there was an error: #{e}"
|
191
|
+
Bkblz.log.error e.backtrace.join "\n"
|
192
|
+
Bkblz.log.warn "cleaning up the bucket"
|
193
|
+
ensure
|
194
|
+
clear_the_bucket session, bucket
|
195
|
+
end
|
125
196
|
end
|
197
|
+
end
|
126
198
|
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
end
|
131
|
-
list_files_response = api_session.send(
|
132
|
-
Bkblz::V1::ListFileNamesRequest.new bucket, 10)
|
199
|
+
def clear_the_bucket(session, bucket)
|
200
|
+
list_files_response = session.send(
|
201
|
+
Bkblz::V1::ListFileVersionsRequest.new bucket)
|
133
202
|
bucket_files_info = list_files_response.files
|
134
|
-
Bkblz.log.info "files by name => #{bucket_files_info.map(&:file_name).join "\n"}"
|
135
203
|
|
136
204
|
Bkblz.log.info do <<-EOS
|
137
205
|
# Delete all the files in the bucket that we added. This is
|
@@ -140,7 +208,7 @@ Bkblz::V1::Session.authorize Bkblz.config do |api_session|
|
|
140
208
|
end
|
141
209
|
bucket_files_info.each do |file_info|
|
142
210
|
request = Bkblz::V1::DeleteFileVersionRequest.new file_info
|
143
|
-
delete_file_version_response =
|
211
|
+
delete_file_version_response = session.send request
|
144
212
|
Bkblz.log.info "deleted file => #{delete_file_version_response.to_model.file_name}"
|
145
213
|
end
|
146
214
|
|
@@ -149,6 +217,8 @@ Bkblz::V1::Session.authorize Bkblz.config do |api_session|
|
|
149
217
|
EOS
|
150
218
|
end
|
151
219
|
request = Bkblz::V1::DeleteBucketRequest.new bucket
|
152
|
-
delete_bucket_response =
|
220
|
+
delete_bucket_response = session.send request
|
153
221
|
Bkblz.log.info "deleted bucket => #{bucket.bucket_name}/#{bucket.bucket_id}"
|
154
222
|
end
|
223
|
+
|
224
|
+
run_readme
|
data/bin/bkblz
CHANGED
@@ -1,5 +1,4 @@
|
|
1
1
|
#!/usr/bin/env ruby
|
2
|
-
$: << "lib"
|
3
2
|
require "bkblz"
|
4
3
|
require "thor"
|
5
4
|
require "yaml"
|
@@ -83,8 +82,7 @@ module Bkblz
|
|
83
82
|
|
84
83
|
file_info = run_task do
|
85
84
|
Bkblz::Task::UploadFile.run Bkblz.config, {
|
86
|
-
:
|
87
|
-
:handle_type => :bucket_name,
|
85
|
+
:bucket_name => bucket_name,
|
88
86
|
:file_path => local_file_path
|
89
87
|
}
|
90
88
|
end
|
data/lib/bkblz/v1/all.rb
CHANGED
@@ -0,0 +1,67 @@
|
|
1
|
+
module Bkblz
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class DownloadFileResponse < Response
|
5
|
+
response_model Model::FileDownload
|
6
|
+
|
7
|
+
def parse(http_response)
|
8
|
+
file_download_fields = {
|
9
|
+
:body => http_response.body,
|
10
|
+
:content_length => http_response["content-length"],
|
11
|
+
:content_type => http_response["content-type"],
|
12
|
+
:file_id => http_response["x-bz-file-id"],
|
13
|
+
:file_name => http_response["x-bz-file-name"],
|
14
|
+
:sha1 => http_response["x-bz-content-sha1"],
|
15
|
+
:x_bz_info => {}
|
16
|
+
}
|
17
|
+
|
18
|
+
http_response.each_header do |k, v|
|
19
|
+
if k.to_s.downcase.match /^x-bz-info/
|
20
|
+
file_download_fields[:x_bz_info][k.to_sym] = v
|
21
|
+
end
|
22
|
+
end
|
23
|
+
|
24
|
+
file_download_fields
|
25
|
+
end
|
26
|
+
end
|
27
|
+
|
28
|
+
class DownloadFileByIdRequest < Request
|
29
|
+
|
30
|
+
response_class DownloadFileResponse
|
31
|
+
url_suffix "/b2api/v1/b2_download_file_by_id"
|
32
|
+
|
33
|
+
def initialize(file_info, byte_range=nil)
|
34
|
+
@body = {:file_id => file_info.file_id}
|
35
|
+
@byte_range = byte_range
|
36
|
+
end
|
37
|
+
|
38
|
+
def build_request(session)
|
39
|
+
headers = {}
|
40
|
+
headers[:Range] = "bytes=%d-%d" % @byte_range.minmax if @byte_range
|
41
|
+
session.create_post url(session), @body, headers
|
42
|
+
end
|
43
|
+
end
|
44
|
+
|
45
|
+
class DownloadFileByNameRequest < Request
|
46
|
+
|
47
|
+
response_class DownloadFileResponse
|
48
|
+
|
49
|
+
def initialize(bucket, file_name, byte_range=nil)
|
50
|
+
@bucket = bucket
|
51
|
+
@file_name = file_name
|
52
|
+
@byte_range = byte_range
|
53
|
+
end
|
54
|
+
|
55
|
+
def build_request(session)
|
56
|
+
headers = {}
|
57
|
+
headers[:Range] = "bytes=%d-%d" % @byte_range.minmax if @byte_range
|
58
|
+
session.create_get url_for_file(session), headers
|
59
|
+
end
|
60
|
+
|
61
|
+
private
|
62
|
+
def url_for_file(session)
|
63
|
+
session.create_url(["file", @bucket.bucket_name, @file_name].join "/")
|
64
|
+
end
|
65
|
+
end
|
66
|
+
end
|
67
|
+
end
|
data/lib/bkblz/v1/models.rb
CHANGED
@@ -10,6 +10,11 @@ module Bkblz
|
|
10
10
|
:action, :content_length, :file_id, :file_name, :size, :upload_timestamp
|
11
11
|
]
|
12
12
|
|
13
|
+
# Returned by download_file_by_name and download_file_by_id
|
14
|
+
FileDownload = Model.define *[
|
15
|
+
:body, :content_length, :content_type, :file_id, :file_name, :sha1, :x_bz_info
|
16
|
+
]
|
17
|
+
|
13
18
|
# Returned by upload_file
|
14
19
|
FileInfo = Model.define *[
|
15
20
|
:account_id, :bucket_id, :content_length, :content_sha1, :content_type,
|
data/lib/bkblz/v1/request.rb
CHANGED
@@ -58,9 +58,10 @@ module Bkblz
|
|
58
58
|
error_response = ErrorResponse.new response, self
|
59
59
|
raise RequestError.create error_response
|
60
60
|
end
|
61
|
-
Bkblz.log.
|
61
|
+
Bkblz.log.debug1(self) { "#build_response => #{response}" }
|
62
62
|
|
63
63
|
response_class = self.class.response_class || Response
|
64
|
+
Bkblz.log.debug1(self) { "#creating response of class => #{response_class}" }
|
64
65
|
response_class.new response, self
|
65
66
|
end
|
66
67
|
|
data/lib/bkblz/v1/response.rb
CHANGED
data/lib/bkblz/v1/session.rb
CHANGED
@@ -42,28 +42,44 @@ module Bkblz
|
|
42
42
|
URI.join auth_response.api_url, url_suffix
|
43
43
|
end
|
44
44
|
|
45
|
+
def create_get(url, addl_headers={})
|
46
|
+
Bkblz.log.debug { "creating GET for request => #{url}" }
|
47
|
+
check_authorized
|
48
|
+
|
49
|
+
request = Net::HTTP::Get.new uri_from_url(url)
|
50
|
+
add_request_headers request, addl_headers
|
51
|
+
request
|
52
|
+
end
|
53
|
+
|
45
54
|
def create_post(url, body=nil, addl_headers={})
|
46
|
-
Bkblz.log.debug { "creating
|
55
|
+
Bkblz.log.debug { "creating POST for request => #{url}" }
|
47
56
|
check_authorized
|
48
57
|
|
49
|
-
|
50
|
-
request = Net::HTTP::Post.new uri
|
58
|
+
request = Net::HTTP::Post.new uri_from_url(url)
|
51
59
|
|
52
60
|
if body.is_a? Hash
|
53
61
|
body = Bkblz::MapKeyFormatter.camelcase_keys(body).to_json
|
54
62
|
end
|
55
63
|
request.body = body if body
|
56
64
|
|
65
|
+
add_request_headers request, addl_headers
|
66
|
+
|
67
|
+
request
|
68
|
+
end
|
69
|
+
|
70
|
+
private
|
71
|
+
def uri_from_url(url)
|
72
|
+
url.is_a?(URI) ? url : URI(url)
|
73
|
+
end
|
74
|
+
|
75
|
+
def add_request_headers(request, addl_headers)
|
57
76
|
headers = {:"Authorization" => auth_response.authorization_token}
|
58
77
|
headers.merge(addl_headers).each do |k,v|
|
59
|
-
Bkblz.log.
|
78
|
+
Bkblz.log.debug1(self) { "adding request header => #{k}:#{v}" }
|
60
79
|
request.add_field k.to_s, v unless v.nil?
|
61
80
|
end
|
62
|
-
|
63
|
-
request
|
64
81
|
end
|
65
82
|
|
66
|
-
private
|
67
83
|
def check_authorized
|
68
84
|
raise SessionNotAuthorizedError unless authorized?
|
69
85
|
end
|
data/lib/bkblz/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: bkblz
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.1.
|
4
|
+
version: 0.1.4
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Erick Johnson
|
8
8
|
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2016-11-
|
11
|
+
date: 2016-11-07 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: thor
|
@@ -101,6 +101,7 @@ files:
|
|
101
101
|
- lib/bkblz/v1/create_bucket.rb
|
102
102
|
- lib/bkblz/v1/delete_bucket.rb
|
103
103
|
- lib/bkblz/v1/delete_file_version.rb
|
104
|
+
- lib/bkblz/v1/download_file.rb
|
104
105
|
- lib/bkblz/v1/error_response.rb
|
105
106
|
- lib/bkblz/v1/get_upload_url.rb
|
106
107
|
- lib/bkblz/v1/list_buckets.rb
|