| @@ -32,7 +32,7 @@ func Test_Package(t *testing.T) { | |||
| URL: "http://localhost:7893", | |||
| }) | |||
| _, err := cli.PackageGetWithObjects(PackageGetWithObjectsInfos{UserID: 0, PackageID: 13}) | |||
| _, err := cli.PackageGetWithObjects(PackageGetWithObjectsInfos{UserID: 1, PackageID: 13}) | |||
| So(err, ShouldBeNil) | |||
| }) | |||
| } | |||
| @@ -0,0 +1,86 @@ | |||
| package cdssdk | |||
| import ( | |||
| "net/url" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | |||
| ) | |||
| type BucketService struct { | |||
| *Client | |||
| } | |||
| func (c *Client) Bucket() *BucketService { | |||
| return &BucketService{c} | |||
| } | |||
| const BucketCreatePath = "/bucket/create" | |||
| type BucketCreateReq struct { | |||
| UserID UserID `json:"userID" binding:"required"` | |||
| BucketName string `json:"bucketName" binding:"required"` | |||
| } | |||
| type BucketCreateResp struct { | |||
| BucketID BucketID `json:"bucketID"` | |||
| } | |||
| func (c *BucketService) Create(req BucketCreateReq) (*BucketCreateResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, BucketCreatePath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ | |||
| Body: req, | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| codeResp, err := myhttp.ParseJSONResponse[response[BucketCreateResp]](resp) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if codeResp.Code == errorcode.OK { | |||
| return &codeResp.Data, nil | |||
| } | |||
| return nil, codeResp.ToError() | |||
| } | |||
| const BucketDeletePath = "/bucket/delete" | |||
| type BucketDeleteReq struct { | |||
| UserID UserID `json:"userID" binding:"required"` | |||
| BucketID BucketID `json:"bucketID" binding:"required"` | |||
| } | |||
| type BucketDeleteResp struct{} | |||
| func (c *BucketService) Delete(req BucketDeleteReq) (*BucketDeleteResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, BucketDeletePath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ | |||
| Body: req, | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| codeResp, err := myhttp.ParseJSONResponse[response[BucketDeleteResp]](resp) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| if codeResp.Code == errorcode.OK { | |||
| return &codeResp.Data, nil | |||
| } | |||
| return nil, codeResp.ToError() | |||
| } | |||
| @@ -7,7 +7,7 @@ import ( | |||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | |||
| ) | |||
| var CacheMovePackagePath = "/cache/movePackage" | |||
| const CacheMovePackagePath = "/cache/movePackage" | |||
| type CacheMovePackageReq struct { | |||
| UserID UserID `json:"userID"` | |||
| @@ -112,6 +112,8 @@ type Object struct { | |||
| Size int64 `db:"Size" json:"size,string"` | |||
| FileHash string `db:"FileHash" json:"fileHash"` | |||
| Redundancy Redundancy `db:"Redundancy" json:"redundancy"` | |||
| CreateTime time.Time `db:"CreateTime" json:"createTime"` | |||
| UpdateTime time.Time `db:"UpdateTime" json:"updateTime"` | |||
| } | |||
| type Node struct { | |||
| @@ -132,6 +134,19 @@ type PinnedObject struct { | |||
| CreateTime time.Time `db:"CreateTime" json:"createTime"` | |||
| } | |||
| type Bucket struct { | |||
| BucketID BucketID `db:"BucketID" json:"bucketID"` | |||
| Name string `db:"Name" json:"name"` | |||
| CreatorID UserID `db:"CreatorID" json:"creatorID"` | |||
| } | |||
| type NodeConnectivity struct { | |||
| FromNodeID NodeID `db:"FromNodeID" json:"fromNodeID"` | |||
| ToNodeID NodeID `db:"ToNodeID" json:"ToNodeID"` | |||
| Delay *float32 `db:"Delay" json:"delay"` | |||
| TestTime time.Time `db:"TestTime" json:"testTime"` | |||
| } | |||
| type NodePackageCachingInfo struct { | |||
| NodeID NodeID `json:"nodeID"` | |||
| FileSize int64 `json:"fileSize"` | |||
| @@ -7,17 +7,95 @@ import ( | |||
| "strings" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/iterator" | |||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | |||
| "gitlink.org.cn/cloudream/common/utils/serder" | |||
| ) | |||
| type ObjectService struct { | |||
| *Client | |||
| } | |||
| func (c *Client) Object() *ObjectService { | |||
| return &ObjectService{ | |||
| Client: c, | |||
| } | |||
| } | |||
| const ObjectUploadPath = "/object/upload" | |||
| type ObjectUploadReq struct { | |||
| ObjectUploadInfo | |||
| Files UploadObjectIterator `json:"-"` | |||
| } | |||
| type ObjectUploadInfo struct { | |||
| UserID UserID `json:"userID" binding:"required"` | |||
| PackageID PackageID `json:"packageID" binding:"required"` | |||
| NodeAffinity *NodeID `json:"nodeAffinity"` | |||
| } | |||
| type IterObjectUpload struct { | |||
| Path string | |||
| File io.ReadCloser | |||
| } | |||
| type UploadObjectIterator = iterator.Iterator[*IterObjectUpload] | |||
| type ObjectUploadResp struct{} | |||
| func (c *ObjectService) Upload(req ObjectUploadReq) (*ObjectUploadResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, ObjectUploadPath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| infoJSON, err := serder.ObjectToJSON(req) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("upload info to json: %w", err) | |||
| } | |||
| resp, err := myhttp.PostMultiPart(url, myhttp.MultiPartRequestParam{ | |||
| Form: map[string]string{"info": string(infoJSON)}, | |||
| Files: iterator.Map(req.Files, func(src *IterObjectUpload) (*myhttp.IterMultiPartFile, error) { | |||
| return &myhttp.IterMultiPartFile{ | |||
| FieldName: "files", | |||
| FileName: src.Path, | |||
| File: src.File, | |||
| }, nil | |||
| }), | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| contType := resp.Header.Get("Content-Type") | |||
| if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||
| var codeResp response[ObjectUploadResp] | |||
| if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||
| return nil, fmt.Errorf("parsing response: %w", err) | |||
| } | |||
| if codeResp.Code == errorcode.OK { | |||
| return &codeResp.Data, nil | |||
| } | |||
| return nil, codeResp.ToError() | |||
| } | |||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||
| } | |||
| const ObjectDownloadPath = "/object/download" | |||
| type ObjectDownloadReq struct { | |||
| UserID int64 `json:"userID"` | |||
| ObjectID int64 `json:"objectID"` | |||
| } | |||
| func (c *Client) ObjectDownload(req ObjectDownloadReq) (io.ReadCloser, error) { | |||
| url, err := url.JoinPath(c.baseURL, "/object/download") | |||
| func (c *ObjectService) Download(req ObjectDownloadReq) (io.ReadCloser, error) { | |||
| url, err := url.JoinPath(c.baseURL, ObjectDownloadPath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -47,7 +125,7 @@ func (c *Client) ObjectDownload(req ObjectDownloadReq) (io.ReadCloser, error) { | |||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||
| } | |||
| var ObjectGetPackageObjectsPath = "/object/getPackageObjects" | |||
| const ObjectGetPackageObjectsPath = "/object/getPackageObjects" | |||
| type ObjectGetPackageObjectsReq struct { | |||
| UserID UserID `json:"userID"` | |||
| @@ -57,7 +135,7 @@ type ObjectGetPackageObjectsResp struct { | |||
| Objects []Object `json:"objects"` | |||
| } | |||
| func (c *Client) ObjectGetPackageObjects(req ObjectGetPackageObjectsReq) (*ObjectGetPackageObjectsResp, error) { | |||
| func (c *ObjectService) GetPackageObjects(req ObjectGetPackageObjectsReq) (*ObjectGetPackageObjectsResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, ObjectGetPackageObjectsPath) | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -2,16 +2,24 @@ package cdssdk | |||
| import ( | |||
| "fmt" | |||
| "io" | |||
| "net/url" | |||
| "strings" | |||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||
| "gitlink.org.cn/cloudream/common/pkgs/iterator" | |||
| myhttp "gitlink.org.cn/cloudream/common/utils/http" | |||
| "gitlink.org.cn/cloudream/common/utils/serder" | |||
| ) | |||
| type PackageService struct { | |||
| *Client | |||
| } | |||
| func (c *Client) Package() *PackageService { | |||
| return &PackageService{c} | |||
| } | |||
| const PackageGetPath = "/package/get" | |||
| type PackageGetReq struct { | |||
| UserID UserID `json:"userID"` | |||
| PackageID PackageID `json:"packageID"` | |||
| @@ -20,8 +28,8 @@ type PackageGetResp struct { | |||
| Package | |||
| } | |||
| func (c *Client) PackageGet(req PackageGetReq) (*PackageGetResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, "/package/get") | |||
| func (c *PackageService) Get(req PackageGetReq) (*PackageGetResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, PackageGetPath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| @@ -45,66 +53,41 @@ func (c *Client) PackageGet(req PackageGetReq) (*PackageGetResp, error) { | |||
| return nil, codeResp.ToError() | |||
| } | |||
| type PackageUploadReq struct { | |||
| UserID UserID `json:"userID"` | |||
| BucketID BucketID `json:"bucketID"` | |||
| Name string `json:"name"` | |||
| NodeAffinity *NodeID `json:"nodeAffinity"` | |||
| Files PackageUploadFileIterator `json:"-"` | |||
| } | |||
| const PackageCreatePath = "/package/create" | |||
| type IterPackageUploadFile struct { | |||
| Path string | |||
| File io.ReadCloser | |||
| type PackageCreateReq struct { | |||
| UserID UserID `json:"userID"` | |||
| BucketID BucketID `json:"bucketID"` | |||
| Name string `json:"name"` | |||
| } | |||
| type PackageUploadFileIterator = iterator.Iterator[*IterPackageUploadFile] | |||
| type PackageUploadResp struct { | |||
| type PackageCreateResp struct { | |||
| PackageID PackageID `json:"packageID,string"` | |||
| } | |||
| func (c *Client) PackageUpload(req PackageUploadReq) (*PackageUploadResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, "/package/upload") | |||
| func (s *PackageService) Create(req PackageCreateReq) (*PackageCreateResp, error) { | |||
| url, err := url.JoinPath(s.baseURL, PackageCreatePath) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| infoJSON, err := serder.ObjectToJSON(req) | |||
| if err != nil { | |||
| return nil, fmt.Errorf("package info to json: %w", err) | |||
| } | |||
| resp, err := myhttp.PostMultiPart(url, myhttp.MultiPartRequestParam{ | |||
| Form: map[string]string{"info": string(infoJSON)}, | |||
| Files: iterator.Map(req.Files, func(src *IterPackageUploadFile) (*myhttp.IterMultiPartFile, error) { | |||
| return &myhttp.IterMultiPartFile{ | |||
| FieldName: "files", | |||
| FileName: src.Path, | |||
| File: src.File, | |||
| }, nil | |||
| }), | |||
| resp, err := myhttp.PostJSON(url, myhttp.RequestParam{ | |||
| Body: req, | |||
| }) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| contType := resp.Header.Get("Content-Type") | |||
| if strings.Contains(contType, myhttp.ContentTypeJSON) { | |||
| var codeResp response[PackageUploadResp] | |||
| if err := serder.JSONToObjectStream(resp.Body, &codeResp); err != nil { | |||
| return nil, fmt.Errorf("parsing response: %w", err) | |||
| } | |||
| if codeResp.Code == errorcode.OK { | |||
| return &codeResp.Data, nil | |||
| } | |||
| return nil, codeResp.ToError() | |||
| codeResp, err := myhttp.ParseJSONResponse[response[PackageCreateResp]](resp) | |||
| if err != nil { | |||
| return nil, err | |||
| } | |||
| return nil, fmt.Errorf("unknow response content type: %s", contType) | |||
| if codeResp.Code == errorcode.OK { | |||
| return &codeResp.Data, nil | |||
| } | |||
| return nil, codeResp.ToError() | |||
| } | |||
| type PackageDeleteReq struct { | |||
| @@ -112,7 +95,7 @@ type PackageDeleteReq struct { | |||
| PackageID PackageID `json:"packageID"` | |||
| } | |||
| func (c *Client) PackageDelete(req PackageDeleteReq) error { | |||
| func (c *PackageService) Delete(req PackageDeleteReq) error { | |||
| url, err := url.JoinPath(c.baseURL, "/package/delete") | |||
| if err != nil { | |||
| return err | |||
| @@ -152,7 +135,7 @@ type PackageGetCachedNodesResp struct { | |||
| PackageCachingInfo | |||
| } | |||
| func (c *Client) PackageGetCachedNodes(req PackageGetCachedNodesReq) (*PackageGetCachedNodesResp, error) { | |||
| func (c *PackageService) GetCachedNodes(req PackageGetCachedNodesReq) (*PackageGetCachedNodesResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, "/package/getCachedNodes") | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -190,7 +173,7 @@ type PackageGetLoadedNodesResp struct { | |||
| NodeIDs []NodeID `json:"nodeIDs"` | |||
| } | |||
| func (c *Client) PackageGetLoadedNodes(req PackageGetLoadedNodesReq) (*PackageGetLoadedNodesResp, error) { | |||
| func (c *PackageService) GetLoadedNodes(req PackageGetLoadedNodesReq) (*PackageGetLoadedNodesResp, error) { | |||
| url, err := url.JoinPath(c.baseURL, "/package/getLoadedNodes") | |||
| if err != nil { | |||
| return nil, err | |||
| @@ -23,16 +23,24 @@ func Test_PackageGet(t *testing.T) { | |||
| } | |||
| pkgName := uuid.NewString() | |||
| upResp, err := cli.PackageUpload(PackageUploadReq{ | |||
| UserID: 0, | |||
| createResp, err := cli.Package().Create(PackageCreateReq{ | |||
| UserID: 1, | |||
| BucketID: 1, | |||
| Name: pkgName, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.Object().Upload(ObjectUploadReq{ | |||
| ObjectUploadInfo: ObjectUploadInfo{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }, | |||
| Files: iterator.Array( | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test2", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| @@ -40,18 +48,18 @@ func Test_PackageGet(t *testing.T) { | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| getResp, err := cli.PackageGet(PackageGetReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| getResp, err := cli.Package().Get(PackageGetReq{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| So(getResp.PackageID, ShouldEqual, upResp.PackageID) | |||
| So(getResp.PackageID, ShouldEqual, createResp.PackageID) | |||
| So(getResp.Package.Name, ShouldEqual, pkgName) | |||
| err = cli.PackageDelete(PackageDeleteReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| err = cli.Package().Delete(PackageDeleteReq{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| }) | |||
| @@ -69,17 +77,27 @@ func Test_Object(t *testing.T) { | |||
| } | |||
| nodeAff := NodeID(2) | |||
| upResp, err := cli.PackageUpload(PackageUploadReq{ | |||
| UserID: 0, | |||
| BucketID: 1, | |||
| Name: uuid.NewString(), | |||
| NodeAffinity: &nodeAff, | |||
| pkgName := uuid.NewString() | |||
| createResp, err := cli.Package().Create(PackageCreateReq{ | |||
| UserID: 1, | |||
| BucketID: 1, | |||
| Name: pkgName, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.Object().Upload(ObjectUploadReq{ | |||
| ObjectUploadInfo: ObjectUploadInfo{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| NodeAffinity: &nodeAff, | |||
| }, | |||
| Files: iterator.Array( | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test2", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| @@ -88,7 +106,7 @@ func Test_Object(t *testing.T) { | |||
| So(err, ShouldBeNil) | |||
| // downFs, err := cli.ObjectDownload(ObjectDownloadReq{ | |||
| // UserID: 0, | |||
| // UserID: 1, | |||
| // ObjectID: upResp.ObjectID, | |||
| // }) | |||
| // So(err, ShouldBeNil) | |||
| @@ -98,9 +116,9 @@ func Test_Object(t *testing.T) { | |||
| // So(downFileData, ShouldResemble, fileData) | |||
| // downFs.Close() | |||
| err = cli.PackageDelete(PackageDeleteReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| err = cli.Package().Delete(PackageDeleteReq{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| }) | |||
| @@ -117,16 +135,25 @@ func Test_Storage(t *testing.T) { | |||
| fileData[i] = byte(i) | |||
| } | |||
| upResp, err := cli.PackageUpload(PackageUploadReq{ | |||
| UserID: 0, | |||
| pkgName := uuid.NewString() | |||
| createResp, err := cli.Package().Create(PackageCreateReq{ | |||
| UserID: 1, | |||
| BucketID: 1, | |||
| Name: uuid.NewString(), | |||
| Name: pkgName, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.Object().Upload(ObjectUploadReq{ | |||
| ObjectUploadInfo: ObjectUploadInfo{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }, | |||
| Files: iterator.Array( | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test2", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| @@ -135,15 +162,15 @@ func Test_Storage(t *testing.T) { | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.StorageLoadPackage(StorageLoadPackageReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| StorageID: 1, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| err = cli.PackageDelete(PackageDeleteReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| err = cli.Package().Delete(PackageDeleteReq{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| }) | |||
| @@ -160,16 +187,25 @@ func Test_Cache(t *testing.T) { | |||
| fileData[i] = byte(i) | |||
| } | |||
| upResp, err := cli.PackageUpload(PackageUploadReq{ | |||
| UserID: 0, | |||
| pkgName := uuid.NewString() | |||
| createResp, err := cli.Package().Create(PackageCreateReq{ | |||
| UserID: 1, | |||
| BucketID: 1, | |||
| Name: uuid.NewString(), | |||
| Name: pkgName, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.Object().Upload(ObjectUploadReq{ | |||
| ObjectUploadInfo: ObjectUploadInfo{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }, | |||
| Files: iterator.Array( | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test.txt", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| &IterPackageUploadFile{ | |||
| &IterObjectUpload{ | |||
| Path: "test2.txt", | |||
| File: io.NopCloser(bytes.NewBuffer(fileData)), | |||
| }, | |||
| @@ -178,15 +214,15 @@ func Test_Cache(t *testing.T) { | |||
| So(err, ShouldBeNil) | |||
| _, err = cli.CacheMovePackage(CacheMovePackageReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| NodeID: 1, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| err = cli.PackageDelete(PackageDeleteReq{ | |||
| UserID: 0, | |||
| PackageID: upResp.PackageID, | |||
| err = cli.Package().Delete(PackageDeleteReq{ | |||
| UserID: 1, | |||
| PackageID: createResp.PackageID, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| }) | |||
| @@ -197,16 +233,16 @@ func Test_GetNodeInfos(t *testing.T) { | |||
| cli := NewClient(&Config{ | |||
| URL: "http://localhost:7890", | |||
| }) | |||
| resp1, err := cli.PackageGetCachedNodes(PackageGetCachedNodesReq{ | |||
| resp1, err := cli.Package().GetCachedNodes(PackageGetCachedNodesReq{ | |||
| PackageID: 11, | |||
| UserID: 0, | |||
| UserID: 1, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| fmt.Printf("resp1: %v\n", resp1) | |||
| resp2, err := cli.PackageGetLoadedNodes(PackageGetLoadedNodesReq{ | |||
| resp2, err := cli.Package().GetLoadedNodes(PackageGetLoadedNodesReq{ | |||
| PackageID: 11, | |||
| UserID: 0, | |||
| UserID: 1, | |||
| }) | |||
| So(err, ShouldBeNil) | |||
| fmt.Printf("resp2: %v\n", resp2) | |||
| @@ -36,6 +36,14 @@ func Sort[T any](arr []T, cmp Comparer[T]) []T { | |||
| return arr | |||
| } | |||
| func SortAsc[T constraints.Ordered](arr []T) []T { | |||
| return Sort(arr, Cmp[T]) | |||
| } | |||
| func SortDesc[T constraints.Ordered](arr []T) []T { | |||
| return Sort(arr, func(left, right T) int { return Cmp(right, left) }) | |||
| } | |||
| // false < true | |||
| func CmpBool(left, right bool) int { | |||
| leftVal := 0 | |||