@@ -3,6 +3,7 @@ package cloudwatcher
33import (
44 "encoding/json"
55 "fmt"
6+ "path"
67 "sync/atomic"
78 "time"
89
@@ -11,28 +12,31 @@ import (
1112 "golang.org/x/oauth2"
1213)
1314
15+ // DropboxWatcher is the specialized watcher for Dropbox service
1416type DropboxWatcher struct {
1517 WatcherBase
1618
1719 syncing uint32
1820
1921 ticker * time.Ticker
2022 stop chan bool
21- config * DropboxConfiguration
23+ config * dropboxConfiguration
2224 cache map [string ]* DropboxObject
25+ client files.Client
2326}
2427
28+ // DropboxObject is the object that contains the info of the file
2529type DropboxObject struct {
2630 Key string
2731 Size int64
2832 LastModified time.Time
2933 Hash string
3034}
3135
32- type DropboxConfiguration struct {
36+ type dropboxConfiguration struct {
3337 Debug Bool `json:"debug"`
3438 JToken string `json:"token"`
35- ClientId string `json:"client_id"`
39+ ClientID string `json:"client_id"`
3640 ClientSecret string `json:"client_secret"`
3741
3842 token * oauth2.Token
@@ -42,6 +46,7 @@ func newDropboxWatcher(dir string, interval time.Duration) (Watcher, error) {
4246 w := & DropboxWatcher {
4347 cache : make (map [string ]* DropboxObject ),
4448 config : nil ,
49+ client : nil ,
4550 stop : make (chan bool , 1 ),
4651 WatcherBase : WatcherBase {
4752 Events : make (chan Event , 100 ),
@@ -54,13 +59,14 @@ func newDropboxWatcher(dir string, interval time.Duration) (Watcher, error) {
5459 return w , nil
5560}
5661
62+ // SetConfig is used to configure the DropboxWatcher
5763func (w * DropboxWatcher ) SetConfig (m map [string ]string ) error {
5864 j , err := json .Marshal (m )
5965 if err != nil {
6066 return err
6167 }
6268
63- config := DropboxConfiguration {}
69+ config := dropboxConfiguration {}
6470 if err := json .Unmarshal (j , & config ); err != nil {
6571 return err
6672 }
@@ -78,6 +84,7 @@ func (w *DropboxWatcher) SetConfig(m map[string]string) error {
7884 return nil
7985}
8086
87+ // Start launches the polling process
8188func (w * DropboxWatcher ) Start () error {
8289 if w .config == nil {
8390 return fmt .Errorf ("configuration for Dropbox needed" )
@@ -102,8 +109,24 @@ func (w *DropboxWatcher) Start() error {
102109 return nil
103110}
104111
112+ // Close stop the polling process
105113func (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 )
107130}
108131
109132func (w * DropboxWatcher ) sync () {
@@ -113,8 +136,11 @@ func (w *DropboxWatcher) sync() {
113136 }
114137 defer atomic .StoreUint32 (& w .syncing , 0 )
115138
116- fileList := make (map [string ]* DropboxObject , 0 )
139+ if w .client == nil {
140+ w .initDropboxClient ()
141+ }
117142
143+ fileList := make (map [string ]* DropboxObject , 0 )
118144 err := w .enumerateFiles (w .watchDir , func (obj * DropboxObject ) bool {
119145 // Store the files to check the deleted one
120146 fileList [obj .Key ] = obj
@@ -123,7 +149,7 @@ func (w *DropboxWatcher) sync() {
123149 // Object has been cached previously by Key
124150 if cached != nil {
125151 // 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 {
127153 event := Event {
128154 Key : obj .Key ,
129155 Type : FileChanged ,
@@ -162,29 +188,19 @@ func (w *DropboxWatcher) sync() {
162188}
163189
164190func (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 )
175191 arg := files .NewListFolderArg (prefix )
176192 arg .Recursive = true
177193
178194 var entries []files.IsMetadata
179- res , err := dbx .ListFolder (arg )
195+ res , err := w . client .ListFolder (arg )
180196 if err != nil {
181197 listRevisionError , ok := err .(files.ListRevisionsAPIError )
182198 if ok {
183199 // Don't treat a "not_folder" error as fatal; recover by sending a
184200 // get_metadata request for the same path and using that response instead.
185201 if listRevisionError .EndpointError .Path .Tag == files .LookupErrorNotFolder {
186202 var metaRes files.IsMetadata
187- metaRes , err = w .getFileMetadata (dbx , prefix )
203+ metaRes , err = w .getFileMetadata (w . client , prefix )
188204 entries = []files.IsMetadata {metaRes }
189205 } else {
190206 // 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
200216 for res .HasMore {
201217 arg := files .NewListFolderContinueArg (res .Cursor )
202218
203- res , err = dbx .ListFolderContinue (arg )
219+ res , err = w . client .ListFolderContinue (arg )
204220 if err != nil {
205221 return err
206222 }
@@ -214,10 +230,14 @@ func (w *DropboxWatcher) enumerateFiles(prefix string, callback func(object *Dro
214230 switch f := entry .(type ) {
215231 case * files.FileMetadata :
216232 o .Key = f .PathDisplay
233+ if f .PathDisplay == "" {
234+ o .Key = path .Join (f .PathLower , f .Name )
235+ }
217236 o .Size = int64 (f .Size )
218237 o .LastModified = f .ServerModified
219238 o .Hash = f .ContentHash
220239 callback (o )
240+ default :
221241 }
222242 }
223243
0 commit comments