123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167 |
- package gdrivefs
- import (
- "time"
- drive "google.golang.org/api/drive/v3"
- "google.golang.org/api/googleapi"
- "dev.hexasoftware.com/hxs/cloudmount/internal/core"
- "dev.hexasoftware.com/hxs/cloudmount/internal/fs/basefs"
- "dev.hexasoftware.com/hxs/prettylog"
- )
- var (
- log = prettylog.New("gdrivefs")
- )
- type GDriveFS struct {
- *basefs.BaseFS
- serviceConfig *Config
- nextRefresh time.Time
- }
- func New(core *core.Core) core.DriverFS {
- fs := &GDriveFS{basefs.New(core), &Config{}, time.Now()}
- client := fs.initClient() // Init Oauth2 client
- fs.BaseFS.Client = client // This will be removed
- fs.BaseFS.Service = &gdriveService{client}
- return fs
- }
- func (fs *GDriveFS) Start() {
- go func() {
- fs.Refresh() // First load
- // Change reader loop
- startPageTokenRes, err := fs.Client.Changes.GetStartPageToken().Do()
- if err != nil {
- log.Println("GDrive err", err)
- }
- savedStartPageToken := startPageTokenRes.StartPageToken
- for {
- pageToken := savedStartPageToken
- for pageToken != "" {
- changesRes, err := fs.Client.Changes.List(pageToken).Fields(googleapi.Field("newStartPageToken,nextPageToken,changes(removed,fileId,file(" + fileFields + "))")).Do()
- if err != nil {
- log.Println("Err fetching changes", err)
- break
- }
- //log.Println("Changes:", len(changesRes.Changes))
- for _, c := range changesRes.Changes {
- _, entry := fs.Root.FindByGID(c.FileId)
- if c.Removed {
- if entry == nil {
- continue
- } else {
- fs.Root.RemoveEntry(entry)
- }
- continue
- }
- if entry != nil {
- entry.SetFile(&basefs.GFile{c.File}, fs.Config.UID, fs.Config.GID)
- } else {
- //Create new one
- fs.Root.FileEntry(c.File) // Creating new one
- }
- }
- if changesRes.NewStartPageToken != "" {
- savedStartPageToken = changesRes.NewStartPageToken
- }
- pageToken = changesRes.NextPageToken
- }
- time.Sleep(fs.Config.RefreshTime)
- }
- }()
- }
- const fileFields = googleapi.Field("id, name, size,mimeType, parents,createdTime,modifiedTime")
- const gdFields = googleapi.Field("files(" + fileFields + ")")
- func (fs *GDriveFS) Refresh() {
- fileList := []*drive.File{}
- fileMap := map[string]*drive.File{} // Temporary map by google drive fileID
- r, err := fs.Client.Files.List().
- OrderBy("createdTime").
- PageSize(1000).
- SupportsTeamDrives(true).
- IncludeTeamDriveItems(true).
- Fields(googleapi.Field("nextPageToken"), gdFields).
- Do()
- if err != nil {
- // Sometimes gdrive returns error 500 randomly
- log.Println("GDrive ERR:", err)
- fs.Refresh() // retry
- return
- }
- fileList = append(fileList, r.Files...)
- // Rest of the pages
- for r.NextPageToken != "" {
- r, err = fs.Client.Files.List().
- OrderBy("createdTime").
- PageToken(r.NextPageToken).
- Fields(googleapi.Field("nextPageToken"), gdFields).
- Do()
- if err != nil {
- log.Println("GDrive ERR:", err)
- fs.Refresh() // retry // Same as above
- return
- }
- fileList = append(fileList, r.Files...)
- }
- log.Println("Total entries:", len(fileList))
- // Cache ID for faster retrieval, might not be necessary
- for _, f := range fileList {
- fileMap[f.Id] = f
- }
- if err != nil || r == nil {
- log.Println("Unable to retrieve files", err)
- return
- }
- // Create clean fileList
- root := basefs.NewFileContainer(fs.BaseFS)
- var appendFile func(gfile *drive.File)
- appendFile = func(gfile *drive.File) {
- for _, pID := range gfile.Parents {
- parentFile, ok := fileMap[pID]
- if !ok {
- parentFile, err = fs.Client.Files.Get(pID).Do()
- if err != nil {
- log.Println("Error fetching single file:", err)
- }
- fileMap[parentFile.Id] = parentFile
- }
- appendFile(parentFile) // Recurse
- }
- // Find existing entry
- inode, entry := fs.Root.FindByGID(gfile.Id)
- // Store for later add
- if entry == nil {
- inode, entry = fs.Root.FileEntry(gfile) // Add New and retrieve
- }
- root.SetEntry(inode, entry)
- // add File
- }
- for _, f := range fileList { // Ordered
- appendFile(f) // Check parent first
- }
- log.Println("Refresh done, update root")
- fs.Root = root
- //fs.root.children = root.children
- log.Println("File count:", root.Count())
- }
|