| @@ -48,6 +48,8 @@ func (s *Server) InitRouters(rt gin.IRoutes, ah *auth.Auth) { | |||||
| rt.POST(cliapi.UserSpaceDownloadPackagePath, certAuth, s.UserSpace().DownloadPackage) | rt.POST(cliapi.UserSpaceDownloadPackagePath, certAuth, s.UserSpace().DownloadPackage) | ||||
| rt.POST(cliapi.UserSpaceCreatePackagePath, certAuth, s.UserSpace().CreatePackage) | rt.POST(cliapi.UserSpaceCreatePackagePath, certAuth, s.UserSpace().CreatePackage) | ||||
| rt.GET(cliapi.UserSpaceGetPath, certAuth, s.UserSpace().Get) | rt.GET(cliapi.UserSpaceGetPath, certAuth, s.UserSpace().Get) | ||||
| rt.GET(cliapi.UserSpaceGetByNamePath, certAuth, s.UserSpace().GetByName) | |||||
| rt.GET(cliapi.UserSpaceGetAllPath, certAuth, s.UserSpace().GetAll) | |||||
| rt.POST(cliapi.UserSpaceCreatePath, certAuth, s.UserSpace().Create) | rt.POST(cliapi.UserSpaceCreatePath, certAuth, s.UserSpace().Create) | ||||
| rt.POST(cliapi.UserSpaceUpdatePath, certAuth, s.UserSpace().Update) | rt.POST(cliapi.UserSpaceUpdatePath, certAuth, s.UserSpace().Update) | ||||
| rt.POST(cliapi.UserSpaceDeletePath, certAuth, s.UserSpace().Delete) | rt.POST(cliapi.UserSpaceDeletePath, certAuth, s.UserSpace().Delete) | ||||
| @@ -85,6 +85,43 @@ func (s *UserSpaceService) Get(ctx *gin.Context) { | |||||
| })) | })) | ||||
| } | } | ||||
| func (s *UserSpaceService) GetByName(ctx *gin.Context) { | |||||
| log := logger.WithField("HTTP", "UserSpace.GetByName") | |||||
| var req cliapi.UserSpaceGetByName | |||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | |||||
| log.Warnf("binding query: %s", err.Error()) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | |||||
| } | |||||
| info, err := s.svc.UserSpaceSvc().GetByName(req.Name) | |||||
| if err != nil { | |||||
| log.Warnf("getting info: %s", err.Error()) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get userspace info failed")) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceGetByNameResp{ | |||||
| UserSpace: info, | |||||
| })) | |||||
| } | |||||
| func (s *UserSpaceService) GetAll(ctx *gin.Context) { | |||||
| log := logger.WithField("HTTP", "UserSpace.GetAll") | |||||
| allInfos, err := s.svc.UserSpaceSvc().GetAll() | |||||
| if err != nil { | |||||
| log.Warnf("getting info: %s", err.Error()) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get userspaces info failed")) | |||||
| return | |||||
| } | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceGetAllResp{ | |||||
| UserSpaces: allInfos, | |||||
| })) | |||||
| } | |||||
| func (s *UserSpaceService) Create(ctx *gin.Context) { | func (s *UserSpaceService) Create(ctx *gin.Context) { | ||||
| log := logger.WithField("HTTP", "UserSpace.Create") | log := logger.WithField("HTTP", "UserSpace.Create") | ||||
| @@ -41,6 +41,10 @@ func (svc *UserSpaceService) GetByName(name string) (clitypes.UserSpace, error) | |||||
| return svc.DB.UserSpace().GetByName(svc.DB.DefCtx(), name) | return svc.DB.UserSpace().GetByName(svc.DB.DefCtx(), name) | ||||
| } | } | ||||
| func (svc *UserSpaceService) GetAll() ([]clitypes.UserSpace, error) { | |||||
| return svc.DB.UserSpace().GetAll(svc.DB.DefCtx()) | |||||
| } | |||||
| func (svc *UserSpaceService) Create(req cliapi.UserSpaceCreate) (*cliapi.UserSpaceCreateResp, *ecode.CodeError) { | func (svc *UserSpaceService) Create(req cliapi.UserSpaceCreate) (*cliapi.UserSpaceCreateResp, *ecode.CodeError) { | ||||
| db2 := svc.DB | db2 := svc.DB | ||||
| space, err := db.DoTx01(db2, func(tx db.SQLContext) (clitypes.UserSpace, error) { | space, err := db.DoTx01(db2, func(tx db.SQLContext) (clitypes.UserSpace, error) { | ||||
| @@ -78,6 +78,49 @@ func (c *Client) UserSpaceGet(req UserSpaceGet) (*UserSpaceGetResp, error) { | |||||
| return JSONAPI(&c.cfg, c.httpCli, &req, &UserSpaceGetResp{}) | return JSONAPI(&c.cfg, c.httpCli, &req, &UserSpaceGetResp{}) | ||||
| } | } | ||||
| const UserSpaceGetByNamePath = "/userspace/getByName" | |||||
| type UserSpaceGetByName struct { | |||||
| Name string `form:"name" url:"name" binding:"required"` | |||||
| } | |||||
| func (r *UserSpaceGetByName) MakeParam() *sdks.RequestParam { | |||||
| return sdks.MakeQueryParam(http.MethodGet, UserSpaceGetByNamePath, r) | |||||
| } | |||||
| type UserSpaceGetByNameResp struct { | |||||
| clitypes.UserSpace | |||||
| } | |||||
| func (r *UserSpaceGetByNameResp) ParseResponse(resp *http.Response) error { | |||||
| return sdks.ParseCodeDataJSONResponse(resp, r) | |||||
| } | |||||
| func (c *Client) UserSpaceGetByName(req UserSpaceGetByName) (*UserSpaceGetByNameResp, error) { | |||||
| return JSONAPI(&c.cfg, c.httpCli, &req, &UserSpaceGetByNameResp{}) | |||||
| } | |||||
| const UserSpaceGetAllPath = "/userspace/getAll" | |||||
| type UserSpaceGetAll struct{} | |||||
| func (r *UserSpaceGetAll) MakeParam() *sdks.RequestParam { | |||||
| return sdks.MakeQueryParam(http.MethodGet, UserSpaceGetAllPath, nil) | |||||
| } | |||||
| type UserSpaceGetAllResp struct { | |||||
| UserSpaces []clitypes.UserSpace `json:"userSpaces"` | |||||
| } | |||||
| func (r *UserSpaceGetAllResp) ParseResponse(resp *http.Response) error { | |||||
| return sdks.ParseCodeDataJSONResponse(resp, r) | |||||
| } | |||||
| func (c *Client) UserSpaceGetAll() (*UserSpaceGetAllResp, error) { | |||||
| req := UserSpaceGetAll{} | |||||
| return JSONAPI(&c.cfg, c.httpCli, &req, &UserSpaceGetAllResp{}) | |||||
| } | |||||
| // 创建用户空间 | // 创建用户空间 | ||||
| const UserSpaceCreatePath = "/userspace/create" | const UserSpaceCreatePath = "/userspace/create" | ||||
| @@ -1,12 +1,16 @@ | |||||
| package types | package types | ||||
| import ( | import ( | ||||
| "fmt" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/types" | "gitlink.org.cn/cloudream/common/pkgs/types" | ||||
| "gitlink.org.cn/cloudream/common/utils/serder" | "gitlink.org.cn/cloudream/common/utils/serder" | ||||
| ) | ) | ||||
| type StorageCredential interface { | type StorageCredential interface { | ||||
| // fmt.Stringer | |||||
| GetStorageCredentialType() string | GetStorageCredentialType() string | ||||
| String(showPassword bool) string | |||||
| } | } | ||||
| var _ = serder.UseTypeUnionInternallyTagged(types.Ref(types.NewTypeUnion[StorageCredential]( | var _ = serder.UseTypeUnionInternallyTagged(types.Ref(types.NewTypeUnion[StorageCredential]( | ||||
| @@ -26,6 +30,10 @@ type LocalCred struct { | |||||
| RootDir string `json:"rootDir"` | RootDir string `json:"rootDir"` | ||||
| } | } | ||||
| func (c *LocalCred) String(showPassword bool) string { | |||||
| return fmt.Sprintf("RootDir=%s", c.RootDir) | |||||
| } | |||||
| // type MashupCred struct { | // type MashupCred struct { | ||||
| // StorageCredential `json:"-"` | // StorageCredential `json:"-"` | ||||
| // serder.Metadata `union:"Mashup"` | // serder.Metadata `union:"Mashup"` | ||||
| @@ -41,6 +49,14 @@ type OSSCred struct { | |||||
| SK string `json:"secretAccessKey"` | SK string `json:"secretAccessKey"` | ||||
| } | } | ||||
| func (c *OSSCred) String(showPassword bool) string { | |||||
| maskedSK := "****" | |||||
| if showPassword { | |||||
| maskedSK = c.SK | |||||
| } | |||||
| return fmt.Sprintf("AK=%s, SK=%s", c.AK, maskedSK) | |||||
| } | |||||
| type OBSCred struct { | type OBSCred struct { | ||||
| StorageCredential `json:"-"` | StorageCredential `json:"-"` | ||||
| serder.Metadata `union:"OBS"` | serder.Metadata `union:"OBS"` | ||||
| @@ -49,6 +65,14 @@ type OBSCred struct { | |||||
| SK string `json:"secretAccessKey"` | SK string `json:"secretAccessKey"` | ||||
| } | } | ||||
| func (c *OBSCred) String(showPassword bool) string { | |||||
| maskedSK := "****" | |||||
| if showPassword { | |||||
| maskedSK = c.SK | |||||
| } | |||||
| return fmt.Sprintf("AK=%s, SK=%s", c.AK, maskedSK) | |||||
| } | |||||
| type COSCred struct { | type COSCred struct { | ||||
| StorageCredential `json:"-"` | StorageCredential `json:"-"` | ||||
| serder.Metadata `union:"COS"` | serder.Metadata `union:"COS"` | ||||
| @@ -57,6 +81,14 @@ type COSCred struct { | |||||
| SK string `json:"secretAccessKey"` | SK string `json:"secretAccessKey"` | ||||
| } | } | ||||
| func (c *COSCred) String(showPassword bool) string { | |||||
| maskedSK := "****" | |||||
| if showPassword { | |||||
| maskedSK = c.SK | |||||
| } | |||||
| return fmt.Sprintf("AK=%s, SK=%s", c.AK, maskedSK) | |||||
| } | |||||
| type EFileCred struct { | type EFileCred struct { | ||||
| StorageCredential `json:"-"` | StorageCredential `json:"-"` | ||||
| serder.Metadata `union:"EFile"` | serder.Metadata `union:"EFile"` | ||||
| @@ -69,6 +101,14 @@ type EFileCred struct { | |||||
| OrgID string `json:"orgID"` | OrgID string `json:"orgID"` | ||||
| } | } | ||||
| func (c *EFileCred) String(showPassword bool) string { | |||||
| maskedSK := "****" | |||||
| if showPassword { | |||||
| maskedSK = c.Password | |||||
| } | |||||
| return fmt.Sprintf("TokenURL=%s, APIURL=%s, TokenExpire=%d, User=%s, Password=%s, OrgID=%s", c.TokenURL, c.APIURL, c.TokenExpire, c.User, maskedSK, c.OrgID) | |||||
| } | |||||
| // 通用的S3协议的存储服务 | // 通用的S3协议的存储服务 | ||||
| type S3Cred struct { | type S3Cred struct { | ||||
| StorageCredential `json:"-"` | StorageCredential `json:"-"` | ||||
| @@ -77,3 +117,11 @@ type S3Cred struct { | |||||
| AK string `json:"accessKeyId"` | AK string `json:"accessKeyId"` | ||||
| SK string `json:"secretAccessKey"` | SK string `json:"secretAccessKey"` | ||||
| } | } | ||||
| func (c *S3Cred) String(showPassword bool) string { | |||||
| maskedSK := "****" | |||||
| if showPassword { | |||||
| maskedSK = c.SK | |||||
| } | |||||
| return fmt.Sprintf("AK=%s, SK=%s", c.AK, maskedSK) | |||||
| } | |||||
| @@ -49,19 +49,31 @@ require ( | |||||
| github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect | github.com/aws/aws-sdk-go-v2/service/internal/presigned-url v1.12.15 // indirect | ||||
| github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 // indirect | github.com/aws/aws-sdk-go-v2/service/internal/s3shared v1.18.6 // indirect | ||||
| github.com/aws/smithy-go v1.22.2 // indirect | github.com/aws/smithy-go v1.22.2 // indirect | ||||
| github.com/aymanbagabas/go-osc52/v2 v2.0.1 // indirect | |||||
| github.com/bytedance/sonic v1.11.6 // indirect | github.com/bytedance/sonic v1.11.6 // indirect | ||||
| github.com/bytedance/sonic/loader v0.1.1 // indirect | github.com/bytedance/sonic/loader v0.1.1 // indirect | ||||
| github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc // indirect | |||||
| github.com/charmbracelet/lipgloss v1.1.0 // indirect | |||||
| github.com/charmbracelet/x/ansi v0.8.0 // indirect | |||||
| github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd // indirect | |||||
| github.com/charmbracelet/x/term v0.2.1 // indirect | |||||
| github.com/cloudwego/base64x v0.1.4 // indirect | github.com/cloudwego/base64x v0.1.4 // indirect | ||||
| github.com/cloudwego/iasm v0.2.0 // indirect | github.com/cloudwego/iasm v0.2.0 // indirect | ||||
| github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect | github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc // indirect | ||||
| github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f // indirect | |||||
| github.com/gabriel-vasile/mimetype v1.4.6 // indirect | github.com/gabriel-vasile/mimetype v1.4.6 // indirect | ||||
| github.com/goccy/go-json v0.10.3 // indirect | github.com/goccy/go-json v0.10.3 // indirect | ||||
| github.com/jinzhu/inflection v1.0.0 // indirect | github.com/jinzhu/inflection v1.0.0 // indirect | ||||
| github.com/jinzhu/now v1.1.5 // indirect | github.com/jinzhu/now v1.1.5 // indirect | ||||
| github.com/jonboulle/clockwork v0.4.0 // indirect | github.com/jonboulle/clockwork v0.4.0 // indirect | ||||
| github.com/kr/pretty v0.3.1 // indirect | github.com/kr/pretty v0.3.1 // indirect | ||||
| github.com/lucasb-eyer/go-colorful v1.2.0 // indirect | |||||
| github.com/mattn/go-colorable v0.1.13 // indirect | github.com/mattn/go-colorable v0.1.13 // indirect | ||||
| github.com/mattn/go-localereader v0.0.1 // indirect | |||||
| github.com/mattn/go-tty v0.0.3 // indirect | github.com/mattn/go-tty v0.0.3 // indirect | ||||
| github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 // indirect | |||||
| github.com/muesli/cancelreader v0.2.2 // indirect | |||||
| github.com/muesli/termenv v0.16.0 // indirect | |||||
| github.com/pelletier/go-toml/v2 v2.2.2 // indirect | github.com/pelletier/go-toml/v2 v2.2.2 // indirect | ||||
| github.com/pkg/term v1.2.0-beta.2 // indirect | github.com/pkg/term v1.2.0-beta.2 // indirect | ||||
| github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | github.com/pmezard/go-difflib v1.0.1-0.20181226105442-5d4384ee4fb2 // indirect | ||||
| @@ -69,6 +81,7 @@ require ( | |||||
| github.com/rogpeppe/go-internal v1.12.0 // indirect | github.com/rogpeppe/go-internal v1.12.0 // indirect | ||||
| github.com/tjfoc/gmsm v1.4.1 // indirect | github.com/tjfoc/gmsm v1.4.1 // indirect | ||||
| github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | github.com/twitchyliquid64/golang-asm v0.15.1 // indirect | ||||
| github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e // indirect | |||||
| go.mongodb.org/mongo-driver v1.12.0 // indirect | go.mongodb.org/mongo-driver v1.12.0 // indirect | ||||
| golang.org/x/arch v0.8.0 // indirect | golang.org/x/arch v0.8.0 // indirect | ||||
| golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect | golang.org/x/exp v0.0.0-20250218142911-aa4b98e5adaa // indirect | ||||
| @@ -81,6 +94,8 @@ require ( | |||||
| require ( | require ( | ||||
| github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect | github.com/antonfisher/nested-logrus-formatter v1.3.1 // indirect | ||||
| github.com/c-bata/go-prompt v0.2.6 | github.com/c-bata/go-prompt v0.2.6 | ||||
| github.com/charmbracelet/bubbletea v1.3.5 | |||||
| github.com/chzyer/readline v1.5.1 | |||||
| github.com/gin-contrib/sse v0.1.0 // indirect | github.com/gin-contrib/sse v0.1.0 // indirect | ||||
| github.com/go-playground/locales v0.14.1 // indirect | github.com/go-playground/locales v0.14.1 // indirect | ||||
| github.com/go-playground/universal-translator v0.18.1 // indirect | github.com/go-playground/universal-translator v0.18.1 // indirect | ||||
| @@ -28,6 +28,8 @@ github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0 h1:nyuzXooUNJexRT0Oy0UQY6AhOzxPx | |||||
| github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY= | github.com/aws/aws-sdk-go-v2/service/s3 v1.71.0/go.mod h1:sT/iQz8JK3u/5gZkT+Hmr7GzVZehUMkRZpOaAwYXeGY= | ||||
| github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= | github.com/aws/smithy-go v1.22.2 h1:6D9hW43xKFrRx/tXXfAlIZc4JI+yQe6snnWcQyxSyLQ= | ||||
| github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= | github.com/aws/smithy-go v1.22.2/go.mod h1:irrKGvNn1InZwb2d7fkIRNucdfwR8R+Ts3wxYa/cJHg= | ||||
| github.com/aymanbagabas/go-osc52/v2 v2.0.1 h1:HwpRHbFMcZLEVr42D4p7XBqjyuxQH5SMiErDT4WkJ2k= | |||||
| github.com/aymanbagabas/go-osc52/v2 v2.0.1/go.mod h1:uYgXzlJ7ZpABp8OJ+exZzJJhRNQ2ASbcXHWsFqH8hp8= | |||||
| github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= | github.com/bytedance/sonic v1.11.6 h1:oUp34TzMlL+OY1OUWxHqsdkgC/Zfc85zGqw9siXjrc0= | ||||
| github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= | github.com/bytedance/sonic v1.11.6/go.mod h1:LysEHSvpvDySVdC2f87zGWf6CIKJcAvqab1ZaiQtds4= | ||||
| github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= | github.com/bytedance/sonic/loader v0.1.1 h1:c+e5Pt1k/cy5wMveRDyk2X4B9hF4g7an8N3zCYjJFNM= | ||||
| @@ -35,6 +37,22 @@ github.com/bytedance/sonic/loader v0.1.1/go.mod h1:ncP89zfokxS5LZrJxl5z0UJcsk4M4 | |||||
| github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= | github.com/c-bata/go-prompt v0.2.6 h1:POP+nrHE+DfLYx370bedwNhsqmpCUynWPxuHi0C5vZI= | ||||
| github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= | github.com/c-bata/go-prompt v0.2.6/go.mod h1:/LMAke8wD2FsNu9EXNdHxNLbd9MedkPnCdfpU9wwHfY= | ||||
| github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | github.com/census-instrumentation/opencensus-proto v0.2.1/go.mod h1:f6KPmirojxKA12rnyqOA5BBL4O983OfeGPqjHWSTneU= | ||||
| github.com/charmbracelet/bubbletea v1.3.5 h1:JAMNLTbqMOhSwoELIr0qyP4VidFq72/6E9j7HHmRKQc= | |||||
| github.com/charmbracelet/bubbletea v1.3.5/go.mod h1:TkCnmH+aBd4LrXhXcqrKiYwRs7qyQx5rBgH5fVY3v54= | |||||
| github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc h1:4pZI35227imm7yK2bGPcfpFEmuY1gc2YSTShr4iJBfs= | |||||
| github.com/charmbracelet/colorprofile v0.2.3-0.20250311203215-f60798e515dc/go.mod h1:X4/0JoqgTIPSFcRA/P6INZzIuyqdFY5rm8tb41s9okk= | |||||
| github.com/charmbracelet/lipgloss v1.1.0 h1:vYXsiLHVkK7fp74RkV7b2kq9+zDLoEU4MZoFqR/noCY= | |||||
| github.com/charmbracelet/lipgloss v1.1.0/go.mod h1:/6Q8FR2o+kj8rz4Dq0zQc3vYf7X+B0binUUBwA0aL30= | |||||
| github.com/charmbracelet/x/ansi v0.8.0 h1:9GTq3xq9caJW8ZrBTe0LIe2fvfLR/bYXKTx2llXn7xE= | |||||
| github.com/charmbracelet/x/ansi v0.8.0/go.mod h1:wdYl/ONOLHLIVmQaxbIYEC/cRKOQyjTkowiI4blgS9Q= | |||||
| github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd h1:vy0GVL4jeHEwG5YOXDmi86oYw2yuYUGqz6a8sLwg0X8= | |||||
| github.com/charmbracelet/x/cellbuf v0.0.13-0.20250311204145-2c3ea96c31dd/go.mod h1:xe0nKWGd3eJgtqZRaN9RjMtK7xUYchjzPr7q6kcvCCs= | |||||
| github.com/charmbracelet/x/term v0.2.1 h1:AQeHeLZ1OqSXhrAWpYUtZyX1T3zVxfpZuEQMIQaGIAQ= | |||||
| github.com/charmbracelet/x/term v0.2.1/go.mod h1:oQ4enTYFV7QN4m0i9mzHrViD7TQKvNEEkHUMCmsxdUg= | |||||
| github.com/chzyer/logex v1.2.1/go.mod h1:JLbx6lG2kDbNRFnfkgvh4eRJRPX1QCoOIWomwysCBrQ= | |||||
| github.com/chzyer/readline v1.5.1 h1:upd/6fQk4src78LMRzh5vItIt361/o4uq553V8B5sGI= | |||||
| github.com/chzyer/readline v1.5.1/go.mod h1:Eh+b79XXUwfKfcPLepksvw2tcLE/Ct21YObkaSkeBlk= | |||||
| github.com/chzyer/test v1.0.0/go.mod h1:2JlltgoNkt4TW/z9V/IzDdFaMTM2JPIi26O1pF38GC8= | |||||
| github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | github.com/client9/misspell v0.3.4/go.mod h1:qj6jICC3Q7zFZvVWo7KLAzC3yx5G7kyvSDkc90ppPyw= | ||||
| github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= | github.com/cloudwego/base64x v0.1.4 h1:jwCgWpFanWmN8xoIUHa2rtzmkd5J2plF/dnLS6Xd/0Y= | ||||
| github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= | github.com/cloudwego/base64x v0.1.4/go.mod h1:0zlkT4Wn5C6NdauXdJRhSKRlJvmclQ1hhJgA0rcu/8w= | ||||
| @@ -50,6 +68,8 @@ github.com/davecgh/go-spew v1.1.2-0.20180830191138-d8f796af33cc/go.mod h1:J7Y8Yc | |||||
| github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | github.com/envoyproxy/go-control-plane v0.9.0/go.mod h1:YTl/9mNaCwkRvm6d1a2C3ymFceY/DCBVvsKhRF0iEA4= | ||||
| github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= | github.com/envoyproxy/go-control-plane v0.9.4/go.mod h1:6rpuAdCZL397s3pYoYcLgu1mIlRU8Am5FuJP05cCM98= | ||||
| github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= | github.com/envoyproxy/protoc-gen-validate v0.1.0/go.mod h1:iSmxcyjqTsJpI2R4NaDN7+kN2VEUnK/pcBlmesArF7c= | ||||
| github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f h1:Y/CXytFA4m6baUTXGLOoWe4PQhGxaX0KpnayAqC48p4= | |||||
| github.com/erikgeiser/coninput v0.0.0-20211004153227-1c3628e74d0f/go.mod h1:vw97MGsxSvLiUE2X8qFplwetxpGLQrlU1Q9AUEIzCaM= | |||||
| github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= | github.com/gabriel-vasile/mimetype v1.4.6 h1:3+PzJTKLkvgjeTbts6msPJt4DixhT4YtFNf1gtGe3zc= | ||||
| github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= | github.com/gabriel-vasile/mimetype v1.4.6/go.mod h1:JX1qVKqZd40hUPpAfiNTe0Sne7hdfKSbOqqmkq8GCXc= | ||||
| github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= | ||||
| @@ -143,6 +163,8 @@ github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348 h1:MtvEpTB6LX3v | |||||
| github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= | github.com/kylelemons/godebug v0.0.0-20170820004349-d65d576e9348/go.mod h1:B69LEHPfb2qLo0BaaOLcbitczOKLWTsrBG9LczfCD4k= | ||||
| github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= | github.com/leodido/go-urn v1.4.0 h1:WT9HwE9SGECu3lg4d/dIA+jxlljEa1/ffXKmRjqdmIQ= | ||||
| github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= | github.com/leodido/go-urn v1.4.0/go.mod h1:bvxc+MVxLKB4z00jd1z+Dvzr47oO32F/QSNjSBOlFxI= | ||||
| github.com/lucasb-eyer/go-colorful v1.2.0 h1:1nnpGOrhyZZuNyfu1QjKiUICQ74+3FNCN69Aj6K7nkY= | |||||
| github.com/lucasb-eyer/go-colorful v1.2.0/go.mod h1:R4dSotOR9KMtayYi1e77YzuveK+i7ruzyGqttikkLy0= | |||||
| github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= | github.com/magefile/mage v1.15.0 h1:BvGheCMAsG3bWUDbZ8AyXXpCNwU9u5CB6sM+HNb9HYg= | ||||
| github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= | github.com/magefile/mage v1.15.0/go.mod h1:z5UZb/iS3GoOSn0JgWuiw7dxlurVYTu+/jHXqQg881A= | ||||
| github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | github.com/mattn/go-colorable v0.1.4/go.mod h1:U0ppj6V5qS13XJ6of8GYAs25YV2eR4EVcfRqFIhoBtE= | ||||
| @@ -155,6 +177,8 @@ github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Ky | |||||
| github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | github.com/mattn/go-isatty v0.0.16/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= | ||||
| github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | github.com/mattn/go-isatty v0.0.20 h1:xfD0iDuEKnDkl03q4limB+vH+GxLEtL/jb4xVJSWWEY= | ||||
| github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | github.com/mattn/go-isatty v0.0.20/go.mod h1:W+V8PltTTMOvKvAeJH7IuucS94S2C6jfK/D7dTCTo3Y= | ||||
| github.com/mattn/go-localereader v0.0.1 h1:ygSAOl7ZXTx4RdPYinUpg6W99U8jWvWi9Ye2JC/oIi4= | |||||
| github.com/mattn/go-localereader v0.0.1/go.mod h1:8fBrzywKY7BI3czFoHkuzRoWE9C+EiG4R1k4Cjx5p88= | |||||
| github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | github.com/mattn/go-runewidth v0.0.6/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||||
| github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | github.com/mattn/go-runewidth v0.0.9/go.mod h1:H031xJmbD/WCDINGzjvQ9THkh0rPKHF+m2gUSrubnMI= | ||||
| github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= | github.com/mattn/go-runewidth v0.0.16 h1:E5ScNMtiwvlvB5paMFdw9p4kSQzbXFikJ5SQO6TULQc= | ||||
| @@ -171,6 +195,12 @@ github.com/modern-go/concurrent v0.0.0-20180306012644-bacd9c7ef1dd/go.mod h1:6dJ | |||||
| github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= | ||||
| github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= | ||||
| github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= | github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc= | ||||
| github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6 h1:ZK8zHtRHOkbHy6Mmr5D264iyp3TiX5OmNcI5cIARiQI= | |||||
| github.com/muesli/ansi v0.0.0-20230316100256-276c6243b2f6/go.mod h1:CJlz5H+gyd6CUWT45Oy4q24RdLyn7Md9Vj2/ldJBSIo= | |||||
| github.com/muesli/cancelreader v0.2.2 h1:3I4Kt4BQjOR54NavqnDogx/MIoWBFa0StPA8ELUXHmA= | |||||
| github.com/muesli/cancelreader v0.2.2/go.mod h1:3XuTXfFS2VjM+HTLZY9Ak0l6eUKfijIfMUZ4EgX0QYo= | |||||
| github.com/muesli/termenv v0.16.0 h1:S5AlUN9dENB57rsbnkPyfdGuWIlkmzJjbFf0Tf5FWUc= | |||||
| github.com/muesli/termenv v0.16.0/go.mod h1:ZRfOIKPFDYQoDFF4Olj7/QJbW60Ol/kL1pU3VfY/Cnk= | |||||
| github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= | github.com/pelletier/go-toml/v2 v2.2.2 h1:aYUidT7k73Pcl9nb2gScu7NSrKCSHIDE89b3+6Wq+LM= | ||||
| github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= | github.com/pelletier/go-toml/v2 v2.2.2/go.mod h1:1t835xjRzz80PqgE6HHgN2JOsmgYu/h4qDAS4n929Rs= | ||||
| github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA= | ||||
| @@ -225,6 +255,8 @@ github.com/ugorji/go/codec v1.2.12/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZ | |||||
| github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= | github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI= | ||||
| github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= | github.com/xdg-go/scram v1.1.2/go.mod h1:RT/sEzTbU5y00aCK8UOx6R7YryM0iF1N2MOmC3kKLN4= | ||||
| github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= | github.com/xdg-go/stringprep v1.0.4/go.mod h1:mPGuuIYwz7CmR2bT9j4GbQqutWS1zV24gijq1dTyGkM= | ||||
| github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e h1:JVG44RsyaB9T2KIHavMF/ppJZNG9ZpyihvCd0w101no= | |||||
| github.com/xo/terminfo v0.0.0-20220910002029-abceb7e1c41e/go.mod h1:RbqR21r5mrJuqunuUZ/Dhy/avygyECGrLceyNeo4LiM= | |||||
| github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA= | ||||
| github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | github.com/yuin/goldmark v1.4.13/go.mod h1:6yULJ656Px+3vBD8DxQVa3kxgyrAnzto9xy5taEt/CY= | ||||
| github.com/zyedidia/generic v1.2.1 h1:Zv5KS/N2m0XZZiuLS82qheRG4X1o5gsWreGb0hR7XDc= | github.com/zyedidia/generic v1.2.1 h1:Zv5KS/N2m0XZZiuLS82qheRG4X1o5gsWreGb0hR7XDc= | ||||
| @@ -291,6 +323,8 @@ golang.org/x/sys v0.0.0-20200930185726-fdedc70b468f/go.mod h1:h1NjWce9XRLGQEsW7w | |||||
| golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs= | ||||
| golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||||
| golang.org/x/sys v0.0.0-20220310020820-b874c991c1a5/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | |||||
| golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220520151302-bc2c85ada10a/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220715151400-c0bba94af5f8/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | golang.org/x/sys v0.0.0-20220722155257-8c9f86f7a55f/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= | ||||
| @@ -2,4 +2,5 @@ package all | |||||
| import ( | import ( | ||||
| _ "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd/bucket" | _ "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd/bucket" | ||||
| _ "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd/userspace" | |||||
| ) | ) | ||||
| @@ -74,7 +74,7 @@ func RootExecute() { | |||||
| } | } | ||||
| if endpoint == "" { | if endpoint == "" { | ||||
| endpoint = "https://127.0.0.1:7890" | |||||
| endpoint = "https://127.0.0.1:8890" | |||||
| } | } | ||||
| cli := cliapi.NewClient(api.Config{ | cli := cliapi.NewClient(api.Config{ | ||||
| @@ -0,0 +1,563 @@ | |||||
| package userspace | |||||
| import ( | |||||
| "fmt" | |||||
| "strconv" | |||||
| "strings" | |||||
| "github.com/chzyer/readline" | |||||
| "github.com/spf13/cobra" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||||
| cortypes "gitlink.org.cn/cloudream/jcs-pub/coordinator/types" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" | |||||
| ) | |||||
| type MyUserSpace struct { | |||||
| api.UserSpaceCreate | |||||
| } | |||||
| func init() { | |||||
| cmd := cobra.Command{ | |||||
| Use: "create", | |||||
| Short: "add a new cloud storage", | |||||
| Run: func(c *cobra.Command, args []string) { | |||||
| ctx := cmd.GetCmdCtx(c) | |||||
| create(c, ctx) | |||||
| }, | |||||
| } | |||||
| UserSpaceCmd.AddCommand(&cmd) | |||||
| } | |||||
| func create(c *cobra.Command, ctx *cmd.CommandContext) { | |||||
| var userSpace MyUserSpace | |||||
| rl, err := readline.New("> ") | |||||
| if err != nil { | |||||
| fmt.Printf("初始化命令行失败: %v\n", err) | |||||
| return | |||||
| } | |||||
| defer rl.Close() | |||||
| rl.SetPrompt("\033[36m请输入存储服务名称(Name): \033[0m") | |||||
| name, err := rl.Readline() | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| userSpace.Name = name | |||||
| storageType, err := promptSelectStorage() | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| switch storageType { | |||||
| case "Local": | |||||
| err = userSpace.collectLocalConfig(rl) | |||||
| case "OBS": | |||||
| err = userSpace.collectObsConfig(rl) | |||||
| case "OSS": | |||||
| err = userSpace.collectOssConfig(rl) | |||||
| case "COS": | |||||
| err = userSpace.collectCosConfig(rl) | |||||
| case "EFile": | |||||
| err = userSpace.collectEfileConfig(rl) | |||||
| case "S3": | |||||
| err = userSpace.collectS3Config(rl) | |||||
| } | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| err = userSpace.collectShardStore(rl) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| err = userSpace.collectWorkingDir(rl) | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| _, err = ctx.Client.UserSpaceCreate(userSpace.UserSpaceCreate) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m保存配置失败: %v\033[0m", err) | |||||
| return | |||||
| } | |||||
| fmt.Println("\033[32m配置保存成功!\033[0m") | |||||
| } | |||||
| func promptSelectStorage() (string, error) { | |||||
| rl, _ := readline.NewEx(&readline.Config{ | |||||
| Prompt: "\033[36m»\033[0m ", | |||||
| HistoryFile: "/tmp/storage_history.txt", | |||||
| InterruptPrompt: "^C", | |||||
| }) | |||||
| defer rl.Close() | |||||
| fmt.Println("\033[1;36m请选择存储类型(StorageType):\033[0m") | |||||
| options := []string{"Local", "OBS", "OSS", "COS", "EFile", "S3"} | |||||
| for i, option := range options { | |||||
| fmt.Printf("\033[33m%d. %s\033[0m\n", i+1, option) | |||||
| } | |||||
| for { | |||||
| line, err := rl.Readline() | |||||
| if err != nil { | |||||
| return "", err | |||||
| } | |||||
| trimmed := strings.TrimSpace(line) | |||||
| switch trimmed { | |||||
| case "1": | |||||
| return "Local", nil | |||||
| case "2": | |||||
| return "OBS", nil | |||||
| case "3": | |||||
| return "OSS", nil | |||||
| case "4": | |||||
| return "COS", nil | |||||
| case "5": | |||||
| return "EFile", nil | |||||
| case "6": | |||||
| return "S3", nil | |||||
| default: | |||||
| fmt.Printf("\033[31m错误: 无效选项 '%s',请输入序号!\033[0m\n", line) | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectLocalConfig(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入StorageName: \033[0m") | |||||
| storageName, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Location: \033[0m") | |||||
| location, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入RootDir: \033[0m") | |||||
| rootDir, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| userSpace.Storage = &cortypes.LocalType{ | |||||
| Type: "Local", | |||||
| Location: cortypes.Location{ | |||||
| StorageName: storageName, | |||||
| Location: location, | |||||
| }, | |||||
| } | |||||
| userSpace.Credential = &cortypes.LocalCred{ | |||||
| Type: "Local", | |||||
| RootDir: rootDir, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectObsConfig(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入Region: \033[0m") | |||||
| region, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Endpoint: \033[0m") | |||||
| endpoint, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Bucket: \033[0m") | |||||
| bucket, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入ProjectID: \033[0m") | |||||
| projectID, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Storage = &cortypes.OBSType{ | |||||
| Type: "OBS", | |||||
| Region: region, | |||||
| Endpoint: endpoint, | |||||
| Bucket: bucket, | |||||
| ProjectID: projectID, | |||||
| } | |||||
| userSpace.Credential = &cortypes.OBSCred{ | |||||
| Type: "OBS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否支持存储服务间直传文件?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.S2STransferFeature{ | |||||
| Type: "S2STransfer", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| fmt.Println("\033[36m不支持存储服务间直传文件 \033[0m") | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectOssConfig(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入Region: \033[0m") | |||||
| region, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Endpoint: \033[0m") | |||||
| endpoint, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Bucket: \033[0m") | |||||
| bucket, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Storage = &cortypes.OSSType{ | |||||
| Region: region, | |||||
| Endpoint: endpoint, | |||||
| Bucket: bucket, | |||||
| } | |||||
| userSpace.Credential = &cortypes.OSSCred{ | |||||
| Type: "OSS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectCosConfig(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入Region: \033[0m") | |||||
| region, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Endpoint: \033[0m") | |||||
| endpoint, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Bucket: \033[0m") | |||||
| bucket, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Storage = &cortypes.COSType{ | |||||
| Type: "COS", | |||||
| Region: region, | |||||
| Endpoint: endpoint, | |||||
| Bucket: bucket, | |||||
| } | |||||
| userSpace.Credential = &cortypes.COSCred{ | |||||
| Type: "COS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectEfileConfig(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入ClusterID: \033[0m") | |||||
| clusterID, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入TokenURL: \033[0m") | |||||
| tokenURL, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入APIURL: \033[0m") | |||||
| apiURL, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| tokenExpire := 0 | |||||
| for { | |||||
| rl.SetPrompt("\033[36m请输入TokenExpire: \033[0m") | |||||
| valueInt, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| if strings.TrimSpace(valueInt) == "" { | |||||
| fmt.Println("\033[31m错误:输入不能为空,请输入正整数\033[0m") | |||||
| continue | |||||
| } | |||||
| num, err := strconv.ParseInt(valueInt, 10, 64) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m错误:'%s' 不是有效整数,请输入正整数\033[0m\n", valueInt) | |||||
| continue | |||||
| } | |||||
| if num <= 0 { | |||||
| fmt.Printf("\033[31m错误:%d 不是正整数,请输入大于 0 的整数\033[0m\n", num) | |||||
| continue | |||||
| } | |||||
| tokenExpire = int(num) | |||||
| break | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入User: \033[0m") | |||||
| user, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| passwordBytes, err := rl.ReadPassword("\033[36m请输入Password: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| password := string(passwordBytes) | |||||
| rl.SetPrompt("\033[36m请输入OrgID: \033[0m") | |||||
| orgID, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| userSpace.Storage = &cortypes.EFileType{ | |||||
| Type: "EFile", | |||||
| ClusterID: clusterID, | |||||
| } | |||||
| userSpace.Credential = &cortypes.EFileCred{ | |||||
| Type: "EFile", | |||||
| TokenURL: tokenURL, | |||||
| APIURL: apiURL, | |||||
| TokenExpire: tokenExpire, | |||||
| User: user, | |||||
| Password: password, | |||||
| OrgID: orgID, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否提供能进行EC计算的接口?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.ECMultiplierFeature{ | |||||
| Type: "ECMultiplier", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| fmt.Println("\033[36m未提供能进行EC计算的接口 \033[0m") | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectS3Config(rl *readline.Instance) error { | |||||
| var err error | |||||
| rl.SetPrompt("\033[36m请输入Region: \033[0m") | |||||
| region, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Endpoint: \033[0m") | |||||
| endpoint, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入Bucket: \033[0m") | |||||
| bucket, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Storage = &cortypes.S3Type{ | |||||
| Type: "S3", | |||||
| Region: region, | |||||
| Endpoint: endpoint, | |||||
| Bucket: bucket, | |||||
| } | |||||
| userSpace.Credential = &cortypes.S3Cred{ | |||||
| Type: "S3", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否支持分段上传?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.MultipartUploadFeature{ | |||||
| Type: "MultipartUpload", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| fmt.Println("\033[36m不支持分段上传 \033[0m") | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectShardStore(rl *readline.Instance) error { | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否开启分片存储功能?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| for { | |||||
| rl.SetPrompt("\033[36m请输入最大Size: \033[0m") | |||||
| sizeInput, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| if strings.TrimSpace(sizeInput) == "" { | |||||
| fmt.Println("\033[31m错误:输入不能为空31m错误:输入不能为空,请输入正整数\033[0m") | |||||
| continue | |||||
| } | |||||
| maxSize, err := strconv.ParseInt(sizeInput, 10, 64) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m错误:'%s' 不是有效整数,请输入正整数\033[0m\n", sizeInput) | |||||
| continue | |||||
| } | |||||
| if maxSize <= 0 { | |||||
| fmt.Printf("\033[31m错误:%d 不是正整数,请输入大于 0 的整数\033[0m\n", maxSize) | |||||
| continue | |||||
| } | |||||
| userSpace.ShardStore = &cortypes.ShardStoreUserConfig{ | |||||
| MaxSize: maxSize, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| case "n", "no": | |||||
| fmt.Println("\033[31m分片存储未启用 \033[0m") | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *MyUserSpace) collectWorkingDir(rl *readline.Instance) error { | |||||
| for { | |||||
| rl.SetPrompt("\033[36m默认工作路径(WorkingDir)为jcs,是否修改?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| rl.SetPrompt("\033[36m请输入新的工作路径(WorkingDir): \033[0m") | |||||
| newValue, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| if newValue != "" { | |||||
| userSpace.WorkingDir = newValue | |||||
| } | |||||
| return nil | |||||
| case "n", "no": | |||||
| userSpace.WorkingDir = "jcs" | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,111 @@ | |||||
| package userspace | |||||
| import ( | |||||
| "fmt" | |||||
| "strconv" | |||||
| "strings" | |||||
| "github.com/chzyer/readline" | |||||
| "github.com/spf13/cobra" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" | |||||
| ) | |||||
| func init() { | |||||
| cmd := cobra.Command{ | |||||
| Use: "delete", | |||||
| Short: "delete a cloud storage", | |||||
| Run: func(c *cobra.Command, args []string) { | |||||
| ctx := cmd.GetCmdCtx(c) | |||||
| delete(c, ctx) | |||||
| }, | |||||
| } | |||||
| UserSpaceCmd.AddCommand(&cmd) | |||||
| } | |||||
| func delete(c *cobra.Command, ctx *cmd.CommandContext) { | |||||
| rl, err := readline.New("> ") | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m初始化命令行失败: %v\033[0m\n", err) | |||||
| return | |||||
| } | |||||
| defer rl.Close() | |||||
| fmt.Printf("\033[1;36m请选择删除依据: \033[0m\n") | |||||
| options := []string{"ID", "Name"} | |||||
| for i, option := range options { | |||||
| fmt.Printf("\033[33m%d. %s\033[0m\n", i+1, option) | |||||
| } | |||||
| rl.SetPrompt("\033[36m> \033[0m") | |||||
| line, err := rl.Readline() | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| var userSpace clitypes.UserSpace | |||||
| trimmed := strings.TrimSpace(line) | |||||
| switch trimmed { | |||||
| case "1": | |||||
| rl.SetPrompt("\033[36m请输入云存储ID(ID): \033[0m") | |||||
| idInput, err := rl.Readline() | |||||
| if err != nil || idInput == "" { | |||||
| return | |||||
| } | |||||
| id, err := strconv.ParseInt(strings.TrimSpace(idInput), 10, 64) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31mID 格式错误: %v\033[0m\n", err) | |||||
| return | |||||
| } | |||||
| resp, err := ctx.Client.UserSpaceGet(cliapi.UserSpaceGet{ | |||||
| UserSpaceID: clitypes.UserSpaceID(id), | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m保存配置失败: %v\033[0m", err) | |||||
| return | |||||
| } | |||||
| userSpace = resp.UserSpace | |||||
| case "2": | |||||
| rl.SetPrompt("\033[36m请输入云存储名称(Name): \033[0m") | |||||
| nameInput, err := rl.Readline() | |||||
| if err != nil || nameInput == "" { | |||||
| fmt.Println("\033[31m输入已取消\033[0m") | |||||
| return | |||||
| } | |||||
| name := strings.TrimSpace(nameInput) | |||||
| resp, err := ctx.Client.UserSpaceGetByName(cliapi.UserSpaceGetByName{ | |||||
| Name: name, | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m保存配置失败: %v\033[0m", err) | |||||
| return | |||||
| } | |||||
| userSpace = resp.UserSpace | |||||
| default: | |||||
| fmt.Printf("\033[31m错误: 无效选项 '%s',请输入序号!\033[0m\n", line) | |||||
| } | |||||
| fmt.Println("\n\033[1;36m找到云存储:\033[0m") | |||||
| fmt.Printf("\033[1;36mID:%d 名称:%s 类型:%s\033[0m\n", userSpace.UserSpaceID, userSpace.Name, userSpace.Storage.GetStorageType()) | |||||
| rl.SetPrompt("\033[31m确认删除?(y/n): \033[0m") | |||||
| confirm, err := rl.Readline() | |||||
| if err != nil || strings.ToLower(strings.TrimSpace(confirm)) != "y" { | |||||
| return | |||||
| } | |||||
| _, err = ctx.Client.UserSpaceDelete(cliapi.UserSpaceDelete{ | |||||
| UserSpaceID: userSpace.UserSpaceID, | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m删除失败: %v\033[0m\n", err) | |||||
| return | |||||
| } | |||||
| fmt.Printf("\n\033[32m删除成功: %s\033[0m\n", userSpace.Name) | |||||
| } | |||||
| @@ -0,0 +1,106 @@ | |||||
| package userspace | |||||
| import ( | |||||
| "fmt" | |||||
| "strconv" | |||||
| "github.com/jedib0t/go-pretty/v6/table" | |||||
| "github.com/spf13/cobra" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" | |||||
| ) | |||||
| func init() { | |||||
| var opt lsOpt | |||||
| cmd := cobra.Command{ | |||||
| Use: "ls", | |||||
| Args: cobra.MaximumNArgs(1), | |||||
| Run: func(c *cobra.Command, args []string) { | |||||
| ctx := cmd.GetCmdCtx(c) | |||||
| ls(c, ctx, opt, args) | |||||
| }, | |||||
| } | |||||
| cmd.Flags().BoolVarP(&opt.ByID, "id", "", false, "按id查询") | |||||
| cmd.Flags().BoolVarP(&opt.ShowPassword, "password", "p", false, "显示密码信息,请在安全环境下使用") | |||||
| UserSpaceCmd.AddCommand(&cmd) | |||||
| } | |||||
| type lsOpt struct { | |||||
| ByID bool | |||||
| ShowPassword bool | |||||
| } | |||||
| func ls(c *cobra.Command, ctx *cmd.CommandContext, opt lsOpt, args []string) { | |||||
| // 仅ls无参数 | |||||
| if len(args) == 0 { | |||||
| resp, err := ctx.Client.UserSpaceGetAll() | |||||
| if err != nil { | |||||
| cmd.ErrorExitln(err.Error()) | |||||
| return | |||||
| } | |||||
| fmt.Printf("total: %d\n", len(resp.UserSpaces)) | |||||
| tb := table.NewWriter() | |||||
| tb.AppendHeader(table.Row{"ID", "Name", "StorageType"}) | |||||
| for _, userSpace := range resp.UserSpaces { | |||||
| tb.AppendRow(table.Row{userSpace.UserSpaceID, userSpace.Name, userSpace.Storage.GetStorageType()}) | |||||
| } | |||||
| fmt.Println(tb.Render()) | |||||
| return | |||||
| } | |||||
| searchKey := args[0] | |||||
| var userSpace *clitypes.UserSpace | |||||
| if opt.ByID { | |||||
| id, err := strconv.Atoi(searchKey) | |||||
| if err != nil { | |||||
| cmd.ErrorExitln("ID必须是数字") | |||||
| return | |||||
| } | |||||
| result, err := ctx.Client.UserSpaceGet(cliapi.UserSpaceGet{ | |||||
| UserSpaceID: clitypes.UserSpaceID(id), | |||||
| }) | |||||
| if err != nil { | |||||
| cmd.ErrorExitln(err.Error()) | |||||
| return | |||||
| } | |||||
| userSpace = &result.UserSpace | |||||
| } else { | |||||
| result, err := ctx.Client.UserSpaceGetByName(cliapi.UserSpaceGetByName{ | |||||
| Name: searchKey, | |||||
| }) | |||||
| if err != nil { | |||||
| cmd.ErrorExitln(err.Error()) | |||||
| return | |||||
| } | |||||
| userSpace = &result.UserSpace | |||||
| } | |||||
| if userSpace == nil { | |||||
| cmd.ErrorExitln(fmt.Sprintf("未找到匹配的云存储: %s", searchKey)) | |||||
| return | |||||
| } | |||||
| fmt.Println("\n\033[1;36m云存储详情\033[0m") | |||||
| fmt.Println("----------------------------------") | |||||
| fmt.Printf("\033[1m%-8s\033[0m %d\n", "ID:", userSpace.UserSpaceID) | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "名称:", userSpace.Name) | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "类型:", userSpace.Storage.GetStorageType()) | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "Location:", userSpace.Storage.GetLocation().Location) | |||||
| if opt.ShowPassword { | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "Credential:", userSpace.Credential.String(true)) | |||||
| } else { | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "Credential:", userSpace.Credential.String(false)) | |||||
| } | |||||
| if len(userSpace.Features) > 0 { | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "Features:", userSpace.Features[0].GetFeatureType()) | |||||
| } | |||||
| fmt.Printf("\033[1m%-8s\033[0m %s\n", "WorkingDir:", userSpace.WorkingDir) | |||||
| fmt.Println("----------------------------------") | |||||
| } | |||||
| @@ -0,0 +1,321 @@ | |||||
| package userspace | |||||
| import ( | |||||
| "fmt" | |||||
| "strconv" | |||||
| "strings" | |||||
| "github.com/chzyer/readline" | |||||
| "github.com/spf13/cobra" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | |||||
| clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| cortypes "gitlink.org.cn/cloudream/jcs-pub/coordinator/types" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" | |||||
| ) | |||||
| type UserSpaceUpdate struct { | |||||
| api.UserSpaceUpdate | |||||
| } | |||||
| func init() { | |||||
| cmd := cobra.Command{ | |||||
| Use: "update", | |||||
| Short: "update a new cloud storage", | |||||
| Run: func(c *cobra.Command, args []string) { | |||||
| ctx := cmd.GetCmdCtx(c) | |||||
| update(c, ctx) | |||||
| }, | |||||
| } | |||||
| UserSpaceCmd.AddCommand(&cmd) | |||||
| } | |||||
| func update(c *cobra.Command, ctx *cmd.CommandContext) { | |||||
| rl, err := readline.New("> ") | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m初始化命令行失败: %v\033[0m\n", err) | |||||
| return | |||||
| } | |||||
| defer rl.Close() | |||||
| rl.SetPrompt("\033[36m请输入云存储ID(ID): \033[0m") | |||||
| idInput, err := rl.Readline() | |||||
| if err != nil || idInput == "" { | |||||
| return | |||||
| } | |||||
| id, err := strconv.ParseInt(strings.TrimSpace(idInput), 10, 64) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31mID 格式错误: %v\033[0m\n", err) | |||||
| return | |||||
| } | |||||
| resp, err := ctx.Client.UserSpaceGet(cliapi.UserSpaceGet{ | |||||
| UserSpaceID: clitypes.UserSpaceID(id), | |||||
| }) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m云存储id=%d 不存在: %v\033[0m\n", id, err) | |||||
| return | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入修改后的存储服务名称(Name): \033[0m") | |||||
| name, err := rl.Readline() | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| var userSpaceUpdate UserSpaceUpdate | |||||
| userSpaceUpdate.UserSpaceID = clitypes.UserSpaceID(id) | |||||
| userSpaceUpdate.Name = name | |||||
| storageType := resp.UserSpace.Storage.GetStorageType() | |||||
| switch storageType { | |||||
| case "Local": | |||||
| err = userSpaceUpdate.collectLocalConfig(rl) | |||||
| case "OBS": | |||||
| err = userSpaceUpdate.collectObsConfig(rl) | |||||
| case "OSS": | |||||
| err = userSpaceUpdate.collectOssConfig(rl) | |||||
| case "COS": | |||||
| err = userSpaceUpdate.collectCosConfig(rl) | |||||
| case "EFile": | |||||
| err = userSpaceUpdate.collectEfileConfig(rl) | |||||
| case "S3": | |||||
| err = userSpaceUpdate.collectS3Config(rl) | |||||
| } | |||||
| if err != nil { | |||||
| return | |||||
| } | |||||
| _, err = ctx.Client.UserSpaceUpdate(userSpaceUpdate.UserSpaceUpdate) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m更新配置失败: %v\033[0m", err) | |||||
| return | |||||
| } | |||||
| fmt.Println("\033[32m配置更新成功!\033[0m") | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectLocalConfig(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入RootDir: \033[0m") | |||||
| rootDir, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| userSpace.Credential = &cortypes.LocalCred{ | |||||
| Type: "Local", | |||||
| RootDir: rootDir, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectObsConfig(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Credential = &cortypes.OBSCred{ | |||||
| Type: "OBS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否支持存储服务间直传文件?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.S2STransferFeature{ | |||||
| Type: "S2STransfer", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| userSpace.Features = nil | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectOssConfig(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Credential = &cortypes.OSSCred{ | |||||
| Type: "OSS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectCosConfig(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Credential = &cortypes.COSCred{ | |||||
| Type: "COS", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectEfileConfig(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入TokenURL: \033[0m") | |||||
| tokenURL, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入APIURL: \033[0m") | |||||
| apiURL, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| tokenExpire := 0 | |||||
| for { | |||||
| rl.SetPrompt("\033[36m请输入TokenExpire: \033[0m") | |||||
| valueInt, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| if strings.TrimSpace(valueInt) == "" { | |||||
| fmt.Println("\033[31m错误:输入不能为空,请输入正整数\033[0m") | |||||
| continue | |||||
| } | |||||
| num, err := strconv.ParseInt(valueInt, 10, 64) | |||||
| if err != nil { | |||||
| fmt.Printf("\033[31m错误:'%s' 不是有效整数,请输入正整数\033[0m\n", valueInt) | |||||
| continue | |||||
| } | |||||
| if num <= 0 { | |||||
| fmt.Printf("\033[31m错误:%d 不是正整数,请输入大于 0 的整数\033[0m\n", num) | |||||
| continue | |||||
| } | |||||
| tokenExpire = int(num) | |||||
| break | |||||
| } | |||||
| rl.SetPrompt("\033[36m请输入User: \033[0m") | |||||
| user, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| passwordBytes, err := rl.ReadPassword("\033[36m请输入Password: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| password := string(passwordBytes) | |||||
| rl.SetPrompt("\033[36m请输入OrgID: \033[0m") | |||||
| orgID, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| userSpace.Credential = &cortypes.EFileCred{ | |||||
| Type: "EFile", | |||||
| TokenURL: tokenURL, | |||||
| APIURL: apiURL, | |||||
| TokenExpire: tokenExpire, | |||||
| User: user, | |||||
| Password: password, | |||||
| OrgID: orgID, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否提供能进行EC计算的接口?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.ECMultiplierFeature{ | |||||
| Type: "ECMultiplier", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| userSpace.Features = nil | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| func (userSpace *UserSpaceUpdate) collectS3Config(rl *readline.Instance) error { | |||||
| rl.SetPrompt("\033[36m请输入AccessKeyID: \033[0m") | |||||
| accessKey, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretBytes, err := rl.ReadPassword("\033[36m请输入AccessKeySecret: \033[0m") | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| secretKey := string(secretBytes) | |||||
| userSpace.Credential = &cortypes.S3Cred{ | |||||
| Type: "S3", | |||||
| AK: accessKey, | |||||
| SK: secretKey, | |||||
| } | |||||
| for { | |||||
| rl.SetPrompt("\033[36m是否支持分段上传?(y/n): \033[0m") | |||||
| input, err := rl.Readline() | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| switch strings.ToLower(strings.TrimSpace(input)) { | |||||
| case "y", "yes": | |||||
| userSpace.Features = append(userSpace.Features, &cortypes.MultipartUploadFeature{ | |||||
| Type: "MultipartUpload", | |||||
| }) | |||||
| return nil | |||||
| case "n", "no": | |||||
| userSpace.Features = nil | |||||
| return nil | |||||
| default: | |||||
| fmt.Println("\033[31m无效输入!请输入 y/n 或 yes/no \033[0m") | |||||
| } | |||||
| } | |||||
| } | |||||
| @@ -0,0 +1,14 @@ | |||||
| package userspace | |||||
| import ( | |||||
| "github.com/spf13/cobra" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/jcsctl/cmd" | |||||
| ) | |||||
| var UserSpaceCmd = &cobra.Command{ | |||||
| Use: "userspace", | |||||
| } | |||||
| func init() { | |||||
| cmd.RootCmd.AddCommand(UserSpaceCmd) | |||||
| } | |||||