b2-client 1.0.6 → 1.0.7

Sign up to get free protection for your applications and to get access to all the features.
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: []