| @@ -0,0 +1,219 @@ | |||||
| package cmdline | |||||
| import ( | |||||
| "crypto/ecdsa" | |||||
| "crypto/elliptic" | |||||
| "crypto/rand" | |||||
| "crypto/x509" | |||||
| "crypto/x509/pkix" | |||||
| "encoding/pem" | |||||
| "fmt" | |||||
| "math/big" | |||||
| "os" | |||||
| "path/filepath" | |||||
| "time" | |||||
| "github.com/spf13/cobra" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||||
| ) | |||||
| func init() { | |||||
| certCmd := cobra.Command{ | |||||
| Use: "cert", | |||||
| } | |||||
| RootCmd.AddCommand(&certCmd) | |||||
| certRoot := cobra.Command{ | |||||
| Use: "root [outputDir]", | |||||
| Args: cobra.ExactArgs(1), | |||||
| Run: func(cmd *cobra.Command, args []string) { | |||||
| certRoot(args[0]) | |||||
| }, | |||||
| } | |||||
| certCmd.AddCommand(&certRoot) | |||||
| var certFilePath string | |||||
| var keyFilePath string | |||||
| certServer := cobra.Command{ | |||||
| Use: "server [outputDir]", | |||||
| Args: cobra.ExactArgs(1), | |||||
| Run: func(cmd *cobra.Command, args []string) { | |||||
| certServer(certFilePath, keyFilePath, args[0]) | |||||
| }, | |||||
| } | |||||
| certServer.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path") | |||||
| certServer.Flags().StringVar(&keyFilePath, "key", "", "CA key file path") | |||||
| certCmd.AddCommand(&certServer) | |||||
| certClient := cobra.Command{ | |||||
| Use: "client [outputDir]", | |||||
| Args: cobra.ExactArgs(1), | |||||
| Run: func(cmd *cobra.Command, args []string) { | |||||
| certClient(certFilePath, keyFilePath, args[0]) | |||||
| }, | |||||
| } | |||||
| certClient.Flags().StringVar(&certFilePath, "cert", "", "CA certificate file path") | |||||
| certClient.Flags().StringVar(&keyFilePath, "key", "", "CA key file path") | |||||
| certCmd.AddCommand(&certClient) | |||||
| } | |||||
| func certRoot(output string) { | |||||
| caPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 创建 CA 证书模板 | |||||
| caTemplate := &x509.Certificate{ | |||||
| SerialNumber: big.NewInt(1), | |||||
| Subject: pkix.Name{ | |||||
| Organization: []string{"JCS"}, | |||||
| }, | |||||
| NotBefore: time.Now(), | |||||
| NotAfter: time.Now().AddDate(10, 0, 0), // 有效期10年 | |||||
| KeyUsage: x509.KeyUsageCertSign | x509.KeyUsageDigitalSignature, | |||||
| BasicConstraintsValid: true, | |||||
| IsCA: true, | |||||
| } | |||||
| // 自签名 CA 证书 | |||||
| caCertDER, _ := x509.CreateCertificate(rand.Reader, caTemplate, caTemplate, &caPriv.PublicKey, caPriv) | |||||
| // 保存 CA 证书和私钥 | |||||
| writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER) | |||||
| privDER, _ := x509.MarshalECPrivateKey(caPriv) | |||||
| writePem(filepath.Join(output, "ca_key.pem"), "EC PRIVATE KEY", privDER) | |||||
| fmt.Println("CA certificate and key saved to", output) | |||||
| } | |||||
| func certServer(certFile string, keyFile string, output string) { | |||||
| // 读取 CA 证书和私钥 | |||||
| caCertPEM, err := os.ReadFile(certFile) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to read CA certificate:", err) | |||||
| return | |||||
| } | |||||
| caKeyPEM, err := os.ReadFile(keyFile) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to read CA key:", err) | |||||
| return | |||||
| } | |||||
| caCertPEMBlock, _ := pem.Decode(caCertPEM) | |||||
| if caCertPEMBlock == nil { | |||||
| fmt.Println("Failed to decode CA certificate") | |||||
| return | |||||
| } | |||||
| caKeyPEMBlock, _ := pem.Decode(caKeyPEM) | |||||
| if caKeyPEMBlock == nil { | |||||
| fmt.Println("Failed to decode CA key") | |||||
| return | |||||
| } | |||||
| caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to parse CA certificate:", err) | |||||
| return | |||||
| } | |||||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to parse CA key:", err) | |||||
| return | |||||
| } | |||||
| // 生成服务端私钥 | |||||
| serverPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 服务端证书模板 | |||||
| serverTemplate := &x509.Certificate{ | |||||
| SerialNumber: big.NewInt(2), | |||||
| Subject: pkix.Name{ | |||||
| CommonName: "localhost", | |||||
| }, | |||||
| NotBefore: time.Now(), | |||||
| NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年 | |||||
| KeyUsage: x509.KeyUsageDigitalSignature, | |||||
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth}, | |||||
| BasicConstraintsValid: true, | |||||
| } | |||||
| // 添加主机名/IP 到证书 | |||||
| serverTemplate.DNSNames = []string{auth.ClientInternalSNI} | |||||
| // 用 CA 签发服务端证书 | |||||
| serverCertDER, _ := x509.CreateCertificate(rand.Reader, serverTemplate, caCert, &serverPriv.PublicKey, caKey) | |||||
| // 保存服务端证书和私钥 | |||||
| writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER) | |||||
| privPem, _ := x509.MarshalECPrivateKey(serverPriv) | |||||
| writePem(filepath.Join(output, "server_key.pem"), "EC PRIVATE KEY", privPem) | |||||
| fmt.Println("Server certificate and key saved to", output) | |||||
| } | |||||
| func certClient(certFile string, keyFile string, output string) { | |||||
| // 读取 CA 证书和私钥 | |||||
| caCertPEM, err := os.ReadFile(certFile) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to read CA certificate:", err) | |||||
| return | |||||
| } | |||||
| caKeyPEM, err := os.ReadFile(keyFile) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to read CA key:", err) | |||||
| return | |||||
| } | |||||
| caCertPEMBlock, _ := pem.Decode(caCertPEM) | |||||
| if caCertPEMBlock == nil { | |||||
| fmt.Println("Failed to decode CA certificate") | |||||
| return | |||||
| } | |||||
| caKeyPEMBlock, _ := pem.Decode(caKeyPEM) | |||||
| if caKeyPEMBlock == nil { | |||||
| fmt.Println("Failed to decode CA key") | |||||
| return | |||||
| } | |||||
| caCert, err := x509.ParseCertificate(caCertPEMBlock.Bytes) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to parse CA certificate:", err) | |||||
| return | |||||
| } | |||||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||||
| if err != nil { | |||||
| fmt.Println("Failed to parse CA key:", err) | |||||
| return | |||||
| } | |||||
| // 生成客户端私钥 | |||||
| clientPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 客户端证书模板 | |||||
| clientTemplate := &x509.Certificate{ | |||||
| SerialNumber: big.NewInt(3), | |||||
| Subject: pkix.Name{ | |||||
| CommonName: "client", | |||||
| }, | |||||
| NotBefore: time.Now(), | |||||
| NotAfter: time.Now().AddDate(1, 0, 0), // 有效期1年 | |||||
| KeyUsage: x509.KeyUsageDigitalSignature, | |||||
| ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth}, | |||||
| BasicConstraintsValid: true, | |||||
| } | |||||
| // 用 CA 签发客户端证书 | |||||
| clientCertDER, _ := x509.CreateCertificate(rand.Reader, clientTemplate, caCert, &clientPriv.PublicKey, caKey) | |||||
| // 保存客户端证书和私钥 | |||||
| writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER) | |||||
| privPem, _ := x509.MarshalECPrivateKey(clientPriv) | |||||
| writePem(filepath.Join(output, "client_key.pem"), "EC PRIVATE KEY", privPem) | |||||
| fmt.Println("Client certificate and key saved to", output) | |||||
| } | |||||
| func writePem(filename, pemType string, bytes []byte) { | |||||
| f, _ := os.Create(filename) | |||||
| pem.Encode(f, &pem.Block{Type: pemType, Bytes: bytes}) | |||||
| f.Close() | |||||
| } | |||||
| @@ -192,13 +192,20 @@ func serveHTTP(configPath string, opts serveHTTPOptions) { | |||||
| svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | ||||
| // HTTP接口 | // HTTP接口 | ||||
| httpCfg := config.Cfg().HTTP | |||||
| if !opts.DisableHTTP && httpCfg != nil && httpCfg.Enabled { | |||||
| httpCfgJSON := config.Cfg().HTTP | |||||
| if !opts.DisableHTTP && httpCfgJSON != nil && httpCfgJSON.Enabled { | |||||
| if opts.HTTPListenAddr != "" { | if opts.HTTPListenAddr != "" { | ||||
| httpCfg.Listen = opts.HTTPListenAddr | |||||
| httpCfgJSON.Listen = opts.HTTPListenAddr | |||||
| } | } | ||||
| } else { | } else { | ||||
| httpCfg = nil | |||||
| httpCfgJSON = &http.ConfigJSON{ | |||||
| Enabled: false, | |||||
| } | |||||
| } | |||||
| httpCfg, err := httpCfgJSON.Build() | |||||
| if err != nil { | |||||
| logger.Errorf("build http config: %v", err) | |||||
| os.Exit(1) | |||||
| } | } | ||||
| httpSvr := http.NewServer(httpCfg, svc) | httpSvr := http.NewServer(httpCfg, svc) | ||||
| httpChan := httpSvr.Start() | httpChan := httpSvr.Start() | ||||
| @@ -174,13 +174,20 @@ func vfsTest(configPath string, opts serveHTTPOptions) { | |||||
| svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | svc := services.NewService(publock, dlder, acStat, uploader, strgSel, stgMeta, db, evtPub, mnt, stgPool) | ||||
| // HTTP接口 | // HTTP接口 | ||||
| httpCfg := config.Cfg().HTTP | |||||
| if !opts.DisableHTTP && httpCfg != nil && httpCfg.Enabled { | |||||
| httpCfgJSON := config.Cfg().HTTP | |||||
| if !opts.DisableHTTP && httpCfgJSON != nil && httpCfgJSON.Enabled { | |||||
| if opts.HTTPListenAddr != "" { | if opts.HTTPListenAddr != "" { | ||||
| httpCfg.Listen = opts.HTTPListenAddr | |||||
| httpCfgJSON.Listen = opts.HTTPListenAddr | |||||
| } | } | ||||
| } else { | } else { | ||||
| httpCfg = nil | |||||
| httpCfgJSON = &http.ConfigJSON{ | |||||
| Enabled: false, | |||||
| } | |||||
| } | |||||
| httpCfg, err := httpCfgJSON.Build() | |||||
| if err != nil { | |||||
| logger.Errorf("build http config: %v", err) | |||||
| os.Exit(1) | |||||
| } | } | ||||
| httpSvr := http.NewServer(httpCfg, svc) | httpSvr := http.NewServer(httpCfg, svc) | ||||
| httpChan := httpSvr.Start() | httpChan := httpSvr.Start() | ||||
| @@ -28,7 +28,7 @@ type Config struct { | |||||
| Downloader downloader.Config `json:"downloader"` | Downloader downloader.Config `json:"downloader"` | ||||
| DownloadStrategy strategy.Config `json:"downloadStrategy"` | DownloadStrategy strategy.Config `json:"downloadStrategy"` | ||||
| TickTock ticktock.Config `json:"tickTock"` | TickTock ticktock.Config `json:"tickTock"` | ||||
| HTTP *http.Config `json:"http"` | |||||
| HTTP *http.ConfigJSON `json:"http"` | |||||
| Mount *mntcfg.Config `json:"mount"` | Mount *mntcfg.Config `json:"mount"` | ||||
| AccessToken *accesstoken.Config `json:"accessToken"` | AccessToken *accesstoken.Config `json:"accessToken"` | ||||
| } | } | ||||
| @@ -0,0 +1,80 @@ | |||||
| package auth | |||||
| import ( | |||||
| "crypto/tls" | |||||
| "github.com/gin-gonic/gin" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/signer" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | |||||
| const ( | |||||
| ClientInternalSNI = "client.jcs-pub.internal" | |||||
| ) | |||||
| type Auth struct { | |||||
| cfg *types.Config | |||||
| } | |||||
| func New(cfg *types.Config) *Auth { | |||||
| return &Auth{ | |||||
| cfg: cfg, | |||||
| } | |||||
| } | |||||
| func (a *Auth) TLSConfigSelector(hello *tls.ClientHelloInfo) (*tls.Config, error) { | |||||
| switch hello.ServerName { | |||||
| case ClientInternalSNI: | |||||
| return &tls.Config{ | |||||
| Certificates: []tls.Certificate{a.cfg.ServerCert}, | |||||
| ClientAuth: tls.RequireAndVerifyClientCert, | |||||
| ClientCAs: a.cfg.RootCA, | |||||
| NextProtos: []string{"h2", "http/1.1"}, | |||||
| }, nil | |||||
| default: | |||||
| return &tls.Config{ | |||||
| Certificates: []tls.Certificate{a.cfg.ServerCert}, | |||||
| ClientAuth: tls.NoClientCert, | |||||
| NextProtos: []string{"h2", "http/1.1"}, | |||||
| }, nil | |||||
| } | |||||
| } | |||||
| func (a *Auth) RejectNoCertAuth(c *gin.Context) { | |||||
| if c.Request.TLS == nil || c.Request.TLS.ServerName != ClientInternalSNI { | |||||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "must provide client certificate")) | |||||
| return | |||||
| } | |||||
| c.Next() | |||||
| } | |||||
| func (a *Auth) Presigned(c *gin.Context) { | |||||
| log := logger.WithField("HTTP", "Auth") | |||||
| accID := signer.GetAccessKeyID(c.Request.URL) | |||||
| if accID == "" { | |||||
| log.Warn("access key id not found in query string") | |||||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "access key id not found in query string")) | |||||
| return | |||||
| } | |||||
| cliCert := a.cfg.ClientCerts[accID] | |||||
| if cliCert == nil { | |||||
| log.Warnf("client cert not found for access key id %s", accID) | |||||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, "client cert not found for access key id %s", accID)) | |||||
| return | |||||
| } | |||||
| err := signer.VerifyPresigned(cliCert.VerifyKey, c.Request.Method, c.Request.URL) | |||||
| if err != nil { | |||||
| log.Warn(err.Error()) | |||||
| c.AbortWithStatusJSON(401, types.Failed(ecode.Unauthorized, err.Error())) | |||||
| return | |||||
| } | |||||
| c.Next() | |||||
| } | |||||
| @@ -2,4 +2,4 @@ package http | |||||
| import "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | import "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | ||||
| type Config = types.Config | |||||
| type ConfigJSON = types.ConfigJSON | |||||
| @@ -2,11 +2,13 @@ package http | |||||
| import ( | import ( | ||||
| "context" | "context" | ||||
| "crypto/tls" | |||||
| "net/http" | "net/http" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/async" | "gitlink.org.cn/cloudream/common/pkgs/async" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | ||||
| v1 "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/v1" | v1 "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/v1" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | ||||
| @@ -24,25 +26,26 @@ type ExitEvent struct { | |||||
| } | } | ||||
| type Server struct { | type Server struct { | ||||
| cfg *types.Config | |||||
| cfg types.Config | |||||
| httpSrv *http.Server | httpSrv *http.Server | ||||
| svc *services.Service | svc *services.Service | ||||
| eventChan *ServerEventChan | eventChan *ServerEventChan | ||||
| auth *auth.Auth | |||||
| v1Svr *v1.Server | v1Svr *v1.Server | ||||
| } | } | ||||
| func NewServer(cfg *types.Config, svc *services.Service) *Server { | |||||
| func NewServer(cfg types.Config, svc *services.Service) *Server { | |||||
| return &Server{ | return &Server{ | ||||
| cfg: cfg, | cfg: cfg, | ||||
| svc: svc, | svc: svc, | ||||
| eventChan: async.NewUnboundChannel[ServerEvent](), | eventChan: async.NewUnboundChannel[ServerEvent](), | ||||
| v1Svr: v1.NewServer(cfg, svc), | |||||
| v1Svr: v1.NewServer(&cfg, svc), | |||||
| } | } | ||||
| } | } | ||||
| func (s *Server) Start() *ServerEventChan { | func (s *Server) Start() *ServerEventChan { | ||||
| go func() { | go func() { | ||||
| if s.cfg == nil { | |||||
| if !s.cfg.Enabled { | |||||
| return | return | ||||
| } | } | ||||
| @@ -51,12 +54,16 @@ func (s *Server) Start() *ServerEventChan { | |||||
| Addr: s.cfg.Listen, | Addr: s.cfg.Listen, | ||||
| Handler: engine, | Handler: engine, | ||||
| } | } | ||||
| s.auth = auth.New(&s.cfg) | |||||
| s.httpSrv.TLSConfig = &tls.Config{ | |||||
| GetConfigForClient: s.auth.TLSConfigSelector, | |||||
| } | |||||
| s.v1Svr.InitRouters(engine.Group("/v1")) | |||||
| s.v1Svr.InitRouters(engine.Group("/v1"), s.auth) | |||||
| logger.Infof("start serving http at: %s", s.cfg.Listen) | logger.Infof("start serving http at: %s", s.cfg.Listen) | ||||
| err := s.httpSrv.ListenAndServe() | |||||
| err := s.httpSrv.ListenAndServeTLS("", "") | |||||
| s.eventChan.Send(ExitEvent{Err: err}) | s.eventChan.Send(ExitEvent{Err: err}) | ||||
| }() | }() | ||||
| return s.eventChan | return s.eventChan | ||||
| @@ -1,12 +1,109 @@ | |||||
| package types | package types | ||||
| import "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| import ( | |||||
| "crypto/ecdsa" | |||||
| "crypto/sha256" | |||||
| "crypto/tls" | |||||
| "crypto/x509" | |||||
| "encoding/hex" | |||||
| "encoding/pem" | |||||
| "fmt" | |||||
| "os" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/sdk/signer" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/types" | |||||
| ) | |||||
| type ConfigJSON struct { | |||||
| Enabled bool `json:"enabled"` | |||||
| Listen string `json:"listen"` | |||||
| RootCA string `json:"rootCA"` | |||||
| ServerCert string `json:"serverCert"` | |||||
| ServerKey string `json:"serverKey"` | |||||
| // 可信的客户端证书列表,在进行预签名接口中会用到。 | |||||
| ClientCerts []string `json:"clientCerts"` | |||||
| MaxBodySize int64 `json:"maxBodySize"` | |||||
| UserSpaceID types.UserSpaceID `json:"userSpaceID"` // TODO 进行访问量统计时,当前客户端所属的存储ID。临时解决方案。 | |||||
| } | |||||
| func (c *ConfigJSON) Build() (Config, error) { | |||||
| if !c.Enabled { | |||||
| return Config{ | |||||
| Enabled: false, | |||||
| }, nil | |||||
| } | |||||
| rootCAPool := x509.NewCertPool() | |||||
| rootCAPem, err := os.ReadFile(c.RootCA) | |||||
| if err != nil { | |||||
| return Config{}, fmt.Errorf("reading root CA: %w", err) | |||||
| } | |||||
| if !rootCAPool.AppendCertsFromPEM(rootCAPem) { | |||||
| return Config{}, fmt.Errorf("parsing root CA failed") | |||||
| } | |||||
| svrCert, err := tls.LoadX509KeyPair(c.ServerCert, c.ServerKey) | |||||
| if err != nil { | |||||
| return Config{}, fmt.Errorf("loading server cert: %w", err) | |||||
| } | |||||
| clientCerts := make(map[string]*ClientCert) | |||||
| for _, p := range c.ClientCerts { | |||||
| certPEM, err := os.ReadFile(p) | |||||
| if err != nil { | |||||
| return Config{}, fmt.Errorf("reading client cert %v: %w", p, err) | |||||
| } | |||||
| b, _ := pem.Decode(certPEM) | |||||
| if len(b.Bytes) == 0 { | |||||
| return Config{}, fmt.Errorf("decode client cert %v failed", p) | |||||
| } | |||||
| if b.Type != "CERTIFICATE" { | |||||
| return Config{}, fmt.Errorf("invalid client cert %v: not a certificate", p) | |||||
| } | |||||
| cert, err := x509.ParseCertificate(b.Bytes) | |||||
| if err != nil { | |||||
| return Config{}, fmt.Errorf("parsing client cert %v: %w", p, err) | |||||
| } | |||||
| pubKey, ok := cert.PublicKey.(*ecdsa.PublicKey) | |||||
| if !ok { | |||||
| return Config{}, fmt.Errorf("invalid client cert %v: not an ECDSA public key", p) | |||||
| } | |||||
| pubKeyDer, _ := x509.MarshalPKIXPublicKey(pubKey) | |||||
| pubHash := sha256.Sum256(pubKeyDer) | |||||
| clientCerts[hex.EncodeToString(pubHash[:])] = &ClientCert{ | |||||
| Cert: cert, | |||||
| VerifyKey: signer.NewVerifyKey(pubKey), | |||||
| } | |||||
| } | |||||
| return Config{ | |||||
| Enabled: c.Enabled, | |||||
| Listen: c.Listen, | |||||
| RootCA: rootCAPool, | |||||
| ServerCert: svrCert, | |||||
| ClientCerts: clientCerts, | |||||
| MaxBodySize: c.MaxBodySize, | |||||
| UserSpaceID: c.UserSpaceID, | |||||
| }, nil | |||||
| } | |||||
| type Config struct { | type Config struct { | ||||
| Enabled bool `json:"enabled"` | |||||
| Listen string `json:"listen"` | |||||
| AuthAccessKey string `json:"authAccessKey"` // TODO 临时办法 | |||||
| AuthSecretKey string `json:"authSecretKey"` | |||||
| MaxBodySize int64 `json:"maxBodySize"` | |||||
| UserSpaceID types.UserSpaceID `json:"userSpaceID"` // TODO 进行访问量统计时,当前客户端所属的存储ID。临时解决方案。 | |||||
| Enabled bool | |||||
| Listen string | |||||
| RootCA *x509.CertPool | |||||
| ServerCert tls.Certificate | |||||
| ClientCerts map[string]*ClientCert | |||||
| MaxBodySize int64 | |||||
| UserSpaceID types.UserSpaceID | |||||
| } | |||||
| type ClientCert struct { | |||||
| Cert *x509.Certificate | |||||
| VerifyKey *signer.VerifyKey | |||||
| } | } | ||||
| @@ -0,0 +1 @@ | |||||
| package types | |||||
| @@ -1,12 +1,12 @@ | |||||
| package http | |||||
| package types | |||||
| import ( | import ( | ||||
| "fmt" | "fmt" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | "gitlink.org.cn/cloudream/common/consts/errorcode" | ||||
| "gitlink.org.cn/cloudream/common/pkgs/mq" | |||||
| "gitlink.org.cn/cloudream/common/utils/serder" | "gitlink.org.cn/cloudream/common/utils/serder" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type Response struct { | type Response struct { | ||||
| @@ -23,15 +23,15 @@ func OK(data any) Response { | |||||
| } | } | ||||
| } | } | ||||
| func Failed(code string, format string, args ...any) Response { | |||||
| func Failed(code ecode.ErrorCode, format string, args ...any) Response { | |||||
| return Response{ | return Response{ | ||||
| Code: code, | |||||
| Code: string(code), | |||||
| Message: fmt.Sprintf(format, args...), | Message: fmt.Sprintf(format, args...), | ||||
| } | } | ||||
| } | } | ||||
| func FailedError(err error) Response { | func FailedError(err error) Response { | ||||
| if codeErr, ok := err.(*mq.CodeMessageError); ok { | |||||
| if codeErr, ok := err.(*ecode.CodeError); ok { | |||||
| return Failed(codeErr.Code, codeErr.Message) | return Failed(codeErr.Code, codeErr.Message) | ||||
| } | } | ||||
| @@ -1,5 +1,6 @@ | |||||
| package http | package http | ||||
| /* | |||||
| import ( | import ( | ||||
| "bytes" | "bytes" | ||||
| "context" | "context" | ||||
| @@ -28,12 +29,12 @@ const ( | |||||
| ) | ) | ||||
| type AWSAuth struct { | type AWSAuth struct { | ||||
| cfg *types.Config | |||||
| cfg *types.ConfigJSON | |||||
| cred aws.Credentials | cred aws.Credentials | ||||
| signer *v4.Signer | signer *v4.Signer | ||||
| } | } | ||||
| func NewAWSAuth(cfg *types.Config) *AWSAuth { | |||||
| func NewAWSAuth(cfg *types.ConfigJSON) *AWSAuth { | |||||
| auth := &AWSAuth{ | auth := &AWSAuth{ | ||||
| cfg: cfg, | cfg: cfg, | ||||
| } | } | ||||
| @@ -56,13 +57,13 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||||
| authorizationHeader := c.GetHeader(AuthorizationHeader) | authorizationHeader := c.GetHeader(AuthorizationHeader) | ||||
| if authorizationHeader == "" { | if authorizationHeader == "" { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "authorization header is missing")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "authorization header is missing")) | |||||
| return | return | ||||
| } | } | ||||
| _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "invalid Authorization header format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "invalid Authorization header format")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -70,18 +71,18 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||||
| rd := io.LimitReader(c.Request.Body, a.cfg.MaxBodySize) | rd := io.LimitReader(c.Request.Body, a.cfg.MaxBodySize) | ||||
| body, err := io.ReadAll(rd) | body, err := io.ReadAll(rd) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "read request body failed")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "read request body failed")) | |||||
| return | return | ||||
| } | } | ||||
| timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date header format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date header format")) | |||||
| return | return | ||||
| } | } | ||||
| if time.Now().After(timestamp.Add(5 * time.Minute)) { | if time.Now().After(timestamp.Add(5 * time.Minute)) { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "X-Amz-Date is expired")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "X-Amz-Date is expired")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -91,7 +92,7 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||||
| // 构造验签用的请求 | // 构造验签用的请求 | ||||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||||
| return | return | ||||
| } | } | ||||
| for _, h := range headers { | for _, h := range headers { | ||||
| @@ -108,14 +109,14 @@ func (a *AWSAuth) Auth(c *gin.Context) { | |||||
| err = signer.SignHTTP(context.TODO(), a.cred, verifyReq, hexPayloadHash, AuthService, AuthRegion, timestamp) | err = signer.SignHTTP(context.TODO(), a.cred, verifyReq, hexPayloadHash, AuthService, AuthRegion, timestamp) | ||||
| if err != nil { | if err != nil { | ||||
| logger.Warnf("sign request: %v", err) | logger.Warnf("sign request: %v", err) | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||||
| return | return | ||||
| } | } | ||||
| verifySig := getSignatureFromAWSHeader(verifyReq) | verifySig := getSignatureFromAWSHeader(verifyReq) | ||||
| if !strings.EqualFold(verifySig, reqSig) { | if !strings.EqualFold(verifySig, reqSig) { | ||||
| logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifyReq.Header.Get(AuthorizationHeader)) | logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifyReq.Header.Get(AuthorizationHeader)) | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -132,31 +133,31 @@ func (a *AWSAuth) AuthWithoutBody(c *gin.Context) { | |||||
| authorizationHeader := c.GetHeader(AuthorizationHeader) | authorizationHeader := c.GetHeader(AuthorizationHeader) | ||||
| if authorizationHeader == "" { | if authorizationHeader == "" { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "authorization header is missing")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "authorization header is missing")) | |||||
| return | return | ||||
| } | } | ||||
| _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | _, headers, reqSig, err := parseAuthorizationHeader(authorizationHeader) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.Unauthorized, "invalid Authorization header format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.Unauthorized, "invalid Authorization header format")) | |||||
| return | return | ||||
| } | } | ||||
| timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | timestamp, err := time.Parse("20060102T150405Z", c.GetHeader("X-Amz-Date")) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date header format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date header format")) | |||||
| return | return | ||||
| } | } | ||||
| if time.Now().After(timestamp.Add(5 * time.Minute)) { | if time.Now().After(timestamp.Add(5 * time.Minute)) { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "X-Amz-Date is expired")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "X-Amz-Date is expired")) | |||||
| return | return | ||||
| } | } | ||||
| // 构造验签用的请求 | // 构造验签用的请求 | ||||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||||
| return | return | ||||
| } | } | ||||
| for _, h := range headers { | for _, h := range headers { | ||||
| @@ -173,14 +174,14 @@ func (a *AWSAuth) AuthWithoutBody(c *gin.Context) { | |||||
| if err != nil { | if err != nil { | ||||
| logger.Warnf("sign request: %v", err) | logger.Warnf("sign request: %v", err) | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||||
| return | return | ||||
| } | } | ||||
| verifySig := getSignatureFromAWSHeader(verifyReq) | verifySig := getSignatureFromAWSHeader(verifyReq) | ||||
| if !strings.EqualFold(verifySig, reqSig) { | if !strings.EqualFold(verifySig, reqSig) { | ||||
| logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifySig) | logger.Warnf("signature mismatch, input header: %s, verify: %s", authorizationHeader, verifySig) | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -198,7 +199,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||||
| signature := query.Get("X-Amz-Signature") | signature := query.Get("X-Amz-Signature") | ||||
| query.Del("X-Amz-Signature") | query.Del("X-Amz-Signature") | ||||
| if signature == "" { | if signature == "" { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing X-Amz-Signature query parameter")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing X-Amz-Signature query parameter")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -209,7 +210,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||||
| expiresStr := query.Get("X-Expires") | expiresStr := query.Get("X-Expires") | ||||
| expires, err := strconv.ParseInt(expiresStr, 10, 64) | expires, err := strconv.ParseInt(expiresStr, 10, 64) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Expires format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Expires format")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -219,7 +220,7 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||||
| verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | verifyReq, err := http.NewRequest(c.Request.Method, c.Request.URL.String(), nil) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, err.Error())) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, err.Error())) | |||||
| return | return | ||||
| } | } | ||||
| for _, h := range signedHeaders { | for _, h := range signedHeaders { | ||||
| @@ -234,26 +235,26 @@ func (a *AWSAuth) PresignedAuth(c *gin.Context) { | |||||
| timestamp, err := time.Parse("20060102T150405Z", date) | timestamp, err := time.Parse("20060102T150405Z", date) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "invalid X-Amz-Date format")) | |||||
| c.AbortWithStatusJSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "invalid X-Amz-Date format")) | |||||
| return | return | ||||
| } | } | ||||
| if time.Now().After(timestamp.Add(time.Duration(expires) * time.Second)) { | if time.Now().After(timestamp.Add(time.Duration(expires) * time.Second)) { | ||||
| c.AbortWithStatusJSON(http.StatusUnauthorized, Failed(errorcode.Unauthorized, "request expired")) | |||||
| c.AbortWithStatusJSON(http.StatusUnauthorized, types.Failed(ecode.Unauthorized, "request expired")) | |||||
| return | return | ||||
| } | } | ||||
| signer := v4.NewSigner() | signer := v4.NewSigner() | ||||
| uri, _, err := signer.PresignHTTP(context.TODO(), a.cred, verifyReq, "", AuthService, AuthRegion, timestamp) | uri, _, err := signer.PresignHTTP(context.TODO(), a.cred, verifyReq, "", AuthService, AuthRegion, timestamp) | ||||
| if err != nil { | if err != nil { | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.OperationFailed, "sign request failed")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.OperationFailed, "sign request failed")) | |||||
| return | return | ||||
| } | } | ||||
| verifySig := getSignatureFromAWSQuery(uri) | verifySig := getSignatureFromAWSQuery(uri) | ||||
| if !strings.EqualFold(verifySig, signature) { | if !strings.EqualFold(verifySig, signature) { | ||||
| logger.Warnf("signature mismatch, input: %s, verify: %s", signature, verifySig) | logger.Warnf("signature mismatch, input: %s, verify: %s", signature, verifySig) | ||||
| c.AbortWithStatusJSON(http.StatusOK, Failed(errorcode.Unauthorized, "signature mismatch")) | |||||
| c.AbortWithStatusJSON(http.StatusOK, types.Failed(ecode.Unauthorized, "signature mismatch")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -319,3 +320,4 @@ func getSignatureFromAWSQuery(uri string) string { | |||||
| return uri[idx+len("X-Amz-Signature=") : andIdx] | return uri[idx+len("X-Amz-Signature=") : andIdx] | ||||
| } | } | ||||
| */ | |||||
| @@ -6,9 +6,10 @@ import ( | |||||
| "time" | "time" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type BucketService struct { | type BucketService struct { | ||||
| @@ -27,18 +28,18 @@ func (s *BucketService) GetByName(ctx *gin.Context) { | |||||
| var req cliapi.BucketGetByName | var req cliapi.BucketGetByName | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| bucket, err := s.svc.BucketSvc().GetBucketByName(req.Name) | bucket, err := s.svc.BucketSvc().GetBucketByName(req.Name) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting bucket by name: %s", err.Error()) | log.Warnf("getting bucket by name: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketGetByNameResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketGetByNameResp{ | |||||
| Bucket: bucket, | Bucket: bucket, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -49,18 +50,18 @@ func (s *BucketService) Create(ctx *gin.Context) { | |||||
| var req cliapi.BucketCreate | var req cliapi.BucketCreate | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| bucket, err := s.svc.BucketSvc().CreateBucket(req.Name, time.Now()) | bucket, err := s.svc.BucketSvc().CreateBucket(req.Name, time.Now()) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("creating bucket: %s", err.Error()) | log.Warnf("creating bucket: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketCreateResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketCreateResp{ | |||||
| Bucket: bucket, | Bucket: bucket, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -71,17 +72,17 @@ func (s *BucketService) Delete(ctx *gin.Context) { | |||||
| var req cliapi.BucketDelete | var req cliapi.BucketDelete | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| if err := s.svc.BucketSvc().DeleteBucket(req.BucketID); err != nil { | if err := s.svc.BucketSvc().DeleteBucket(req.BucketID); err != nil { | ||||
| log.Warnf("deleting bucket: %s", err.Error()) | log.Warnf("deleting bucket: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete bucket failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete bucket types.Failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(nil)) | |||||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||||
| } | } | ||||
| func (s *BucketService) ListAll(ctx *gin.Context) { | func (s *BucketService) ListAll(ctx *gin.Context) { | ||||
| @@ -90,18 +91,18 @@ func (s *BucketService) ListAll(ctx *gin.Context) { | |||||
| var req cliapi.BucketListAll | var req cliapi.BucketListAll | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| buckets, err := s.svc.BucketSvc().ListAllBuckets() | buckets, err := s.svc.BucketSvc().ListAllBuckets() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("list all buckets: %s", err.Error()) | log.Warnf("list all buckets: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("list all buckets: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("list all buckets: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.BucketListAllResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.BucketListAllResp{ | |||||
| Buckets: buckets, | Buckets: buckets, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -4,9 +4,10 @@ import ( | |||||
| "net/http" | "net/http" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type MountService struct { | type MountService struct { | ||||
| @@ -25,12 +26,12 @@ func (m *MountService) DumpStatus(ctx *gin.Context) { | |||||
| var req cliapi.MountDumpStatus | var req cliapi.MountDumpStatus | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| dumpStatus := m.svc.Mount.Dump() | dumpStatus := m.svc.Mount.Dump() | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.MountDumpStatusResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.MountDumpStatusResp{ | |||||
| MountStatus: dumpStatus, | MountStatus: dumpStatus, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -40,10 +41,10 @@ func (m *MountService) StartReclaimSpace(ctx *gin.Context) { | |||||
| // var req cliapi.MountReclaimSpace | // var req cliapi.MountReclaimSpace | ||||
| // if err := ctx.ShouldBindJSON(&req); err != nil { | // if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| // log.Warnf("binding body: %s", err.Error()) | // log.Warnf("binding body: %s", err.Error()) | ||||
| // ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| // ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| // return | // return | ||||
| // } | // } | ||||
| m.svc.Mount.StartReclaimSpace() | m.svc.Mount.StartReclaimSpace() | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.StartMountReclaimSpaceResp{})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.StartMountReclaimSpaceResp{})) | |||||
| } | } | ||||
| @@ -10,12 +10,13 @@ import ( | |||||
| "path/filepath" | "path/filepath" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/common/utils/math2" | "gitlink.org.cn/cloudream/common/utils/math2" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "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" | clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type ObjectService struct { | type ObjectService struct { | ||||
| @@ -34,18 +35,18 @@ func (s *ObjectService) ListByPath(ctx *gin.Context) { | |||||
| var req cliapi.ObjectListByPath | var req cliapi.ObjectListByPath | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, err := s.svc.ObjectSvc().GetByPath(req) | resp, err := s.svc.ObjectSvc().GetByPath(req) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("listing objects: %s", err.Error()) | log.Warnf("listing objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *ObjectService) ListByIDs(ctx *gin.Context) { | func (s *ObjectService) ListByIDs(ctx *gin.Context) { | ||||
| @@ -54,18 +55,18 @@ func (s *ObjectService) ListByIDs(ctx *gin.Context) { | |||||
| var req cliapi.ObjectListByIDs | var req cliapi.ObjectListByIDs | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| objs, err := s.svc.ObjectSvc().GetByIDs(req.ObjectIDs) | objs, err := s.svc.ObjectSvc().GetByIDs(req.ObjectIDs) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("listing objects: %s", err.Error()) | log.Warnf("listing objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectListByIDsResp{Objects: objs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectListByIDsResp{Objects: objs})) | |||||
| } | } | ||||
| type ObjectUploadReq struct { | type ObjectUploadReq struct { | ||||
| @@ -79,14 +80,14 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||||
| var req ObjectUploadReq | var req ObjectUploadReq | ||||
| if err := ctx.ShouldBind(&req); err != nil { | if err := ctx.ShouldBind(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| up, err := s.svc.Uploader.BeginUpdate(req.Info.PackageID, req.Info.Affinity, req.Info.CopyTo, req.Info.CopyToPath) | up, err := s.svc.Uploader.BeginUpdate(req.Info.PackageID, req.Info.Affinity, req.Info.CopyTo, req.Info.CopyToPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("begin update: %s", err.Error()) | log.Warnf("begin update: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| defer up.Abort() | defer up.Abort() | ||||
| @@ -96,14 +97,14 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||||
| f, err := file.Open() | f, err := file.Open() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("open file: %s", err.Error()) | log.Warnf("open file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| path, err := url.PathUnescape(file.Filename) | path, err := url.PathUnescape(file.Filename) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("unescape filename: %s", err.Error()) | log.Warnf("unescape filename: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| path = filepath.ToSlash(path) | path = filepath.ToSlash(path) | ||||
| @@ -111,7 +112,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||||
| err = up.Upload(path, f) | err = up.Upload(path, f) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("uploading file: %s", err.Error()) | log.Warnf("uploading file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| pathes = append(pathes, path) | pathes = append(pathes, path) | ||||
| @@ -120,7 +121,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||||
| ret, err := up.Commit() | ret, err := up.Commit() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("commit update: %s", err.Error()) | log.Warnf("commit update: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| @@ -129,7 +130,7 @@ func (s *ObjectService) Upload(ctx *gin.Context) { | |||||
| uploadeds[i] = ret.Objects[pathes[i]] | uploadeds[i] = ret.Objects[pathes[i]] | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadResp{Uploadeds: uploadeds})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadResp{Uploadeds: uploadeds})) | |||||
| } | } | ||||
| func (s *ObjectService) Download(ctx *gin.Context) { | func (s *ObjectService) Download(ctx *gin.Context) { | ||||
| @@ -138,7 +139,7 @@ func (s *ObjectService) Download(ctx *gin.Context) { | |||||
| var req cliapi.ObjectDownload | var req cliapi.ObjectDownload | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -155,12 +156,12 @@ func (s *ObjectService) Download(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading object: %s", err.Error()) | log.Warnf("downloading object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||||
| return | return | ||||
| } | } | ||||
| if file.File == nil { | if file.File == nil { | ||||
| log.Warnf("object not found: %d", req.ObjectID) | log.Warnf("object not found: %d", req.ObjectID) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||||
| return | return | ||||
| } | } | ||||
| defer file.File.Close() | defer file.File.Close() | ||||
| @@ -186,7 +187,7 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||||
| var req cliapi.ObjectDownloadByPath | var req cliapi.ObjectDownloadByPath | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -195,13 +196,13 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting object by path: %s", err.Error()) | log.Warnf("getting object by path: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||||
| return | return | ||||
| } | } | ||||
| if len(resp.Objects) == 0 { | if len(resp.Objects) == 0 { | ||||
| log.Warnf("object not found: %s", req.Path) | log.Warnf("object not found: %s", req.Path) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -218,7 +219,7 @@ func (s *ObjectService) DownloadByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading object: %s", err.Error()) | log.Warnf("downloading object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||||
| return | return | ||||
| } | } | ||||
| defer file.File.Close() | defer file.File.Close() | ||||
| @@ -243,18 +244,18 @@ func (s *ObjectService) UpdateInfo(ctx *gin.Context) { | |||||
| var req cliapi.ObjectUpdateInfo | var req cliapi.ObjectUpdateInfo | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| sucs, err := s.svc.ObjectSvc().UpdateInfo(req.Updatings) | sucs, err := s.svc.ObjectSvc().UpdateInfo(req.Updatings) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("updating objects: %s", err.Error()) | log.Warnf("updating objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "update objects failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "update objects failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUpdateInfoResp{Successes: sucs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUpdateInfoResp{Successes: sucs})) | |||||
| } | } | ||||
| func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | ||||
| @@ -263,7 +264,7 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||||
| var req cliapi.ObjectUpdateInfoByPath | var req cliapi.ObjectUpdateInfoByPath | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -272,12 +273,12 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting object by path: %s", err.Error()) | log.Warnf("getting object by path: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||||
| return | return | ||||
| } | } | ||||
| if len(resp.Objects) == 0 { | if len(resp.Objects) == 0 { | ||||
| log.Warnf("object not found: %s", req.Path) | log.Warnf("object not found: %s", req.Path) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -287,13 +288,13 @@ func (s *ObjectService) UpdateInfoByPath(ctx *gin.Context) { | |||||
| }}) | }}) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("updating objects: %s", err.Error()) | log.Warnf("updating objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "update objects failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "update objects failed")) | |||||
| return | return | ||||
| } | } | ||||
| if len(sucs) == 0 { | if len(sucs) == 0 { | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUpdateInfoByPathResp{})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUpdateInfoByPathResp{})) | |||||
| } | } | ||||
| func (s *ObjectService) Move(ctx *gin.Context) { | func (s *ObjectService) Move(ctx *gin.Context) { | ||||
| @@ -302,18 +303,18 @@ func (s *ObjectService) Move(ctx *gin.Context) { | |||||
| var req cliapi.ObjectMove | var req cliapi.ObjectMove | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| sucs, err := s.svc.ObjectSvc().Move(req.Movings) | sucs, err := s.svc.ObjectSvc().Move(req.Movings) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("moving objects: %s", err.Error()) | log.Warnf("moving objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "move objects failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "move objects failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectMoveResp{Successes: sucs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectMoveResp{Successes: sucs})) | |||||
| } | } | ||||
| func (s *ObjectService) Delete(ctx *gin.Context) { | func (s *ObjectService) Delete(ctx *gin.Context) { | ||||
| @@ -322,18 +323,18 @@ func (s *ObjectService) Delete(ctx *gin.Context) { | |||||
| var req cliapi.ObjectDelete | var req cliapi.ObjectDelete | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| err := s.svc.ObjectSvc().Delete(req.ObjectIDs) | err := s.svc.ObjectSvc().Delete(req.ObjectIDs) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("deleting objects: %s", err.Error()) | log.Warnf("deleting objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete objects failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete objects failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(nil)) | |||||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||||
| } | } | ||||
| func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | ||||
| @@ -342,7 +343,7 @@ func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | |||||
| var req cliapi.ObjectDeleteByPath | var req cliapi.ObjectDeleteByPath | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -351,22 +352,22 @@ func (s *ObjectService) DeleteByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting object by path: %s", err.Error()) | log.Warnf("getting object by path: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||||
| return | return | ||||
| } | } | ||||
| if len(resp.Objects) == 0 { | if len(resp.Objects) == 0 { | ||||
| ctx.JSON(http.StatusOK, OK(nil)) | |||||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||||
| return | return | ||||
| } | } | ||||
| err = s.svc.ObjectSvc().Delete([]clitypes.ObjectID{resp.Objects[0].ObjectID}) | err = s.svc.ObjectSvc().Delete([]clitypes.ObjectID{resp.Objects[0].ObjectID}) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("deleting objects: %s", err.Error()) | log.Warnf("deleting objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete objects failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete objects failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(nil)) | |||||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||||
| } | } | ||||
| func (s *ObjectService) Clone(ctx *gin.Context) { | func (s *ObjectService) Clone(ctx *gin.Context) { | ||||
| @@ -375,18 +376,18 @@ func (s *ObjectService) Clone(ctx *gin.Context) { | |||||
| var req cliapi.ObjectClone | var req cliapi.ObjectClone | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| objs, err := s.svc.ObjectSvc().Clone(req.Clonings) | objs, err := s.svc.ObjectSvc().Clone(req.Clonings) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("cloning object: %s", err.Error()) | log.Warnf("cloning object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "clone object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "clone object failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCloneResp{Objects: objs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCloneResp{Objects: objs})) | |||||
| } | } | ||||
| func (s *ObjectService) GetPackageObjects(ctx *gin.Context) { | func (s *ObjectService) GetPackageObjects(ctx *gin.Context) { | ||||
| @@ -395,18 +396,18 @@ func (s *ObjectService) GetPackageObjects(ctx *gin.Context) { | |||||
| var req cliapi.ObjectGetPackageObjects | var req cliapi.ObjectGetPackageObjects | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| objs, err := s.svc.ObjectSvc().GetPackageObjects(req.PackageID) | objs, err := s.svc.ObjectSvc().GetPackageObjects(req.PackageID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting package objects: %s", err.Error()) | log.Warnf("getting package objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get package object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get package object failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectGetPackageObjectsResp{Objects: objs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectGetPackageObjectsResp{Objects: objs})) | |||||
| } | } | ||||
| func (s *ObjectService) NewMultipartUpload(ctx *gin.Context) { | func (s *ObjectService) NewMultipartUpload(ctx *gin.Context) { | ||||
| @@ -415,18 +416,18 @@ func (s *ObjectService) NewMultipartUpload(ctx *gin.Context) { | |||||
| var req cliapi.ObjectNewMultipartUpload | var req cliapi.ObjectNewMultipartUpload | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("new multipart upload object: %s", err.Error()) | log.Warnf("new multipart upload object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "new multipart upload object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "new multipart upload object failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectNewMultipartUploadResp{Object: obj})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectNewMultipartUploadResp{Object: obj})) | |||||
| } | } | ||||
| type ObjectUploadPartReq struct { | type ObjectUploadPartReq struct { | ||||
| @@ -440,14 +441,14 @@ func (s *ObjectService) UploadPart(ctx *gin.Context) { | |||||
| var req ObjectUploadPartReq | var req ObjectUploadPartReq | ||||
| if err := ctx.ShouldBind(&req); err != nil { | if err := ctx.ShouldBind(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| file, err := req.File.Open() | file, err := req.File.Open() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("open file: %s", err.Error()) | log.Warnf("open file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "open file failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "open file failed")) | |||||
| return | return | ||||
| } | } | ||||
| defer file.Close() | defer file.Close() | ||||
| @@ -455,11 +456,11 @@ func (s *ObjectService) UploadPart(ctx *gin.Context) { | |||||
| err = s.svc.Uploader.UploadPart(req.Info.ObjectID, req.Info.Index, file) | err = s.svc.Uploader.UploadPart(req.Info.ObjectID, req.Info.Index, file) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("uploading part: %s", err.Error()) | log.Warnf("uploading part: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadPartResp{})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadPartResp{})) | |||||
| } | } | ||||
| func (s *ObjectService) CompleteMultipartUpload(ctx *gin.Context) { | func (s *ObjectService) CompleteMultipartUpload(ctx *gin.Context) { | ||||
| @@ -468,16 +469,16 @@ func (s *ObjectService) CompleteMultipartUpload(ctx *gin.Context) { | |||||
| var req cliapi.ObjectCompleteMultipartUpload | var req cliapi.ObjectCompleteMultipartUpload | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("completing multipart upload: %s", err.Error()) | log.Warnf("completing multipart upload: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||||
| } | } | ||||
| @@ -8,10 +8,11 @@ import ( | |||||
| "path/filepath" | "path/filepath" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "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" | clitypes "gitlink.org.cn/cloudream/jcs-pub/client/types" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| // PackageService 包服务,负责处理包相关的HTTP请求。 | // PackageService 包服务,负责处理包相关的HTTP请求。 | ||||
| @@ -32,18 +33,18 @@ func (s *PackageService) Get(ctx *gin.Context) { | |||||
| var req cliapi.PackageGetReq | var req cliapi.PackageGetReq | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkg, err := s.svc.PackageSvc().Get(req.PackageID) | pkg, err := s.svc.PackageSvc().Get(req.PackageID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting package: %s", err.Error()) | log.Warnf("getting package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageGetResp{Package: pkg})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageGetResp{Package: pkg})) | |||||
| } | } | ||||
| func (s *PackageService) GetByFullName(ctx *gin.Context) { | func (s *PackageService) GetByFullName(ctx *gin.Context) { | ||||
| @@ -52,18 +53,18 @@ func (s *PackageService) GetByFullName(ctx *gin.Context) { | |||||
| var req cliapi.PackageGetByFullName | var req cliapi.PackageGetByFullName | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkg, err := s.svc.PackageSvc().GetByFullName(req.BucketName, req.PackageName) | pkg, err := s.svc.PackageSvc().GetByFullName(req.BucketName, req.PackageName) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting package by name: %s", err.Error()) | log.Warnf("getting package by name: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageGetByFullNameResp{Package: pkg})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageGetByFullNameResp{Package: pkg})) | |||||
| } | } | ||||
| // Create 处理创建新包的HTTP请求。 | // Create 处理创建新包的HTTP请求。 | ||||
| @@ -72,18 +73,18 @@ func (s *PackageService) Create(ctx *gin.Context) { | |||||
| var req cliapi.PackageCreate | var req cliapi.PackageCreate | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkg, err := s.svc.PackageSvc().Create(req.BucketID, req.Name) | pkg, err := s.svc.PackageSvc().Create(req.BucketID, req.Name) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("creating package: %s", err.Error()) | log.Warnf("creating package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, FailedError(err)) | |||||
| ctx.JSON(http.StatusOK, types.FailedError(err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCreateResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCreateResp{ | |||||
| Package: pkg, | Package: pkg, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -99,20 +100,20 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||||
| var req PackageCreateUpload | var req PackageCreateUpload | ||||
| if err := ctx.ShouldBind(&req); err != nil { | if err := ctx.ShouldBind(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| if len(req.Info.CopyTo) != len(req.Info.CopyToPath) { | if len(req.Info.CopyTo) != len(req.Info.CopyToPath) { | ||||
| log.Warnf("CopyTo and CopyToPath count not match") | log.Warnf("CopyTo and CopyToPath count not match") | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.BadArgument, "CopyTo and CopyToPath count not match")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.BadArgument, "CopyTo and CopyToPath count not match")) | |||||
| return | return | ||||
| } | } | ||||
| up, err := s.svc.Uploader.BeginCreateUpload(req.Info.BucketID, req.Info.Name, req.Info.CopyTo, req.Info.CopyToPath) | up, err := s.svc.Uploader.BeginCreateUpload(req.Info.BucketID, req.Info.Name, req.Info.CopyTo, req.Info.CopyToPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("begin package create upload: %s", err.Error()) | log.Warnf("begin package create upload: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "%v", err)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "%v", err)) | |||||
| return | return | ||||
| } | } | ||||
| defer up.Abort() | defer up.Abort() | ||||
| @@ -122,14 +123,14 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||||
| f, err := file.Open() | f, err := file.Open() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("open file: %s", err.Error()) | log.Warnf("open file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("open file %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| path, err := url.PathUnescape(file.Filename) | path, err := url.PathUnescape(file.Filename) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("unescape filename: %s", err.Error()) | log.Warnf("unescape filename: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("unescape filename %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| path = filepath.ToSlash(path) | path = filepath.ToSlash(path) | ||||
| @@ -137,7 +138,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||||
| err = up.Upload(path, f) | err = up.Upload(path, f) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("uploading file: %s", err.Error()) | log.Warnf("uploading file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", file.Filename, err))) | |||||
| return | return | ||||
| } | } | ||||
| pathes = append(pathes, path) | pathes = append(pathes, path) | ||||
| @@ -146,7 +147,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||||
| ret, err := up.Commit() | ret, err := up.Commit() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("commit create upload: %s", err.Error()) | log.Warnf("commit create upload: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit create upload: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit create upload: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| @@ -155,7 +156,7 @@ func (s *PackageService) CreateLoad(ctx *gin.Context) { | |||||
| objs[i] = ret.Objects[pathes[i]] | objs[i] = ret.Objects[pathes[i]] | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCreateUploadResp{Package: ret.Package, Objects: objs})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCreateUploadResp{Package: ret.Package, Objects: objs})) | |||||
| } | } | ||||
| func (s *PackageService) Delete(ctx *gin.Context) { | func (s *PackageService) Delete(ctx *gin.Context) { | ||||
| @@ -164,18 +165,18 @@ func (s *PackageService) Delete(ctx *gin.Context) { | |||||
| var req cliapi.PackageDelete | var req cliapi.PackageDelete | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| err := s.svc.PackageSvc().DeletePackage(req.PackageID) | err := s.svc.PackageSvc().DeletePackage(req.PackageID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("deleting package: %s", err.Error()) | log.Warnf("deleting package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "delete package failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "delete package failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(nil)) | |||||
| ctx.JSON(http.StatusOK, types.OK(nil)) | |||||
| } | } | ||||
| func (s *PackageService) Clone(ctx *gin.Context) { | func (s *PackageService) Clone(ctx *gin.Context) { | ||||
| @@ -184,18 +185,18 @@ func (s *PackageService) Clone(ctx *gin.Context) { | |||||
| var req cliapi.PackageClone | var req cliapi.PackageClone | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkg, err := s.svc.PackageSvc().Clone(req.PackageID, req.BucketID, req.Name) | pkg, err := s.svc.PackageSvc().Clone(req.PackageID, req.BucketID, req.Name) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("cloning package: %s", err.Error()) | log.Warnf("cloning package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "clone package failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "clone package failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageCloneResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageCloneResp{ | |||||
| Package: pkg, | Package: pkg, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -206,18 +207,18 @@ func (s *PackageService) ListBucketPackages(ctx *gin.Context) { | |||||
| var req cliapi.PackageListBucketPackages | var req cliapi.PackageListBucketPackages | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkgs, err := s.svc.PackageSvc().GetBucketPackages(req.BucketID) | pkgs, err := s.svc.PackageSvc().GetBucketPackages(req.BucketID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting bucket packages: %s", err.Error()) | log.Warnf("getting bucket packages: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get bucket packages failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get bucket packages failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PackageListBucketPackagesResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PackageListBucketPackagesResp{ | |||||
| Packages: pkgs, | Packages: pkgs, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -9,11 +9,12 @@ import ( | |||||
| "path/filepath" | "path/filepath" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/common/utils/math2" | "gitlink.org.cn/cloudream/common/utils/math2" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/downloader" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type PresignedService struct { | type PresignedService struct { | ||||
| @@ -32,18 +33,18 @@ func (s *PresignedService) ObjectListByPath(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectListByPath | var req cliapi.PresignedObjectListByPath | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, err := s.svc.ObjectSvc().GetByPath(req.ObjectListByPath) | resp, err := s.svc.ObjectSvc().GetByPath(req.ObjectListByPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("listing objects: %s", err.Error()) | log.Warnf("listing objects: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("listing objects: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | ||||
| @@ -52,7 +53,7 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectDownloadByPath | var req cliapi.PresignedObjectDownloadByPath | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -61,12 +62,12 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting object by path: %s", err.Error()) | log.Warnf("getting object by path: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get object by path failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get object by path failed")) | |||||
| return | return | ||||
| } | } | ||||
| if len(resp.Objects) == 0 { | if len(resp.Objects) == 0 { | ||||
| log.Warnf("object not found: %s", req.Path) | log.Warnf("object not found: %s", req.Path) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.DataNotFound, "object not found")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.DataNotFound, "object not found")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -83,7 +84,7 @@ func (s *PresignedService) ObjectDownloadByPath(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading object: %s", err.Error()) | log.Warnf("downloading object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||||
| return | return | ||||
| } | } | ||||
| defer file.File.Close() | defer file.File.Close() | ||||
| @@ -108,7 +109,7 @@ func (s *PresignedService) ObjectDownload(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectDownload | var req cliapi.PresignedObjectDownload | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| @@ -125,7 +126,7 @@ func (s *PresignedService) ObjectDownload(ctx *gin.Context) { | |||||
| }) | }) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading object: %s", err.Error()) | log.Warnf("downloading object: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "download object failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "download object failed")) | |||||
| return | return | ||||
| } | } | ||||
| defer file.File.Close() | defer file.File.Close() | ||||
| @@ -150,14 +151,14 @@ func (s *PresignedService) ObjectUpload(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectUpload | var req cliapi.PresignedObjectUpload | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| up, err := s.svc.Uploader.BeginUpdate(req.PackageID, req.Affinity, req.CopyTo, req.CopyToPath) | up, err := s.svc.Uploader.BeginUpdate(req.PackageID, req.Affinity, req.CopyTo, req.CopyToPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("begin update: %s", err.Error()) | log.Warnf("begin update: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("begin update: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| defer up.Abort() | defer up.Abort() | ||||
| @@ -167,18 +168,18 @@ func (s *PresignedService) ObjectUpload(ctx *gin.Context) { | |||||
| err = up.Upload(path, ctx.Request.Body) | err = up.Upload(path, ctx.Request.Body) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("uploading file: %s", err.Error()) | log.Warnf("uploading file: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("uploading file %v: %v", req.Path, err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("uploading file %v: %v", req.Path, err))) | |||||
| return | return | ||||
| } | } | ||||
| ret, err := up.Commit() | ret, err := up.Commit() | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("commit update: %s", err.Error()) | log.Warnf("commit update: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("commit update: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PresignedObjectUploadResp{Object: ret.Objects[path]})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PresignedObjectUploadResp{Object: ret.Objects[path]})) | |||||
| } | } | ||||
| func (s *PresignedService) ObjectNewMultipartUpload(ctx *gin.Context) { | func (s *PresignedService) ObjectNewMultipartUpload(ctx *gin.Context) { | ||||
| @@ -187,18 +188,18 @@ func (s *PresignedService) ObjectNewMultipartUpload(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectNewMultipartUpload | var req cliapi.PresignedObjectNewMultipartUpload | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | obj, err := s.svc.ObjectSvc().NewMultipartUploadObject(req.PackageID, req.Path) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("new multipart upload: %s", err.Error()) | log.Warnf("new multipart upload: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("new multipart upload: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("new multipart upload: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.PresignedObjectUploadResp{Object: obj})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.PresignedObjectUploadResp{Object: obj})) | |||||
| } | } | ||||
| func (s *PresignedService) ObjectUploadPart(ctx *gin.Context) { | func (s *PresignedService) ObjectUploadPart(ctx *gin.Context) { | ||||
| @@ -207,18 +208,18 @@ func (s *PresignedService) ObjectUploadPart(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectUploadPart | var req cliapi.PresignedObjectUploadPart | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| err := s.svc.Uploader.UploadPart(req.ObjectID, req.Index, ctx.Request.Body) | err := s.svc.Uploader.UploadPart(req.ObjectID, req.Index, ctx.Request.Body) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("uploading part: %s", err.Error()) | log.Warnf("uploading part: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("upload part: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectUploadPartResp{})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectUploadPartResp{})) | |||||
| } | } | ||||
| func (s *PresignedService) ObjectCompleteMultipartUpload(ctx *gin.Context) { | func (s *PresignedService) ObjectCompleteMultipartUpload(ctx *gin.Context) { | ||||
| @@ -227,16 +228,16 @@ func (s *PresignedService) ObjectCompleteMultipartUpload(ctx *gin.Context) { | |||||
| var req cliapi.PresignedObjectCompleteMultipartUpload | var req cliapi.PresignedObjectCompleteMultipartUpload | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | obj, err := s.svc.ObjectSvc().CompleteMultipartUpload(req.ObjectID, req.Indexes) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("completing multipart upload: %s", err.Error()) | log.Warnf("completing multipart upload: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("complete multipart upload: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.ObjectCompleteMultipartUploadResp{Object: obj})) | |||||
| } | } | ||||
| @@ -2,6 +2,7 @@ package http | |||||
| import ( | import ( | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/auth" | |||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | "gitlink.org.cn/cloudream/jcs-pub/client/internal/services" | ||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | ||||
| @@ -19,57 +20,58 @@ func NewServer(cfg *types.Config, svc *services.Service) *Server { | |||||
| } | } | ||||
| } | } | ||||
| func (s *Server) InitRouters(rt gin.IRoutes) { | |||||
| awsAuth := NewAWSAuth(s.cfg) | |||||
| func (s *Server) InitRouters(rt gin.IRoutes, ah *auth.Auth) { | |||||
| certAuth := ah.RejectNoCertAuth | |||||
| signAuth := ah.Presigned | |||||
| rt.GET(cliapi.ObjectListPathByPath, awsAuth.Auth, s.Object().ListByPath) | |||||
| rt.GET(cliapi.ObjectListByIDsPath, awsAuth.Auth, s.Object().ListByIDs) | |||||
| rt.GET(cliapi.ObjectDownloadPath, awsAuth.Auth, s.Object().Download) | |||||
| rt.GET(cliapi.ObjectDownloadByPathPath, awsAuth.Auth, s.Object().DownloadByPath) | |||||
| rt.POST(cliapi.ObjectUploadPath, awsAuth.AuthWithoutBody, s.Object().Upload) | |||||
| rt.GET(cliapi.ObjectGetPackageObjectsPath, awsAuth.Auth, s.Object().GetPackageObjects) | |||||
| rt.POST(cliapi.ObjectUpdateInfoPath, awsAuth.Auth, s.Object().UpdateInfo) | |||||
| rt.POST(cliapi.ObjectUpdateInfoByPathPath, awsAuth.Auth, s.Object().UpdateInfoByPath) | |||||
| rt.POST(cliapi.ObjectMovePath, awsAuth.Auth, s.Object().Move) | |||||
| rt.POST(cliapi.ObjectDeletePath, awsAuth.Auth, s.Object().Delete) | |||||
| rt.POST(cliapi.ObjectDeleteByPathPath, awsAuth.Auth, s.Object().DeleteByPath) | |||||
| rt.POST(cliapi.ObjectClonePath, awsAuth.Auth, s.Object().Clone) | |||||
| rt.GET(cliapi.ObjectListPathByPath, certAuth, s.Object().ListByPath) | |||||
| rt.GET(cliapi.ObjectListByIDsPath, certAuth, s.Object().ListByIDs) | |||||
| rt.GET(cliapi.ObjectDownloadPath, certAuth, s.Object().Download) | |||||
| rt.GET(cliapi.ObjectDownloadByPathPath, certAuth, s.Object().DownloadByPath) | |||||
| rt.POST(cliapi.ObjectUploadPath, certAuth, s.Object().Upload) | |||||
| rt.GET(cliapi.ObjectGetPackageObjectsPath, certAuth, s.Object().GetPackageObjects) | |||||
| rt.POST(cliapi.ObjectUpdateInfoPath, certAuth, s.Object().UpdateInfo) | |||||
| rt.POST(cliapi.ObjectUpdateInfoByPathPath, certAuth, s.Object().UpdateInfoByPath) | |||||
| rt.POST(cliapi.ObjectMovePath, certAuth, s.Object().Move) | |||||
| rt.POST(cliapi.ObjectDeletePath, certAuth, s.Object().Delete) | |||||
| rt.POST(cliapi.ObjectDeleteByPathPath, certAuth, s.Object().DeleteByPath) | |||||
| rt.POST(cliapi.ObjectClonePath, certAuth, s.Object().Clone) | |||||
| rt.GET(cliapi.PackageGetPath, awsAuth.Auth, s.Package().Get) | |||||
| rt.GET(cliapi.PackageGetByFullNamePath, awsAuth.Auth, s.Package().GetByFullName) | |||||
| rt.POST(cliapi.PackageCreatePath, awsAuth.Auth, s.Package().Create) | |||||
| rt.POST(cliapi.PackageCreateUploadPath, awsAuth.Auth, s.Package().CreateLoad) | |||||
| rt.POST(cliapi.PackageDeletePath, awsAuth.Auth, s.Package().Delete) | |||||
| rt.POST(cliapi.PackageClonePath, awsAuth.Auth, s.Package().Clone) | |||||
| rt.GET(cliapi.PackageListBucketPackagesPath, awsAuth.Auth, s.Package().ListBucketPackages) | |||||
| rt.GET(cliapi.PackageGetPath, certAuth, s.Package().Get) | |||||
| rt.GET(cliapi.PackageGetByFullNamePath, certAuth, s.Package().GetByFullName) | |||||
| rt.POST(cliapi.PackageCreatePath, certAuth, s.Package().Create) | |||||
| rt.POST(cliapi.PackageCreateUploadPath, certAuth, s.Package().CreateLoad) | |||||
| rt.POST(cliapi.PackageDeletePath, certAuth, s.Package().Delete) | |||||
| rt.POST(cliapi.PackageClonePath, certAuth, s.Package().Clone) | |||||
| rt.GET(cliapi.PackageListBucketPackagesPath, certAuth, s.Package().ListBucketPackages) | |||||
| rt.POST(cliapi.UserSpaceDownloadPackagePath, awsAuth.Auth, s.UserSpace().DownloadPackage) | |||||
| rt.POST(cliapi.UserSpaceCreatePackagePath, awsAuth.Auth, s.UserSpace().CreatePackage) | |||||
| rt.GET(cliapi.UserSpaceGetPath, awsAuth.Auth, s.UserSpace().Get) | |||||
| rt.POST(cliapi.UserSpaceCreatePath, awsAuth.Auth, s.UserSpace().Create) | |||||
| rt.POST(cliapi.UserSpaceUpdatePath, awsAuth.Auth, s.UserSpace().Update) | |||||
| rt.POST(cliapi.UserSpaceDeletePath, awsAuth.Auth, s.UserSpace().Delete) | |||||
| rt.POST(cliapi.UserSpaceTestPath, awsAuth.Auth, s.UserSpace().Test) | |||||
| rt.POST(cliapi.UserSpaceSpaceToSpacePath, awsAuth.Auth, s.UserSpace().SpaceToSpace) | |||||
| rt.POST(cliapi.UserSpaceDownloadPackagePath, certAuth, s.UserSpace().DownloadPackage) | |||||
| rt.POST(cliapi.UserSpaceCreatePackagePath, certAuth, s.UserSpace().CreatePackage) | |||||
| rt.GET(cliapi.UserSpaceGetPath, certAuth, s.UserSpace().Get) | |||||
| rt.POST(cliapi.UserSpaceCreatePath, certAuth, s.UserSpace().Create) | |||||
| rt.POST(cliapi.UserSpaceUpdatePath, certAuth, s.UserSpace().Update) | |||||
| rt.POST(cliapi.UserSpaceDeletePath, certAuth, s.UserSpace().Delete) | |||||
| rt.POST(cliapi.UserSpaceTestPath, certAuth, s.UserSpace().Test) | |||||
| rt.POST(cliapi.UserSpaceSpaceToSpacePath, certAuth, s.UserSpace().SpaceToSpace) | |||||
| rt.GET(cliapi.BucketGetByNamePath, awsAuth.Auth, s.Bucket().GetByName) | |||||
| rt.POST(cliapi.BucketCreatePath, awsAuth.Auth, s.Bucket().Create) | |||||
| rt.POST(cliapi.BucketDeletePath, awsAuth.Auth, s.Bucket().Delete) | |||||
| rt.GET(cliapi.BucketListAllPath, awsAuth.Auth, s.Bucket().ListAll) | |||||
| rt.GET(cliapi.BucketGetByNamePath, certAuth, s.Bucket().GetByName) | |||||
| rt.POST(cliapi.BucketCreatePath, certAuth, s.Bucket().Create) | |||||
| rt.POST(cliapi.BucketDeletePath, certAuth, s.Bucket().Delete) | |||||
| rt.GET(cliapi.BucketListAllPath, certAuth, s.Bucket().ListAll) | |||||
| rt.POST(cliapi.ObjectNewMultipartUploadPath, awsAuth.Auth, s.Object().NewMultipartUpload) | |||||
| rt.POST(cliapi.ObjectUploadPartPath, awsAuth.AuthWithoutBody, s.Object().UploadPart) | |||||
| rt.POST(cliapi.ObjectCompleteMultipartUploadPath, awsAuth.Auth, s.Object().CompleteMultipartUpload) | |||||
| rt.POST(cliapi.ObjectNewMultipartUploadPath, certAuth, s.Object().NewMultipartUpload) | |||||
| rt.POST(cliapi.ObjectUploadPartPath, certAuth, s.Object().UploadPart) | |||||
| rt.POST(cliapi.ObjectCompleteMultipartUploadPath, certAuth, s.Object().CompleteMultipartUpload) | |||||
| rt.GET(cliapi.PresignedObjectListByPathPath, awsAuth.PresignedAuth, s.Presigned().ObjectListByPath) | |||||
| rt.GET(cliapi.PresignedObjectDownloadByPathPath, awsAuth.PresignedAuth, s.Presigned().ObjectDownloadByPath) | |||||
| rt.GET(cliapi.PresignedObjectDownloadPath, awsAuth.PresignedAuth, s.Presigned().ObjectDownload) | |||||
| rt.POST(cliapi.PresignedObjectUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectUpload) | |||||
| rt.GET(cliapi.PresignedObjectListByPathPath, signAuth, s.Presigned().ObjectListByPath) | |||||
| rt.GET(cliapi.PresignedObjectDownloadByPathPath, signAuth, s.Presigned().ObjectDownloadByPath) | |||||
| rt.GET(cliapi.PresignedObjectDownloadPath, signAuth, s.Presigned().ObjectDownload) | |||||
| rt.POST(cliapi.PresignedObjectUploadPath, signAuth, s.Presigned().ObjectUpload) | |||||
| rt.POST(cliapi.PresignedObjectNewMultipartUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectNewMultipartUpload) | |||||
| rt.POST(cliapi.PresignedObjectUploadPartPath, awsAuth.PresignedAuth, s.Presigned().ObjectUploadPart) | |||||
| rt.POST(cliapi.PresignedObjectCompleteMultipartUploadPath, awsAuth.PresignedAuth, s.Presigned().ObjectCompleteMultipartUpload) | |||||
| rt.POST(cliapi.PresignedObjectNewMultipartUploadPath, signAuth, s.Presigned().ObjectNewMultipartUpload) | |||||
| rt.POST(cliapi.PresignedObjectUploadPartPath, signAuth, s.Presigned().ObjectUploadPart) | |||||
| rt.POST(cliapi.PresignedObjectCompleteMultipartUploadPath, signAuth, s.Presigned().ObjectCompleteMultipartUpload) | |||||
| rt.GET(cliapi.MountDumpStatusPath, awsAuth.Auth, s.Mount().DumpStatus) | |||||
| rt.POST(cliapi.MountStartReclaimSpacePath, awsAuth.Auth, s.Mount().StartReclaimSpace) | |||||
| rt.GET(cliapi.MountDumpStatusPath, certAuth, s.Mount().DumpStatus) | |||||
| rt.POST(cliapi.MountStartReclaimSpacePath, certAuth, s.Mount().StartReclaimSpace) | |||||
| } | } | ||||
| @@ -5,9 +5,10 @@ import ( | |||||
| "net/http" | "net/http" | ||||
| "github.com/gin-gonic/gin" | "github.com/gin-gonic/gin" | ||||
| "gitlink.org.cn/cloudream/common/consts/errorcode" | |||||
| "gitlink.org.cn/cloudream/common/pkgs/logger" | "gitlink.org.cn/cloudream/common/pkgs/logger" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/client/internal/http/types" | |||||
| cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | cliapi "gitlink.org.cn/cloudream/jcs-pub/client/sdk/api/v1" | ||||
| "gitlink.org.cn/cloudream/jcs-pub/common/ecode" | |||||
| ) | ) | ||||
| type UserSpaceService struct { | type UserSpaceService struct { | ||||
| @@ -26,18 +27,18 @@ func (s *UserSpaceService) DownloadPackage(ctx *gin.Context) { | |||||
| var req cliapi.UserSpaceDownloadPackageReq | var req cliapi.UserSpaceDownloadPackageReq | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| err := s.svc.UserSpaceSvc().DownloadPackage(req.PackageID, req.UserSpaceID, req.RootPath) | err := s.svc.UserSpaceSvc().DownloadPackage(req.PackageID, req.UserSpaceID, req.RootPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("downloading package: %s", err.Error()) | log.Warnf("downloading package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "%v", err)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "%v", err)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceDownloadPackageResp{})) | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceDownloadPackageResp{})) | |||||
| } | } | ||||
| func (s *UserSpaceService) CreatePackage(ctx *gin.Context) { | func (s *UserSpaceService) CreatePackage(ctx *gin.Context) { | ||||
| @@ -46,18 +47,18 @@ func (s *UserSpaceService) CreatePackage(ctx *gin.Context) { | |||||
| var req cliapi.UserSpaceCreatePackageReq | var req cliapi.UserSpaceCreatePackageReq | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| pkg, err := s.svc.Uploader.UserSpaceUpload(req.UserSpaceID, req.Path, req.BucketID, req.Name, req.SpaceAffinity) | pkg, err := s.svc.Uploader.UserSpaceUpload(req.UserSpaceID, req.Path, req.BucketID, req.Name, req.SpaceAffinity) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("userspace create package: %s", err.Error()) | log.Warnf("userspace create package: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, fmt.Sprintf("userspace create package: %v", err))) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, fmt.Sprintf("userspace create package: %v", err))) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceCreatePackageResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceCreatePackageResp{ | |||||
| Package: *pkg, | Package: *pkg, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -68,18 +69,18 @@ func (s *UserSpaceService) Get(ctx *gin.Context) { | |||||
| var req cliapi.UserSpaceGet | var req cliapi.UserSpaceGet | ||||
| if err := ctx.ShouldBindQuery(&req); err != nil { | if err := ctx.ShouldBindQuery(&req); err != nil { | ||||
| log.Warnf("binding query: %s", err.Error()) | log.Warnf("binding query: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| info, err := s.svc.UserSpaceSvc().Get(req.UserSpaceID) | info, err := s.svc.UserSpaceSvc().Get(req.UserSpaceID) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("getting info: %s", err.Error()) | log.Warnf("getting info: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "get userspace inf failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "get userspace inf failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceGetResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceGetResp{ | |||||
| UserSpace: info, | UserSpace: info, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -87,42 +88,42 @@ func (s *UserSpaceService) Get(ctx *gin.Context) { | |||||
| 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") | ||||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceCreate](ctx) | |||||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceCreate](ctx) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, cerr := s.svc.UserSpaceSvc().Create(req) | resp, cerr := s.svc.UserSpaceSvc().Create(req) | ||||
| if cerr != nil { | if cerr != nil { | ||||
| log.Warnf("creating userspace: %v", cerr) | log.Warnf("creating userspace: %v", cerr) | ||||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *UserSpaceService) Update(ctx *gin.Context) { | func (s *UserSpaceService) Update(ctx *gin.Context) { | ||||
| log := logger.WithField("HTTP", "UserSpace.Update") | log := logger.WithField("HTTP", "UserSpace.Update") | ||||
| var req cliapi.UserSpaceUpdate | var req cliapi.UserSpaceUpdate | ||||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceUpdate](ctx) | |||||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceUpdate](ctx) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, cerr := s.svc.UserSpaceSvc().Update(req) | resp, cerr := s.svc.UserSpaceSvc().Update(req) | ||||
| if cerr != nil { | if cerr != nil { | ||||
| log.Warnf("updating userspace: %v", cerr) | log.Warnf("updating userspace: %v", cerr) | ||||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *UserSpaceService) Delete(ctx *gin.Context) { | func (s *UserSpaceService) Delete(ctx *gin.Context) { | ||||
| @@ -131,39 +132,39 @@ func (s *UserSpaceService) Delete(ctx *gin.Context) { | |||||
| var req cliapi.UserSpaceDelete | var req cliapi.UserSpaceDelete | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, cerr := s.svc.UserSpaceSvc().Delete(req) | resp, cerr := s.svc.UserSpaceSvc().Delete(req) | ||||
| if cerr != nil { | if cerr != nil { | ||||
| log.Warnf("deleting userspace: %v", cerr) | log.Warnf("deleting userspace: %v", cerr) | ||||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *UserSpaceService) Test(ctx *gin.Context) { | func (s *UserSpaceService) Test(ctx *gin.Context) { | ||||
| log := logger.WithField("HTTP", "UserSpace.Test") | log := logger.WithField("HTTP", "UserSpace.Test") | ||||
| var req cliapi.UserSpaceTest | var req cliapi.UserSpaceTest | ||||
| req, err := ShouldBindJSONEx[cliapi.UserSpaceTest](ctx) | |||||
| req, err := types.ShouldBindJSONEx[cliapi.UserSpaceTest](ctx) | |||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| resp, cerr := s.svc.UserSpaceSvc().Test(req) | resp, cerr := s.svc.UserSpaceSvc().Test(req) | ||||
| if cerr != nil { | if cerr != nil { | ||||
| log.Warnf("testing userspace: %v", cerr) | log.Warnf("testing userspace: %v", cerr) | ||||
| ctx.JSON(http.StatusOK, Failed(string(cerr.Code), cerr.Message)) | |||||
| ctx.JSON(http.StatusOK, types.Failed(cerr.Code, cerr.Message)) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(resp)) | |||||
| ctx.JSON(http.StatusOK, types.OK(resp)) | |||||
| } | } | ||||
| func (s *UserSpaceService) SpaceToSpace(ctx *gin.Context) { | func (s *UserSpaceService) SpaceToSpace(ctx *gin.Context) { | ||||
| @@ -172,18 +173,18 @@ func (s *UserSpaceService) SpaceToSpace(ctx *gin.Context) { | |||||
| var req cliapi.UserSpaceSpaceToSpace | var req cliapi.UserSpaceSpaceToSpace | ||||
| if err := ctx.ShouldBindJSON(&req); err != nil { | if err := ctx.ShouldBindJSON(&req); err != nil { | ||||
| log.Warnf("binding body: %s", err.Error()) | log.Warnf("binding body: %s", err.Error()) | ||||
| ctx.JSON(http.StatusBadRequest, Failed(errorcode.BadArgument, "missing argument or invalid argument")) | |||||
| ctx.JSON(http.StatusBadRequest, types.Failed(ecode.BadArgument, "missing argument or invalid argument")) | |||||
| return | return | ||||
| } | } | ||||
| ret, err := s.svc.UserSpaceSvc().SpaceToSpace(req.SrcUserSpaceID, req.SrcPath, req.DstUserSpaceID, req.DstPath) | ret, err := s.svc.UserSpaceSvc().SpaceToSpace(req.SrcUserSpaceID, req.SrcPath, req.DstUserSpaceID, req.DstPath) | ||||
| if err != nil { | if err != nil { | ||||
| log.Warnf("space2space: %s", err.Error()) | log.Warnf("space2space: %s", err.Error()) | ||||
| ctx.JSON(http.StatusOK, Failed(errorcode.OperationFailed, "space2space failed")) | |||||
| ctx.JSON(http.StatusOK, types.Failed(ecode.OperationFailed, "space2space failed")) | |||||
| return | return | ||||
| } | } | ||||
| ctx.JSON(http.StatusOK, OK(cliapi.UserSpaceSpaceToSpaceResp{ | |||||
| ctx.JSON(http.StatusOK, types.OK(cliapi.UserSpaceSpaceToSpaceResp{ | |||||
| SpaceToSpaceResult: ret, | SpaceToSpaceResult: ret, | ||||
| })) | })) | ||||
| } | } | ||||
| @@ -0,0 +1,150 @@ | |||||
| package signer | |||||
| import ( | |||||
| "crypto/ecdsa" | |||||
| "crypto/rand" | |||||
| "crypto/sha256" | |||||
| "encoding/hex" | |||||
| "fmt" | |||||
| "net/url" | |||||
| "strconv" | |||||
| "strings" | |||||
| "time" | |||||
| "gitlink.org.cn/cloudream/common/utils/sort2" | |||||
| ) | |||||
| var ErrSignatureMismatch = fmt.Errorf("signature mismatch") | |||||
| var ErrExpired = fmt.Errorf("signature expired") | |||||
| const ( | |||||
| DateQueryKey = "x-jcs-date" | |||||
| ExpiresQueryKey = "x-jcs-expires" | |||||
| SignatureQueryKey = "x-jcs-signature" | |||||
| AccessKeyIDQueryKey = "x-jcs-access-key-id" | |||||
| AlgorithmQueryKey = "x-jcs-algorithm" | |||||
| AlgorithmValue = "ECDSA256" | |||||
| DateFormat = "20060102T150405Z" | |||||
| ) | |||||
| type SignKey struct { | |||||
| privateKey *ecdsa.PrivateKey | |||||
| accessKeyID string | |||||
| } | |||||
| func PresignURL(key *SignKey, method string, u *url.URL, signingTime time.Time, expiresSeconds int) error { | |||||
| date := signingTime.Format(DateFormat) | |||||
| queries := u.Query() | |||||
| queries.Set(DateQueryKey, date) | |||||
| queries.Set(ExpiresQueryKey, fmt.Sprintf("%v", expiresSeconds)) | |||||
| queries.Set(AccessKeyIDQueryKey, key.accessKeyID) | |||||
| queries.Set(AlgorithmQueryKey, AlgorithmValue) | |||||
| ss := makeStringToSign(method, u.Host, u.Path, queries) | |||||
| ssHash := sha256.Sum256([]byte(ss)) | |||||
| sign, err := ecdsa.SignASN1(rand.Reader, key.privateKey, ssHash[:]) | |||||
| if err != nil { | |||||
| return err | |||||
| } | |||||
| queries.Set(SignatureQueryKey, hex.EncodeToString(sign)) | |||||
| u.RawQuery = queries.Encode() | |||||
| return nil | |||||
| } | |||||
| type VerifyKey struct { | |||||
| publicKey *ecdsa.PublicKey | |||||
| } | |||||
| func NewVerifyKey(publicKey *ecdsa.PublicKey) *VerifyKey { | |||||
| return &VerifyKey{publicKey: publicKey} | |||||
| } | |||||
| func GetAccessKeyID(u *url.URL) string { | |||||
| return u.Query().Get(AccessKeyIDQueryKey) | |||||
| } | |||||
| func VerifyPresigned(key *VerifyKey, method string, u *url.URL) error { | |||||
| queries := u.Query() | |||||
| dateStr := queries.Get(DateQueryKey) | |||||
| if dateStr == "" { | |||||
| return fmt.Errorf("missing date in query string") | |||||
| } | |||||
| date, err := time.Parse(DateFormat, dateStr) | |||||
| if err != nil { | |||||
| return fmt.Errorf("invalid date format: %v", err) | |||||
| } | |||||
| expiresStr := queries.Get(ExpiresQueryKey) | |||||
| if expiresStr == "" { | |||||
| return fmt.Errorf("missing expires in query string") | |||||
| } | |||||
| expires, err := strconv.Atoi(expiresStr) | |||||
| if err != nil { | |||||
| return fmt.Errorf("invalid expires format: %v", err) | |||||
| } | |||||
| if time.Now().After(date.Add(time.Duration(expires) * time.Second)) { | |||||
| return ErrExpired | |||||
| } | |||||
| signatureStr := queries.Get(SignatureQueryKey) | |||||
| signature, err := hex.DecodeString(signatureStr) | |||||
| if err != nil { | |||||
| return fmt.Errorf("invalid signature format: %v", err) | |||||
| } | |||||
| queries.Del(SignatureQueryKey) | |||||
| ss := makeStringToSign(method, u.Host, u.Path, queries) | |||||
| ssHash := sha256.Sum256([]byte(ss)) | |||||
| if !ecdsa.VerifyASN1(key.publicKey, ssHash[:], signature) { | |||||
| return ErrSignatureMismatch | |||||
| } | |||||
| return nil | |||||
| } | |||||
| func makeStringToSign(method string, host string, path string, queries url.Values) string { | |||||
| type queryKv struct { | |||||
| Key string | |||||
| Values []string | |||||
| } | |||||
| var queryKvs []queryKv | |||||
| for k, vs := range queries { | |||||
| vs = sort2.SortAsc(vs) | |||||
| queryKvs = append(queryKvs, queryKv{Key: k, Values: vs}) | |||||
| } | |||||
| queryKvs = sort2.Sort(queryKvs, func(left, right queryKv) int { | |||||
| return strings.Compare(left.Key, right.Key) | |||||
| }) | |||||
| var str strings.Builder | |||||
| str.WriteString(method) | |||||
| str.WriteByte('\n') | |||||
| str.WriteString(host) | |||||
| str.WriteByte('\n') | |||||
| str.WriteString(path) | |||||
| str.WriteByte('\n') | |||||
| for _, kv := range queryKvs { | |||||
| str.WriteString(kv.Key) | |||||
| str.WriteByte('=') | |||||
| for i, v := range kv.Values { | |||||
| if i > 0 { | |||||
| str.WriteByte(',') | |||||
| } | |||||
| str.WriteString(v) | |||||
| } | |||||
| str.WriteByte('\n') | |||||
| } | |||||
| return str.String() | |||||
| } | |||||
| @@ -79,6 +79,7 @@ func createClient(stgType *cortypes.OBSType, cred *cortypes.OBSCred) (*s3.Client | |||||
| } | } | ||||
| awsConfig.Credentials = &credentials.StaticCredentialsProvider{Value: cre} | awsConfig.Credentials = &credentials.StaticCredentialsProvider{Value: cre} | ||||
| awsConfig.Region = stgType.Region | awsConfig.Region = stgType.Region | ||||
| awsConfig.RetryMaxAttempts = 1 | |||||
| options := []func(*s3.Options){} | options := []func(*s3.Options){} | ||||
| options = append(options, func(s3Opt *s3.Options) { | options = append(options, func(s3Opt *s3.Options) { | ||||
| @@ -1,8 +1,9 @@ | |||||
| package cmd | package cmd | ||||
| import ( | import ( | ||||
| "crypto/ecdsa" | |||||
| "crypto/elliptic" | |||||
| "crypto/rand" | "crypto/rand" | ||||
| "crypto/rsa" | |||||
| "crypto/x509" | "crypto/x509" | ||||
| "crypto/x509/pkix" | "crypto/x509/pkix" | ||||
| "encoding/pem" | "encoding/pem" | ||||
| @@ -58,7 +59,7 @@ func init() { | |||||
| } | } | ||||
| func certRoot(output string) { | func certRoot(output string) { | ||||
| caPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||||
| caPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 创建 CA 证书模板 | // 创建 CA 证书模板 | ||||
| caTemplate := &x509.Certificate{ | caTemplate := &x509.Certificate{ | ||||
| @@ -78,7 +79,9 @@ func certRoot(output string) { | |||||
| // 保存 CA 证书和私钥 | // 保存 CA 证书和私钥 | ||||
| writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER) | writePem(filepath.Join(output, "ca_cert.pem"), "CERTIFICATE", caCertDER) | ||||
| writePem(filepath.Join(output, "ca_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(caPriv)) | |||||
| privPem, _ := x509.MarshalECPrivateKey(caPriv) | |||||
| writePem(filepath.Join(output, "ca_key.pem"), "EC PRIVATE KEY", privPem) | |||||
| fmt.Println("CA certificate and key saved to", output) | fmt.Println("CA certificate and key saved to", output) | ||||
| } | } | ||||
| @@ -111,14 +114,14 @@ func certServer(certFile string, keyFile string, output string) { | |||||
| return | return | ||||
| } | } | ||||
| caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes) | |||||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("Failed to parse CA key:", err) | fmt.Println("Failed to parse CA key:", err) | ||||
| return | return | ||||
| } | } | ||||
| // 生成服务端私钥 | // 生成服务端私钥 | ||||
| serverPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||||
| serverPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 服务端证书模板 | // 服务端证书模板 | ||||
| serverTemplate := &x509.Certificate{ | serverTemplate := &x509.Certificate{ | ||||
| @@ -141,7 +144,9 @@ func certServer(certFile string, keyFile string, output string) { | |||||
| // 保存服务端证书和私钥 | // 保存服务端证书和私钥 | ||||
| writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER) | writePem(filepath.Join(output, "server_cert.pem"), "CERTIFICATE", serverCertDER) | ||||
| writePem(filepath.Join(output, "server_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(serverPriv)) | |||||
| privPem, _ := x509.MarshalECPrivateKey(serverPriv) | |||||
| writePem(filepath.Join(output, "server_key.pem"), "EC PRIVATE KEY", privPem) | |||||
| fmt.Println("Server certificate and key saved to", output) | fmt.Println("Server certificate and key saved to", output) | ||||
| } | } | ||||
| @@ -174,14 +179,14 @@ func certClient(certFile string, keyFile string, output string) { | |||||
| return | return | ||||
| } | } | ||||
| caKey, err := x509.ParsePKCS1PrivateKey(caKeyPEMBlock.Bytes) | |||||
| caKey, err := x509.ParseECPrivateKey(caKeyPEMBlock.Bytes) | |||||
| if err != nil { | if err != nil { | ||||
| fmt.Println("Failed to parse CA key:", err) | fmt.Println("Failed to parse CA key:", err) | ||||
| return | return | ||||
| } | } | ||||
| // 生成客户端私钥 | // 生成客户端私钥 | ||||
| clientPriv, _ := rsa.GenerateKey(rand.Reader, 2048) | |||||
| clientPriv, _ := ecdsa.GenerateKey(elliptic.P256(), rand.Reader) | |||||
| // 客户端证书模板 | // 客户端证书模板 | ||||
| clientTemplate := &x509.Certificate{ | clientTemplate := &x509.Certificate{ | ||||
| @@ -201,7 +206,9 @@ func certClient(certFile string, keyFile string, output string) { | |||||
| // 保存客户端证书和私钥 | // 保存客户端证书和私钥 | ||||
| writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER) | writePem(filepath.Join(output, "client_cert.pem"), "CERTIFICATE", clientCertDER) | ||||
| writePem(filepath.Join(output, "client_key.pem"), "RSA PRIVATE KEY", x509.MarshalPKCS1PrivateKey(clientPriv)) | |||||
| privPem, _ := x509.MarshalECPrivateKey(clientPriv) | |||||
| writePem(filepath.Join(output, "client_key.pem"), "EC PRIVATE KEY", privPem) | |||||
| fmt.Println("Client certificate and key saved to", output) | fmt.Println("Client certificate and key saved to", output) | ||||
| } | } | ||||