service.go 7.1 KB

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