@@ -3,6 +3,7 @@ package cloudwatcher
3
3
import (
4
4
"encoding/json"
5
5
"fmt"
6
+ "path"
6
7
"sync/atomic"
7
8
"time"
8
9
@@ -11,28 +12,31 @@ import (
11
12
"golang.org/x/oauth2"
12
13
)
13
14
15
+ // DropboxWatcher is the specialized watcher for Dropbox service
14
16
type DropboxWatcher struct {
15
17
WatcherBase
16
18
17
19
syncing uint32
18
20
19
21
ticker * time.Ticker
20
22
stop chan bool
21
- config * DropboxConfiguration
23
+ config * dropboxConfiguration
22
24
cache map [string ]* DropboxObject
25
+ client files.Client
23
26
}
24
27
28
+ // DropboxObject is the object that contains the info of the file
25
29
type DropboxObject struct {
26
30
Key string
27
31
Size int64
28
32
LastModified time.Time
29
33
Hash string
30
34
}
31
35
32
- type DropboxConfiguration struct {
36
+ type dropboxConfiguration struct {
33
37
Debug Bool `json:"debug"`
34
38
JToken string `json:"token"`
35
- ClientId string `json:"client_id"`
39
+ ClientID string `json:"client_id"`
36
40
ClientSecret string `json:"client_secret"`
37
41
38
42
token * oauth2.Token
@@ -42,6 +46,7 @@ func newDropboxWatcher(dir string, interval time.Duration) (Watcher, error) {
42
46
w := & DropboxWatcher {
43
47
cache : make (map [string ]* DropboxObject ),
44
48
config : nil ,
49
+ client : nil ,
45
50
stop : make (chan bool , 1 ),
46
51
WatcherBase : WatcherBase {
47
52
Events : make (chan Event , 100 ),
@@ -54,13 +59,14 @@ func newDropboxWatcher(dir string, interval time.Duration) (Watcher, error) {
54
59
return w , nil
55
60
}
56
61
62
+ // SetConfig is used to configure the DropboxWatcher
57
63
func (w * DropboxWatcher ) SetConfig (m map [string ]string ) error {
58
64
j , err := json .Marshal (m )
59
65
if err != nil {
60
66
return err
61
67
}
62
68
63
- config := DropboxConfiguration {}
69
+ config := dropboxConfiguration {}
64
70
if err := json .Unmarshal (j , & config ); err != nil {
65
71
return err
66
72
}
@@ -78,6 +84,7 @@ func (w *DropboxWatcher) SetConfig(m map[string]string) error {
78
84
return nil
79
85
}
80
86
87
+ // Start launches the polling process
81
88
func (w * DropboxWatcher ) Start () error {
82
89
if w .config == nil {
83
90
return fmt .Errorf ("configuration for Dropbox needed" )
@@ -102,8 +109,24 @@ func (w *DropboxWatcher) Start() error {
102
109
return nil
103
110
}
104
111
112
+ // Close stop the polling process
105
113
func (w * DropboxWatcher ) Close () {
106
- w .stop <- true
114
+ if w .stop != nil {
115
+ w .stop <- true
116
+ }
117
+ }
118
+
119
+ func (w * DropboxWatcher ) initDropboxClient () {
120
+ logLevel := dropbox .LogOff
121
+ if w .config .Debug {
122
+ logLevel = dropbox .LogDebug
123
+ }
124
+
125
+ config := dropbox.Config {
126
+ Token : w .config .token .AccessToken ,
127
+ LogLevel : logLevel ,
128
+ }
129
+ w .client = files .New (config )
107
130
}
108
131
109
132
func (w * DropboxWatcher ) sync () {
@@ -113,8 +136,11 @@ func (w *DropboxWatcher) sync() {
113
136
}
114
137
defer atomic .StoreUint32 (& w .syncing , 0 )
115
138
116
- fileList := make (map [string ]* DropboxObject , 0 )
139
+ if w .client == nil {
140
+ w .initDropboxClient ()
141
+ }
117
142
143
+ fileList := make (map [string ]* DropboxObject , 0 )
118
144
err := w .enumerateFiles (w .watchDir , func (obj * DropboxObject ) bool {
119
145
// Store the files to check the deleted one
120
146
fileList [obj .Key ] = obj
@@ -123,7 +149,7 @@ func (w *DropboxWatcher) sync() {
123
149
// Object has been cached previously by Key
124
150
if cached != nil {
125
151
// Check if the LastModified has been changed
126
- if ! cached .LastModified .Equal (obj .LastModified ) || cached .Hash != obj .Hash {
152
+ if ! cached .LastModified .Equal (obj .LastModified ) || cached .Hash != obj .Hash || cached . Size != obj . Size {
127
153
event := Event {
128
154
Key : obj .Key ,
129
155
Type : FileChanged ,
@@ -162,29 +188,19 @@ func (w *DropboxWatcher) sync() {
162
188
}
163
189
164
190
func (w * DropboxWatcher ) enumerateFiles (prefix string , callback func (object * DropboxObject ) bool ) error {
165
- logLevel := dropbox .LogOff
166
- if w .config .Debug {
167
- logLevel = dropbox .LogDebug
168
- }
169
-
170
- config := dropbox.Config {
171
- Token : w .config .token .AccessToken ,
172
- LogLevel : logLevel ,
173
- }
174
- dbx := files .New (config )
175
191
arg := files .NewListFolderArg (prefix )
176
192
arg .Recursive = true
177
193
178
194
var entries []files.IsMetadata
179
- res , err := dbx .ListFolder (arg )
195
+ res , err := w . client .ListFolder (arg )
180
196
if err != nil {
181
197
listRevisionError , ok := err .(files.ListRevisionsAPIError )
182
198
if ok {
183
199
// Don't treat a "not_folder" error as fatal; recover by sending a
184
200
// get_metadata request for the same path and using that response instead.
185
201
if listRevisionError .EndpointError .Path .Tag == files .LookupErrorNotFolder {
186
202
var metaRes files.IsMetadata
187
- metaRes , err = w .getFileMetadata (dbx , prefix )
203
+ metaRes , err = w .getFileMetadata (w . client , prefix )
188
204
entries = []files.IsMetadata {metaRes }
189
205
} else {
190
206
// Return if there's an error other than "not_folder" or if the follow-up
@@ -200,7 +216,7 @@ func (w *DropboxWatcher) enumerateFiles(prefix string, callback func(object *Dro
200
216
for res .HasMore {
201
217
arg := files .NewListFolderContinueArg (res .Cursor )
202
218
203
- res , err = dbx .ListFolderContinue (arg )
219
+ res , err = w . client .ListFolderContinue (arg )
204
220
if err != nil {
205
221
return err
206
222
}
@@ -214,10 +230,14 @@ func (w *DropboxWatcher) enumerateFiles(prefix string, callback func(object *Dro
214
230
switch f := entry .(type ) {
215
231
case * files.FileMetadata :
216
232
o .Key = f .PathDisplay
233
+ if f .PathDisplay == "" {
234
+ o .Key = path .Join (f .PathLower , f .Name )
235
+ }
217
236
o .Size = int64 (f .Size )
218
237
o .LastModified = f .ServerModified
219
238
o .Hash = f .ContentHash
220
239
callback (o )
240
+ default :
221
241
}
222
242
}
223
243
0 commit comments