backup-backblaze 0.1.2 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,11 @@
1
+ module Backup
2
+ module Backblaze
3
+ class UrlToken
4
+ def initialize url, auth
5
+ @url, @auth = url, auth
6
+ end
7
+
8
+ attr_reader :url, :auth
9
+ end
10
+ end
11
+ end
@@ -1,5 +1,5 @@
1
1
  module Backup
2
2
  module Backblaze
3
- VERSION = '0.1.2'
3
+ VERSION = '0.2.0'
4
4
  end
5
5
  end
@@ -0,0 +1,157 @@
1
+ % execute with SWI-Prolog:
2
+ %
3
+ % generate the when clauses for matching
4
+ % swipl -q -l retry.pl -t to_whens
5
+ %
6
+ % generate the map for dependency checking
7
+ % swipl -q -l retry.pl -t to_map
8
+
9
+ :- use_module(library(bounds)).
10
+
11
+ % The complete list as of 04-Sep-2018
12
+ all_b2api(b2_authorize_account).
13
+ all_b2api(b2_cancel_large_file).
14
+ all_b2api(b2_create_bucket).
15
+ all_b2api(b2_create_key).
16
+ all_b2api(b2_delete_bucket).
17
+ all_b2api(b2_delete_file_version).
18
+ all_b2api(b2_delete_key).
19
+ all_b2api(b2_download_file_by_id).
20
+ all_b2api(b2_download_file_by_name).
21
+ all_b2api(b2_finish_large_file).
22
+ all_b2api(b2_get_download_authorization).
23
+ all_b2api(b2_get_file_info).
24
+ all_b2api(b2_get_upload_part_url).
25
+ all_b2api(b2_get_upload_url).
26
+ all_b2api(b2_hide_file).
27
+ all_b2api(b2_list_buckets).
28
+ all_b2api(b2_list_file_names).
29
+ all_b2api(b2_list_file_versions).
30
+ all_b2api(b2_list_keys).
31
+ all_b2api(b2_list_parts).
32
+ all_b2api(b2_list_unfinished_large_files).
33
+ all_b2api(b2_start_large_file).
34
+ all_b2api(b2_update_bucket).
35
+ all_b2api(b2_upload_file).
36
+ all_b2api(b2_upload_part ).
37
+
38
+ % All api calls we're interested in.
39
+ % In approximate frequency of usage order.
40
+ some_b2api(b2_upload_part).
41
+ some_b2api(b2_get_upload_part_url).
42
+ some_b2api(b2_get_upload_url).
43
+ some_b2api(b2_upload_file).
44
+ some_b2api(b2_authorize_account).
45
+ some_b2api(b2_list_buckets).
46
+ some_b2api(b2_list_file_names).
47
+ some_b2api(b2_delete_file_version).
48
+ some_b2api(b2_finish_large_file).
49
+ some_b2api(b2_start_large_file).
50
+
51
+ b2api(A) :- some_b2api(A).
52
+
53
+ % Needs library(bounds). Leaves the bounds as a predicate, which is nicer to
54
+ % read, can be output as a ruby range, and still matches correctly.
55
+ five_hundreds(V) :- V in 500..599.
56
+
57
+ % these two have special retries
58
+ upload_retry(b2_upload_part, b2_get_upload_part_url).
59
+ upload_retry(b2_upload_file, b2_get_upload_url).
60
+
61
+ % These two codes from 401 are allowed to retry
62
+ not_authorised_retryable_code(expired_auth_token).
63
+ not_authorised_retryable_code(bad_auth_token).
64
+
65
+ % Sources:
66
+ % https://www.backblaze.com/b2/docs/calling.html
67
+ % https://www.backblaze.com/b2/docs/uploading.html
68
+ % https://www.backblaze.com/b2/docs/integration_checklist.html
69
+
70
+ %%%%%%%%%%%%%%
71
+ % HttpStatus is one of the Http status codes, as an integer
72
+ % Code is a backblaze-specific string, read from the response body
73
+ % RetryCalls is the set of calls to use to retry the OriginalCall
74
+ % retry(OriginalCall, HttpStatus, Code, RetryCalls)
75
+
76
+ % No retry, cos it succeeded :-D
77
+ retry(_, HttpStatus, _, []) :- HttpStatus in 200..399, false.
78
+
79
+ % upload-specific 401 :- re-fetch upload url.
80
+ %
81
+ % Some docs say only for expired_auth_token? Other docs say just retry
82
+ % regardless of code.
83
+ retry( Call, 401, Code, [Retry,Call] ) :-
84
+ not_authorised_retryable_code(Code),
85
+ upload_retry(Call,Retry).
86
+
87
+ % upload-specific 408,5xx - re-fetch upload url
88
+ retry( Call, HttpStatus, _Code, [Retry,Call] ) :-
89
+ (HttpStatus = 408; five_hundreds(HttpStatus)),
90
+ upload_retry(Call,Retry).
91
+
92
+ % upload-specific 429 - just retry the call
93
+ retry( Call, 429, _Code, [Call] ) :- upload_retry(Call,_).
94
+
95
+ % non-upload 401 failures - re-auth account
96
+ retry( Call, 401, Code, [b2_authorize_account,Call] ) :-
97
+ Call \= b2_authorize_account, % b2_authorize_account can't retry with b2_authorize_account
98
+ not(upload_retry(Call,_)),
99
+ not_authorised_retryable_code(Code),
100
+ not(upload_retry(Call,_)).
101
+
102
+ % non-upload with 408, 429, and 5xx - retry call (after a backoff)
103
+ retry( Call,HttpStatus,_Code,[Call] ) :-
104
+ not(upload_retry(Call,_)),
105
+ (member(HttpStatus, [408,429]); five_hundreds(HttpStatus)),
106
+ not(upload_retry(Call,_)).
107
+
108
+ %%%%%%%%%%%%%%%%%%%
109
+ % generate all posibilities
110
+ allballs( Call,HttpStatus,Code,Retry ) :-
111
+ b2api(Call),
112
+ retry(Call,HttpStatus,Code,Retry).
113
+
114
+ %%%%%%%%%%%%%%%%%%%
115
+ % Various conversions to ruby
116
+
117
+ % use with with_output_to, can't figure out another way :-\
118
+ to_ruby_commas([]).
119
+ to_ruby_commas([Last]) :- !, to_ruby(Last).
120
+ to_ruby_commas([Fst|Rst]) :- to_ruby(Fst), format(','), to_ruby_commas(Rst).
121
+
122
+ % This has to be before ruby_lit(A). Dunno why.
123
+ to_ruby(Range) :- attvar(Range), get_attr(Range, bounds, bounds(N,X,_)), format('~d..~d', [N,X]).
124
+ to_ruby(A) :- atom(A), format(':~a', A).
125
+ to_ruby(S) :- string(S), format('"~s"', S).
126
+ to_ruby(N) :- integer(N), format('~d', N).
127
+ to_ruby(F) :- float(F), format( '~f', F).
128
+ to_ruby(L) :- is_list(L), format('[~@]', to_ruby_commas(L)).
129
+ to_ruby(ruby_lit(A)) :- format('~w', A).
130
+
131
+ default_to_any(Code,DefCode) :- ground(Code) -> format(atom(DefCode), ':~a', Code); DefCode = 'Any'.
132
+
133
+ all_whens :-
134
+ allballs( Call, HttpStatus, Code, Retries ),
135
+ to_when( Call, HttpStatus, Code, Retries ).
136
+
137
+ to_when( Call, HttpStatus, Code, Retries ) :-
138
+ default_to_any(Code,DefaultedAnyCode),
139
+ format('when [~@, ~@, ~a] then ~@~n', [to_ruby(Call),to_ruby(HttpStatus),DefaultedAnyCode,to_ruby(Retries)] ).
140
+
141
+ to_whens :- findall(_,all_whens,_).
142
+ to_whens(Term) :- findall(_,(apply(Term,C,Hs,Co,Re),retry(C,Hs,Co,Re)),_).
143
+
144
+ some_whens :-
145
+ findall(
146
+ _,
147
+ (member(C,[b2_upload_part,b2_upload_file,b2_authorize_account,any_call]),retry(C,Hs,Co,Re),to_when(C,Hs,Co,Re))
148
+ ,_).
149
+
150
+ map_all :-
151
+ format('retries = Hash.new{|h,k| h[k] = Set.new}~n'),
152
+ allballs( Call, _HttpStatus, _Code, Retries ),
153
+ selectchk(Call,Retries,Uniqs),
154
+ Uniqs \= [],
155
+ format('retries[~@].merge(~@)~n', [to_ruby(Call),to_ruby(Uniqs)] ).
156
+
157
+ to_map :- findall(_,map_all,_), format('retries~n').
@@ -0,0 +1,42 @@
1
+ require 'set'
2
+
3
+ module Backup
4
+ module Backblaze
5
+ module RetryLookup
6
+ def (Any = Object.new).=== _other; true end
7
+
8
+ module Matcher
9
+ refine Array do
10
+ def === other
11
+ return false unless size == other.size
12
+ size.times.all? do |idx|
13
+ self[idx] === other[idx]
14
+ end
15
+ end
16
+ end
17
+ end
18
+
19
+ using Matcher
20
+
21
+ # Generated from retry.pl
22
+ #
23
+ # Cross-product of all the retry scenarios we know about. This probably
24
+ # isn't the fastest way to calculate retries. But they're rare, so the
25
+ # slowdown doesn't matter. There is a more general pattern, but I don't
26
+ # want to get sucked into implementing unification.
27
+ module_function def retry_sequence api_call, http_status, code
28
+ case [api_call.to_sym, http_status, code.to_sym]
29
+ <%= `swipl -q -l #{__dir__}/retry.pl -t to_whens`.gsub(/^(\s*)/, ' ') -%>
30
+ else [] # No retry. eg 400 and most 401 should just fail immediately
31
+ end
32
+ end
33
+
34
+ module_function def retry_dependencies
35
+ @retry_dependencies ||= begin
36
+ # didn't want to fight with prolog to generate uniq values here, so just let ruby do it.
37
+ <%= `swipl -q -l #{__dir__}/retry.pl -t to_map`.gsub(/^(\s*)/, ' ') -%>
38
+ end
39
+ end
40
+ end
41
+ end
42
+ end
metadata CHANGED
@@ -1,14 +1,14 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: backup-backblaze
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.2
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - John Anderson
8
8
  autorequire:
9
9
  bindir: exe
10
10
  cert_chain: []
11
- date: 2018-08-23 00:00:00.000000000 Z
11
+ date: 2018-09-10 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
14
  name: bundler
@@ -115,12 +115,18 @@ files:
115
115
  - bin/setup
116
116
  - lib/backup/backblaze.rb
117
117
  - lib/backup/backblaze/account.rb
118
+ - lib/backup/backblaze/api_importer.rb
118
119
  - lib/backup/backblaze/back_blaze.rb
119
120
  - lib/backup/backblaze/hash_wrap.rb
121
+ - lib/backup/backblaze/http.rb
120
122
  - lib/backup/backblaze/retry.rb
123
+ - lib/backup/backblaze/retry_lookup.rb
121
124
  - lib/backup/backblaze/upload_file.rb
122
125
  - lib/backup/backblaze/upload_large_file.rb
126
+ - lib/backup/backblaze/url_token.rb
123
127
  - lib/backup/backblaze/version.rb
128
+ - src/retry.pl
129
+ - src/retry_lookup.erb
124
130
  homepage: http://github.com/djellemah/backup-backblaze
125
131
  licenses:
126
132
  - MIT