backblaze 0.1.0.pre.alpha → 0.2.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/.gitignore +1 -0
- data/README.md +1 -1
- data/Rakefile +30 -0
- data/lib/backblaze/b2.rb +35 -2
- data/lib/backblaze/b2/base.rb +68 -0
- data/lib/backblaze/b2/bucket.rb +41 -51
- data/lib/backblaze/b2/file.rb +77 -2
- data/lib/backblaze/b2/file_version.rb +28 -0
- data/lib/backblaze/errors.rb +22 -0
- data/lib/backblaze/version.rb +1 -1
- metadata +4 -4
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 58cfca96218c6f265a44d93fdeaf373a51431b7f
|
4
|
+
data.tar.gz: 12856ac81e879a92feb8177a17a1d15b83df8504
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 02635c9ba73cbadd3610481e70bc92cd93b42a8fefa4005aaed57e3683b5c60d6a45ef641f074156a341924d515f59dab6b29fe8e25b6cc0c1f250b92dae04cb
|
7
|
+
data.tar.gz: 1d1a3dcc23ada161c464dff4f93864062ffee887400403629ff7753faab660e964b288c39e164137eccf4902a9b6d7ac2bcc24b5860ba5f71901f39ae8b170e1
|
data/.gitignore
CHANGED
data/README.md
CHANGED
@@ -1,6 +1,6 @@
|
|
1
1
|
# Backblaze
|
2
2
|
|
3
|
-
The Backblaze ruby gem is an implementation of the [Backblaze B2 Cloud Storage API](https://www.backblaze.com/b2/docs/). In addition to simplifying calls, it also implements an object oriented structure for dealing with files.
|
3
|
+
The Backblaze ruby gem is an implementation of the [Backblaze B2 Cloud Storage API](https://www.backblaze.com/b2/docs/). In addition to simplifying calls, it also implements an object oriented structure for dealing with files. Calling the api through different objects will not cause each to get updated. Always assume that data retrieved is just a snapshot from when the object was retrieved.
|
4
4
|
|
5
5
|
## Installation
|
6
6
|
|
data/Rakefile
CHANGED
@@ -4,3 +4,33 @@ require "rspec/core/rake_task"
|
|
4
4
|
RSpec::Core::RakeTask.new(:spec)
|
5
5
|
|
6
6
|
task :default => :spec
|
7
|
+
|
8
|
+
task :console do
|
9
|
+
require 'pry'
|
10
|
+
require 'backblaze'
|
11
|
+
|
12
|
+
def reload!
|
13
|
+
headers = Backblaze::B2::Base.headers
|
14
|
+
vars = Backblaze::B2.instance_variables.map{|k| [k, Backblaze::B2.instance_variable_get(k)]}.to_h
|
15
|
+
base_uri = Backblaze::B2::Base.base_uri
|
16
|
+
files = $LOADED_FEATURES.select { |feat| feat =~ /\/backblaze\// }
|
17
|
+
files.each { |file| load file }
|
18
|
+
vars.each do |key, value|
|
19
|
+
Backblaze::B2.instance_variable_set(key, value)
|
20
|
+
end
|
21
|
+
Backblaze::B2::Base.base_uri(base_uri)
|
22
|
+
Backblaze::B2::Base.headers(headers)
|
23
|
+
true
|
24
|
+
end
|
25
|
+
|
26
|
+
# Will try to auto load the first .b2_login file it finds
|
27
|
+
success = false
|
28
|
+
Dir['.b2_login*'].each do |file|
|
29
|
+
break if success
|
30
|
+
puts file
|
31
|
+
success = Backblaze::B2.credentials_file(file, raise_errors: false, logging: true)
|
32
|
+
end
|
33
|
+
|
34
|
+
ARGV.clear
|
35
|
+
Pry.start
|
36
|
+
end
|
data/lib/backblaze/b2.rb
CHANGED
@@ -1,10 +1,11 @@
|
|
1
1
|
require "backblaze/b2/base"
|
2
2
|
require "backblaze/b2/bucket"
|
3
3
|
require "backblaze/b2/file"
|
4
|
+
require "backblaze/b2/file_version"
|
4
5
|
|
5
6
|
module Backblaze::B2
|
6
7
|
class << self
|
7
|
-
attr_reader :account_id, :token, :api_url, :download_url
|
8
|
+
attr_reader :account_id, :token, :api_url, :download_url, :api_path
|
8
9
|
|
9
10
|
##
|
10
11
|
# Authenticates with the server to get the authorization data. Raises an error if there is a problem
|
@@ -17,7 +18,8 @@ module Backblaze::B2
|
|
17
18
|
options = {
|
18
19
|
basic_auth: {username: account_id, password: application_key}
|
19
20
|
}
|
20
|
-
|
21
|
+
api_path = "/#{api_path}/".gsub(/\/+/, '/')
|
22
|
+
response = HTTParty.get("https://api.backblaze.com#{api_path}b2_authorize_account", options)
|
21
23
|
raise Backblaze::AuthError.new(response) unless response.code == 200
|
22
24
|
|
23
25
|
@account_id = response['accountId']
|
@@ -29,5 +31,36 @@ module Backblaze::B2
|
|
29
31
|
Backblaze::B2::Base.base_uri "#{@api_url}#{api_path}"
|
30
32
|
Backblaze::B2::Base.headers 'Authorization' => @token, 'Content-Type' => 'application/json'
|
31
33
|
end
|
34
|
+
|
35
|
+
def credentials_file(filename, raise_errors: true, logging: false)
|
36
|
+
opts = nil
|
37
|
+
open(filename, 'r') do |f|
|
38
|
+
if ::File.extname(filename) == '.json'
|
39
|
+
require 'json'
|
40
|
+
opts = JSON.load(f)
|
41
|
+
else
|
42
|
+
require 'psych'
|
43
|
+
opts = Psych.load(f.read)
|
44
|
+
end
|
45
|
+
end
|
46
|
+
parsed = {}
|
47
|
+
[:application_key, :account_id, :api_path].each do |key|
|
48
|
+
if opts[key.to_s].is_a? String
|
49
|
+
parsed[key] = opts[key.to_s]
|
50
|
+
end
|
51
|
+
end
|
52
|
+
if [:application_key, :account_id].inject(true) { |status, key| status && !parsed[key].nil? }
|
53
|
+
puts "Attempting #{parsed[:account_id]}" if logging
|
54
|
+
login(parsed)
|
55
|
+
true
|
56
|
+
else
|
57
|
+
puts "Missing params" if logging
|
58
|
+
false
|
59
|
+
end
|
60
|
+
rescue => e
|
61
|
+
puts e if logging
|
62
|
+
raise e if raise_errors
|
63
|
+
false
|
64
|
+
end
|
32
65
|
end
|
33
66
|
end
|
data/lib/backblaze/b2/base.rb
CHANGED
@@ -23,5 +23,73 @@ module Backblaze::B2
|
|
23
23
|
self.class.send(req, path, options, &block)
|
24
24
|
end
|
25
25
|
end
|
26
|
+
|
27
|
+
protected
|
28
|
+
|
29
|
+
def file_versions(bucket_id:, convert:, limit:, double_check_server:, file_name: nil, &block)
|
30
|
+
retreive_count = (double_check_server ? 0 : -1)
|
31
|
+
files = file_list(bucket_id: bucket_id, limit: limit, retreived: retreive_count, file_name: file_name, first_file: nil, start_field: 'startFileId'.freeze)
|
32
|
+
|
33
|
+
files.map! do |f|
|
34
|
+
if block.nil?
|
35
|
+
Backblaze::B2::FileVersion.new(f)
|
36
|
+
else
|
37
|
+
block.call(f)
|
38
|
+
end
|
39
|
+
end if convert
|
40
|
+
files.compact
|
41
|
+
end
|
42
|
+
|
43
|
+
def file_list(limit:, retreived:, first_file:, start_field:, bucket_id:, file_name: nil)
|
44
|
+
params = {'bucketId'.freeze => bucket_id}
|
45
|
+
if limit == -1
|
46
|
+
params['maxFileCount'.freeze] = 1000
|
47
|
+
elsif limit > 1000
|
48
|
+
params['maxFileCount'.freeze] = 1000
|
49
|
+
elsif limit > 0
|
50
|
+
params['maxFileCount'.freeze] = limit
|
51
|
+
else
|
52
|
+
return []
|
53
|
+
end
|
54
|
+
unless first_file.nil?
|
55
|
+
params[start_field] = first_file
|
56
|
+
end
|
57
|
+
|
58
|
+
response = post("/b2_list_file_#{start_field == 'startFileName' ? 'names' : 'versions'}", body: params.to_json)
|
59
|
+
|
60
|
+
files = response['files'.freeze]
|
61
|
+
halt = false
|
62
|
+
files.map! do |f|
|
63
|
+
if halt
|
64
|
+
nil
|
65
|
+
else
|
66
|
+
ret = Hash[f.map{|k,v| [Backblaze::Utils.underscore(k).to_sym, v]}]
|
67
|
+
if file_name && file_name != ret[:file_name]
|
68
|
+
halt = true
|
69
|
+
end
|
70
|
+
halt ? nil : ret
|
71
|
+
end
|
72
|
+
end.compact!
|
73
|
+
|
74
|
+
retreived = retreived + files.size if retreived >= 0
|
75
|
+
if limit > 0
|
76
|
+
limit = limit - (retreived >= 0 ? files.size : 1000)
|
77
|
+
limit = 0 if limit < 0
|
78
|
+
end
|
79
|
+
|
80
|
+
next_item = response[start_field.sub('start'.freeze, 'next'.freeze)]
|
81
|
+
|
82
|
+
if (limit > 0 || limit == -1) && !!next_item && !halt
|
83
|
+
files.concat file_list(
|
84
|
+
first_file: next_item,
|
85
|
+
limit: limit,
|
86
|
+
retreived: retreived,
|
87
|
+
start_field: start_field,
|
88
|
+
bucket_id: bucket_id
|
89
|
+
)
|
90
|
+
else
|
91
|
+
files
|
92
|
+
end
|
93
|
+
end
|
26
94
|
end
|
27
95
|
end
|
data/lib/backblaze/b2/bucket.rb
CHANGED
@@ -3,14 +3,13 @@ module Backblaze::B2
|
|
3
3
|
##
|
4
4
|
# A class to represent the online buckets. Mostly used for file access
|
5
5
|
class Bucket < Base
|
6
|
-
|
7
6
|
##
|
8
7
|
# Creates a bucket from all of the possible parameters. This sould be rarely used and instead use a finder or creator
|
9
8
|
# @param [#to_s] bucket_name the bucket name
|
10
9
|
# @param [#to_s] bucket_id the bucket id
|
11
10
|
# @param [#to_s] bucket_type the bucket publicity type
|
12
11
|
# @param [#to_s] account_id the account to which this bucket belongs
|
13
|
-
def initialize(bucket_name:, bucket_id:, bucket_type:, account_id:)
|
12
|
+
def initialize(bucket_name:, bucket_id:, bucket_type:, account_id:, cache: false)
|
14
13
|
@bucket_name = bucket_name
|
15
14
|
@bucket_id = bucket_id
|
16
15
|
@bucket_type = bucket_type
|
@@ -66,17 +65,18 @@ module Backblaze::B2
|
|
66
65
|
# @return [Array<Hash>] when convert is false
|
67
66
|
# @note many of these methods are for the recusion
|
68
67
|
def file_names(limit: 100, cache: false, convert: true, double_check_server: false)
|
69
|
-
if cache && !@
|
70
|
-
if limit <= @
|
71
|
-
return @
|
68
|
+
if cache && !@file_name_cache.nil?
|
69
|
+
if limit <= @file_name_cache[:limit] && convert == @file_name_cache[:convert]
|
70
|
+
return @file_name_cache[:files]
|
72
71
|
end
|
73
72
|
end
|
74
73
|
|
75
74
|
retreive_count = (double_check_server ? 0 : -1)
|
76
|
-
files = file_list(limit: limit, retreived: retreive_count, first_file: nil, start_field: 'startFileName'.freeze)
|
75
|
+
files = file_list(bucket_id: bucket_id, limit: limit, retreived: retreive_count, first_file: nil, start_field: 'startFileName'.freeze)
|
77
76
|
|
77
|
+
merge_params = {bucket_id: bucket_id}
|
78
78
|
files.map! do |f|
|
79
|
-
Backblaze::B2::File.new(f)
|
79
|
+
Backblaze::B2::File.new(f.merge(merge_params))
|
80
80
|
end if convert
|
81
81
|
if cache
|
82
82
|
@file_name_cache = {limit: limit, convert: convert, files: files}
|
@@ -84,6 +84,27 @@ module Backblaze::B2
|
|
84
84
|
files
|
85
85
|
end
|
86
86
|
|
87
|
+
def file_versions(limit: 100, cache: false, convert: true, double_check_server: false)
|
88
|
+
if cache && !@file_versions_cache.nil?
|
89
|
+
if limit <= @file_versions_cache[:limit] && convert == @file_versions_cache[:convert]
|
90
|
+
return @file_versions_cache[:files]
|
91
|
+
end
|
92
|
+
end
|
93
|
+
file_versions = super(limit: 100, convert: convert, double_check_server: double_check_server, bucket_id: bucket_id)
|
94
|
+
files = file_versions.group_by {|version| convert ? version.file_name : version[:file_name]}
|
95
|
+
if convert
|
96
|
+
files = files.map do |name, versions|
|
97
|
+
File.new(file_name: name, bucket_id: bucket_id, versions: versions)
|
98
|
+
end
|
99
|
+
end
|
100
|
+
if cache
|
101
|
+
@file_versions_cache = {limit: limit, convert: convert, files: files}
|
102
|
+
else
|
103
|
+
@file_versions_cache = {}
|
104
|
+
end
|
105
|
+
files
|
106
|
+
end
|
107
|
+
|
87
108
|
class << self
|
88
109
|
##
|
89
110
|
# Create a bucket
|
@@ -102,54 +123,23 @@ module Backblaze::B2
|
|
102
123
|
|
103
124
|
raise Backblaze::BucketError.new(response) unless response.code / 100 == 2
|
104
125
|
|
105
|
-
params =
|
126
|
+
params = Hash[response.map{|k,v| [Backblaze::Utils.underscore(k).to_sym, v]}]
|
106
127
|
|
107
128
|
new(params)
|
108
129
|
end
|
109
|
-
end
|
110
130
|
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
end
|
124
|
-
unless first_file.nil?
|
125
|
-
params[start_field] = first_file
|
126
|
-
end
|
127
|
-
|
128
|
-
response = post("/b2_list_file_#{start_field == 'startFileName' ? 'names' : 'versions'}", body: params.to_json)
|
129
|
-
|
130
|
-
files = response['files']
|
131
|
-
files.map! do |f|
|
132
|
-
f.map {|k, v| [underscore(k).to_sym, v]}.to_h
|
133
|
-
end
|
134
|
-
|
135
|
-
retreived = retreived + files.size if retreived >= 0
|
136
|
-
if limit > 0
|
137
|
-
limit = limit - (retreived >= 0 ? files.size : 1000)
|
138
|
-
limit = 0 if limit < 0
|
139
|
-
end
|
140
|
-
|
141
|
-
next_item = response[start_field.sub('start', 'next')]
|
142
|
-
|
143
|
-
if (limit > 0 || limit == -1) && !!next_item
|
144
|
-
files.concat file_list(
|
145
|
-
first_file: next_item,
|
146
|
-
limit: limit,
|
147
|
-
convert: convert,
|
148
|
-
retreived: retreived,
|
149
|
-
start_field: start_field
|
150
|
-
)
|
151
|
-
else
|
152
|
-
files
|
131
|
+
##
|
132
|
+
# List buckets for account
|
133
|
+
# @return [Array<Backblaze::Bucket>] buckets for this account
|
134
|
+
def buckets
|
135
|
+
body = {
|
136
|
+
accountId: Backblaze::B2.account_id
|
137
|
+
}
|
138
|
+
response = post('/b2_list_buckets', body: body.to_json)
|
139
|
+
response['buckets'].map do |bucket|
|
140
|
+
params = Hash[bucket.map{|k,v| [Backblaze::Utils.underscore(k).to_sym, v]}]
|
141
|
+
new(params)
|
142
|
+
end
|
153
143
|
end
|
154
144
|
end
|
155
145
|
end
|
data/lib/backblaze/b2/file.rb
CHANGED
@@ -1,8 +1,83 @@
|
|
1
1
|
module Backblaze::B2
|
2
2
|
class File < Base
|
3
|
-
def initialize(
|
4
|
-
@
|
3
|
+
def initialize(file_name:, bucket_id:, versions: nil, **file_version_args)
|
4
|
+
@file_name = file_name
|
5
|
+
@bucket_id = bucket_id
|
6
|
+
if versions
|
7
|
+
@fetched_all = true
|
8
|
+
@versions = versions
|
9
|
+
else
|
10
|
+
@fetched_all = false
|
11
|
+
@versions = [FileVersion.new(file_version_args.merge(file_name: file_name))]
|
12
|
+
end
|
13
|
+
end
|
14
|
+
|
15
|
+
def [](version)
|
16
|
+
versions[version]
|
17
|
+
end
|
18
|
+
|
19
|
+
def file_name
|
20
|
+
@file_name
|
21
|
+
end
|
22
|
+
alias_method :name, :file_name
|
23
|
+
|
24
|
+
def versions
|
25
|
+
unless @fetched_all
|
26
|
+
@versions = file_versions(bucket_id: @bucket_id, convert: true, limit: -1, double_check_server: false, file_name: file_name)
|
27
|
+
@fetched_all = true
|
28
|
+
end
|
29
|
+
@versions
|
30
|
+
end
|
31
|
+
|
32
|
+
def latest
|
33
|
+
@versions.first
|
34
|
+
end
|
35
|
+
|
36
|
+
def destroy!(thread_count: 4)
|
37
|
+
versions
|
38
|
+
thread_count = @versions.length if thread_count > @versions.length || thread_count < 1
|
39
|
+
lock = Mutex.new
|
40
|
+
errors = []
|
41
|
+
threads = []
|
42
|
+
thread_count.times do
|
43
|
+
threads << Thread.new do
|
44
|
+
version = nil
|
45
|
+
loop do
|
46
|
+
lock.synchronize { version = @versions.pop }
|
47
|
+
break if version.nil?
|
48
|
+
begin
|
49
|
+
version.destroy!
|
50
|
+
rescue Backblaze::FileError => e
|
51
|
+
lock.synchronize { errors << e }
|
52
|
+
end
|
53
|
+
end
|
54
|
+
end
|
55
|
+
end
|
56
|
+
threads.map(&:join)
|
57
|
+
@destroyed = true
|
58
|
+
if errors.any?
|
59
|
+
raise Backblaze::DestroyErrors.new(errors)
|
60
|
+
end
|
61
|
+
end
|
62
|
+
|
63
|
+
def exists?
|
64
|
+
!@destroyed
|
65
|
+
end
|
66
|
+
|
67
|
+
def method_missing(m, *args, &block)
|
68
|
+
if latest.respond_to?(m)
|
69
|
+
latest.send(m, *args, &block)
|
70
|
+
else
|
71
|
+
super
|
72
|
+
end
|
73
|
+
end
|
5
74
|
|
75
|
+
def respond_to?(m)
|
76
|
+
if latest.respond_to?(m)
|
77
|
+
true
|
78
|
+
else
|
79
|
+
super
|
80
|
+
end
|
6
81
|
end
|
7
82
|
end
|
8
83
|
end
|
@@ -1,5 +1,33 @@
|
|
1
1
|
module Backblaze::B2
|
2
2
|
class FileVersion < Base
|
3
|
+
attr_reader :file_id, :size, :action, :upload_timestamp, :file_name
|
3
4
|
|
5
|
+
def initialize(file_id:, size:, upload_timestamp:, action:, file_name:)
|
6
|
+
@file_id = file_id
|
7
|
+
@size = size
|
8
|
+
@action = action
|
9
|
+
@file_name = file_name
|
10
|
+
@upload_timestamp = Time.at(upload_timestamp / 1000.0)
|
11
|
+
end
|
12
|
+
|
13
|
+
def get_info
|
14
|
+
unless defined?(@get_info)
|
15
|
+
response = post('/b2_get_file_info', body: {fileId: file_id}.to_json)
|
16
|
+
raise Backblaze::FileError.new(response) unless response.code == 200
|
17
|
+
|
18
|
+
@get_info = Hash[response.map{|k,v| [Backblaze::Utils.underscore(k).to_sym, v]}]
|
19
|
+
end
|
20
|
+
@get_info
|
21
|
+
end
|
22
|
+
|
23
|
+
def destroy!
|
24
|
+
response = post('/b2_delete_file_version', body: {fileName: file_name, fileId: file_id}.to_json)
|
25
|
+
raise Backblaze::FileError.new(response) unless response.code == 200
|
26
|
+
@destroyed = true
|
27
|
+
end
|
28
|
+
|
29
|
+
def exists?
|
30
|
+
!@destroyed
|
31
|
+
end
|
4
32
|
end
|
5
33
|
end
|
data/lib/backblaze/errors.rb
CHANGED
@@ -53,6 +53,24 @@ module Backblaze
|
|
53
53
|
end
|
54
54
|
end
|
55
55
|
|
56
|
+
##
|
57
|
+
# Errors destroying file versions
|
58
|
+
class DestroyErrors < Error
|
59
|
+
##
|
60
|
+
# Creates the Error
|
61
|
+
# @param [Array<Backblaze::FileError>] errors errors raised destroying files
|
62
|
+
def initialize(errors)
|
63
|
+
@errors = errors
|
64
|
+
end
|
65
|
+
|
66
|
+
##
|
67
|
+
# The Backblaze B2 error messages which broke things
|
68
|
+
# @return [Array<Backblaze::FileError>] errors errors raised destroying files
|
69
|
+
def errors
|
70
|
+
@errors
|
71
|
+
end
|
72
|
+
end
|
73
|
+
|
56
74
|
##
|
57
75
|
# Error class for authentication errors
|
58
76
|
class AuthError < RequestError; end
|
@@ -60,4 +78,8 @@ module Backblaze
|
|
60
78
|
##
|
61
79
|
# Error class for bucket errors
|
62
80
|
class BucketError < RequestError; end
|
81
|
+
|
82
|
+
##
|
83
|
+
# Error class for file errors
|
84
|
+
class FileError < RequestError; end
|
63
85
|
end
|
data/lib/backblaze/version.rb
CHANGED
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: backblaze
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.2.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Winston Durand
|
8
8
|
autorequire:
|
9
9
|
bindir: exe
|
10
10
|
cert_chain: []
|
11
|
-
date: 2015-
|
11
|
+
date: 2015-11-21 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: bundler
|
@@ -151,9 +151,9 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
151
151
|
version: '0'
|
152
152
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
153
153
|
requirements:
|
154
|
-
- - "
|
154
|
+
- - ">="
|
155
155
|
- !ruby/object:Gem::Version
|
156
|
-
version:
|
156
|
+
version: '0'
|
157
157
|
requirements: []
|
158
158
|
rubyforge_project:
|
159
159
|
rubygems_version: 2.4.5
|