forked from IceWhaleTech/CasaOS
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
47 changed files
with
3,711 additions
and
67 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
package drivers | ||
|
||
import ( | ||
_ "github.com/IceWhaleTech/CasaOS/drivers/google_drive" | ||
) | ||
|
||
// All do nothing,just for import | ||
// same as _ import | ||
func All() { | ||
|
||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,30 @@ | ||
package base | ||
|
||
import ( | ||
"net/http" | ||
"time" | ||
|
||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
var NoRedirectClient *resty.Client | ||
var RestyClient = NewRestyClient() | ||
var HttpClient = &http.Client{} | ||
var UserAgent = "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/87.0.4280.88 Safari/537.36" | ||
var DefaultTimeout = time.Second * 30 | ||
|
||
func init() { | ||
NoRedirectClient = resty.New().SetRedirectPolicy( | ||
resty.RedirectPolicyFunc(func(req *http.Request, via []*http.Request) error { | ||
return http.ErrUseLastResponse | ||
}), | ||
) | ||
NoRedirectClient.SetHeader("user-agent", UserAgent) | ||
} | ||
|
||
func NewRestyClient() *resty.Client { | ||
return resty.New(). | ||
SetHeader("user-agent", UserAgent). | ||
SetRetryCount(3). | ||
SetTimeout(DefaultTimeout) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,12 @@ | ||
package base | ||
|
||
import "github.com/go-resty/resty/v2" | ||
|
||
type Json map[string]interface{} | ||
|
||
type TokenResp struct { | ||
AccessToken string `json:"access_token"` | ||
RefreshToken string `json:"refresh_token"` | ||
} | ||
|
||
type ReqCallback func(req *resty.Request) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,170 @@ | ||
package google_drive | ||
|
||
import ( | ||
"context" | ||
"errors" | ||
"fmt" | ||
"net/http" | ||
"strconv" | ||
|
||
"github.com/IceWhaleTech/CasaOS/drivers/base" | ||
"github.com/IceWhaleTech/CasaOS/internal/driver" | ||
"github.com/IceWhaleTech/CasaOS/model" | ||
"github.com/IceWhaleTech/CasaOS/pkg/utils" | ||
"github.com/go-resty/resty/v2" | ||
) | ||
|
||
type GoogleDrive struct { | ||
model.Storage | ||
Addition | ||
AccessToken string | ||
} | ||
|
||
func (d *GoogleDrive) Config() driver.Config { | ||
return config | ||
} | ||
|
||
func (d *GoogleDrive) GetAddition() driver.Additional { | ||
return &d.Addition | ||
} | ||
|
||
func (d *GoogleDrive) Init(ctx context.Context) error { | ||
if d.ChunkSize == 0 { | ||
d.ChunkSize = 5 | ||
} | ||
if len(d.RefreshToken) == 0 { | ||
return d.getRefreshToken() | ||
} | ||
return d.refreshToken() | ||
} | ||
|
||
func (d *GoogleDrive) Drop(ctx context.Context) error { | ||
return nil | ||
} | ||
|
||
func (d *GoogleDrive) List(ctx context.Context, dir model.Obj, args model.ListArgs) ([]model.Obj, error) { | ||
files, err := d.getFiles(dir.GetID()) | ||
if err != nil { | ||
return nil, err | ||
} | ||
return utils.SliceConvert(files, func(src File) (model.Obj, error) { | ||
return fileToObj(src), nil | ||
}) | ||
} | ||
|
||
func (d *GoogleDrive) Link(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { | ||
url := fmt.Sprintf("https://www.googleapis.com/drive/v3/files/%s?includeItemsFromAllDrives=true&supportsAllDrives=true", file.GetID()) | ||
_, err := d.request(url, http.MethodGet, nil, nil) | ||
if err != nil { | ||
return nil, err | ||
} | ||
link := model.Link{ | ||
URL: url + "&alt=media", | ||
Header: http.Header{ | ||
"Authorization": []string{"Bearer " + d.AccessToken}, | ||
}, | ||
} | ||
return &link, nil | ||
} | ||
|
||
func (d *GoogleDrive) MakeDir(ctx context.Context, parentDir model.Obj, dirName string) error { | ||
data := base.Json{ | ||
"name": dirName, | ||
"parents": []string{parentDir.GetID()}, | ||
"mimeType": "application/vnd.google-apps.folder", | ||
} | ||
_, err := d.request("https://www.googleapis.com/drive/v3/files", http.MethodPost, func(req *resty.Request) { | ||
req.SetBody(data) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *GoogleDrive) Move(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
query := map[string]string{ | ||
"addParents": dstDir.GetID(), | ||
"removeParents": "root", | ||
} | ||
url := "https://www.googleapis.com/drive/v3/files/" + srcObj.GetID() | ||
_, err := d.request(url, http.MethodPatch, func(req *resty.Request) { | ||
req.SetQueryParams(query) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *GoogleDrive) Rename(ctx context.Context, srcObj model.Obj, newName string) error { | ||
data := base.Json{ | ||
"name": newName, | ||
} | ||
url := "https://www.googleapis.com/drive/v3/files/" + srcObj.GetID() | ||
_, err := d.request(url, http.MethodPatch, func(req *resty.Request) { | ||
req.SetBody(data) | ||
}, nil) | ||
return err | ||
} | ||
|
||
func (d *GoogleDrive) Copy(ctx context.Context, srcObj, dstDir model.Obj) error { | ||
return errors.New("not support") | ||
} | ||
|
||
func (d *GoogleDrive) Remove(ctx context.Context, obj model.Obj) error { | ||
url := "https://www.googleapis.com/drive/v3/files/" + obj.GetID() | ||
_, err := d.request(url, http.MethodDelete, nil, nil) | ||
return err | ||
} | ||
|
||
func (d *GoogleDrive) Put(ctx context.Context, dstDir model.Obj, stream model.FileStreamer, up driver.UpdateProgress) error { | ||
obj := stream.GetOld() | ||
var ( | ||
e Error | ||
url string | ||
data base.Json | ||
res *resty.Response | ||
err error | ||
) | ||
if obj != nil { | ||
url = fmt.Sprintf("https://www.googleapis.com/upload/drive/v3/files/%s?uploadType=resumable&supportsAllDrives=true", obj.GetID()) | ||
data = base.Json{} | ||
} else { | ||
data = base.Json{ | ||
"name": stream.GetName(), | ||
"parents": []string{dstDir.GetID()}, | ||
} | ||
url = "https://www.googleapis.com/upload/drive/v3/files?uploadType=resumable&supportsAllDrives=true" | ||
} | ||
req := base.NoRedirectClient.R(). | ||
SetHeaders(map[string]string{ | ||
"Authorization": "Bearer " + d.AccessToken, | ||
"X-Upload-Content-Type": stream.GetMimetype(), | ||
"X-Upload-Content-Length": strconv.FormatInt(stream.GetSize(), 10), | ||
}). | ||
SetError(&e).SetBody(data).SetContext(ctx) | ||
if obj != nil { | ||
res, err = req.Patch(url) | ||
} else { | ||
res, err = req.Post(url) | ||
} | ||
if err != nil { | ||
return err | ||
} | ||
if e.Error.Code != 0 { | ||
if e.Error.Code == 401 { | ||
err = d.refreshToken() | ||
if err != nil { | ||
return err | ||
} | ||
return d.Put(ctx, dstDir, stream, up) | ||
} | ||
return fmt.Errorf("%s: %v", e.Error.Message, e.Error.Errors) | ||
} | ||
putUrl := res.Header().Get("location") | ||
if stream.GetSize() < d.ChunkSize*1024*1024 { | ||
_, err = d.request(putUrl, http.MethodPut, func(req *resty.Request) { | ||
req.SetHeader("Content-Length", strconv.FormatInt(stream.GetSize(), 10)).SetBody(stream.GetReadCloser()) | ||
}, nil) | ||
} else { | ||
err = d.chunkUpload(ctx, stream, putUrl) | ||
} | ||
return err | ||
} | ||
|
||
var _ driver.Driver = (*GoogleDrive)(nil) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,31 @@ | ||
package google_drive | ||
|
||
import ( | ||
"github.com/IceWhaleTech/CasaOS/internal/driver" | ||
"github.com/IceWhaleTech/CasaOS/internal/op" | ||
) | ||
|
||
type Addition struct { | ||
driver.RootID | ||
RefreshToken string `json:"refresh_token" required:"true"` | ||
OrderBy string `json:"order_by" type:"string" help:"such as: folder,name,modifiedTime"` | ||
OrderDirection string `json:"order_direction" type:"select" options:"asc,desc"` | ||
ClientID string `json:"client_id" required:"true" default:"865173455964-4ce3gdl73ak5s15kn1vkn73htc8tant2.apps.googleusercontent.com"` | ||
ClientSecret string `json:"client_secret" required:"true" default:"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"` | ||
ChunkSize int64 `json:"chunk_size" type:"number" default:"5" help:"chunk size while uploading (unit: MB)"` | ||
AuthUrl string `json:"auth_url" type:"string" default:"https://accounts.google.com/o/oauth2/auth/oauthchooseaccount?response_type=code&client_id=865173455964-4ce3gdl73ak5s15kn1vkn73htc8tant2.apps.googleusercontent.com&redirect_uri=http%3A%2F%2Ftest-get.casaos.io&scope=https%3A%2F%2Fwww.googleapis.com%2Fauth%2Fdrive&access_type=offline&approval_prompt=force&state=${HOST}%2Fv1%2Frecover%2FGoogleDrive&service=lso&o2v=1&flowName=GeneralOAuthFlow"` | ||
Icon string `json:"icon" type:"string" default:"https://i.pcmag.com/imagery/reviews/02PHW91bUvLOs36qNbBzOiR-12.fit_scale.size_760x427.v1569471162.png"` | ||
Code string `json:"code" type:"string" help:"code from auth_url"` | ||
} | ||
|
||
var config = driver.Config{ | ||
Name: "GoogleDrive", | ||
OnlyProxy: true, | ||
DefaultRoot: "root", | ||
} | ||
|
||
func init() { | ||
op.RegisterDriver(func() driver.Driver { | ||
return &GoogleDrive{} | ||
}) | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,66 @@ | ||
package google_drive | ||
|
||
import ( | ||
"strconv" | ||
"time" | ||
|
||
"github.com/IceWhaleTech/CasaOS/model" | ||
log "github.com/sirupsen/logrus" | ||
) | ||
|
||
type TokenError struct { | ||
Error string `json:"error"` | ||
ErrorDescription string `json:"error_description"` | ||
} | ||
|
||
type Files struct { | ||
NextPageToken string `json:"nextPageToken"` | ||
Files []File `json:"files"` | ||
} | ||
|
||
type File struct { | ||
Id string `json:"id"` | ||
Name string `json:"name"` | ||
MimeType string `json:"mimeType"` | ||
ModifiedTime time.Time `json:"modifiedTime"` | ||
Size string `json:"size"` | ||
ThumbnailLink string `json:"thumbnailLink"` | ||
ShortcutDetails struct { | ||
TargetId string `json:"targetId"` | ||
TargetMimeType string `json:"targetMimeType"` | ||
} `json:"shortcutDetails"` | ||
} | ||
|
||
func fileToObj(f File) *model.ObjThumb { | ||
log.Debugf("google file: %+v", f) | ||
size, _ := strconv.ParseInt(f.Size, 10, 64) | ||
obj := &model.ObjThumb{ | ||
Object: model.Object{ | ||
ID: f.Id, | ||
Name: f.Name, | ||
Size: size, | ||
Modified: f.ModifiedTime, | ||
IsFolder: f.MimeType == "application/vnd.google-apps.folder", | ||
}, | ||
Thumbnail: model.Thumbnail{}, | ||
} | ||
if f.MimeType == "application/vnd.google-apps.shortcut" { | ||
obj.ID = f.ShortcutDetails.TargetId | ||
obj.IsFolder = f.ShortcutDetails.TargetMimeType == "application/vnd.google-apps.folder" | ||
} | ||
return obj | ||
} | ||
|
||
type Error struct { | ||
Error struct { | ||
Errors []struct { | ||
Domain string `json:"domain"` | ||
Reason string `json:"reason"` | ||
Message string `json:"message"` | ||
LocationType string `json:"location_type"` | ||
Location string `json:"location"` | ||
} | ||
Code int `json:"code"` | ||
Message string `json:"message"` | ||
} `json:"error"` | ||
} |
Oops, something went wrong.