b2-client 1.0.2 → 1.0.7
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/lib/b2.rb +34 -32
- data/lib/b2/api_connection.rb +118 -0
- data/lib/b2/bucket.rb +22 -8
- data/lib/b2/connection.rb +104 -85
- data/lib/b2/errors.rb +15 -0
- data/lib/b2/file.rb +2 -10
- data/lib/b2/version.rb +1 -1
- metadata +8 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 70e5dc6cc5de5772f02f575cceefa1137ce7750cf2042067c6e06d1809e0758f
|
4
|
+
data.tar.gz: 96e70fb4bbd010ff178a3ac506a62cf5dd85c65d9c6477c78c89687aeda21b5c
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 7908671a61289946d1330ffa0668d38c0952607ab07932520abb3791ff6a217c8ded4b97e66f2b98784368dac62a55aa412ed636ee386bade7d37c80b013c729
|
7
|
+
data.tar.gz: 5e38e319103709afaca046533501b82f30050b48db439ac927bfc67b0fd0ce7f222327c439092236658f821aa3e025d457280acbaf7b1f1faa57cffeb12f0e95
|
data/lib/b2.rb
CHANGED
@@ -2,50 +2,57 @@ require 'uri'
|
|
2
2
|
require 'json'
|
3
3
|
require 'net/http'
|
4
4
|
|
5
|
+
require File.expand_path('../b2/errors', __FILE__)
|
5
6
|
require File.expand_path('../b2/file', __FILE__)
|
6
7
|
require File.expand_path('../b2/bucket', __FILE__)
|
8
|
+
require File.expand_path('../b2/api_connection', __FILE__)
|
7
9
|
require File.expand_path('../b2/connection', __FILE__)
|
8
10
|
require File.expand_path('../b2/upload_chunker', __FILE__)
|
9
11
|
|
10
12
|
class B2
|
11
13
|
|
12
|
-
def
|
13
|
-
|
14
|
-
|
15
|
-
|
14
|
+
def self.encode(value)
|
15
|
+
URI.encode_www_form_component(value.force_encoding(Encoding::UTF_8)).gsub("%2F", "/")
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.decode(value)
|
19
|
+
URI.decode_www_form_component(value, Encoding::UTF_8)
|
20
|
+
end
|
21
|
+
|
22
|
+
def initialize(key_id: , secret: )
|
23
|
+
@connection = B2::Connection.new(key_id, secret)
|
24
|
+
end
|
25
|
+
|
26
|
+
def account_id
|
27
|
+
@connection.account_id
|
16
28
|
end
|
17
29
|
|
18
30
|
def buckets
|
19
|
-
@connection.
|
20
|
-
B2::Bucket.new(b, @connection)
|
21
|
-
end
|
31
|
+
@connection.buckets
|
22
32
|
end
|
23
|
-
|
24
|
-
def
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
@buckets_cache = buckets
|
29
|
-
@buckets_cache.find{ |b| b.name == name }&.id
|
33
|
+
|
34
|
+
def bucket(name)
|
35
|
+
bs = @connection.post('/b2api/v2/b2_list_buckets', {accountId: account_id, bucketName: name})['buckets']
|
36
|
+
B2::Bucket.new(bs.first, @connection)
|
30
37
|
end
|
31
38
|
|
32
39
|
def file(bucket, key)
|
33
|
-
bucket_id = lookup_bucket_id(bucket)
|
40
|
+
bucket_id = @connection.lookup_bucket_id(bucket)
|
34
41
|
|
35
|
-
file = @connection.post('/b2api/
|
42
|
+
file = @connection.post('/b2api/v2/b2_list_file_names', {
|
36
43
|
bucketId: bucket_id,
|
37
44
|
startFileName: key
|
38
45
|
})['files'].find {|f| f['fileName'] == key }
|
39
46
|
|
40
|
-
file ? B2::File.new(file.merge({'bucketId' => bucket_id})) : nil
|
47
|
+
file ? B2::File.new(file.merge({'bucketId' => bucket_id}), @connection) : nil
|
41
48
|
end
|
42
49
|
|
43
50
|
def delete(bucket, key)
|
44
51
|
object = file(bucket, key)
|
45
52
|
if object
|
46
|
-
@connection.post('/b2api/
|
47
|
-
fileName:
|
48
|
-
fileId:
|
53
|
+
@connection.post('/b2api/v2/b2_delete_file_version', {
|
54
|
+
fileName: object.name,
|
55
|
+
fileId: object.id
|
49
56
|
})
|
50
57
|
else
|
51
58
|
false
|
@@ -53,8 +60,8 @@ class B2
|
|
53
60
|
end
|
54
61
|
|
55
62
|
def get_upload_token(bucket)
|
56
|
-
@connection.post("/b2api/
|
57
|
-
bucketId: lookup_bucket_id(bucket)
|
63
|
+
@connection.post("/b2api/v2/b2_get_upload_url", {
|
64
|
+
bucketId: @connection.lookup_bucket_id(bucket)
|
58
65
|
})
|
59
66
|
end
|
60
67
|
|
@@ -68,7 +75,7 @@ class B2
|
|
68
75
|
chunker = B2::UploadChunker.new(io_or_string)
|
69
76
|
req = Net::HTTP::Post.new(uri.path)
|
70
77
|
req['Authorization'] = upload['authorizationToken']
|
71
|
-
req['X-Bz-File-Name'] = B2
|
78
|
+
req['X-Bz-File-Name'] = B2.encode(key)
|
72
79
|
req['Content-Type'] = mime_type || 'b2/x-auto'
|
73
80
|
req['X-Bz-Content-Sha1'] = 'hex_digits_at_end'
|
74
81
|
info.each do |key, value|
|
@@ -85,13 +92,8 @@ class B2
|
|
85
92
|
end
|
86
93
|
end
|
87
94
|
|
88
|
-
def get_download_url(bucket, filename,
|
89
|
-
|
90
|
-
bucketId: lookup_bucket_id(bucket),
|
91
|
-
fileNamePrefix: filename,
|
92
|
-
validDurationInSeconds: expires_in
|
93
|
-
})
|
94
|
-
@connection.download_url + '/file/' + bucket + '/' + filename + "?Authorization=" + response['authorizationToken']
|
95
|
+
def get_download_url(bucket, filename, **options)
|
96
|
+
@connection.get_download_url(bucket, filename, **options)
|
95
97
|
end
|
96
98
|
|
97
99
|
def download(bucket, key, to=nil, &block)
|
@@ -100,11 +102,11 @@ class B2
|
|
100
102
|
|
101
103
|
|
102
104
|
def download_to_file(bucket, key, filename)
|
103
|
-
file = File.open(filename, '
|
105
|
+
file = ::File.open(filename, 'wb')
|
104
106
|
download(bucket, key) do |chunk|
|
105
107
|
file << chunk
|
106
108
|
end
|
107
109
|
file.close
|
108
110
|
end
|
109
111
|
|
110
|
-
end
|
112
|
+
end
|
@@ -0,0 +1,118 @@
|
|
1
|
+
class B2
|
2
|
+
class APIConnection
|
3
|
+
|
4
|
+
attr_reader :key_id, :key_secret, :download_url
|
5
|
+
|
6
|
+
def initialize(key_id, secret)
|
7
|
+
@key_id = key_id
|
8
|
+
@key_secret = secret
|
9
|
+
end
|
10
|
+
|
11
|
+
def connect!
|
12
|
+
conn = Net::HTTP.new('api.backblazeb2.com', 443)
|
13
|
+
conn.use_ssl = true
|
14
|
+
|
15
|
+
req = Net::HTTP::Get.new('/b2api/v2/b2_authorize_account')
|
16
|
+
req.basic_auth(@key_id, @key_secret)
|
17
|
+
|
18
|
+
key_expiration = Time.now.to_i + 86_400 #24hr expiry
|
19
|
+
resp = conn.start { |http| http.request(req) }
|
20
|
+
if resp.is_a?(Net::HTTPSuccess)
|
21
|
+
resp = JSON.parse(resp.body)
|
22
|
+
else
|
23
|
+
raise "Error connecting to B2 API"
|
24
|
+
end
|
25
|
+
|
26
|
+
uri = URI.parse(resp['apiUrl'])
|
27
|
+
@connection = Net::HTTP.new(uri.host, uri.port)
|
28
|
+
@connection.use_ssl = uri.scheme == 'https'
|
29
|
+
@connection.start
|
30
|
+
|
31
|
+
@auth_token_expires_at = key_expiration
|
32
|
+
@account_id = resp['accountId']
|
33
|
+
@minimum_part_size = resp['absoluteMinimumPartSize']
|
34
|
+
@recommended_part_size = resp['recommendedPartSize']
|
35
|
+
@auth_token = resp['authorizationToken']
|
36
|
+
@download_url = resp['downloadUrl']
|
37
|
+
end
|
38
|
+
|
39
|
+
def account_id
|
40
|
+
return @account_id if !@account_id.nil?
|
41
|
+
|
42
|
+
connect!
|
43
|
+
@account_id
|
44
|
+
end
|
45
|
+
|
46
|
+
def disconnect!
|
47
|
+
if @connection
|
48
|
+
@connection.finish if @connection.active?
|
49
|
+
@connection = nil
|
50
|
+
end
|
51
|
+
end
|
52
|
+
|
53
|
+
def reconnect!
|
54
|
+
disconnect!
|
55
|
+
connect!
|
56
|
+
end
|
57
|
+
|
58
|
+
def authorization_token
|
59
|
+
if @auth_token_expires_at.nil? || @auth_token_expires_at <= Time.now.to_i
|
60
|
+
reconnect!
|
61
|
+
end
|
62
|
+
@auth_token
|
63
|
+
end
|
64
|
+
|
65
|
+
def active?
|
66
|
+
!@connection.nil? && @connection.active?
|
67
|
+
end
|
68
|
+
|
69
|
+
def connection
|
70
|
+
reconnect! if !active?
|
71
|
+
@connection
|
72
|
+
end
|
73
|
+
|
74
|
+
def send_request(request, body=nil, &block)
|
75
|
+
retries = 0
|
76
|
+
request['Authorization'] = authorization_token
|
77
|
+
request.body = (body.is_a?(String) ? body : JSON.generate(body)) if body
|
78
|
+
|
79
|
+
return_value = nil
|
80
|
+
close_connection = false
|
81
|
+
begin
|
82
|
+
connection.request(request) do |response|
|
83
|
+
close_connection = response['Connection'] == 'close'
|
84
|
+
|
85
|
+
case response
|
86
|
+
when Net::HTTPSuccess
|
87
|
+
if block_given?
|
88
|
+
return_value = yield(response)
|
89
|
+
else
|
90
|
+
return_value = JSON.parse(response.body)
|
91
|
+
end
|
92
|
+
else
|
93
|
+
body = JSON.parse(response.body)
|
94
|
+
case body['code']
|
95
|
+
when 'not_found'
|
96
|
+
raise B2::NotFound(body['message'])
|
97
|
+
when 'expired_auth_token'
|
98
|
+
raise B2::ExpiredAuthToken(body['message'])
|
99
|
+
else
|
100
|
+
raise "Error connecting to B2 API #{response.body}"
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
|
105
|
+
# Unexpected EOF (end of file) errors can occur when streaming from a
|
106
|
+
# remote because of Backblaze quota restrictions.
|
107
|
+
rescue B2::ExpiredAuthToken, EOFError
|
108
|
+
reconnect!
|
109
|
+
retries =+ 1
|
110
|
+
retry if retries < 2
|
111
|
+
end
|
112
|
+
disconnect! if close_connection
|
113
|
+
|
114
|
+
return_value
|
115
|
+
end
|
116
|
+
|
117
|
+
end
|
118
|
+
end
|
data/lib/b2/bucket.rb
CHANGED
@@ -14,7 +14,7 @@ class B2
|
|
14
14
|
end
|
15
15
|
|
16
16
|
def get_upload_token
|
17
|
-
@connection.post("/b2api/
|
17
|
+
@connection.post("/b2api/v2/b2_get_upload_url", { bucketId: @id })
|
18
18
|
end
|
19
19
|
|
20
20
|
def upload_file(key, io_or_string, mime_type: nil, sha1: nil, content_disposition: nil, info: {})
|
@@ -27,12 +27,12 @@ class B2
|
|
27
27
|
chunker = sha1 ? io_or_string : B2::UploadChunker.new(io_or_string)
|
28
28
|
req = Net::HTTP::Post.new(uri.path)
|
29
29
|
req['Authorization'] = upload['authorizationToken']
|
30
|
-
req['X-Bz-File-Name'] = B2
|
30
|
+
req['X-Bz-File-Name'] = B2.encode(key)
|
31
31
|
req['Content-Type'] = mime_type || 'b2/x-auto'
|
32
32
|
req['X-Bz-Content-Sha1'] = sha1 ? sha1 : 'hex_digits_at_end'
|
33
|
-
req['X-Bz-Info-b2-content-disposition'] = content_disposition if content_disposition
|
33
|
+
req['X-Bz-Info-b2-content-disposition'] = B2.encode(content_disposition) if content_disposition
|
34
34
|
info.each do |key, value|
|
35
|
-
req["X-Bz-Info-#{key}"] = value
|
35
|
+
req["X-Bz-Info-#{key}"] = B2.encode(value)
|
36
36
|
end
|
37
37
|
req['Content-Length'] = chunker.size
|
38
38
|
req.body_stream = chunker
|
@@ -41,14 +41,24 @@ class B2
|
|
41
41
|
result = if resp.is_a?(Net::HTTPSuccess)
|
42
42
|
JSON.parse(resp.body)
|
43
43
|
else
|
44
|
-
raise "Error connecting to B2 API"
|
44
|
+
raise "Error connecting to B2 API #{resp.body}"
|
45
45
|
end
|
46
46
|
|
47
47
|
B2::File.new(result, @connection)
|
48
48
|
end
|
49
|
+
|
50
|
+
def keys(prefix: nil, delimiter: nil)
|
51
|
+
#TODO: add abilty to get all names
|
52
|
+
@connection.post('/b2api/v2/b2_list_file_names', {
|
53
|
+
bucketId: @id,
|
54
|
+
maxFileCount: 1000,
|
55
|
+
prefix: prefix,
|
56
|
+
delimiter: delimiter
|
57
|
+
})['files'].map{ |f| f['fileName'] }
|
58
|
+
end
|
49
59
|
|
50
60
|
def has_key?(key)
|
51
|
-
!@connection.post('/b2api/
|
61
|
+
!@connection.post('/b2api/v2/b2_list_file_names', {
|
52
62
|
bucketId: @id,
|
53
63
|
startFileName: key,
|
54
64
|
maxFileCount: 1,
|
@@ -57,7 +67,7 @@ class B2
|
|
57
67
|
end
|
58
68
|
|
59
69
|
def file(key)
|
60
|
-
file = @connection.post('/b2api/
|
70
|
+
file = @connection.post('/b2api/v2/b2_list_file_names', {
|
61
71
|
bucketId: @id,
|
62
72
|
startFileName: key,
|
63
73
|
maxFileCount: 1,
|
@@ -67,6 +77,10 @@ class B2
|
|
67
77
|
file ? B2::File.new(file.merge({'bucketId' => @id}), @connection) : nil
|
68
78
|
end
|
69
79
|
|
80
|
+
def get_download_url(key, **options)
|
81
|
+
@connection.get_download_url(@name, key, **options)
|
82
|
+
end
|
83
|
+
|
70
84
|
def download(key, to=nil, &block)
|
71
85
|
@connection.download(@name, key, to, &block)
|
72
86
|
end
|
@@ -76,4 +90,4 @@ class B2
|
|
76
90
|
end
|
77
91
|
|
78
92
|
end
|
79
|
-
end
|
93
|
+
end
|
data/lib/b2/connection.rb
CHANGED
@@ -1,122 +1,140 @@
|
|
1
|
+
require 'cgi'
|
2
|
+
require 'thread'
|
3
|
+
|
1
4
|
class B2
|
2
5
|
class Connection
|
3
6
|
|
4
|
-
|
5
|
-
|
6
|
-
|
7
|
-
@
|
8
|
-
@
|
7
|
+
def initialize(key_id, secret, pool: 5, timeout: 5)
|
8
|
+
@mutex = Mutex.new
|
9
|
+
@availability = ConditionVariable.new
|
10
|
+
@max = pool
|
11
|
+
@timeout = timeout
|
12
|
+
@free_pool = []
|
13
|
+
@used_pool = []
|
14
|
+
|
15
|
+
@key_id = key_id
|
16
|
+
@key_secret = secret
|
17
|
+
|
18
|
+
@buckets_cache = Hash.new { |hash, name| hash[name] = bucket(name) }
|
9
19
|
end
|
10
20
|
|
11
|
-
def
|
12
|
-
|
13
|
-
conn.use_ssl = true
|
21
|
+
def account_id
|
22
|
+
return @account_id if !@account_id.nil?
|
14
23
|
|
15
|
-
|
16
|
-
|
24
|
+
@account_id = with_connection { |conn| conn.account_id }
|
25
|
+
end
|
17
26
|
|
18
|
-
|
19
|
-
|
20
|
-
|
21
|
-
|
22
|
-
|
23
|
-
|
27
|
+
def with_connection
|
28
|
+
conn = @mutex.synchronize do
|
29
|
+
cxn = if !@free_pool.empty?
|
30
|
+
@free_pool.shift
|
31
|
+
elsif @free_pool.size + @used_pool.size < @max
|
32
|
+
B2::APIConnection.new(@key_id, @key_secret)
|
33
|
+
else
|
34
|
+
@availability.wait(@mutex, @timeout)
|
35
|
+
@free_pool.shift || B2::APIConnection.new(@key_id, @key_secret)
|
36
|
+
end
|
37
|
+
|
38
|
+
@used_pool << cxn
|
39
|
+
cxn
|
40
|
+
end
|
41
|
+
|
42
|
+
yield conn
|
43
|
+
ensure
|
44
|
+
@mutex.synchronize do
|
45
|
+
@used_pool.delete(conn)
|
46
|
+
@free_pool << conn if conn.active?
|
47
|
+
@availability.signal()
|
24
48
|
end
|
25
|
-
|
26
|
-
uri = URI.parse(resp['apiUrl'])
|
27
|
-
@connection = Net::HTTP.new(uri.host, uri.port)
|
28
|
-
@connection.use_ssl = uri.scheme == 'https'
|
29
|
-
@connection.start
|
30
|
-
|
31
|
-
@auth_token_expires_at = key_expiration
|
32
|
-
@minimum_part_size = resp['absoluteMinimumPartSize']
|
33
|
-
@recommended_part_size = resp['recommendedPartSize']
|
34
|
-
@auth_token = resp['authorizationToken']
|
35
|
-
@download_url = resp['downloadUrl']
|
36
49
|
end
|
37
50
|
|
38
|
-
def
|
39
|
-
|
40
|
-
@connection.finish if @connection.active?
|
41
|
-
@connection = nil
|
42
|
-
end
|
51
|
+
def authorization_token
|
52
|
+
with_connection { |conn| conn.authorization_token }
|
43
53
|
end
|
44
54
|
|
45
|
-
def
|
46
|
-
|
47
|
-
connect!
|
55
|
+
def send_request(request, body=nil, &block)
|
56
|
+
with_connection { |conn| conn.send_request(request, body, &block) }
|
48
57
|
end
|
49
58
|
|
50
|
-
def
|
51
|
-
|
52
|
-
|
59
|
+
def download_url
|
60
|
+
with_connection { |conn| conn.download_url }
|
61
|
+
end
|
62
|
+
|
63
|
+
def buckets
|
64
|
+
post('/b2api/v2/b2_list_buckets', {accountId: account_id})['buckets'].map do |b|
|
65
|
+
B2::Bucket.new(b, self)
|
53
66
|
end
|
54
|
-
@auth_token
|
55
67
|
end
|
56
68
|
|
57
|
-
def
|
58
|
-
|
69
|
+
def bucket(name)
|
70
|
+
response = post('/b2api/v2/b2_list_buckets', {
|
71
|
+
accountId: account_id,
|
72
|
+
bucketName: name
|
73
|
+
})['buckets']
|
74
|
+
response.map { |b| B2::Bucket.new(b, self) }.first
|
59
75
|
end
|
60
76
|
|
61
|
-
def
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
return_value = nil
|
66
|
-
close_connection = false
|
67
|
-
@connection.request(request) do |response|
|
68
|
-
close_connection = response['Connection'] == 'close'
|
69
|
-
|
70
|
-
case response
|
71
|
-
when Net::HTTPSuccess
|
72
|
-
if block_given?
|
73
|
-
return_value = yield(response)
|
74
|
-
else
|
75
|
-
return_value = JSON.parse(response.body)
|
76
|
-
end
|
77
|
-
else
|
78
|
-
raise "Error connecting to B2 API #{response.body}"
|
79
|
-
end
|
80
|
-
end
|
81
|
-
@connection.finish if close_connection
|
77
|
+
def lookup_bucket_id(name)
|
78
|
+
@buckets_cache[name].id
|
79
|
+
end
|
82
80
|
|
83
|
-
|
81
|
+
def get_download_url(bucket, filename, expires_in: 3_600, disposition: nil)
|
82
|
+
response = post("/b2api/v2/b2_get_download_authorization", {
|
83
|
+
bucketId: lookup_bucket_id(bucket),
|
84
|
+
fileNamePrefix: filename,
|
85
|
+
validDurationInSeconds: expires_in,
|
86
|
+
b2ContentDisposition: disposition
|
87
|
+
})
|
88
|
+
url = download_url + '/file/' + bucket + '/' + filename + "?Authorization=" + response['authorizationToken']
|
89
|
+
url += "&b2ContentDisposition=#{CGI.escape(disposition)}" if disposition
|
90
|
+
url
|
84
91
|
end
|
85
|
-
|
86
|
-
def download(bucket, key, to=nil
|
92
|
+
|
93
|
+
def download(bucket, key, to=nil)
|
87
94
|
opened_file = (to && to.is_a?(String))
|
88
95
|
to = ::File.open(to, 'wb') if to.is_a?(String)
|
89
96
|
digestor = Digest::SHA1.new
|
90
97
|
data = ""
|
91
98
|
|
92
|
-
uri = URI.parse(
|
99
|
+
uri = URI.parse(download_url)
|
93
100
|
conn = Net::HTTP.new(uri.host, uri.port)
|
94
101
|
conn.use_ssl = uri.scheme == 'https'
|
95
102
|
|
96
103
|
req = Net::HTTP::Get.new("/file/#{bucket}/#{key}")
|
97
104
|
req['Authorization'] = authorization_token
|
98
105
|
conn.start do |http|
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
106
|
+
http.request(req) do |response|
|
107
|
+
case response
|
108
|
+
when Net::HTTPSuccess
|
109
|
+
response.read_body do |chunk|
|
110
|
+
digestor << chunk
|
111
|
+
if to
|
112
|
+
to << chunk
|
113
|
+
elsif block_given?
|
114
|
+
yield(chunk)
|
115
|
+
else
|
116
|
+
data << chunk
|
117
|
+
end
|
110
118
|
end
|
111
|
-
end
|
112
119
|
|
113
|
-
|
114
|
-
|
120
|
+
if response['X-Bz-Content-Sha1'] != 'none' && digestor.hexdigest != response['X-Bz-Content-Sha1']
|
121
|
+
rase B2::FileIntegrityError.new("SHA1 Mismatch, expected: \"#{response['X-Bz-Content-Sha1']}\", actual: \"#{digestor.hexdigest}\"")
|
122
|
+
end
|
123
|
+
when Net::HTTPNotFound
|
124
|
+
raise B2::NotFound.new(JSON.parse(response.body)['message'])
|
125
|
+
else
|
126
|
+
begin
|
127
|
+
body = JSON.parse(response.body)
|
128
|
+
if body['code'] == 'not_found'
|
129
|
+
raise B2::NotFound(body['message'])
|
130
|
+
else
|
131
|
+
raise "#{body['code']} (#{body['message']})"
|
132
|
+
end
|
133
|
+
rescue
|
134
|
+
raise response.body
|
135
|
+
end
|
115
136
|
end
|
116
|
-
else
|
117
|
-
raise response.body
|
118
137
|
end
|
119
|
-
end
|
120
138
|
end
|
121
139
|
|
122
140
|
if opened_file
|
@@ -124,7 +142,7 @@ class B2
|
|
124
142
|
elsif to
|
125
143
|
to.flush
|
126
144
|
end
|
127
|
-
|
145
|
+
!block_given? && to.nil? ? data : nil
|
128
146
|
end
|
129
147
|
|
130
148
|
def get(path, body=nil, &block)
|
@@ -140,4 +158,5 @@ class B2
|
|
140
158
|
end
|
141
159
|
|
142
160
|
end
|
143
|
-
end
|
161
|
+
end
|
162
|
+
|
data/lib/b2/errors.rb
ADDED
data/lib/b2/file.rb
CHANGED
@@ -5,7 +5,7 @@ class B2
|
|
5
5
|
|
6
6
|
def initialize(attrs, connection)
|
7
7
|
@id = attrs['fileId']
|
8
|
-
@name = B2
|
8
|
+
@name = B2.decode(attrs['fileName'])
|
9
9
|
@account_id = attrs['accountId']
|
10
10
|
@bucket_id = attrs['bucketId']
|
11
11
|
@size = attrs['contentLength']
|
@@ -17,16 +17,8 @@ class B2
|
|
17
17
|
@connection = connection
|
18
18
|
end
|
19
19
|
|
20
|
-
def self.encode_filename(str)
|
21
|
-
URI.encode_www_form_component(str.force_encoding(Encoding::UTF_8)).gsub("%2F", "/")
|
22
|
-
end
|
23
|
-
|
24
|
-
def self.decode_filename(str)
|
25
|
-
URI.decode_www_form_component(str, Encoding::UTF_8)
|
26
|
-
end
|
27
|
-
|
28
20
|
def delete!
|
29
|
-
@connection.post('/b2api/
|
21
|
+
@connection.post('/b2api/v2/b2_delete_file_version', {
|
30
22
|
fileId: @id,
|
31
23
|
fileName: @name
|
32
24
|
})
|
data/lib/b2/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: b2-client
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 1.0.
|
4
|
+
version: 1.0.7
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jon Bracy
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date:
|
11
|
+
date: 2020-07-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -36,9 +36,11 @@ files:
|
|
36
36
|
- README.md
|
37
37
|
- b2-client.gemspec
|
38
38
|
- lib/b2.rb
|
39
|
+
- lib/b2/api_connection.rb
|
39
40
|
- lib/b2/bucket.rb
|
40
41
|
- lib/b2/client.rb
|
41
42
|
- lib/b2/connection.rb
|
43
|
+
- lib/b2/errors.rb
|
42
44
|
- lib/b2/file.rb
|
43
45
|
- lib/b2/upload_chunker.rb
|
44
46
|
- lib/b2/version.rb
|
@@ -46,7 +48,7 @@ homepage: https://github.com/malomalo/b2
|
|
46
48
|
licenses:
|
47
49
|
- MIT
|
48
50
|
metadata: {}
|
49
|
-
post_install_message:
|
51
|
+
post_install_message:
|
50
52
|
rdoc_options: []
|
51
53
|
require_paths:
|
52
54
|
- lib
|
@@ -61,9 +63,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
61
63
|
- !ruby/object:Gem::Version
|
62
64
|
version: '0'
|
63
65
|
requirements: []
|
64
|
-
|
65
|
-
|
66
|
-
signing_key:
|
66
|
+
rubygems_version: 3.1.2
|
67
|
+
signing_key:
|
67
68
|
specification_version: 4
|
68
69
|
summary: Backblaze B2 Client
|
69
70
|
test_files: []
|