diff --git a/README.md b/README.md index 9f4b3d8..475cdbb 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,7 @@ **其他语言: [English](README_en.md) | [中文](README.md)** -# JCS-pub(云际存储公共基础设施+开箱即用云际存储客户端) +# JCS-pub(云际存储公共基础设施)+ JCS-client(开箱即用云际存储客户端) + ## 项目简介 云际存储是基于云际对等协作机制,纳管多个云的存储资源,为用户提供统一数据存储服务的一种存储服务模式。其核心理念是强调各个云的对等独立地位,通过非侵入方式联接多个云的存储资源;强调云际协作,综合运用各个云的存算网资源,提供高质量存储服务。 @@ -66,13 +67,13 @@ - 请发邮件至`song-jc@foxmail.com`领取账号密码和证书,申请流程如下图。

## 架构图

### 1、云存储空间
- 使用云际存储客户端前,用户需自行准备云存储空间。云存储空间主要指对象存储服务的桶和文件存储服务的目录。可使用用户在公有云开通的云存储服务,也可以使用用户私有的云存储服务。
diff --git a/README_en.md b/README_en.md
index ffe72d7..5898258 100644
--- a/README_en.md
+++ b/README_en.md
@@ -1,17 +1,17 @@
**Read in: [English](README_en.md) | [中文](README.md)**
-# JCS-pub (JointCloud Storage Public Infrastructure + Ready-to-Use Storage Client)
+# JCS-pub (JointCloud Storage Public Infrastructure) + JCS-client (Ready-to-Use JointCloud Storage Client)
## Project Overview
-JointCloud Storage is a storage service model built on a peer-to-peer jointcloud collaboration mechanism. It manages storage resources across multiple clouds and provides users with a unified data storage service. The core idea emphasizes the independent and equal status of each cloud, connecting them in a non-intrusive manner. It also promotes intercloud collaboration by integrating computing, storage, and networking resources across clouds to deliver high-quality storage services.
+JointCloud Storage is a storage service model built on a peer-to-peer JointCloud collaboration mechanism. It manages storage resources across multiple clouds and provides users with a unified data storage service. The core idea emphasizes the independent and equal status of each cloud, connecting them in a non-intrusive manner. It also promotes intercloud collaboration by integrating computing, storage, and networking resources across clouds to deliver high-quality storage services.
-This project aims to turn JointCloud Storage into a public infrastructure that is easy to use for individuals and enterprises alike. By simply using a ready-to-use storage client, users can quickly access efficient jointcloud storage without the need to deploy additional components. At the same time, the system allows flexible customization of its features to meet diverse needs.
+This project aims to turn JointCloud Storage into a public infrastructure that is easy to use for individuals and enterprises alike. By simply using a JCS-client, users can quickly access efficient jointcloud storage without the need to deploy additional components. At the same time, the system allows flexible customization of its features to meet diverse needs.
## Evolution Roadmap

## Features
@@ -23,7 +23,7 @@ This project aims to turn JointCloud Storage into a public infrastructure that i
- Filtering Rules: Migrate files based on size, file extension, or directory path.
- Scheduling Control: Define migration time windows.
- Post-Migration Actions: Allow users to choose whether to retain or delete the original data after migration.
-- **Migration Efficiency Optimization**: Improve migration performance and reduce bandwidth costs by leveraging the **JointCloud Storage Public Infrastructure**.
+- **Migration Efficiency Optimization**: Improve migration performance and reduce bandwidth costs by leveraging the JCS-pub.
### 2. Cross-Cloud Data Storage
@@ -37,7 +37,7 @@ This project aims to turn JointCloud Storage into a public infrastructure that i
- REST API
- Command-line interface
- FUSE file system
-- **Access Efficiency Optimization**: Boost cross-cloud data access speed and reduce traffic costs via the **JointCloud Storage Public Infrastructure**.
+- **Access Efficiency Optimization**: Boost cross-cloud data access speed and reduce traffic costs via the JCS-pub.
### 3. Hybrid Local + Multi-Cloud Storage
@@ -46,7 +46,7 @@ This project aims to turn JointCloud Storage into a public infrastructure that i
- Data Filtering: Dynamically select files for remote sync based on size, path, or extension.
- Local Retention: Configure whether to keep local copies of remote data.
- Bidirectional Sync: Independently configure local-to-cloud and cloud-to-local synchronization.
-- **Collaboration Efficiency Optimization**: Enhance sync performance and reduce traffic costs using the **JointCloud Storage Public Infrastructure**.
+- **Collaboration Efficiency Optimization**: Enhance sync performance and reduce traffic costs using the JCS-pub.
- **Multiple Data Access Methods**
- REST API
- Command-line interface
@@ -56,7 +56,7 @@ This project aims to turn JointCloud Storage into a public infrastructure that i
- Simply download and install the client — no additional components or configuration needed.
-### 5. JointCloud Storage Public Infrastructure
+### 5. JCS-pub
- **Unified Hybrid Storage View**: Supports unified access across **local file systems** and **multiple remote cloud platforms**, abstracting the complexity behind a consistent interface.
- **Dual Operation Modes**:
@@ -74,16 +74,16 @@ This project aims to turn JointCloud Storage into a public infrastructure that i
## Architecture Diagram

### 1. Cloud Storage Space
- Before using the JointCloud Storage client, users must prepare their own cloud storage space. This typically refers to object storage buckets or directories in file storage services. Both public cloud storage services and private cloud deployments are supported.
- For tutorials on registering mainstream public cloud storage services, see: [Guide](docs/公有云注册及使用教程.md)
-### 2. JointCloud Storage Public Infrastructure
+### 2. JCS-pub
- The public infrastructure consists of multiple proxy nodes. These nodes collaborate with clients to perform cross-cloud operations such as data migration, upload, and download. They also optimize data transfer routes and support concurrent access, improving performance and reducing bandwidth costs. This design prevents the client from becoming a performance bottleneck.
-### 3. JointCloud Storage Client
+### 3. JCS-client
- The JointCloud Storage Client is deployed on the user's server and serves as both a data service gateway and metadata management node.
- Users manage their cloud storage data through various interfaces provided by the client.
- All metadata and cloud storage credentials remain on the client managed by the user. When a proxy node needs to access a user’s cloud storage, the client temporarily grants access permissions as needed.
@@ -233,7 +233,7 @@ By default, `jcsctl` attempts to connect to the client at `https://127.0.0.1:789
### 3. API
-See the API documentation: [Access here](docs/JCS_pub_API.md)
+See the API documentation: [Access here](docs/JCS_pub_API_en.md)
## Testing & Evaluation
diff --git a/docs/JCS_pub_API.md b/docs/JCS_pub_API.md
index 543a88f..4c0511a 100644
--- a/docs/JCS_pub_API.md
+++ b/docs/JCS_pub_API.md
@@ -1,6 +1,6 @@
# JCS-pub API
-**跳转回README.md [中文](../README.md) [English](../README_en.md)**
+**跳转回[README.md](../README.md)**
## 1 桶相关
diff --git a/docs/JCS_pub_API_en.md b/docs/JCS_pub_API_en.md
new file mode 100644
index 0000000..87dbe86
--- /dev/null
+++ b/docs/JCS_pub_API_en.md
@@ -0,0 +1,1543 @@
+# JCS-pub API
+
+**Back to [README.md](../README_en.md)**
+
+## 1 Bucket Operations
+
+### 1.1 Create Bucket
+
+| Request | +||
|---|---|---|
| POST | +application/json | +/v1/bucket/create | +
| Query | +None | +|
| Body | +
+ {
+ "userID": 1,
+ "name": "bkt1" // Bucket name
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "bucket": {
+ "bucketID": 1, // Bucket ID
+ "name": "bkt1" // Bucket name
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/bucket/getByName | +
| Query | +
+ - name:string // Bucket name + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "bucket": {
+ "bucketID": 1, // Bucket ID
+ "name": "bkt1" // Bucket name
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/bucket/listAll | +
| Query | +None | +|
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "buckets": [{
+ "bucketID": 1, // Bucket ID
+ "name": "bkt1" // Bucket name
+ }]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/bucket/delete | +
| Query | +None | +|
| Body | +
+ {
+ "bucketID":1
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/package/create | +
| Query | +None | +|
| Body | +
+ {
+ "bucketID":1,
+ "name": "" // Package name
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "package": {
+ "packageID": 32,
+ "name": "t1",
+ "bucketID": 1,
+ "createTime": "2025-06-24T16:31:28.5148754+08:00"
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/package/getByFullName | +
| Query | +
+ - bucketName:string // Bucket name +- packageName:string // Package name + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "package": {
+ "packageID": 32,
+ "name": "t1",
+ "bucketID": 1,
+ "createTime": "2025-06-24T16:31:28.5148754+08:00"
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/package/listBucketPackages | +
| Query | +
+ - bucketID:int64 // Bucket ID + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "packages":[{
+ "packageID": 32,
+ "name": "t1",
+ "bucketID": 1,
+ "createTime": "2025-06-24T16:31:28.5148754+08:00"
+ }]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/package/delete | +
| Query | +None | +|
| Body | +
+ {
+ "packageID":1
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +multipart/form-data; boundary=xxxxxxx | +/v1/object/upload | +
| Query | +None | +|
| Body | +
+ Afterwards, the request body is split into multiple parts using the boundary. The first part must have the name info and follow this JSON format: +{
+ "packageID": 1, // Package ID, obtained from the response of the Create Package API
+ "affinity": 1 // Preferred storage space for uploading the file (optional)
+}
+ Each subsequent part is a file. The name should be files, and the filename should be the file path (must be URL-encoded). +Example: +POST /object/upload HTTP/1.1
+User-Agent: PostmanRuntime/7.29.0
+Accept: */*
+Postman-Token: c12fa8b5-d902-46f3-b104-028effa0d531
+Host: localhost:7890
+Accept-Encoding: gzip, deflate, br
+Connection: keep-alive
+Content-Type: multipart/form-data; boundary=-----------------------------818270992847011232305151
+Content-Length: 1649
+
+-----------------------------818270992847011232305151
+Content-Disposition: form-data; name="info"
+
+{
+ "userID": 1,
+ "packageID": 1
+}
+-----------------------------818270992847011232305151
+Content-Disposition: form-data; name="files"; filename="test.txt"
+Content-Type: text/plain
+
+testdata
+-----------------------------818270992847011232305151
+Content-Disposition: form-data; name="files"; filename="a%2Fb%2Ftest2.txt"
+
+testdata2
+-----------------------------818270992847011232305151--
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "uploadeds": [
+ {
+ "objectID": 7,
+ "packageID": 1,
+ "path": "test.txt",
+ "size": "123456",
+ "fileHash": "xxxxxxxxxx",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-05T11:06:28+08:00",
+ "updateTime": "2025-01-10T09:15:39.4452196+08:00"
+ },
+ {
+ "objectID": 8,
+ "packageID": 1,
+ "path": "a/b/test2.txt",
+ "size": "123456",
+ "fileHash": "xxxxxxxxxx",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-05T11:06:28+08:00",
+ "updateTime": "2025-01-10T09:15:39.4452196+08:00"
+ }
+ ]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/object/download | +
| Query | +
+ - objectID:int64 +- offset:int64 +- length:int64 // Length to read. If not provided, the entire object will be read. + |
+ |
| Body | +None | +|
| Response Example | +||
|
+ If the request is successful, the {
+ "code": "OperationFailed",
+ "message": "xxxxxxxx",
+ "data": null
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/object/downloadByPath | +
| Query | +
+ - path:string +- offset:int64 +- length:int64 // Length to read. If not provided, the entire object will be read. + |
+ |
| Body | +None | +|
| Response Example | +||
|
+ If the request is successful, the {
+ "code": "OperationFailed",
+ "message": "xxxxxxxx",
+ "data": null
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/object/listByPath | +
| Query | +
+ - packageID:int64 +- path:string +- isPrefix:bool // If true, perform a prefix search using the path parameter +- noRecursive:bool // If true, when performing a prefix search, the results will separate objects and "directories" like a directory listing +- maxKeys:int // Maximum number of results returned in this query (the total number of items in commonPrefixes + objects) +- continuationToken:string // Start this query from the position specified by the token; leave empty to start from the beginning. This value should be the same as the corresponding field from the previous response. + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "nextContinuationToken": "123456", // Used for the next paginated query
+ "isTruncated": false, // If true, it indicates more results are available for the next query
+ "commonPrefixes": [
+ "a/b/",
+ "a/c/"
+ ],
+ "objects": [
+ {
+ "objectID": 617,
+ "packageID": 12,
+ "path": "a/1.txt",
+ "size": "1293",
+ "fileHash": "Full4E69A8B8CD9F42EDE371DA94458BADFB2308AFCA736AA393784A3D81F4746377",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-19T16:02:25+08:00",
+ "updateTime": "2024-11-19T16:02:25+08:00"
+ },
+ {
+ "objectID": 618,
+ "packageID": 12,
+ "path": "a/2.txt",
+ "size": "1293",
+ "fileHash": "Full4E69A8B8CD9F42EDE371DA94458BADFB2308AFCA736AA393784A3D81F4746377",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-19T16:02:25+08:00",
+ "updateTime": "2024-11-19T16:02:25+08:00"
+ }
+ ]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/object/getPackageObjects | +
| Query | +
+ - packageID:int64 + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "objects": [
+ {
+ "objectID": 617,
+ "packageID": 12,
+ "path": "a/1.txt",
+ "size": "1293",
+ "fileHash": "Full4E69A8B8CD9F42EDE371DA94458BADFB2308AFCA736AA393784A3D81F4746377",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-19T16:02:25+08:00",
+ "updateTime": "2024-11-19T16:02:25+08:00"
+ },
+ {
+ "objectID": 618,
+ "packageID": 12,
+ "path": "a/2.txt",
+ "size": "1293",
+ "fileHash": "Full4E69A8B8CD9F42EDE371DA94458BADFB2308AFCA736AA393784A3D81F4746377",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-19T16:02:25+08:00",
+ "updateTime": "2024-11-19T16:02:25+08:00"
+ }
+ ]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/object/move | +
| Query | +None | +|
| Body | +
+ {
+ "movings":[
+ {
+ "objectID":4, // Original object ID
+ "packageID":3, // Target package ID after moving
+ "path":"trace2.txt" // Target path after moving
+ }
+ ]
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "successes": [ // IDs of successfully moved objects
+ 4
+ ]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/object/delete | +
| Query | +None | +|
| Body | +
+ {
+ "objectIDs":[
+ 4
+ ]
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ The response code will be OK even if the file does not exist. + |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/object/clone | +
| Query | +None | +|
| Body | +
+ {
+ "clonings": [
+ {
+ "objectID": 4, // Original object ID
+ "newPath": "trace3.txt", // The new object's path
+ "newPackageID": 3 // The new object's package ID
+ }
+ ]
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "objects":[{
+ "objectID": 5,
+ "packageID": 3,
+ "path": "trace3.txt",
+ "size": "1293",
+ "fileHash": "Full4E69A8B8CD9F42EDE371DA94458BADFB2308AFCA736AA393784A3D81F4746377",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2024-11-19T16:02:25+08:00",
+ "updateTime": "2024-11-19T16:02:25+08:00"
+ }]
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/object/newMultipartUpload | +
| Query | +None | +|
| Body | +
+ {
+ "packageID": 3,
+ "path": "multi" // The object's path
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "object": {
+ "objectID": 1039,
+ "packageID": 3,
+ "path": "obj.txt",
+ "size": "0",
+ "fileHash": "Full0000000000000000000000000000000000000000000000000000000000000000",
+ "redundancy": {
+ "type": "multipartUpload"
+ },
+ "createTime": "2025-03-04T16:03:18+08:00",
+ "updateTime": "2025-03-11T15:20:44.5182982+08:00"
+ }
+ }
+}
+ The created object can be found using the query interface. + |
+ ||
| Request | +||
|---|---|---|
| POST | +multipart/form-data; boundary=xxxxxxx | +/v1/object/uploadPart | +
| Query | +None | +|
| Body | +
+ Similar to the object upload interface, the request must contain two parts: {
+ "objectID": 1, // The Object ID obtained from the Create Multipart Upload API
+ "index": 1 // The part number used for merging later. Parts with the same index will overwrite the old data.
+}
+ The |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": ""
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/object/completeMultipartUpload | +
| Query | +None | +|
| Body | +
+ {
+ "objectID": 1039, // The Object ID to be merged
+ "indexes": [2,3,1] // The list of part numbers. Duplicate part numbers are allowed; parts will be merged in the specified order. Unused parts will be discarded.
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "object": {
+ "objectID": 1039,
+ "packageID": 3,
+ "path": "obj.txt",
+ "size": "30",
+ "fileHash": "FullB7660EB37969EDC68202258A1838B89493B4C77EA006B1640768D20CEF7A7CD2",
+ "redundancy": {
+ "type": "none"
+ },
+ "createTime": "2025-03-04T16:03:18+08:00",
+ "updateTime": "2025-03-11T15:42:03+08:00"
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/create | +
| Query | +None | +|
| Body | +
+ {
+ "name": "test1",
+ "storage": { // Storage system type
+ "type": "OBS",
+ "region": "",
+ "endpoint": "",
+ "bucket": "",
+ "projectID": ""
+ },
+ "credential": { // Permission information required to access the storage system
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ },
+ "shardStore": { // Configuration for shard storage; if null, shard storage is disabled
+ "maxSize":1024
+ },
+ "features": [], // Configuration of feature functions for the storage system
+ "workingDir": "" // Root directory for storing data of various components, including shard storage
+}
+ - The content of |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "userSpace": {
+ "userSpaceID": 1,
+ "name": "test1",
+ "storage": {
+ "type": "OBS",
+ "region": "",
+ "endpoint": "",
+ "bucket": "",
+ "projectID": ""
+ },
+ "credential": {
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ },
+ "shardStore": {
+ "maxSize": 1024
+ },
+ "features": [],
+ "workingDir": "",
+ "revision": 1
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/update | +
| Query | +None | +|
| Body | +
+ {
+ "userSpaceID": 1,
+ "name": "test1", // New name
+ "credential": { // New credential information
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ }
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "userSpace": {
+ "userSpaceID": 1,
+ "name": "test1",
+ "storage": {
+ "type": "OBS",
+ "region": "",
+ "endpoint": "",
+ "bucket": "",
+ "projectID": ""
+ },
+ "credential": {
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ },
+ "shardStore": {
+ "maxSize": 1024
+ },
+ "features": [],
+ "workingDir": "",
+ "revision": 1
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/delete | +
| Query | +None | +|
| Body | +
+ {
+ "userSpaceID": 1
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ The response code will be OK even if the file does not exist. + |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/userSpace/get | +
| Query | +
+ - userSpaceID: int64 + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "userSpace": {
+ "userSpaceID": 1,
+ "name": "test1",
+ "storage": {
+ "type": "OBS",
+ "region": "",
+ "endpoint": "",
+ "bucket": "",
+ "projectID": ""
+ },
+ "credential": {
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ },
+ "shardStore": {
+ "maxSize": 1024
+ },
+ "features": [],
+ "workingDir": "",
+ "revision": 1
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/test | +
| Query | +None | +|
| Body | +
+ {
+ "storage": {
+ "type": "OBS",
+ "region": "",
+ "endpoint": "",
+ "bucket": "",
+ "projectID": ""
+ },
+ "credential": {
+ "type": "OBS",
+ "accessKeyId": "",
+ "secretAccessKey": ""
+ },
+ "workingDir": ""
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ The OK response indicates the configuration is valid and connected to the storage system. + |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/createPackage | +
| Query | +None | +|
| Body | +
+ {
+ "userSpaceID": 1,
+ "path": "", // Path within the user's storage space. Can be a folder or a file. Note: WorkingDir is not prepended.
+ "bucketID": 1, // bucketID of the newly created package
+ "name": "", // Name of the newly created package
+ "spaceAffinity": 0 // Preferred storage space for uploading files. 0 means no preference.
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "package": {
+ "packageID": 32,
+ "name": "t1",
+ "bucketID": 1,
+ "createTime": "2025-06-24T16:31:28.5148754+08:00"
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/userSpace/downloadPackage | +
| Query | +None | +|
| Body | +
+ {
+ "userSpaceID": 1,
+ "packageID": 1,
+ "rootPath": "", // Root path for storing downloaded files
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/spaceSyncer/createTask | +
| Query | +None | +|
| Body | +
+ {
+ "trigger": { // Sync task trigger condition
+ "type": "Interval",
+ "interval": 30
+ },
+ "mode": { // Sync mode
+ "type": "Diff",
+ "includeSize": false,
+ "includeModTime": true
+ },
+ "filters": [ // Filter rules
+ {
+ "type": "Size",
+ "minSize": 10,
+ "maxSize": 20000
+ }
+ ],
+ "options": { // Options
+ "noEmptyDirectories": false
+ },
+ "srcUserSpaceID": 1, // Source storage space ID
+ "srcPath": "space1/cli", // Path within source storage space
+ "destUserSpaceIDs": [ // Destination storage space IDs
+ 2
+ ],
+ "destPathes": [ // Paths within destination storage spaces
+ "space2/svr"
+ ]
+}
+ The contents of |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "task": {
+ "taskID": 1,
+ "trigger": {
+ "type": "Interval",
+ "interval": 30
+ },
+ "mode": {
+ "type": "Diff",
+ "includeSize": false,
+ "includeModTime": true
+ },
+ "filters": [
+ {
+ "type": "Size",
+ "minSize": 10,
+ "maxSize": 20000
+ }
+ ],
+ "options": {
+ "noEmptyDirectories": false
+ },
+ "srcUserSpaceID": 1,
+ "srcPath": "space1/cli",
+ "destUserSpaceIDs": [
+ 2
+ ],
+ "destPathes": [
+ "space2/svr"
+ ]
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| GET | +application/json | +/v1/spaceSyncer/getTask | +
| Query | +
+ - taskID: int64 + |
+ |
| Body | +None | +|
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": {
+ "task": {
+ "taskID": 1,
+ "trigger": {
+ "type": "Interval",
+ "interval": 30
+ },
+ "mode": {
+ "type": "Diff",
+ "includeSize": false,
+ "includeModTime": true
+ },
+ "filters": [
+ {
+ "type": "Size",
+ "minSize": 10,
+ "maxSize": 20000
+ }
+ ],
+ "options": {
+ "noEmptyDirectories": false
+ },
+ "srcUserSpaceID": 1,
+ "srcPath": "space1/cli",
+ "destUserSpaceIDs": [
+ 2
+ ],
+ "destPathes": [
+ "space2/svr"
+ ]
+ }
+ }
+}
+ |
+ ||
| Request | +||
|---|---|---|
| POST | +application/json | +/v1/spaceSyncer/cancelTask | +
| Query | +None | +|
| Body | +
+ {
+ "taskID": 1
+}
+ |
+ |
| Response Example | +||
+ {
+ "code": "OK",
+ "message": "",
+ "data": null
+}
+ |
+ ||
+
+
+
+
+
+
+
@@ -83,17 +83,17 @@
### 4、创建桶
-1、在控制台页面,点击选择bucket中的“请选择”,在下拉框中选择创建Bucket
+在控制台页面,点击选择bucket中的“请选择”,在下拉框中选择创建Bucket。
-
+
+
+
+
+
+
+
@@ -195,7 +195,7 @@ OSS要接入CDS存储系统,需要填写以下内容:
+
@@ -226,7 +226,7 @@ OSS要接入CDS存储系统,需要填写以下内容:
用手机微信扫描二维码,按要求输入姓名和身份证号,并进行人脸识别,完成认证。
+
@@ -252,17 +252,17 @@ OSS要接入CDS存储系统,需要填写以下内容:
选择自己所在区域,填写桶名称,填写完成后,点击右下角的立即创建。
+
+
+
+
@@ -315,19 +315,19 @@ OSS要接入CDS存储系统,需要填写以下内容:
在弹出框中勾选我已悉知,为账号创建访问密钥会带来的风险,然后点击继续创建。
+
+
+
+
+
+
+
+
+
+
@@ -454,10 +454,10 @@ OBS要接入CDS存储系统,需要填写以下内容:
+
+
@@ -477,7 +477,7 @@ OBS要接入CDS存储系统,需要填写以下内容:
弹出框中会生成访问密钥,点击下载CSV文件或者复制,及时保存生成的SecretID和对应的SecretKey,弹窗关闭后将无法再次获取该密钥信息。
+