forked from m-rots/bernard
/
bernard.go
101 lines (83 loc) · 2.74 KB
/
bernard.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
package bernard
import (
"errors"
"net/http"
"time"
ds "github.com/l3uddz/bernard/datastore"
)
// Authenticator represents any struct which can create an access token on demand
type Authenticator interface {
AccessToken() (string, int64, error)
}
// Bernard is a synchronisation backend for Google Drive.
type Bernard struct {
safeSleep time.Duration
fetch *fetcher
store ds.Datastore
}
// An Option can override some of the default Bernard values.
type Option func(*Bernard)
// WithClient allows one to override the default HTTP client.
func WithClient(client *http.Client) Option {
return func(bernard *Bernard) {
bernard.fetch.client = client
}
}
// WithPreRequestHook allows one to apply rate-limiting before every request.
//
// This function is called before fetching the authentication token to prevent
// tokens from expiring when a rate-limit is applied.
func WithPreRequestHook(preHook func()) Option {
return func(bernard *Bernard) {
bernard.fetch.preHook = preHook
}
}
// WithJSONDecoder allows one to replace Go's default JSON decoding
// with a more memory-efficient and quicker solution.
func WithJSONDecoder(d jsonDecoder) Option {
return func(bernard *Bernard) {
bernard.fetch.decodeJSON = d
}
}
// WithSafeSleep allows one to sleep between the pageToken fetch and
// the full sync. Setting this between 1 and 5 minutes prevents
// any data from going rogue when changes are actively being made
// to the Shared Drive.
//
// The default value of safeSleep is set at 0.
func WithSafeSleep(duration time.Duration) Option {
return func(bernard *Bernard) {
bernard.safeSleep = duration
}
}
// New creates a new instance of Bernard
func New(auth Authenticator, store ds.Datastore, opts ...Option) *Bernard {
const baseURL string = "https://www.googleapis.com/drive/v3"
fetch := &fetcher{
auth: auth,
baseURL: baseURL,
client: &http.Client{
Timeout: 15 * time.Second,
},
decodeJSON: decodeJSON,
sleep: time.Sleep,
}
bernard := &Bernard{
fetch: fetch,
store: store,
}
for _, opt := range opts {
opt(bernard)
}
return bernard
}
// ErrInvalidCredentials can occur when the wrong authentication scopes are used,
// the access token does not have access to the specified resource, or the token
// is simply invalid or expired.
var ErrInvalidCredentials = errors.New("bernard: invalid credentials")
// ErrNotFound only occurs when the provided auth does not have access to the
// Shared Drive or if the Shared Drive does not exist.
var ErrNotFound = errors.New("bernard: cannot find Shared Drive")
// ErrNetwork is the result of a networking error while contacting the Google Drive API.
// This error is only thrown on status codes not equal to 200, 401 and 500.
var ErrNetwork = errors.New("bernard: network related error")