-
-
Notifications
You must be signed in to change notification settings - Fork 1.6k
feat(drivers): add halalcloud_open driver #1430
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Merged
Merged
Changes from all commits
Commits
Show all changes
15 commits
Select commit
Hold shift + click to select a range
e935266
新增清真云Open驱动,支持最新的轻量SDK
zzzhr1990 602898c
Merge branch 'main' into halal-cloud-new-sdk
zzzhr1990 19c9f57
Change Go version in go.mod
zzzhr1990 ba93d48
Apply suggestions from code review
zzzhr1990 9531044
feat(halalcloud_open): support disk usage
KirCute 1299108
Merge branch 'main' into halal-cloud-new-sdk
zzzhr1990 6d22e7a
Set useSingleUpload to true for upload safety
zzzhr1990 850a77c
Update meta.go
zzzhr1990 c3e95f8
remove debug logs
zzzhr1990 9e3dc83
Merge branch 'main' into halal-cloud-new-sdk
zzzhr1990 039e933
bump halalcloud SDK version
zzzhr1990 84a45dd
fix unnecessary params
zzzhr1990 8511cd4
Update drivers/halalcloud_open/driver_init.go
zzzhr1990 99c96eb
Fixed spelling errors; changed hardcoded retry parameters to constants.
zzzhr1990 bb4fdcb
remove pointer in get link function in utils.go
zzzhr1990 File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or 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
This file contains hidden or 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,111 @@ | ||
| package halalcloudopen | ||
|
|
||
| import ( | ||
| "sync" | ||
| "time" | ||
|
|
||
| sdkUser "github.com/halalcloud/golang-sdk-lite/halalcloud/services/user" | ||
| ) | ||
|
|
||
| var ( | ||
| slicePostErrorRetryInterval = time.Second * 120 | ||
| retryTimes = 5 | ||
| ) | ||
|
|
||
| type halalCommon struct { | ||
| // *AuthService // 登录信息 | ||
| UserInfo *sdkUser.User // 用户信息 | ||
| refreshTokenFunc func(token string) error | ||
| // serv *AuthService | ||
| configs sync.Map | ||
| } | ||
|
|
||
| func (m *halalCommon) GetAccessToken() (string, error) { | ||
| value, exists := m.configs.Load("access_token") | ||
| if !exists { | ||
| return "", nil // 如果不存在,返回空字符串 | ||
| } | ||
| return value.(string), nil // 返回配置项的值 | ||
| } | ||
|
|
||
| // GetRefreshToken implements ConfigStore. | ||
| func (m *halalCommon) GetRefreshToken() (string, error) { | ||
| value, exists := m.configs.Load("refresh_token") | ||
| if !exists { | ||
| return "", nil // 如果不存在,返回空字符串 | ||
| } | ||
| return value.(string), nil // 返回配置项的值 | ||
| } | ||
|
|
||
| // SetAccessToken implements ConfigStore. | ||
| func (m *halalCommon) SetAccessToken(token string) error { | ||
| m.configs.Store("access_token", token) | ||
| return nil | ||
| } | ||
|
|
||
| // SetRefreshToken implements ConfigStore. | ||
| func (m *halalCommon) SetRefreshToken(token string) error { | ||
| m.configs.Store("refresh_token", token) | ||
| if m.refreshTokenFunc != nil { | ||
| return m.refreshTokenFunc(token) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // SetToken implements ConfigStore. | ||
| func (m *halalCommon) SetToken(accessToken string, refreshToken string, expiresIn int64) error { | ||
| m.configs.Store("access_token", accessToken) | ||
| m.configs.Store("refresh_token", refreshToken) | ||
| m.configs.Store("expires_in", expiresIn) | ||
| if m.refreshTokenFunc != nil { | ||
| return m.refreshTokenFunc(refreshToken) | ||
| } | ||
| return nil | ||
| } | ||
|
|
||
| // ClearConfigs implements ConfigStore. | ||
| func (m *halalCommon) ClearConfigs() error { | ||
| m.configs = sync.Map{} // 清空map | ||
| return nil | ||
| } | ||
|
|
||
| // DeleteConfig implements ConfigStore. | ||
| func (m *halalCommon) DeleteConfig(key string) error { | ||
| _, exists := m.configs.Load(key) | ||
| if !exists { | ||
| return nil // 如果不存在,直接返回 | ||
| } | ||
| m.configs.Delete(key) // 删除指定的配置项 | ||
| return nil | ||
| } | ||
|
|
||
| // GetConfig implements ConfigStore. | ||
| func (m *halalCommon) GetConfig(key string) (string, error) { | ||
| value, exists := m.configs.Load(key) | ||
| if !exists { | ||
| return "", nil // 如果不存在,返回空字符串 | ||
| } | ||
| return value.(string), nil // 返回配置项的值 | ||
| } | ||
|
|
||
| // ListConfigs implements ConfigStore. | ||
| func (m *halalCommon) ListConfigs() (map[string]string, error) { | ||
| configs := make(map[string]string) | ||
| m.configs.Range(func(key, value interface{}) bool { | ||
| configs[key.(string)] = value.(string) // 将每个配置项添加到map中 | ||
| return true // 继续遍历 | ||
| }) | ||
| return configs, nil // 返回所有配置项 | ||
| } | ||
|
|
||
| // SetConfig implements ConfigStore. | ||
| func (m *halalCommon) SetConfig(key string, value string) error { | ||
| m.configs.Store(key, value) // 使用Store方法设置或更新配置项 | ||
| return nil // 成功设置配置项后返回nil | ||
| } | ||
|
|
||
| func NewHalalCommon() *halalCommon { | ||
| return &halalCommon{ | ||
| configs: sync.Map{}, | ||
| } | ||
| } | ||
This file contains hidden or 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,29 @@ | ||
| package halalcloudopen | ||
|
|
||
| import ( | ||
| "github.com/OpenListTeam/OpenList/v4/internal/driver" | ||
| "github.com/OpenListTeam/OpenList/v4/internal/model" | ||
| sdkClient "github.com/halalcloud/golang-sdk-lite/halalcloud/apiclient" | ||
| sdkUser "github.com/halalcloud/golang-sdk-lite/halalcloud/services/user" | ||
| sdkUserFile "github.com/halalcloud/golang-sdk-lite/halalcloud/services/userfile" | ||
| ) | ||
|
|
||
| type HalalCloudOpen struct { | ||
| *halalCommon | ||
| model.Storage | ||
| Addition | ||
| sdkClient *sdkClient.Client | ||
| sdkUserFileService *sdkUserFile.UserFileService | ||
| sdkUserService *sdkUser.UserService | ||
| uploadThread int | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) Config() driver.Config { | ||
| return config | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) GetAddition() driver.Additional { | ||
| return &d.Addition | ||
| } | ||
|
|
||
| var _ driver.Driver = (*HalalCloudOpen)(nil) |
This file contains hidden or 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,131 @@ | ||
| package halalcloudopen | ||
|
|
||
| import ( | ||
| "context" | ||
| "strconv" | ||
|
|
||
| "github.com/OpenListTeam/OpenList/v4/internal/model" | ||
| sdkModel "github.com/halalcloud/golang-sdk-lite/halalcloud/model" | ||
| sdkUserFile "github.com/halalcloud/golang-sdk-lite/halalcloud/services/userfile" | ||
| ) | ||
|
|
||
| func (d *HalalCloudOpen) getFiles(ctx context.Context, dir model.Obj) ([]model.Obj, error) { | ||
|
|
||
| files := make([]model.Obj, 0) | ||
| limit := int64(100) | ||
| token := "" | ||
|
|
||
| for { | ||
| result, err := d.sdkUserFileService.List(ctx, &sdkUserFile.FileListRequest{ | ||
| Parent: &sdkUserFile.File{Path: dir.GetPath()}, | ||
| ListInfo: &sdkModel.ScanListRequest{ | ||
| Limit: strconv.FormatInt(limit, 10), | ||
| Token: token, | ||
| }, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
|
|
||
| for i := 0; len(result.Files) > i; i++ { | ||
| files = append(files, NewObjFile(result.Files[i])) | ||
| } | ||
|
|
||
| if result.ListInfo == nil || result.ListInfo.Token == "" { | ||
| break | ||
| } | ||
| token = result.ListInfo.Token | ||
|
|
||
| } | ||
| return files, nil | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) makeDir(ctx context.Context, dir model.Obj, name string) (model.Obj, error) { | ||
| _, err := d.sdkUserFileService.Create(ctx, &sdkUserFile.File{ | ||
| Path: dir.GetPath(), | ||
| Name: name, | ||
| }) | ||
| return nil, err | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) move(ctx context.Context, obj model.Obj, dir model.Obj) (model.Obj, error) { | ||
| oldDir := obj.GetPath() | ||
| newDir := dir.GetPath() | ||
| _, err := d.sdkUserFileService.Move(ctx, &sdkUserFile.BatchOperationRequest{ | ||
| Source: []*sdkUserFile.File{ | ||
| { | ||
| Path: oldDir, | ||
| }, | ||
| }, | ||
| Dest: &sdkUserFile.File{ | ||
| Path: newDir, | ||
| }, | ||
| }) | ||
| return nil, err | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) rename(ctx context.Context, obj model.Obj, name string) (model.Obj, error) { | ||
|
|
||
| _, err := d.sdkUserFileService.Rename(ctx, &sdkUserFile.File{ | ||
| Path: obj.GetPath(), | ||
| Name: name, | ||
| }) | ||
| return nil, err | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) copy(ctx context.Context, obj model.Obj, dir model.Obj) (model.Obj, error) { | ||
| id := obj.GetID() | ||
| sourcePath := obj.GetPath() | ||
| if len(id) > 0 { | ||
| sourcePath = "" | ||
| } | ||
|
|
||
| destID := dir.GetID() | ||
| destPath := dir.GetPath() | ||
| if len(destID) > 0 { | ||
| destPath = "" | ||
| } | ||
| dest := &sdkUserFile.File{ | ||
| Path: destPath, | ||
| Identity: destID, | ||
| } | ||
| _, err := d.sdkUserFileService.Copy(ctx, &sdkUserFile.BatchOperationRequest{ | ||
| Source: []*sdkUserFile.File{ | ||
| { | ||
| Path: sourcePath, | ||
| Identity: id, | ||
| }, | ||
| }, | ||
| Dest: dest, | ||
| }) | ||
| return nil, err | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) remove(ctx context.Context, obj model.Obj) error { | ||
| id := obj.GetID() | ||
| _, err := d.sdkUserFileService.Delete(ctx, &sdkUserFile.BatchOperationRequest{ | ||
| Source: []*sdkUserFile.File{ | ||
| { | ||
| Identity: id, | ||
| Path: obj.GetPath(), | ||
| }, | ||
| }, | ||
| }) | ||
| return err | ||
| } | ||
|
|
||
| func (d *HalalCloudOpen) details(ctx context.Context) (*model.StorageDetails, error) { | ||
| ret, err := d.sdkUserService.GetStatisticsAndQuota(ctx) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| total := uint64(ret.DiskStatisticsQuota.BytesQuota) | ||
|
|
||
| free := uint64(ret.DiskStatisticsQuota.BytesFree) | ||
| return &model.StorageDetails{ | ||
| DiskUsage: model.DiskUsage{ | ||
| TotalSpace: total, | ||
| FreeSpace: free, | ||
| }, | ||
| }, nil | ||
| } |
This file contains hidden or 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,108 @@ | ||
| package halalcloudopen | ||
|
|
||
| import ( | ||
| "context" | ||
| "crypto/sha1" | ||
| "io" | ||
| "strconv" | ||
| "time" | ||
|
|
||
| "github.com/OpenListTeam/OpenList/v4/internal/model" | ||
| "github.com/OpenListTeam/OpenList/v4/internal/stream" | ||
| "github.com/OpenListTeam/OpenList/v4/pkg/http_range" | ||
| sdkUserFile "github.com/halalcloud/golang-sdk-lite/halalcloud/services/userfile" | ||
| "github.com/rclone/rclone/lib/readers" | ||
| ) | ||
|
|
||
| func (d *HalalCloudOpen) getLink(ctx context.Context, file model.Obj, args model.LinkArgs) (*model.Link, error) { | ||
| if args.Redirect { | ||
| // return nil, model.ErrUnsupported | ||
| fid := file.GetID() | ||
| fpath := file.GetPath() | ||
| if fid != "" { | ||
| fpath = "" | ||
| } | ||
| fi, err := d.sdkUserFileService.GetDirectDownloadAddress(ctx, &sdkUserFile.DirectDownloadRequest{ | ||
zzzhr1990 marked this conversation as resolved.
Show resolved
Hide resolved
|
||
| Identity: fid, | ||
| Path: fpath, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| expireAt := fi.ExpireAt | ||
| duration := time.Until(time.UnixMilli(expireAt)) | ||
| return &model.Link{ | ||
| URL: fi.DownloadAddress, | ||
| Expiration: &duration, | ||
| }, nil | ||
| } | ||
| result, err := d.sdkUserFileService.ParseFileSlice(ctx, &sdkUserFile.File{ | ||
| Identity: file.GetID(), | ||
| Path: file.GetPath(), | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| fileAddrs := []*sdkUserFile.SliceDownloadInfo{} | ||
| var addressDuration int64 | ||
|
|
||
| nodesNumber := len(result.RawNodes) | ||
| nodesIndex := nodesNumber - 1 | ||
| startIndex, endIndex := 0, nodesIndex | ||
| for nodesIndex >= 0 { | ||
| if nodesIndex >= 200 { | ||
| endIndex = 200 | ||
| } else { | ||
| endIndex = nodesNumber | ||
| } | ||
| for ; endIndex <= nodesNumber; endIndex += 200 { | ||
| if endIndex == 0 { | ||
| endIndex = 1 | ||
| } | ||
| sliceAddress, err := d.sdkUserFileService.GetSliceDownloadAddress(ctx, &sdkUserFile.SliceDownloadAddressRequest{ | ||
| Identity: result.RawNodes[startIndex:endIndex], | ||
| Version: 1, | ||
| }) | ||
| if err != nil { | ||
| return nil, err | ||
| } | ||
| addressDuration, _ = strconv.ParseInt(sliceAddress.ExpireAt, 10, 64) | ||
| fileAddrs = append(fileAddrs, sliceAddress.Addresses...) | ||
| startIndex = endIndex | ||
| nodesIndex -= 200 | ||
| } | ||
|
|
||
| } | ||
|
|
||
| size, _ := strconv.ParseInt(result.FileSize, 10, 64) | ||
| chunks := getChunkSizes(result.Sizes) | ||
| resultRangeReader := func(ctx context.Context, httpRange http_range.Range) (io.ReadCloser, error) { | ||
| length := httpRange.Length | ||
| if httpRange.Length < 0 || httpRange.Start+httpRange.Length >= size { | ||
| length = size - httpRange.Start | ||
| } | ||
| oo := &openObject{ | ||
| ctx: ctx, | ||
| d: fileAddrs, | ||
| chunk: []byte{}, | ||
| chunks: chunks, | ||
| skip: httpRange.Start, | ||
| sha: result.Sha1, | ||
| shaTemp: sha1.New(), | ||
| } | ||
|
|
||
| return readers.NewLimitedReadCloser(oo, length), nil | ||
| } | ||
|
|
||
| var duration time.Duration | ||
| if addressDuration != 0 { | ||
| duration = time.Until(time.UnixMilli(addressDuration)) | ||
| } else { | ||
| duration = time.Until(time.Now().Add(time.Hour)) | ||
| } | ||
|
|
||
| return &model.Link{ | ||
| RangeReader: stream.RateLimitRangeReaderFunc(resultRangeReader), | ||
| Expiration: &duration, | ||
| }, nil | ||
| } | ||
Oops, something went wrong.
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.