service.go 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305
  1. package dropboxfs
  2. import (
  3. "bytes"
  4. "io"
  5. "os"
  6. "strings"
  7. "time"
  8. "golang.org/x/oauth2"
  9. "dev.hexasoftware.com/hxs/cloudmount/internal/core"
  10. "dev.hexasoftware.com/hxs/cloudmount/internal/coreutil"
  11. "dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
  12. "dev.hexasoftware.com/hxs/cloudmount/internal/oauth2util"
  13. "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox"
  14. dbfiles "github.com/dropbox/dropbox-sdk-go-unofficial/dropbox/files"
  15. )
  16. // Service basefs Service implementation
  17. type Service struct {
  18. dbconfig dropbox.Config
  19. savedCursor string
  20. }
  21. func NewService(coreConfig *core.Config) *Service {
  22. serviceConfig := Config{}
  23. log.Println("Initializing dropbox service")
  24. log.Println("Source config:", coreConfig.Source)
  25. err := coreutil.ParseConfig(coreConfig.Source, &serviceConfig)
  26. if err != nil {
  27. errlog.Fatalf("Unable to read <source>: %v", err)
  28. }
  29. config := &oauth2.Config{
  30. ClientID: serviceConfig.ClientSecret.ClientID,
  31. ClientSecret: serviceConfig.ClientSecret.ClientSecret,
  32. RedirectURL: "",
  33. Scopes: []string{},
  34. Endpoint: oauth2.Endpoint{
  35. AuthURL: "https://www.dropbox.com/1/oauth2/authorize",
  36. TokenURL: "https://api.dropbox.com/1/oauth2/token",
  37. },
  38. }
  39. if serviceConfig.Auth == nil {
  40. tok := oauth2util.GetTokenFromWeb(config)
  41. serviceConfig.Auth = tok
  42. coreutil.SaveConfig(coreConfig.Source, &serviceConfig)
  43. }
  44. dbconfig := dropbox.Config{Token: serviceConfig.Auth.AccessToken}
  45. return &Service{dbconfig: dbconfig}
  46. }
  47. // Changes dropbox longpool changes
  48. func (s *Service) Changes() ([]*basefs.Change, error) {
  49. fileService := dbfiles.New(s.dbconfig)
  50. if fileService == nil {
  51. log.Println("File service is nill")
  52. return nil, nil
  53. }
  54. if s.savedCursor == "" {
  55. res, err := fileService.ListFolderGetLatestCursor(&dbfiles.ListFolderArg{Path: "", Recursive: true})
  56. if err != nil {
  57. log.Println("Err:", err)
  58. return nil, err
  59. }
  60. s.savedCursor = res.Cursor
  61. }
  62. res, err := fileService.ListFolderLongpoll(dbfiles.NewListFolderLongpollArg(s.savedCursor))
  63. if err != nil {
  64. log.Println("Err in longpoll", err)
  65. return nil, err
  66. }
  67. if res.Changes == false {
  68. return nil, nil
  69. }
  70. ret := []*basefs.Change{}
  71. for {
  72. res, err := fileService.ListFolderContinue(dbfiles.NewListFolderContinueArg(s.savedCursor))
  73. if err != nil {
  74. return nil, err
  75. }
  76. for _, e := range res.Entries {
  77. var change *basefs.Change
  78. switch t := e.(type) {
  79. case *dbfiles.DeletedMetadata:
  80. change = &basefs.Change{t.PathLower, File(t), true}
  81. case *dbfiles.FileMetadata:
  82. change = &basefs.Change{t.PathLower, File(t), false}
  83. case *dbfiles.FolderMetadata:
  84. change = &basefs.Change{t.PathLower, File(t), false}
  85. }
  86. ret = append(ret, change)
  87. }
  88. if !res.HasMore {
  89. break
  90. }
  91. }
  92. {
  93. // Store new token
  94. res, err := fileService.ListFolderGetLatestCursor(&dbfiles.ListFolderArg{Path: "", Recursive: true})
  95. if err != nil {
  96. log.Println("Err:", err)
  97. return nil, err
  98. }
  99. s.savedCursor = res.Cursor
  100. }
  101. return ret, nil
  102. }
  103. // ListAll implementation
  104. func (s *Service) ListAll() ([]*basefs.File, error) {
  105. fileService := dbfiles.New(s.dbconfig)
  106. // Some how list all files from Dropbox
  107. log.Println("Loading meta data")
  108. ret := []*basefs.File{}
  109. var err error
  110. var res *dbfiles.ListFolderResult
  111. res, err = fileService.ListFolder(&dbfiles.ListFolderArg{Recursive: true, Path: "", IncludeDeleted: false, IncludeMediaInfo: false})
  112. if err != nil {
  113. log.Println("Error listing:", err)
  114. return nil, err
  115. }
  116. log.Println("Loaded: res.Entries", len(res.Entries))
  117. for _, e := range res.Entries {
  118. ret = append(ret, File(e))
  119. }
  120. for res.HasMore {
  121. res, err = fileService.ListFolderContinue(&dbfiles.ListFolderContinueArg{Cursor: res.Cursor})
  122. log.Println("Loaded: res.Entries", len(res.Entries))
  123. for _, e := range res.Entries {
  124. ret = append(ret, File(e))
  125. }
  126. }
  127. return ret, nil
  128. }
  129. // Create file implementation
  130. func (s *Service) Create(parent *basefs.File, name string, isDir bool) (*basefs.File, error) {
  131. fileService := dbfiles.New(s.dbconfig)
  132. parentID := ""
  133. if parent != nil {
  134. parentID = parent.ID
  135. }
  136. if isDir {
  137. data, err := fileService.CreateFolder(&dbfiles.CreateFolderArg{
  138. Autorename: false,
  139. Path: parentID + "/" + name,
  140. })
  141. if err != nil {
  142. return nil, err
  143. }
  144. return File(data), nil
  145. }
  146. newPath := parentID + "/" + name
  147. reader := bytes.NewBuffer([]byte{})
  148. data, err := fileService.Upload(&dbfiles.CommitInfo{
  149. Path: newPath, // ???
  150. Autorename: false,
  151. Mode: &dbfiles.WriteMode{Tagged: dropbox.Tagged{Tag: dbfiles.WriteModeOverwrite}},
  152. }, reader)
  153. if err != nil {
  154. log.Println("Upload Error:", err)
  155. return nil, err
  156. }
  157. return File(data), nil
  158. }
  159. // Upload file implementation
  160. func (s *Service) Upload(reader io.Reader, file *basefs.File) (*basefs.File, error) {
  161. fileService := dbfiles.New(s.dbconfig)
  162. data, err := fileService.Upload(&dbfiles.CommitInfo{
  163. Path: file.ID, // ???
  164. Autorename: false,
  165. Mode: &dbfiles.WriteMode{Tagged: dropbox.Tagged{Tag: dbfiles.WriteModeOverwrite}},
  166. //ClientModified: time.Now().UTC(),
  167. }, reader.(io.Reader))
  168. if err != nil {
  169. log.Println("Upload Error:", err)
  170. return nil, err
  171. }
  172. return File(data), nil
  173. }
  174. // DownloadTo implementation
  175. func (s *Service) DownloadTo(w io.Writer, file *basefs.File) error {
  176. fileService := dbfiles.New(s.dbconfig)
  177. _, content, err := fileService.Download(&dbfiles.DownloadArg{Path: file.ID})
  178. if err != nil {
  179. return err
  180. }
  181. defer content.Close()
  182. io.Copy(w, content)
  183. return nil
  184. }
  185. // Move and Rename file implementation
  186. func (s *Service) Move(file *basefs.File, newParent *basefs.File, name string) (*basefs.File, error) {
  187. fileService := dbfiles.New(s.dbconfig)
  188. newParentID := ""
  189. if newParent != nil {
  190. newParentID = newParent.ID
  191. }
  192. res, err := fileService.Move(&dbfiles.RelocationArg{
  193. RelocationPath: dbfiles.RelocationPath{
  194. FromPath: file.ID,
  195. ToPath: newParentID + "/" + name,
  196. },
  197. })
  198. if err != nil {
  199. return nil, err
  200. }
  201. return File(res), nil
  202. }
  203. // Delete deletes a file entry (including Dir)
  204. func (s *Service) Delete(file *basefs.File) error {
  205. fileService := dbfiles.New(s.dbconfig)
  206. _, err := fileService.Delete(&dbfiles.DeleteArg{Path: file.ID})
  207. if err != nil {
  208. return err
  209. }
  210. return nil
  211. }
  212. // File Metadata to File Converter
  213. func File(metadata dbfiles.IsMetadata) *basefs.File {
  214. var ID string
  215. var name string
  216. var modifiedTime time.Time
  217. var mode = os.FileMode(0644)
  218. var size uint64
  219. //var parentID string
  220. // Common data
  221. var md dbfiles.Metadata
  222. switch t := metadata.(type) {
  223. case *dbfiles.FileMetadata:
  224. md = t.Metadata
  225. modifiedTime = t.ServerModified
  226. size = t.Size
  227. case *dbfiles.FolderMetadata:
  228. md = t.Metadata
  229. modifiedTime = time.Now()
  230. mode = os.FileMode(0755) | os.ModeDir
  231. //parentID = t.SharedFolderId
  232. case *dbfiles.DeletedMetadata:
  233. md = t.Metadata
  234. }
  235. ID = md.PathLower
  236. name = md.Name
  237. createdTime := modifiedTime // we dont have created time on dropbox?
  238. pathParts := strings.Split(ID, "/")
  239. parentID := strings.Join(pathParts[:len(pathParts)-1], "/")
  240. parents := []string{}
  241. if parentID != "" {
  242. parents = []string{parentID}
  243. }
  244. file := &basefs.File{
  245. ID: ID,
  246. Name: name,
  247. Parents: parents,
  248. Size: size,
  249. CreatedTime: createdTime,
  250. ModifiedTime: modifiedTime,
  251. AccessedTime: modifiedTime,
  252. Mode: mode,
  253. }
  254. return file
  255. }