gdrivefs.go 4.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167
  1. package gdrivefs
  2. import (
  3. "time"
  4. drive "google.golang.org/api/drive/v3"
  5. "google.golang.org/api/googleapi"
  6. "dev.hexasoftware.com/hxs/cloudmount/internal/core"
  7. "dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
  8. "dev.hexasoftware.com/hxs/prettylog"
  9. )
  10. var (
  11. log = prettylog.New("gdrivefs")
  12. )
  13. type GDriveFS struct {
  14. *basefs.BaseFS
  15. serviceConfig *Config
  16. nextRefresh time.Time
  17. }
  18. func New(core *core.Core) core.DriverFS {
  19. fs := &GDriveFS{basefs.New(core), &Config{}, time.Now()}
  20. client := fs.initClient() // Init Oauth2 client
  21. fs.BaseFS.Client = client // This will be removed
  22. fs.BaseFS.Service = &gdriveService{client}
  23. return fs
  24. }
  25. func (fs *GDriveFS) Start() {
  26. go func() {
  27. fs.Refresh() // First load
  28. // Change reader loop
  29. startPageTokenRes, err := fs.Client.Changes.GetStartPageToken().Do()
  30. if err != nil {
  31. log.Println("GDrive err", err)
  32. }
  33. savedStartPageToken := startPageTokenRes.StartPageToken
  34. for {
  35. pageToken := savedStartPageToken
  36. for pageToken != "" {
  37. changesRes, err := fs.Client.Changes.List(pageToken).Fields(googleapi.Field("newStartPageToken,nextPageToken,changes(removed,fileId,file(" + fileFields + "))")).Do()
  38. if err != nil {
  39. log.Println("Err fetching changes", err)
  40. break
  41. }
  42. //log.Println("Changes:", len(changesRes.Changes))
  43. for _, c := range changesRes.Changes {
  44. _, entry := fs.Root.FindByGID(c.FileId)
  45. if c.Removed {
  46. if entry == nil {
  47. continue
  48. } else {
  49. fs.Root.RemoveEntry(entry)
  50. }
  51. continue
  52. }
  53. if entry != nil {
  54. entry.SetFile(&basefs.GFile{c.File}, fs.Config.UID, fs.Config.GID)
  55. } else {
  56. //Create new one
  57. fs.Root.FileEntry(c.File) // Creating new one
  58. }
  59. }
  60. if changesRes.NewStartPageToken != "" {
  61. savedStartPageToken = changesRes.NewStartPageToken
  62. }
  63. pageToken = changesRes.NextPageToken
  64. }
  65. time.Sleep(fs.Config.RefreshTime)
  66. }
  67. }()
  68. }
  69. const fileFields = googleapi.Field("id, name, size,mimeType, parents,createdTime,modifiedTime")
  70. const gdFields = googleapi.Field("files(" + fileFields + ")")
  71. func (fs *GDriveFS) Refresh() {
  72. fileList := []*drive.File{}
  73. fileMap := map[string]*drive.File{} // Temporary map by google drive fileID
  74. r, err := fs.Client.Files.List().
  75. OrderBy("createdTime").
  76. PageSize(1000).
  77. SupportsTeamDrives(true).
  78. IncludeTeamDriveItems(true).
  79. Fields(googleapi.Field("nextPageToken"), gdFields).
  80. Do()
  81. if err != nil {
  82. // Sometimes gdrive returns error 500 randomly
  83. log.Println("GDrive ERR:", err)
  84. fs.Refresh() // retry
  85. return
  86. }
  87. fileList = append(fileList, r.Files...)
  88. // Rest of the pages
  89. for r.NextPageToken != "" {
  90. r, err = fs.Client.Files.List().
  91. OrderBy("createdTime").
  92. PageToken(r.NextPageToken).
  93. Fields(googleapi.Field("nextPageToken"), gdFields).
  94. Do()
  95. if err != nil {
  96. log.Println("GDrive ERR:", err)
  97. fs.Refresh() // retry // Same as above
  98. return
  99. }
  100. fileList = append(fileList, r.Files...)
  101. }
  102. log.Println("Total entries:", len(fileList))
  103. // Cache ID for faster retrieval, might not be necessary
  104. for _, f := range fileList {
  105. fileMap[f.Id] = f
  106. }
  107. if err != nil || r == nil {
  108. log.Println("Unable to retrieve files", err)
  109. return
  110. }
  111. // Create clean fileList
  112. root := basefs.NewFileContainer(fs.BaseFS)
  113. var appendFile func(gfile *drive.File)
  114. appendFile = func(gfile *drive.File) {
  115. for _, pID := range gfile.Parents {
  116. parentFile, ok := fileMap[pID]
  117. if !ok {
  118. parentFile, err = fs.Client.Files.Get(pID).Do()
  119. if err != nil {
  120. log.Println("Error fetching single file:", err)
  121. }
  122. fileMap[parentFile.Id] = parentFile
  123. }
  124. appendFile(parentFile) // Recurse
  125. }
  126. // Find existing entry
  127. inode, entry := fs.Root.FindByGID(gfile.Id)
  128. // Store for later add
  129. if entry == nil {
  130. inode, entry = fs.Root.FileEntry(gfile) // Add New and retrieve
  131. }
  132. root.SetEntry(inode, entry)
  133. // add File
  134. }
  135. for _, f := range fileList { // Ordered
  136. appendFile(f) // Check parent first
  137. }
  138. log.Println("Refresh done, update root")
  139. fs.Root = root
  140. //fs.root.children = root.children
  141. log.Println("File count:", root.Count())
  142. }