b2-client 1.0.6 → 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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA256:
3
- metadata.gz: 405cc51a4b94788687e8ccfa7aa774df40c29135b9ac89251405f56c32d73835
4
- data.tar.gz: 820653192390b83efbb713f4104d739b496e75d3ae9c39dec6b99b3ac2e1af77
3
+ metadata.gz: 70e5dc6cc5de5772f02f575cceefa1137ce7750cf2042067c6e06d1809e0758f
4
+ data.tar.gz: 96e70fb4bbd010ff178a3ac506a62cf5dd85c65d9c6477c78c89687aeda21b5c
5
5
  SHA512:
6
- metadata.gz: 73a212dbb80684eca0097f9e784ab8815a559e3a810cdb448eaf74fb9ec49a594c5f3f78790870fc05ce3fe47dc0accfb62f931dce6811178b771f63884fcdd1
7
- data.tar.gz: 7f6a23851372cd9fa317faab23fa09fcca35344e024fe8c1496c3204bffdb258e75197f1e115b45c5b5f400b0f872b738827973bb5469b2d2b11d7a1bc9c6892
6
+ metadata.gz: 7908671a61289946d1330ffa0668d38c0952607ab07932520abb3791ff6a217c8ded4b97e66f2b98784368dac62a55aa412ed636ee386bade7d37c80b013c729
7
+ data.tar.gz: 5e38e319103709afaca046533501b82f30050b48db439ac927bfc67b0fd0ce7f222327c439092236658f821aa3e025d457280acbaf7b1f1faa57cffeb12f0e95
data/lib/b2.rb CHANGED
@@ -11,6 +11,14 @@ require File.expand_path('../b2/upload_chunker', __FILE__)
11
11
 
12
12
  class B2
13
13
 
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
+
14
22
  def initialize(key_id: , secret: )
15
23
  @connection = B2::Connection.new(key_id, secret)
16
24
  end
@@ -67,7 +75,7 @@ class B2
67
75
  chunker = B2::UploadChunker.new(io_or_string)
68
76
  req = Net::HTTP::Post.new(uri.path)
69
77
  req['Authorization'] = upload['authorizationToken']
70
- req['X-Bz-File-Name'] = B2::File.encode_filename(key)
78
+ req['X-Bz-File-Name'] = B2.encode(key)
71
79
  req['Content-Type'] = mime_type || 'b2/x-auto'
72
80
  req['X-Bz-Content-Sha1'] = 'hex_digits_at_end'
73
81
  info.each do |key, value|
@@ -34,7 +34,6 @@ class B2
34
34
  @recommended_part_size = resp['recommendedPartSize']
35
35
  @auth_token = resp['authorizationToken']
36
36
  @download_url = resp['downloadUrl']
37
- @buckets_cache = []
38
37
  end
39
38
 
40
39
  def account_id
@@ -73,24 +72,42 @@ class B2
73
72
  end
74
73
 
75
74
  def send_request(request, body=nil, &block)
75
+ retries = 0
76
76
  request['Authorization'] = authorization_token
77
77
  request.body = (body.is_a?(String) ? body : JSON.generate(body)) if body
78
78
 
79
79
  return_value = nil
80
80
  close_connection = false
81
- connection.request(request) do |response|
82
- close_connection = response['Connection'] == 'close'
83
-
84
- case response
85
- when Net::HTTPSuccess
86
- if block_given?
87
- return_value = yield(response)
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
88
92
  else
89
- return_value = JSON.parse(response.body)
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
90
102
  end
91
- else
92
- raise "Error connecting to B2 API #{response.body}"
93
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
94
111
  end
95
112
  disconnect! if close_connection
96
113
 
@@ -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::File.encode_filename(key)
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,7 +41,7 @@ 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)
@@ -15,7 +15,7 @@ class B2
15
15
  @key_id = key_id
16
16
  @key_secret = secret
17
17
 
18
- @buckets_cache = []
18
+ @buckets_cache = Hash.new { |hash, name| hash[name] = bucket(name) }
19
19
  end
20
20
 
21
21
  def account_id
@@ -65,13 +65,17 @@ class B2
65
65
  B2::Bucket.new(b, self)
66
66
  end
67
67
  end
68
+
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
75
+ end
68
76
 
69
77
  def lookup_bucket_id(name)
70
- bucket = @buckets_cache.find{ |b| b.name == name }
71
- return bucket.id if bucket
72
-
73
- @buckets_cache = buckets
74
- @buckets_cache.find{ |b| b.name == name }&.id
78
+ @buckets_cache[name].id
75
79
  end
76
80
 
77
81
  def get_download_url(bucket, filename, expires_in: 3_600, disposition: nil)
@@ -99,38 +103,38 @@ class B2
99
103
  req = Net::HTTP::Get.new("/file/#{bucket}/#{key}")
100
104
  req['Authorization'] = authorization_token
101
105
  conn.start do |http|
102
- http.request(req) do |response|
103
- case response
104
- when Net::HTTPSuccess
105
- response.read_body do |chunk|
106
- digestor << chunk
107
- if to
108
- to << chunk
109
- elsif block_given?
110
- yield(chunk)
111
- else
112
- data << chunk
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
113
118
  end
114
- end
115
119
 
116
- if response['X-Bz-Content-Sha1'] != 'none' && digestor.hexdigest != response['X-Bz-Content-Sha1']
117
- rase B2::FileIntegrityError.new("SHA1 Mismatch, expected: \"#{response['X-Bz-Content-Sha1']}\", actual: \"#{digestor.hexdigest}\"")
118
- end
119
- when Net::HTTPNotFound
120
- raise B2::NotFound.new(JSON.parse(response.body)['message'])
121
- else
122
- begin
123
- body = JSON.parse(response.body)
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)
124
128
  if body['code'] == 'not_found'
125
- raise B2::NotFound(body['message'])
126
- else
127
- raise "#{body['code']} (#{body['message']})"
129
+ raise B2::NotFound(body['message'])
130
+ else
131
+ raise "#{body['code']} (#{body['message']})"
132
+ end
133
+ rescue
134
+ raise response.body
128
135
  end
129
- rescue
130
- raise response.body
131
136
  end
132
137
  end
133
- end
134
138
  end
135
139
 
136
140
  if opened_file
@@ -8,5 +8,8 @@ class B2
8
8
 
9
9
  class FileIntegrityError < Error
10
10
  end
11
+
12
+ class ExpiredAuthToken < Error
13
+ end
11
14
 
12
15
  end
@@ -5,7 +5,7 @@ class B2
5
5
 
6
6
  def initialize(attrs, connection)
7
7
  @id = attrs['fileId']
8
- @name = B2::File.decode_filename(attrs['fileName'])
8
+ @name = B2.decode(attrs['fileName'])
9
9
  @account_id = attrs['accountId']
10
10
  @bucket_id = attrs['bucketId']
11
11
  @size = attrs['contentLength']
@@ -17,14 +17,6 @@ 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
21
  @connection.post('/b2api/v2/b2_delete_file_version', {
30
22
  fileId: @id,
@@ -1,3 +1,3 @@
1
1
  class B2
2
- VERSION = '1.0.6'
2
+ VERSION = '1.0.7'
3
3
  end
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.6
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: 2020-04-06 00:00:00.000000000 Z
11
+ date: 2020-07-27 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: rake
@@ -48,7 +48,7 @@ homepage: https://github.com/malomalo/b2
48
48
  licenses:
49
49
  - MIT
50
50
  metadata: {}
51
- post_install_message:
51
+ post_install_message:
52
52
  rdoc_options: []
53
53
  require_paths:
54
54
  - lib
@@ -63,8 +63,8 @@ required_rubygems_version: !ruby/object:Gem::Requirement
63
63
  - !ruby/object:Gem::Version
64
64
  version: '0'
65
65
  requirements: []
66
- rubygems_version: 3.0.6
67
- signing_key:
66
+ rubygems_version: 3.1.2
67
+ signing_key:
68
68
  specification_version: 4
69
69
  summary: Backblaze B2 Client
70
70
  test_files: []