Add Huawei Drive support
Add Huawei Drive backend implementation and tests Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com> Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Co-authored-by: Nick Craig-Wood <nick@craig-wood.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
Copilot
Nick Craig-Wood
parent
7c3909589c
commit
18899a58f3
@@ -32,6 +32,7 @@ import (
|
||||
_ "github.com/rclone/rclone/backend/hdfs"
|
||||
_ "github.com/rclone/rclone/backend/hidrive"
|
||||
_ "github.com/rclone/rclone/backend/http"
|
||||
_ "github.com/rclone/rclone/backend/huaweidrive"
|
||||
_ "github.com/rclone/rclone/backend/iclouddrive"
|
||||
_ "github.com/rclone/rclone/backend/imagekit"
|
||||
_ "github.com/rclone/rclone/backend/internetarchive"
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
api文档
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-public-info-0000001050159641
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-aboutget-0000001050151684
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filescopy-0000001050151696
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filescreate-0000001050151686
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filescreatecontent-0000001050151688
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filescreatemultipart-0000001050151694
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filescreateresume-0000001050151690
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesdelete-0000001050153647
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesemptyrecycle-0000001050151698
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesgetmetadata-0000001050153645
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesgetcontent-0000001050153651
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-fileslist-0000001050153649
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesresume-0000001050153643
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filessubscribe-0000001050153637
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdate-0000001050153639
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdatepatchcontent-0000001050151700
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdatepatchmultipart-0000001050153653
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdatepatchresume-0000001050153641
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdateputcontent-0000001050151702
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdateputmultipart-0000001050151704
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-filesupdateputresume-0000001050151692
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-thumbnailget-0000001050151706
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-changesgetstartcursor-0000001050153659
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-changeslist-0000001050151710
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-changessubscribe-0000001050151708
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-channelsstop-0000001050151712
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentscreate-0000001050151716
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsdelete-0000001050151718
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsget-0000001050153665
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentslist-0000001050151714
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsupdate-0000001050153667
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-repliescreate-0000001050151722
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-repliesdelete-0000001050151724
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-repliesget-0000001050153671
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-replieslist-0000001050151720
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-repliesupdate-0000001050153673
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-smallthumbnailget-0000001050151726
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsdelete-0000001050188702
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsget-0000001050430911
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-historyversionsgetcontent-0000001050747405
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentslist-0000001050188698
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-commentsupdate-0000001050190853
|
||||
https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-api-batchcallback-0000001050727110
|
||||
@@ -0,0 +1,255 @@
|
||||
// Package api provides types used by the Huawei Drive API.
|
||||
package api
|
||||
|
||||
import (
|
||||
"time"
|
||||
)
|
||||
|
||||
// About represents response to About.get endpoint
|
||||
type About struct {
|
||||
StorageQuota struct {
|
||||
UsedSpace string `json:"usedSpace"`
|
||||
UserCapacity string `json:"userCapacity"`
|
||||
} `json:"storageQuota"`
|
||||
MaxThumbnailSize int64 `json:"maxThumbnailSize"`
|
||||
NeedUpdate bool `json:"needUpdate"`
|
||||
MaxFileUploadSize string `json:"maxFileUploadSize"`
|
||||
Domain string `json:"domain"`
|
||||
Category string `json:"category"`
|
||||
User User `json:"user"`
|
||||
FolderLevel int `json:"folderLevel"`
|
||||
}
|
||||
|
||||
// User represents a user
|
||||
type User struct {
|
||||
PermissionID string `json:"permissionId"`
|
||||
DisplayName string `json:"displayName"`
|
||||
Me bool `json:"me"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
// FileList represents response to Files.list endpoint
|
||||
type FileList struct {
|
||||
Files []File `json:"files"`
|
||||
NextPageToken string `json:"nextPageToken,omitempty"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
// File represents a file or folder in Huawei Drive
|
||||
type File struct {
|
||||
ID string `json:"id"`
|
||||
FileName string `json:"fileName"`
|
||||
OriginalFilename string `json:"originalFilename,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MimeType string `json:"mimeType"`
|
||||
Category string `json:"category"`
|
||||
Size int64 `json:"size,omitempty"`
|
||||
SHA256 string `json:"sha256,omitempty"`
|
||||
CreatedTime time.Time `json:"createdTime"`
|
||||
EditedTime time.Time `json:"editedTime"`
|
||||
EditedByMeTime time.Time `json:"editedByMeTime,omitempty"`
|
||||
ParentFolder []string `json:"parentFolder,omitempty"`
|
||||
Owners []User `json:"owners"`
|
||||
LastEditor User `json:"lastEditor"`
|
||||
Permissions []Permission `json:"permissions"`
|
||||
PermissionIDs []string `json:"permissionIds"`
|
||||
Capabilities FileCapabilities `json:"capabilities"`
|
||||
OwnedByMe bool `json:"ownedByMe"`
|
||||
EditedByMe bool `json:"editedByMe"`
|
||||
ViewedByMe bool `json:"viewedByMe"`
|
||||
HasShared bool `json:"hasShared"`
|
||||
Recycled bool `json:"recycled"`
|
||||
DirectlyRecycled bool `json:"directlyRecycled"`
|
||||
Favorite bool `json:"favorite"`
|
||||
ExistThumbnail bool `json:"existThumbnail"`
|
||||
ThumbnailVersion int64 `json:"thumbnailVersion"`
|
||||
IconDownloadLink string `json:"iconDownloadLink,omitempty"`
|
||||
ContentDownloadLink string `json:"contentDownloadLink,omitempty"`
|
||||
ContentVersion string `json:"contentVersion,omitempty"`
|
||||
LastHistoryVersionID string `json:"lastHistoryVersionId,omitempty"`
|
||||
OccupiedSpace int64 `json:"occupiedSpace,omitempty"`
|
||||
Version int64 `json:"version"`
|
||||
WritersHasSharePermission bool `json:"writersHasSharePermission"`
|
||||
WriterHasCopyPermission bool `json:"writerHasCopyPermission"`
|
||||
Containers []string `json:"containers"`
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
AppSettings map[string]interface{} `json:"appSettings,omitempty"`
|
||||
ContentExtras *ContentExtras `json:"contentExtras,omitempty"`
|
||||
}
|
||||
|
||||
// IsDir returns true if the file is a directory
|
||||
func (f *File) IsDir() bool {
|
||||
return f.MimeType == FolderMimeType
|
||||
}
|
||||
|
||||
// Permission represents file permission
|
||||
type Permission struct {
|
||||
ID string `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Role string `json:"role"`
|
||||
DisplayName string `json:"displayName,omitempty"`
|
||||
Deleted bool `json:"deleted"`
|
||||
AllowFileDiscovery bool `json:"allowFileDiscovery,omitempty"`
|
||||
Category string `json:"category"`
|
||||
}
|
||||
|
||||
// FileCapabilities represents capabilities for a file
|
||||
type FileCapabilities struct {
|
||||
DownloadPermission bool `json:"downloadPermission"`
|
||||
RenameFilePermission bool `json:"renameFilePermission"`
|
||||
CommentPermission bool `json:"commentPermission"`
|
||||
DeletePermission bool `json:"deletePermission"`
|
||||
ReadHistoryVersionPermission bool `json:"readHistoryVersionPermission"`
|
||||
RecyclePermission bool `json:"recyclePermission"`
|
||||
AddChildNodePermission bool `json:"addChildNodePermission"`
|
||||
UnrecyclePermission bool `json:"unrecyclePermission"`
|
||||
WriterHasChangeCopyPermission bool `json:"writerHasChangeCopyPermission"`
|
||||
CopyPermission bool `json:"copyPermission"`
|
||||
EditContentPermission bool `json:"editContentPermission"`
|
||||
RemoveChildNodePermission bool `json:"removeChildNodePermission"`
|
||||
EditPermission bool `json:"editPermission"`
|
||||
ListChildNodePermission bool `json:"listChildNodePermission"`
|
||||
ShareFilePermission bool `json:"shareFilePermission"`
|
||||
}
|
||||
|
||||
// ContentExtras represents additional content information
|
||||
type ContentExtras struct {
|
||||
Thumbnail *Thumbnail `json:"thumbnail,omitempty"`
|
||||
}
|
||||
|
||||
// Thumbnail represents thumbnail information
|
||||
type Thumbnail struct {
|
||||
Content string `json:"content"` // base64 encoded
|
||||
MimeType string `json:"mimeType"`
|
||||
}
|
||||
|
||||
// CreateFolderRequest represents request to create a folder
|
||||
type CreateFolderRequest struct {
|
||||
FileName string `json:"fileName"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MimeType string `json:"mimeType"`
|
||||
ParentFolder []string `json:"parentFolder,omitempty"`
|
||||
Favorite bool `json:"favorite,omitempty"`
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
AppSettings map[string]interface{} `json:"appSettings,omitempty"`
|
||||
AutoRename int `json:"autoRename,omitempty"`
|
||||
}
|
||||
|
||||
// UpdateFileRequest represents request to update a file
|
||||
type UpdateFileRequest struct {
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
Description string `json:"description,omitempty"`
|
||||
MimeType string `json:"mimeType,omitempty"`
|
||||
Favorite *bool `json:"favorite,omitempty"`
|
||||
Recycled *bool `json:"recycled,omitempty"`
|
||||
OriginalFilename string `json:"originalFilename,omitempty"`
|
||||
WriterHasCopyPermission *bool `json:"writerHasCopyPermission,omitempty"`
|
||||
WritersHasSharePermission *bool `json:"writersHasSharePermission,omitempty"`
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
AppSettings map[string]interface{} `json:"appSettings,omitempty"`
|
||||
AddParentFolder []string `json:"addParentFolder,omitempty"`
|
||||
RemoveParentFolder []string `json:"removeParentFolder,omitempty"`
|
||||
CreatedTime *time.Time `json:"createdTime,omitempty"`
|
||||
EditedTime *time.Time `json:"editedTime,omitempty"`
|
||||
}
|
||||
|
||||
// CopyFileRequest represents request to copy a file
|
||||
type CopyFileRequest struct {
|
||||
FileName string `json:"fileName,omitempty"`
|
||||
MimeType string `json:"mimeType,omitempty"`
|
||||
ParentFolder []string `json:"parentFolder,omitempty"`
|
||||
Properties map[string]interface{} `json:"properties,omitempty"`
|
||||
AppSettings map[string]interface{} `json:"appSettings,omitempty"`
|
||||
}
|
||||
|
||||
// ResumeUploadInitResponse represents response to resume upload init
|
||||
type ResumeUploadInitResponse struct {
|
||||
SliceSize int64 `json:"sliceSize"`
|
||||
}
|
||||
|
||||
// ErrorResponse represents an error response from the API
|
||||
type ErrorResponse struct {
|
||||
Error struct {
|
||||
Code int `json:"code"`
|
||||
Message string `json:"message"`
|
||||
} `json:"error"`
|
||||
}
|
||||
|
||||
// Constants
|
||||
const (
|
||||
// MIME types
|
||||
FolderMimeType = "application/vnd.huawei-apps.folder"
|
||||
|
||||
// Special folder names
|
||||
ApplicationDataFolder = "applicationData"
|
||||
|
||||
// Upload types
|
||||
UploadTypeMultipart = "multipart"
|
||||
UploadTypeContent = "content"
|
||||
UploadTypeResume = "resume"
|
||||
|
||||
// Form types
|
||||
FormContent = "content"
|
||||
FormJSON = "json"
|
||||
|
||||
// Categories
|
||||
CategoryDriveFile = "drive#file"
|
||||
CategoryDriveFileList = "drive#fileList"
|
||||
CategoryDriveAbout = "drive#about"
|
||||
CategoryDriveUser = "drive#user"
|
||||
|
||||
// Global API domain (always available)
|
||||
GlobalDriveAPI = "https://driveapis.cloud.huawei.com.cn"
|
||||
GlobalUploadAPI = "https://driveapis.cloud.huawei.com.cn"
|
||||
)
|
||||
|
||||
// DomainToRootURL maps the domain field from About:get to the regional API root URL.
|
||||
// The API returns the full domain name (e.g., "driveapis.cloud.huawei.com.cn").
|
||||
// If the domain matches the global API, no switch is needed.
|
||||
// See: https://developer.huawei.com/consumer/cn/doc/HMSCore-References/server-public-info-0000001050159641
|
||||
var DomainToRootURL = map[string]string{
|
||||
"china": "https://drive-drcn.cloud.dbankcloud.cn",
|
||||
"europe": "https://drive-dre.cloud.dbankcloud.cn",
|
||||
"aala": "https://drive-dra.cloud.dbankcloud.cn",
|
||||
"russia": "https://drive-drru.cloud.dbankcloud.cn",
|
||||
"drive-drcn.cloud.dbankcloud.cn": "https://drive-drcn.cloud.dbankcloud.cn",
|
||||
"drive-dre.cloud.dbankcloud.cn": "https://drive-dre.cloud.dbankcloud.cn",
|
||||
"drive-dra.cloud.dbankcloud.cn": "https://drive-dra.cloud.dbankcloud.cn",
|
||||
"drive-drru.cloud.dbankcloud.cn": "https://drive-drru.cloud.dbankcloud.cn",
|
||||
}
|
||||
|
||||
// GlobalDomains lists domain values that indicate the global API endpoint (no switch needed)
|
||||
var GlobalDomains = map[string]bool{
|
||||
"driveapis.cloud.huawei.com.cn": true,
|
||||
"drive.cloud.hicloud.com": true,
|
||||
}
|
||||
|
||||
// BoolPtr returns a pointer to a bool value (helper for UpdateFileRequest)
|
||||
func BoolPtr(b bool) *bool {
|
||||
return &b
|
||||
}
|
||||
|
||||
// StartCursor represents response to Changes.getStartCursor endpoint
|
||||
type StartCursor struct {
|
||||
Category string `json:"category"` // "drive#startCursor"
|
||||
StartCursor string `json:"startCursor"`
|
||||
}
|
||||
|
||||
// ChangeList represents response to Changes.list endpoint
|
||||
type ChangeList struct {
|
||||
Category string `json:"category"` // "drive#changeList"
|
||||
NextCursor string `json:"nextCursor,omitempty"`
|
||||
NewStartCursor string `json:"newStartCursor,omitempty"`
|
||||
Changes []ChangeItem `json:"changes"`
|
||||
}
|
||||
|
||||
// ChangeItem represents a single change entry
|
||||
type ChangeItem struct {
|
||||
Category string `json:"category"` // "drive#change"
|
||||
Type string `json:"type"` // resource type, e.g. "File"
|
||||
ChangeType string `json:"changeType"` // change type, e.g. "File"
|
||||
Time string `json:"time"`
|
||||
Deleted bool `json:"deleted"`
|
||||
FileID string `json:"fileId"`
|
||||
File *File `json:"file,omitempty"`
|
||||
}
|
||||
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,458 @@
|
||||
---
|
||||
title: "Huawei Drive"
|
||||
description: "Rclone docs for Huawei Drive"
|
||||
versionIntroduced: "v1.74"
|
||||
---
|
||||
|
||||
# {{< icon "fas fa-cloud" >}} Huawei Drive
|
||||
|
||||
Paths are specified as `huaweidrive:path`
|
||||
|
||||
Huawei Drive paths may be as deep as required, e.g. `huaweidrive:directory/subdirectory`.
|
||||
|
||||
## Configuration
|
||||
|
||||
The initial setup for Huawei Drive involves getting a token from Huawei Drive
|
||||
which you need to do in your browser. `rclone config` walks you
|
||||
through it.
|
||||
|
||||
Here is an example of how to make a remote called `remote`. First run:
|
||||
|
||||
```sh
|
||||
rclone config
|
||||
```
|
||||
|
||||
This will guide you through an interactive setup process:
|
||||
|
||||
```text
|
||||
No remotes found, make a new one?
|
||||
n) New remote
|
||||
r) Rename remote
|
||||
c) Copy remote
|
||||
s) Set configuration password
|
||||
q) Quit config
|
||||
n/r/c/s/q> n
|
||||
name> remote
|
||||
Type of storage to configure.
|
||||
Choose a number from below, or type in your own value
|
||||
[snip]
|
||||
XX / Huawei Drive
|
||||
\ "huaweidrive"
|
||||
[snip]
|
||||
Storage> huaweidrive
|
||||
OAuth Client Id - leave blank to use rclone's default.
|
||||
client_id>
|
||||
OAuth Client Secret - leave blank to use rclone's default.
|
||||
client_secret>
|
||||
Remote config
|
||||
Use web browser to automatically authenticate rclone with remote?
|
||||
* Say Y if the machine running rclone has a web browser you can use
|
||||
* Say N if running rclone on a (remote) machine without web browser access
|
||||
If not sure try Y. If Y failed, try N.
|
||||
y) Yes
|
||||
n) No
|
||||
y/n> y
|
||||
If your browser doesn't open automatically go to the following link: http://127.0.0.1:53682/auth
|
||||
Log in and authorize rclone for access
|
||||
Waiting for code...
|
||||
Got code
|
||||
Configuration complete.
|
||||
Options:
|
||||
- type: huaweidrive
|
||||
- client_id:
|
||||
- client_secret:
|
||||
- token: {"access_token":"XXX","token_type":"Bearer","refresh_token":"XXX","expiry":"2024-03-16T13:57:58.955387075Z"}
|
||||
Keep this "remote" remote?
|
||||
y) Yes this is OK
|
||||
e) Edit this remote
|
||||
d) Delete this remote
|
||||
y/e/d> y
|
||||
```
|
||||
|
||||
See the [remote setup docs](/remote_setup/) for how to set it up on a
|
||||
machine without an internet-connected web browser available.
|
||||
|
||||
Note that rclone runs a webserver on your local machine to collect the
|
||||
token as returned from Huawei if using web browser to automatically
|
||||
authenticate. This only runs from the moment it opens your browser to the moment you get back
|
||||
the verification code. This is on `http://127.0.0.1:53682/` and it
|
||||
may require you to unblock it temporarily if you are running a host
|
||||
firewall, or use manual mode.
|
||||
|
||||
You can then use it like this,
|
||||
|
||||
List directories in top level of your drive
|
||||
|
||||
```sh
|
||||
rclone lsd remote:
|
||||
```
|
||||
|
||||
List all the files in your drive
|
||||
|
||||
```sh
|
||||
rclone ls remote:
|
||||
```
|
||||
|
||||
To copy a local directory to a drive directory called backup
|
||||
|
||||
```sh
|
||||
rclone copy /home/source remote:backup
|
||||
```
|
||||
|
||||
### Getting your own Client ID and Secret
|
||||
|
||||
When you use rclone with Huawei Drive in its default configuration you
|
||||
are using rclone's client_id. This is shared between all the rclone
|
||||
users. There is a global rate limit on the number of queries per
|
||||
second that each client_id can do set by Huawei.
|
||||
|
||||
It is strongly recommended to use your own client ID as the default rclone ID is heavily used. If you have multiple services running, it is recommended to use a separate client ID for each service to avoid rate limiting issues.
|
||||
|
||||
Here is how to create your own Huawei Drive client ID for rclone:
|
||||
|
||||
Follow the detailed guides for complete setup instructions:
|
||||
|
||||
- [Huawei HMS Core Web App Preparations](https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/web-preparations-0000001050050891)
|
||||
- [Huawei HMS Core Server Preparations](https://developer.huawei.com/consumer/cn/doc/HMSCore-Guides/server-preparations-0000001050185577#section194911701377)
|
||||
|
||||
Rclone uses the web application access method to connect to Huawei Drive. Before starting, you need to implement quick login authorization through Huawei Account Open Service. With user authorization credentials, rclone can call Huawei Cloud Drive Service APIs.
|
||||
|
||||
#### Create Server Application
|
||||
|
||||
Before accessing Drive service, developers need to create a server application first. For details, please refer to the WEB Application Access Development Preparation section in the "Huawei Account Service Development Guide".
|
||||
|
||||
#### Enable Drive Application Switch
|
||||
|
||||
1. Log in to the AppGallery Connect website and click "My Projects".
|
||||
2. Find your project in the project list, select the application that needs to access Drive in the project, and click "API Management".
|
||||
3. In the "API Management" area of the "Project Settings" page, click the switch on the right side of Drive Kit to ensure the switch is in the open state.
|
||||
|
||||
#### Sign Huawei Cloud Drive Privacy Notice and User Agreement
|
||||
|
||||
Guide users to visit <https://cloud.huawei.com/>. First-time users need to sign the agreement before they can use Huawei Cloud Drive Service.
|
||||
|
||||
#### Application Access to Obtain Authentication Credential Access Token
|
||||
|
||||
Applications accessing Drive should use authentication credential Access Token. For specific acquisition methods, please refer to the WEB Application Access Development Guide section in the "Huawei Account Service Development Guide".
|
||||
|
||||
Key steps summary:
|
||||
|
||||
1. Log into the [Huawei Developer Console](https://developer.huawei.com/consumer/en/console) with your Huawei account.
|
||||
|
||||
2. Create a new project or select an existing project.
|
||||
|
||||
3. Go to "Manage APIs" and enable the "Drive Kit" API.
|
||||
|
||||
4. Click on "Credentials" in the left side panel.
|
||||
|
||||
5. Click "Create Credentials" and choose "OAuth client ID".
|
||||
|
||||
6. Choose "Web application" as the application type.
|
||||
|
||||
7. Add `http://localhost:53682/` to the "Authorized redirect URIs".
|
||||
|
||||
8. Click "Create" and note down the Client ID and Client Secret.
|
||||
|
||||
9. Provide the noted client ID and client secret to rclone during configuration.
|
||||
|
||||
### Scopes
|
||||
|
||||
Rclone uses the following OAuth2 scopes when accessing Huawei Drive:
|
||||
|
||||
- `https://www.huawei.com/auth/drive` - Full access to Huawei Drive files (excluding application data folder)
|
||||
- `https://www.huawei.com/auth/drive.file` - Access to files created by the application
|
||||
- `openid` - OpenID Connect authentication
|
||||
- `profile` - Access to basic profile information
|
||||
|
||||
The `drive.file` scope is included in the default set used by rclone.
|
||||
|
||||
Alternative scopes available (not used by rclone by default):
|
||||
|
||||
- `https://www.huawei.com/auth/drive.appdata` - Access to application data folder
|
||||
- `https://www.huawei.com/auth/drive.readonly` - Read-only access to file metadata and content
|
||||
- `https://www.huawei.com/auth/drive.metadata` - Read/write access to file metadata only
|
||||
- `https://www.huawei.com/auth/drive.metadata.readonly` - Read-only access to file metadata only
|
||||
|
||||
The default scopes provide read/write access to all files in your Huawei Drive.
|
||||
|
||||
### Modification times and hashes
|
||||
|
||||
Huawei Drive does not support setting modification times. The API
|
||||
always uses server-side timestamps, so file modification times from
|
||||
the source are not preserved during upload. Modification times are
|
||||
available as read-only metadata (`mtime`, `btime`).
|
||||
|
||||
Hash algorithm SHA256 is supported for file integrity verification.
|
||||
|
||||
### Restricted filename characters
|
||||
|
||||
Huawei Drive has strict restrictions on file and directory names:
|
||||
|
||||
- Cannot contain: `< > | : " * ? / \` or emoji characters
|
||||
- Cannot be exactly `. ..`
|
||||
- Maximum length: 250 bytes
|
||||
- Single quotes must be escaped with `\'` in API calls
|
||||
|
||||
These restrictions are handled by rclone's encoding:
|
||||
|
||||
- Backslashes `\` are encoded
|
||||
- Invalid UTF-8 sequences are encoded
|
||||
- Right-side spaces are encoded
|
||||
|
||||
Invalid characters will be [replaced](/overview/#invalid-utf8) according to the encoding settings.
|
||||
|
||||
### Resumable uploads
|
||||
|
||||
Huawei Drive supports resumable uploads for files larger than the upload cutoff (default 20MB).
|
||||
Files are uploaded in chunks which allows for recovery from network interruptions.
|
||||
|
||||
### File size limits
|
||||
|
||||
The maximum file size for Huawei Drive is 50 GiB.
|
||||
|
||||
### Quota information
|
||||
|
||||
To view your current quota you can use the `rclone about remote:`
|
||||
command which will display your usage and quota information.
|
||||
|
||||
<!-- autogenerated options start - DO NOT EDIT - instead edit fs.RegInfo in backend/huaweidrive/huaweidrive.go and run make backenddocs to verify --> <!-- markdownlint-disable-line line-length -->
|
||||
|
||||
### Standard options
|
||||
|
||||
Here are the Standard options specific to huaweidrive (Huawei Drive).
|
||||
|
||||
#### --huaweidrive-client-id
|
||||
|
||||
OAuth Client Id.
|
||||
|
||||
Leave blank normally.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: client_id
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_CLIENT_ID
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --huaweidrive-client-secret
|
||||
|
||||
OAuth Client Secret.
|
||||
|
||||
Leave blank normally.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: client_secret
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_CLIENT_SECRET
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
### Advanced options
|
||||
|
||||
Here are the Advanced options specific to huaweidrive (Huawei Drive).
|
||||
|
||||
#### --huaweidrive-token
|
||||
|
||||
OAuth Access Token as a JSON blob.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: token
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_TOKEN
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --huaweidrive-auth-url
|
||||
|
||||
Auth server URL.
|
||||
|
||||
Leave blank to use the provider defaults.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: auth_url
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_AUTH_URL
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --huaweidrive-token-url
|
||||
|
||||
Token server url.
|
||||
|
||||
Leave blank to use the provider defaults.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: token_url
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_TOKEN_URL
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --huaweidrive-root-folder-id
|
||||
|
||||
ID of the root folder.
|
||||
|
||||
Normally this is auto-detected, but if it fails or you want to speed up startup,
|
||||
you can set it manually.
|
||||
|
||||
Leave blank normally. Rclone will print the detected root folder ID in debug output
|
||||
which you can then save to the config.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: root_folder_id
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_ROOT_FOLDER_ID
|
||||
- Type: string
|
||||
- Required: false
|
||||
|
||||
#### --huaweidrive-chunk-size
|
||||
|
||||
Upload chunk size.
|
||||
|
||||
Must be a power of 2 >= 256k and <= 64MB.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: chunk_size
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_CHUNK_SIZE
|
||||
- Type: SizeSuffix
|
||||
- Default: 8Mi
|
||||
|
||||
#### --huaweidrive-list-chunk
|
||||
|
||||
Size of listing chunk 1-1000.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: list_chunk
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_LIST_CHUNK
|
||||
- Type: int
|
||||
- Default: 1000
|
||||
|
||||
#### --huaweidrive-upload-cutoff
|
||||
|
||||
Cutoff for switching to multipart upload.
|
||||
|
||||
Any files larger than this will be uploaded using resumable upload.
|
||||
The minimum is 0 and the maximum is 20 MiB (Huawei Drive API limit for single request uploads).
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: upload_cutoff
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_UPLOAD_CUTOFF
|
||||
- Type: SizeSuffix
|
||||
- Default: 20Mi
|
||||
|
||||
#### --huaweidrive-encoding
|
||||
|
||||
The encoding for the backend.
|
||||
|
||||
See the [encoding section in the overview](/overview/#encoding) for more info.
|
||||
|
||||
Properties:
|
||||
|
||||
- Config: encoding
|
||||
- Env Var: RCLONE_HUAWEIDRIVE_ENCODING
|
||||
- Type: Encoding
|
||||
- Default: BackSlash,InvalidUtf8,RightSpace
|
||||
|
||||
<!-- autogenerated options stop -->
|
||||
|
||||
## Limitations
|
||||
|
||||
Huawei Drive has some rate limiting which may cause rclone to slow down transfers to avoid hitting the limits.
|
||||
|
||||
### File name restrictions
|
||||
|
||||
- File names cannot contain: `< > | : " * ? / \`
|
||||
- File names cannot be exactly `. ..`
|
||||
- Maximum file name length is 250 bytes
|
||||
- Some unicode characters including emojis are not supported
|
||||
|
||||
### API rate limits
|
||||
|
||||
Huawei Drive imposes API rate limits. Rclone automatically handles these by backing off when limits are hit.
|
||||
|
||||
### OAuth2 token expiry
|
||||
|
||||
- Access tokens expire after 1 hour
|
||||
- Refresh tokens expire after 180 days
|
||||
- Rclone will automatically refresh tokens as needed
|
||||
|
||||
### File size limits
|
||||
|
||||
- Maximum file size is 50 GiB
|
||||
- Files larger than this cannot be uploaded
|
||||
|
||||
### Upload behavior
|
||||
|
||||
- Files smaller than `upload_cutoff` (default 20MB) are uploaded in a single request using content or multipart method
|
||||
- Larger files are uploaded using resumable uploads with configurable chunk size
|
||||
- Maximum single chunk size for resumable uploads is 64MB
|
||||
- Resumable uploads support automatic retry on network errors
|
||||
- SHA256 hash verification is supported for uploaded files
|
||||
|
||||
### Server-side operations
|
||||
|
||||
- Server-side copy: Files can be copied within Huawei Drive without downloading and re-uploading
|
||||
- Server-side move: Files and directories can be moved/renamed on the server side
|
||||
- Directory move: Entire directories can be moved with a single API call
|
||||
|
||||
### Directory operations
|
||||
|
||||
- Huawei Drive supports creating empty directories
|
||||
- Recursive listing is supported via `--fast-list` for efficient directory traversal
|
||||
- Huawei Drive has a special "applicationData" folder for app-specific data (not accessible via rclone's default configuration)
|
||||
|
||||
## Error handling
|
||||
|
||||
Common errors and their meanings:
|
||||
|
||||
- `401 Unauthorized`: Invalid credentials or expired token
|
||||
- `403 Forbidden`: Usually indicates insufficient permissions or API quota exceeded
|
||||
- `404 Not Found`: File or directory does not exist
|
||||
- `409 Conflict`: Directory already exists
|
||||
- `429 Too Many Requests`: API rate limit exceeded, rclone will automatically retry
|
||||
|
||||
## Performance tuning
|
||||
|
||||
For better performance:
|
||||
|
||||
- Increase `--transfers` for concurrent operations (default is 4)
|
||||
- Adjust `chunk_size` based on your network speed and file sizes
|
||||
- Use `--fast-list` for operations on directories with many files to reduce API calls
|
||||
|
||||
## Making backups
|
||||
|
||||
Huawei Drive is suitable for backups with some considerations:
|
||||
|
||||
- Use `rclone sync` rather than `rclone copy` to maintain exact directory structure
|
||||
- Consider using `--backup-dir` to preserve deleted files
|
||||
- Verify transfers with `--checksum` flag for critical data
|
||||
- Be aware of the 50 GiB file size limit for individual files
|
||||
|
||||
## Supported features
|
||||
|
||||
Huawei Drive supports the following rclone features:
|
||||
|
||||
- `Copy` - Server-side copy of files
|
||||
- `Move` - Server-side move/rename of files
|
||||
- `DirMove` - Server-side move of directories
|
||||
- `ListR` - Recursive listing for `--fast-list`
|
||||
- `About` - Storage quota information
|
||||
- `Purge` - Delete directory and all contents
|
||||
- `CleanUp` - Empty the trash
|
||||
- `UserInfo` - Get user account information
|
||||
- `Metadata` - Read and write file metadata/properties
|
||||
- `ChangeNotify` - Poll for remote changes (used by `rclone mount` and `rclone rc vfs/poll-interval`)
|
||||
|
||||
## Integration with other services
|
||||
|
||||
Huawei Drive can be used as a backend for various rclone operations:
|
||||
|
||||
- Mount as a local filesystem using `rclone mount`
|
||||
- Serve over HTTP using `rclone serve http`
|
||||
- Serve over FTP using `rclone serve ftp`
|
||||
- Serve over WebDAV using `rclone serve webdav`
|
||||
|
||||
Note that some operations may be slower than local storage due to API limitations and network latency.
|
||||
@@ -660,6 +660,10 @@ backends:
|
||||
ignoretests:
|
||||
- cmd/bisync
|
||||
- cmd/gitannex
|
||||
- backend: "huaweidrive"
|
||||
remote: "TestHuaweiDrive:"
|
||||
fastlist: true
|
||||
listretries: 5
|
||||
- backend: "shade"
|
||||
remote: "TestShade:"
|
||||
fastlist: false
|
||||
|
||||
Reference in New Issue
Block a user