backup-backblaze 0.1.2 → 0.2.0

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.
@@ -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