diff --git a/dl/design/design.go b/dl/design/design.go index 6734684..d29b629 100644 --- a/dl/design/design.go +++ b/dl/design/design.go @@ -94,6 +94,45 @@ var _ = Service("oci", func() { }) }) }) + + Method("download-file-sha256", func() { + Payload(func() { + Field(1, "repository", String, "OCI artifact repository") + Field(2, "tag", String, "OCI artifact tag") + Field(3, "file", String, "file name in OCI artifact") + Required("repository", "tag", "file") + }) + + Result(func() { + Attribute("length", Int64, "Length is the downloaded content length in bytes.", func() { + Example(4 * 1024 * 1024) + }) + Attribute("contentDisposition", String, "Content-Disposition header for downloading", func() { + Example("attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz.sha256") + }) + Required("length", "contentDisposition") + }) + + Error("invalid_file_path", ErrorResult, "Could not locate file for download") + Error("internal_error", ErrorResult, "Fault while processing download.") + + HTTP(func() { + GET("/oci-file-sha256/{*repository}") + Param("file:file", String, "file name in OCI artifact") + Param("tag:tag", String, "OCI artifact tag") + + // Bypass response body encoder code generation to alleviate need for + // loading the entire response body in memory. + SkipResponseBodyEncodeDecode() + + Response(func() { + // Set the content type for binary data + ContentType("application/plain-text") + Header("length:Content-Length") + Header("contentDisposition:Content-Disposition") + }) + }) + }) }) var _ = Service("ks3", func() { diff --git a/dl/gen/health/client.go b/dl/gen/health/client.go index f96d23f..e4fd370 100644 --- a/dl/gen/health/client.go +++ b/dl/gen/health/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health client // diff --git a/dl/gen/health/endpoints.go b/dl/gen/health/endpoints.go index efdd456..19e86a3 100644 --- a/dl/gen/health/endpoints.go +++ b/dl/gen/health/endpoints.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health endpoints // diff --git a/dl/gen/health/service.go b/dl/gen/health/service.go index 65401fb..f9f76da 100644 --- a/dl/gen/health/service.go +++ b/dl/gen/health/service.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health service // @@ -19,6 +19,12 @@ type Service interface { Livez(context.Context) (res bool, err error) } +// APIName is the name of the API as defined in the design. +const APIName = "dl" + +// APIVersion is the version of the API as defined in the design. +const APIVersion = "0.0.1" + // ServiceName is the name of the service as defined in the design. This is the // same value that is set in the endpoint request contexts under the ServiceKey // key. diff --git a/dl/gen/http/cli/server/cli.go b/dl/gen/http/cli/server/cli.go index 7348378..681b107 100644 --- a/dl/gen/http/cli/server/cli.go +++ b/dl/gen/http/cli/server/cli.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // server HTTP client CLI support package // @@ -25,7 +25,7 @@ import ( // command (subcommand1|subcommand2|...) func UsageCommands() string { return `health (healthz|livez) -oci (list-files|download-file) +oci (list-files|download-file|download-file-sha256) ks3 download-object ` } @@ -33,8 +33,8 @@ ks3 download-object // UsageExamples produces an example of a valid invocation of the CLI tool. func UsageExamples() string { return os.Args[0] + ` health healthz` + "\n" + - os.Args[0] + ` oci list-files --repository "Excepturi perferendis dolores voluptas eius non." --tag "Est reprehenderit quibusdam eveniet velit."` + "\n" + - os.Args[0] + ` ks3 download-object --bucket "Reiciendis eligendi magnam officiis recusandae est fugiat." --key "Provident temporibus occaecati unde."` + "\n" + + os.Args[0] + ` oci list-files --repository "Earum quia." --tag "Nostrum cupiditate ipsa explicabo cum a."` + "\n" + + os.Args[0] + ` ks3 download-object --bucket "Quos quaerat nulla repudiandae magnam vel nobis." --key "At non dignissimos error et repellendus."` + "\n" + "" } @@ -65,6 +65,11 @@ func ParseEndpoint( ociDownloadFileFileFlag = ociDownloadFileFlags.String("file", "REQUIRED", "") ociDownloadFileTagFlag = ociDownloadFileFlags.String("tag", "REQUIRED", "") + ociDownloadFileSha256Flags = flag.NewFlagSet("download-file-sha256", flag.ExitOnError) + ociDownloadFileSha256RepositoryFlag = ociDownloadFileSha256Flags.String("repository", "REQUIRED", "OCI artifact repository") + ociDownloadFileSha256FileFlag = ociDownloadFileSha256Flags.String("file", "REQUIRED", "") + ociDownloadFileSha256TagFlag = ociDownloadFileSha256Flags.String("tag", "REQUIRED", "") + ks3Flags = flag.NewFlagSet("ks3", flag.ContinueOnError) ks3DownloadObjectFlags = flag.NewFlagSet("download-object", flag.ExitOnError) @@ -78,6 +83,7 @@ func ParseEndpoint( ociFlags.Usage = ociUsage ociListFilesFlags.Usage = ociListFilesUsage ociDownloadFileFlags.Usage = ociDownloadFileUsage + ociDownloadFileSha256Flags.Usage = ociDownloadFileSha256Usage ks3Flags.Usage = ks3Usage ks3DownloadObjectFlags.Usage = ks3DownloadObjectUsage @@ -136,6 +142,9 @@ func ParseEndpoint( case "download-file": epf = ociDownloadFileFlags + case "download-file-sha256": + epf = ociDownloadFileSha256Flags + } case "ks3": @@ -184,6 +193,9 @@ func ParseEndpoint( case "download-file": endpoint = c.DownloadFile() data, err = ocic.BuildDownloadFilePayload(*ociDownloadFileRepositoryFlag, *ociDownloadFileFileFlag, *ociDownloadFileTagFlag) + case "download-file-sha256": + endpoint = c.DownloadFileSha256() + data, err = ocic.BuildDownloadFileSha256Payload(*ociDownloadFileSha256RepositoryFlag, *ociDownloadFileSha256FileFlag, *ociDownloadFileSha256TagFlag) } case "ks3": c := ks3c.NewClient(scheme, host, doer, enc, dec, restore) @@ -244,6 +256,7 @@ Usage: COMMAND: list-files: ListFiles implements list-files. download-file: DownloadFile implements download-file. + download-file-sha256: DownloadFileSha256 implements download-file-sha256. Additional help: %[1]s oci COMMAND --help @@ -257,7 +270,7 @@ ListFiles implements list-files. -tag STRING: Example: - %[1]s oci list-files --repository "Excepturi perferendis dolores voluptas eius non." --tag "Est reprehenderit quibusdam eveniet velit." + %[1]s oci list-files --repository "Earum quia." --tag "Nostrum cupiditate ipsa explicabo cum a." `, os.Args[0]) } @@ -274,6 +287,19 @@ Example: `, os.Args[0]) } +func ociDownloadFileSha256Usage() { + fmt.Fprintf(os.Stderr, `%[1]s [flags] oci download-file-sha256 -repository STRING -file STRING -tag STRING + +DownloadFileSha256 implements download-file-sha256. + -repository STRING: OCI artifact repository + -file STRING: + -tag STRING: + +Example: + %[1]s oci download-file-sha256 --repository "Omnis est natus exercitationem aliquid tempora cumque." --file "Reiciendis eligendi magnam officiis recusandae est fugiat." --tag "Provident temporibus occaecati unde." +`, os.Args[0]) +} + // ks3Usage displays the usage of the ks3 command and its subcommands. func ks3Usage() { fmt.Fprintf(os.Stderr, `OCI artifacts download service @@ -295,6 +321,6 @@ DownloadObject implements download-object. -key STRING: object key Example: - %[1]s ks3 download-object --bucket "Reiciendis eligendi magnam officiis recusandae est fugiat." --key "Provident temporibus occaecati unde." + %[1]s ks3 download-object --bucket "Quos quaerat nulla repudiandae magnam vel nobis." --key "At non dignissimos error et repellendus." `, os.Args[0]) } diff --git a/dl/gen/http/health/client/cli.go b/dl/gen/http/health/client/cli.go index d432dfd..3cadff3 100644 --- a/dl/gen/http/health/client/cli.go +++ b/dl/gen/http/health/client/cli.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP client CLI support package // diff --git a/dl/gen/http/health/client/client.go b/dl/gen/http/health/client/client.go index 3eaa821..23baa69 100644 --- a/dl/gen/http/health/client/client.go +++ b/dl/gen/http/health/client/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health client HTTP transport // diff --git a/dl/gen/http/health/client/encode_decode.go b/dl/gen/http/health/client/encode_decode.go index cf9afdf..88f712e 100644 --- a/dl/gen/http/health/client/encode_decode.go +++ b/dl/gen/http/health/client/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP client encoders and decoders // diff --git a/dl/gen/http/health/client/paths.go b/dl/gen/http/health/client/paths.go index 8650f43..81f38bf 100644 --- a/dl/gen/http/health/client/paths.go +++ b/dl/gen/http/health/client/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the health service. // diff --git a/dl/gen/http/health/client/types.go b/dl/gen/http/health/client/types.go index ddeb953..804e1de 100644 --- a/dl/gen/http/health/client/types.go +++ b/dl/gen/http/health/client/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP client types // diff --git a/dl/gen/http/health/server/encode_decode.go b/dl/gen/http/health/server/encode_decode.go index 0b17365..710e9a0 100644 --- a/dl/gen/http/health/server/encode_decode.go +++ b/dl/gen/http/health/server/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP server encoders and decoders // diff --git a/dl/gen/http/health/server/paths.go b/dl/gen/http/health/server/paths.go index b5a0eb2..def2333 100644 --- a/dl/gen/http/health/server/paths.go +++ b/dl/gen/http/health/server/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the health service. // diff --git a/dl/gen/http/health/server/server.go b/dl/gen/http/health/server/server.go index fe75767..7039abb 100644 --- a/dl/gen/http/health/server/server.go +++ b/dl/gen/http/health/server/server.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP server // diff --git a/dl/gen/http/health/server/types.go b/dl/gen/http/health/server/types.go index 2bdd6b6..8628a42 100644 --- a/dl/gen/http/health/server/types.go +++ b/dl/gen/http/health/server/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // health HTTP server types // diff --git a/dl/gen/http/ks3/client/cli.go b/dl/gen/http/ks3/client/cli.go index ce1c99a..d36e09b 100644 --- a/dl/gen/http/ks3/client/cli.go +++ b/dl/gen/http/ks3/client/cli.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP client CLI support package // diff --git a/dl/gen/http/ks3/client/client.go b/dl/gen/http/ks3/client/client.go index 6cd501a..082986c 100644 --- a/dl/gen/http/ks3/client/client.go +++ b/dl/gen/http/ks3/client/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 client HTTP transport // diff --git a/dl/gen/http/ks3/client/encode_decode.go b/dl/gen/http/ks3/client/encode_decode.go index d35cb5e..85ab50f 100644 --- a/dl/gen/http/ks3/client/encode_decode.go +++ b/dl/gen/http/ks3/client/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP client encoders and decoders // diff --git a/dl/gen/http/ks3/client/paths.go b/dl/gen/http/ks3/client/paths.go index fbbd4e2..cd2ae27 100644 --- a/dl/gen/http/ks3/client/paths.go +++ b/dl/gen/http/ks3/client/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the ks3 service. // diff --git a/dl/gen/http/ks3/client/types.go b/dl/gen/http/ks3/client/types.go index 835dda3..07af5f0 100644 --- a/dl/gen/http/ks3/client/types.go +++ b/dl/gen/http/ks3/client/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP client types // diff --git a/dl/gen/http/ks3/server/encode_decode.go b/dl/gen/http/ks3/server/encode_decode.go index bb1bc65..a3b321c 100644 --- a/dl/gen/http/ks3/server/encode_decode.go +++ b/dl/gen/http/ks3/server/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP server encoders and decoders // diff --git a/dl/gen/http/ks3/server/paths.go b/dl/gen/http/ks3/server/paths.go index 30c8959..de8580d 100644 --- a/dl/gen/http/ks3/server/paths.go +++ b/dl/gen/http/ks3/server/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the ks3 service. // diff --git a/dl/gen/http/ks3/server/server.go b/dl/gen/http/ks3/server/server.go index bd0b1d0..1eae85c 100644 --- a/dl/gen/http/ks3/server/server.go +++ b/dl/gen/http/ks3/server/server.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP server // diff --git a/dl/gen/http/ks3/server/types.go b/dl/gen/http/ks3/server/types.go index b02bab2..dc775a4 100644 --- a/dl/gen/http/ks3/server/types.go +++ b/dl/gen/http/ks3/server/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 HTTP server types // diff --git a/dl/gen/http/oci/client/cli.go b/dl/gen/http/oci/client/cli.go index a533a9d..ce8bbba 100644 --- a/dl/gen/http/oci/client/cli.go +++ b/dl/gen/http/oci/client/cli.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP client CLI support package // @@ -51,3 +51,26 @@ func BuildDownloadFilePayload(ociDownloadFileRepository string, ociDownloadFileF return v, nil } + +// BuildDownloadFileSha256Payload builds the payload for the oci +// download-file-sha256 endpoint from CLI flags. +func BuildDownloadFileSha256Payload(ociDownloadFileSha256Repository string, ociDownloadFileSha256File string, ociDownloadFileSha256Tag string) (*oci.DownloadFileSha256Payload, error) { + var repository string + { + repository = ociDownloadFileSha256Repository + } + var file string + { + file = ociDownloadFileSha256File + } + var tag string + { + tag = ociDownloadFileSha256Tag + } + v := &oci.DownloadFileSha256Payload{} + v.Repository = repository + v.File = file + v.Tag = tag + + return v, nil +} diff --git a/dl/gen/http/oci/client/client.go b/dl/gen/http/oci/client/client.go index 52a97eb..63e6dd6 100644 --- a/dl/gen/http/oci/client/client.go +++ b/dl/gen/http/oci/client/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci client HTTP transport // @@ -26,6 +26,10 @@ type Client struct { // download-file endpoint. DownloadFileDoer goahttp.Doer + // DownloadFileSha256 Doer is the HTTP client used to make requests to the + // download-file-sha256 endpoint. + DownloadFileSha256Doer goahttp.Doer + // RestoreResponseBody controls whether the response bodies are reset after // decoding so they can be read again. RestoreResponseBody bool @@ -46,13 +50,14 @@ func NewClient( restoreBody bool, ) *Client { return &Client{ - ListFilesDoer: doer, - DownloadFileDoer: doer, - RestoreResponseBody: restoreBody, - scheme: scheme, - host: host, - decoder: dec, - encoder: enc, + ListFilesDoer: doer, + DownloadFileDoer: doer, + DownloadFileSha256Doer: doer, + RestoreResponseBody: restoreBody, + scheme: scheme, + host: host, + decoder: dec, + encoder: enc, } } @@ -108,3 +113,32 @@ func (c *Client) DownloadFile() goa.Endpoint { return &oci.DownloadFileResponseData{Result: res.(*oci.DownloadFileResult), Body: resp.Body}, nil } } + +// DownloadFileSha256 returns an endpoint that makes HTTP requests to the oci +// service download-file-sha256 server. +func (c *Client) DownloadFileSha256() goa.Endpoint { + var ( + encodeRequest = EncodeDownloadFileSha256Request(c.encoder) + decodeResponse = DecodeDownloadFileSha256Response(c.decoder, c.RestoreResponseBody) + ) + return func(ctx context.Context, v any) (any, error) { + req, err := c.BuildDownloadFileSha256Request(ctx, v) + if err != nil { + return nil, err + } + err = encodeRequest(req, v) + if err != nil { + return nil, err + } + resp, err := c.DownloadFileSha256Doer.Do(req) + if err != nil { + return nil, goahttp.ErrRequestError("oci", "download-file-sha256", err) + } + res, err := decodeResponse(resp) + if err != nil { + resp.Body.Close() + return nil, err + } + return &oci.DownloadFileSha256ResponseData{Result: res.(*oci.DownloadFileSha256Result), Body: resp.Body}, nil + } +} diff --git a/dl/gen/http/oci/client/encode_decode.go b/dl/gen/http/oci/client/encode_decode.go index c419154..5cec040 100644 --- a/dl/gen/http/oci/client/encode_decode.go +++ b/dl/gen/http/oci/client/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP client encoders and decoders // @@ -185,3 +185,94 @@ func DecodeDownloadFileResponse(decoder func(*http.Response) goahttp.Decoder, re } } } + +// BuildDownloadFileSha256Request instantiates a HTTP request object with +// method and path set to call the "oci" service "download-file-sha256" endpoint +func (c *Client) BuildDownloadFileSha256Request(ctx context.Context, v any) (*http.Request, error) { + var ( + repository string + ) + { + p, ok := v.(*oci.DownloadFileSha256Payload) + if !ok { + return nil, goahttp.ErrInvalidType("oci", "download-file-sha256", "*oci.DownloadFileSha256Payload", v) + } + repository = p.Repository + } + u := &url.URL{Scheme: c.scheme, Host: c.host, Path: DownloadFileSha256OciPath(repository)} + req, err := http.NewRequest("GET", u.String(), nil) + if err != nil { + return nil, goahttp.ErrInvalidURL("oci", "download-file-sha256", u.String(), err) + } + if ctx != nil { + req = req.WithContext(ctx) + } + + return req, nil +} + +// EncodeDownloadFileSha256Request returns an encoder for requests sent to the +// oci download-file-sha256 server. +func EncodeDownloadFileSha256Request(encoder func(*http.Request) goahttp.Encoder) func(*http.Request, any) error { + return func(req *http.Request, v any) error { + p, ok := v.(*oci.DownloadFileSha256Payload) + if !ok { + return goahttp.ErrInvalidType("oci", "download-file-sha256", "*oci.DownloadFileSha256Payload", v) + } + values := req.URL.Query() + values.Add("file", p.File) + values.Add("tag", p.Tag) + req.URL.RawQuery = values.Encode() + return nil + } +} + +// DecodeDownloadFileSha256Response returns a decoder for responses returned by +// the oci download-file-sha256 endpoint. restoreBody controls whether the +// response body should be restored after having been read. +func DecodeDownloadFileSha256Response(decoder func(*http.Response) goahttp.Decoder, restoreBody bool) func(*http.Response) (any, error) { + return func(resp *http.Response) (any, error) { + if restoreBody { + b, err := io.ReadAll(resp.Body) + if err != nil { + return nil, err + } + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + defer func() { + resp.Body = io.NopCloser(bytes.NewBuffer(b)) + }() + } + switch resp.StatusCode { + case http.StatusOK: + var ( + length int64 + contentDisposition string + err error + ) + { + lengthRaw := resp.Header.Get("Content-Length") + if lengthRaw == "" { + return nil, goahttp.ErrValidationError("oci", "download-file-sha256", goa.MissingFieldError("length", "header")) + } + v, err2 := strconv.ParseInt(lengthRaw, 10, 64) + if err2 != nil { + err = goa.MergeErrors(err, goa.InvalidFieldTypeError("length", lengthRaw, "integer")) + } + length = v + } + contentDispositionRaw := resp.Header.Get("Content-Disposition") + if contentDispositionRaw == "" { + err = goa.MergeErrors(err, goa.MissingFieldError("contentDisposition", "header")) + } + contentDisposition = contentDispositionRaw + if err != nil { + return nil, goahttp.ErrValidationError("oci", "download-file-sha256", err) + } + res := NewDownloadFileSha256ResultOK(length, contentDisposition) + return res, nil + default: + body, _ := io.ReadAll(resp.Body) + return nil, goahttp.ErrInvalidResponse("oci", "download-file-sha256", resp.StatusCode, string(body)) + } + } +} diff --git a/dl/gen/http/oci/client/paths.go b/dl/gen/http/oci/client/paths.go index f3b95c7..5f289b4 100644 --- a/dl/gen/http/oci/client/paths.go +++ b/dl/gen/http/oci/client/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the oci service. // @@ -20,3 +20,8 @@ func ListFilesOciPath(repository string) string { func DownloadFileOciPath(repository string) string { return fmt.Sprintf("/oci-file/%v", repository) } + +// DownloadFileSha256OciPath returns the URL path to the oci service download-file-sha256 HTTP endpoint. +func DownloadFileSha256OciPath(repository string) string { + return fmt.Sprintf("/oci-file-sha256/%v", repository) +} diff --git a/dl/gen/http/oci/client/types.go b/dl/gen/http/oci/client/types.go index 671d0fa..b8db445 100644 --- a/dl/gen/http/oci/client/types.go +++ b/dl/gen/http/oci/client/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP client types // @@ -20,3 +20,13 @@ func NewDownloadFileResultOK(length int64, contentDisposition string) *oci.Downl return v } + +// NewDownloadFileSha256ResultOK builds a "oci" service "download-file-sha256" +// endpoint result from a HTTP "OK" response. +func NewDownloadFileSha256ResultOK(length int64, contentDisposition string) *oci.DownloadFileSha256Result { + v := &oci.DownloadFileSha256Result{} + v.Length = length + v.ContentDisposition = contentDisposition + + return v +} diff --git a/dl/gen/http/oci/server/encode_decode.go b/dl/gen/http/oci/server/encode_decode.go index cf1e9c1..5a83467 100644 --- a/dl/gen/http/oci/server/encode_decode.go +++ b/dl/gen/http/oci/server/encode_decode.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP server encoders and decoders // @@ -84,11 +84,12 @@ func DecodeDownloadFileRequest(mux goahttp.Muxer, decoder func(*http.Request) go params = mux.Vars(r) ) repository = params["repository"] - file = r.URL.Query().Get("file") + qp := r.URL.Query() + file = qp.Get("file") if file == "" { err = goa.MergeErrors(err, goa.MissingFieldError("file", "query string")) } - tag = r.URL.Query().Get("tag") + tag = qp.Get("tag") if tag == "" { err = goa.MergeErrors(err, goa.MissingFieldError("tag", "query string")) } @@ -100,3 +101,51 @@ func DecodeDownloadFileRequest(mux goahttp.Muxer, decoder func(*http.Request) go return payload, nil } } + +// EncodeDownloadFileSha256Response returns an encoder for responses returned +// by the oci download-file-sha256 endpoint. +func EncodeDownloadFileSha256Response(encoder func(context.Context, http.ResponseWriter) goahttp.Encoder) func(context.Context, http.ResponseWriter, any) error { + return func(ctx context.Context, w http.ResponseWriter, v any) error { + res, _ := v.(*oci.DownloadFileSha256Result) + ctx = context.WithValue(ctx, goahttp.ContentTypeKey, "application/plain-text") + { + val := res.Length + lengths := strconv.FormatInt(val, 10) + w.Header().Set("Content-Length", lengths) + } + w.Header().Set("Content-Disposition", res.ContentDisposition) + w.WriteHeader(http.StatusOK) + return nil + } +} + +// DecodeDownloadFileSha256Request returns a decoder for requests sent to the +// oci download-file-sha256 endpoint. +func DecodeDownloadFileSha256Request(mux goahttp.Muxer, decoder func(*http.Request) goahttp.Decoder) func(*http.Request) (any, error) { + return func(r *http.Request) (any, error) { + var ( + repository string + file string + tag string + err error + + params = mux.Vars(r) + ) + repository = params["repository"] + qp := r.URL.Query() + file = qp.Get("file") + if file == "" { + err = goa.MergeErrors(err, goa.MissingFieldError("file", "query string")) + } + tag = qp.Get("tag") + if tag == "" { + err = goa.MergeErrors(err, goa.MissingFieldError("tag", "query string")) + } + if err != nil { + return nil, err + } + payload := NewDownloadFileSha256Payload(repository, file, tag) + + return payload, nil + } +} diff --git a/dl/gen/http/oci/server/paths.go b/dl/gen/http/oci/server/paths.go index 6b7a75c..c6582ad 100644 --- a/dl/gen/http/oci/server/paths.go +++ b/dl/gen/http/oci/server/paths.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // HTTP request path constructors for the oci service. // @@ -20,3 +20,8 @@ func ListFilesOciPath(repository string) string { func DownloadFileOciPath(repository string) string { return fmt.Sprintf("/oci-file/%v", repository) } + +// DownloadFileSha256OciPath returns the URL path to the oci service download-file-sha256 HTTP endpoint. +func DownloadFileSha256OciPath(repository string) string { + return fmt.Sprintf("/oci-file-sha256/%v", repository) +} diff --git a/dl/gen/http/oci/server/server.go b/dl/gen/http/oci/server/server.go index 58b9a03..b3d0df0 100644 --- a/dl/gen/http/oci/server/server.go +++ b/dl/gen/http/oci/server/server.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP server // @@ -20,9 +20,10 @@ import ( // Server lists the oci service endpoint HTTP handlers. type Server struct { - Mounts []*MountPoint - ListFiles http.Handler - DownloadFile http.Handler + Mounts []*MountPoint + ListFiles http.Handler + DownloadFile http.Handler + DownloadFileSha256 http.Handler } // MountPoint holds information about the mounted endpoints. @@ -54,9 +55,11 @@ func New( Mounts: []*MountPoint{ {"ListFiles", "GET", "/oci-files/{*repository}"}, {"DownloadFile", "GET", "/oci-file/{*repository}"}, + {"DownloadFileSha256", "GET", "/oci-file-sha256/{*repository}"}, }, - ListFiles: NewListFilesHandler(e.ListFiles, mux, decoder, encoder, errhandler, formatter), - DownloadFile: NewDownloadFileHandler(e.DownloadFile, mux, decoder, encoder, errhandler, formatter), + ListFiles: NewListFilesHandler(e.ListFiles, mux, decoder, encoder, errhandler, formatter), + DownloadFile: NewDownloadFileHandler(e.DownloadFile, mux, decoder, encoder, errhandler, formatter), + DownloadFileSha256: NewDownloadFileSha256Handler(e.DownloadFileSha256, mux, decoder, encoder, errhandler, formatter), } } @@ -67,6 +70,7 @@ func (s *Server) Service() string { return "oci" } func (s *Server) Use(m func(http.Handler) http.Handler) { s.ListFiles = m(s.ListFiles) s.DownloadFile = m(s.DownloadFile) + s.DownloadFileSha256 = m(s.DownloadFileSha256) } // MethodNames returns the methods served. @@ -76,6 +80,7 @@ func (s *Server) MethodNames() []string { return oci.MethodNames[:] } func Mount(mux goahttp.Muxer, h *Server) { MountListFilesHandler(mux, h.ListFiles) MountDownloadFileHandler(mux, h.DownloadFile) + MountDownloadFileSha256Handler(mux, h.DownloadFileSha256) } // Mount configures the mux to serve the oci endpoints. @@ -201,3 +206,71 @@ func NewDownloadFileHandler( } }) } + +// MountDownloadFileSha256Handler configures the mux to serve the "oci" service +// "download-file-sha256" endpoint. +func MountDownloadFileSha256Handler(mux goahttp.Muxer, h http.Handler) { + f, ok := h.(http.HandlerFunc) + if !ok { + f = func(w http.ResponseWriter, r *http.Request) { + h.ServeHTTP(w, r) + } + } + mux.Handle("GET", "/oci-file-sha256/{*repository}", f) +} + +// NewDownloadFileSha256Handler creates a HTTP handler which loads the HTTP +// request and calls the "oci" service "download-file-sha256" endpoint. +func NewDownloadFileSha256Handler( + endpoint goa.Endpoint, + mux goahttp.Muxer, + decoder func(*http.Request) goahttp.Decoder, + encoder func(context.Context, http.ResponseWriter) goahttp.Encoder, + errhandler func(context.Context, http.ResponseWriter, error), + formatter func(ctx context.Context, err error) goahttp.Statuser, +) http.Handler { + var ( + decodeRequest = DecodeDownloadFileSha256Request(mux, decoder) + encodeResponse = EncodeDownloadFileSha256Response(encoder) + encodeError = goahttp.ErrorEncoder(encoder, formatter) + ) + return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + ctx := context.WithValue(r.Context(), goahttp.AcceptTypeKey, r.Header.Get("Accept")) + ctx = context.WithValue(ctx, goa.MethodKey, "download-file-sha256") + ctx = context.WithValue(ctx, goa.ServiceKey, "oci") + payload, err := decodeRequest(r) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + res, err := endpoint(ctx, payload) + if err != nil { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + o := res.(*oci.DownloadFileSha256ResponseData) + defer o.Body.Close() + // handle immediate read error like a returned error + buf := bufio.NewReader(o.Body) + if _, err := buf.Peek(1); err != nil && err != io.EOF { + if err := encodeError(ctx, w, err); err != nil { + errhandler(ctx, w, err) + } + return + } + if err := encodeResponse(ctx, w, o.Result); err != nil { + errhandler(ctx, w, err) + return + } + if _, err := io.Copy(w, buf); err != nil { + if f, ok := w.(http.Flusher); ok { + f.Flush() + } + panic(http.ErrAbortHandler) // too late to write an error + } + }) +} diff --git a/dl/gen/http/oci/server/types.go b/dl/gen/http/oci/server/types.go index 12aa41a..2ea9a88 100644 --- a/dl/gen/http/oci/server/types.go +++ b/dl/gen/http/oci/server/types.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci HTTP server types // @@ -29,3 +29,14 @@ func NewDownloadFilePayload(repository string, file string, tag string) *oci.Dow return v } + +// NewDownloadFileSha256Payload builds a oci service download-file-sha256 +// endpoint payload. +func NewDownloadFileSha256Payload(repository string, file string, tag string) *oci.DownloadFileSha256Payload { + v := &oci.DownloadFileSha256Payload{} + v.Repository = repository + v.File = file + v.Tag = tag + + return v +} diff --git a/dl/gen/http/openapi.json b/dl/gen/http/openapi.json index cb26aa2..69e302b 100644 --- a/dl/gen/http/openapi.json +++ b/dl/gen/http/openapi.json @@ -1 +1 @@ -{"swagger":"2.0","info":{"title":"Download OCI artifacts Service","description":"Service for downloading files from OCI artifact","version":""},"host":"localhost:8000","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/healthz":{"get":{"tags":["health"],"summary":"healthz health","operationId":"health#healthz","responses":{"200":{"description":"OK response.","schema":{"type":"boolean"}}},"schemes":["http"]}},"/livez":{"get":{"tags":["health"],"summary":"livez health","operationId":"health#livez","responses":{"200":{"description":"OK response.","schema":{"type":"boolean"}}},"schemes":["http"]}},"/oci-file/{repository}":{"get":{"tags":["oci"],"summary":"download-file oci","operationId":"oci#download-file","produces":["application/octet-stream"],"parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","required":true,"type":"string"},{"name":"tag","in":"query","description":"OCI artifact tag","required":true,"type":"string"},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","type":"string"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","type":"int64"}}}},"schemes":["http"]}},"/oci-files/{repository}":{"get":{"tags":["oci"],"summary":"list-files oci","operationId":"oci#list-files","parameters":[{"name":"tag","in":"query","description":"OCI artifact tag","required":true,"type":"string"},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Et aut labore veniam et maiores qui."}}}},"schemes":["http"]}},"/s3-obj/{bucket}/{key}":{"get":{"tags":["ks3"],"summary":"download-object ks3","operationId":"ks3#download-object","produces":["application/octet-stream"],"parameters":[{"name":"bucket","in":"path","description":"bucket name","required":true,"type":"string"},{"name":"key","in":"path","description":"object key","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","type":"string"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","type":"int64"}}}},"schemes":["http"]}}}} \ No newline at end of file +{"swagger":"2.0","info":{"title":"Download OCI artifacts Service","description":"Service for downloading files from OCI artifact","version":"0.0.1"},"host":"localhost:8000","consumes":["application/json","application/xml","application/gob"],"produces":["application/json","application/xml","application/gob"],"paths":{"/healthz":{"get":{"tags":["health"],"summary":"healthz health","operationId":"health#healthz","responses":{"200":{"description":"OK response.","schema":{"type":"boolean"}}},"schemes":["http"]}},"/livez":{"get":{"tags":["health"],"summary":"livez health","operationId":"health#livez","responses":{"200":{"description":"OK response.","schema":{"type":"boolean"}}},"schemes":["http"]}},"/oci-file-sha256/{repository}":{"get":{"tags":["oci"],"summary":"download-file-sha256 oci","operationId":"oci#download-file-sha256","produces":["application/plain-text"],"parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","required":true,"type":"string"},{"name":"tag","in":"query","description":"OCI artifact tag","required":true,"type":"string"},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","type":"string"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","type":"int64"}}}},"schemes":["http"]}},"/oci-file/{repository}":{"get":{"tags":["oci"],"summary":"download-file oci","operationId":"oci#download-file","produces":["application/octet-stream"],"parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","required":true,"type":"string"},{"name":"tag","in":"query","description":"OCI artifact tag","required":true,"type":"string"},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","type":"string"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","type":"int64"}}}},"schemes":["http"]}},"/oci-files/{repository}":{"get":{"tags":["oci"],"summary":"list-files oci","operationId":"oci#list-files","parameters":[{"name":"tag","in":"query","description":"OCI artifact tag","required":true,"type":"string"},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","schema":{"type":"array","items":{"type":"string","example":"Nam quibusdam recusandae dolor voluptas."}}}},"schemes":["http"]}},"/s3-obj/{bucket}/{key}":{"get":{"tags":["ks3"],"summary":"download-object ks3","operationId":"ks3#download-object","produces":["application/octet-stream"],"parameters":[{"name":"bucket","in":"path","description":"bucket name","required":true,"type":"string"},{"name":"key","in":"path","description":"object key","required":true,"type":"string"}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","type":"string"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","type":"int64"}}}},"schemes":["http"]}}}} \ No newline at end of file diff --git a/dl/gen/http/openapi.yaml b/dl/gen/http/openapi.yaml index 9ecaf3e..edc1961 100644 --- a/dl/gen/http/openapi.yaml +++ b/dl/gen/http/openapi.yaml @@ -2,7 +2,7 @@ swagger: "2.0" info: title: Download OCI artifacts Service description: Service for downloading files from OCI artifact - version: "" + version: 0.0.1 host: localhost:8000 consumes: - application/json @@ -39,6 +39,42 @@ paths: type: boolean schemes: - http + /oci-file-sha256/{repository}: + get: + tags: + - oci + summary: download-file-sha256 oci + operationId: oci#download-file-sha256 + produces: + - application/plain-text + parameters: + - name: file + in: query + description: file name in OCI artifact + required: true + type: string + - name: tag + in: query + description: OCI artifact tag + required: true + type: string + - name: repository + in: path + description: OCI artifact repository + required: true + type: string + responses: + "200": + description: OK response. + headers: + Content-Disposition: + description: Content-Disposition header for downloading + type: string + Content-Length: + description: Length is the downloaded content length in bytes. + type: int64 + schemes: + - http /oci-file/{repository}: get: tags: @@ -99,7 +135,7 @@ paths: type: array items: type: string - example: Et aut labore veniam et maiores qui. + example: Nam quibusdam recusandae dolor voluptas. schemes: - http /s3-obj/{bucket}/{key}: diff --git a/dl/gen/http/openapi3.json b/dl/gen/http/openapi3.json index 7da45d3..ddcc665 100644 --- a/dl/gen/http/openapi3.json +++ b/dl/gen/http/openapi3.json @@ -1 +1 @@ -{"openapi":"3.0.3","info":{"title":"Download OCI artifacts Service","description":"Service for downloading files from OCI artifact","version":"1.0"},"servers":[{"url":"http://localhost:8000"}],"paths":{"/healthz":{"get":{"tags":["health"],"summary":"healthz health","operationId":"health#healthz","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"boolean","example":true},"example":true}}}}}},"/livez":{"get":{"tags":["health"],"summary":"livez health","operationId":"health#livez","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"boolean","example":true},"example":true}}}}}},"/oci-file/{repository}":{"get":{"tags":["oci"],"summary":"download-file oci","operationId":"oci#download-file","parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"file name in OCI artifact","example":"Eligendi aut vero et neque odit."},"example":"At aperiam laboriosam odio ut quam."},{"name":"tag","in":"query","description":"OCI artifact tag","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"OCI artifact tag","example":"Assumenda aliquam est et aut."},"example":"Magnam a corporis."},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"schema":{"type":"string","description":"OCI artifact repository","example":"Sed nihil autem dolor blanditiis accusamus sit."},"example":"Neque sunt ut repellendus."}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","schema":{"type":"string","description":"Content-Disposition header for downloading","example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","schema":{"type":"integer","description":"Length is the downloaded content length in bytes.","example":4194304,"format":"int64"},"example":4194304}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}}},"/oci-files/{repository}":{"get":{"tags":["oci"],"summary":"list-files oci","operationId":"oci#list-files","parameters":[{"name":"tag","in":"query","description":"OCI artifact tag","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"OCI artifact tag","example":"Dolor itaque ullam."},"example":"Repellendus id dolorem dolor quasi qui consectetur."},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"schema":{"type":"string","description":"OCI artifact repository","example":"Et et fugit."},"example":"Quia aperiam sunt quam et asperiores cupiditate."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","example":"Qui itaque quos quaerat nulla."},"example":["Vel nobis asperiores at.","Dignissimos error et repellendus.","Nam quibusdam recusandae dolor voluptas."]},"example":["Et qui quo.","Fugiat tempore sapiente dolorem et laborum impedit.","Vero dolores amet possimus quasi libero nesciunt.","Debitis nostrum maiores est."]}}}}}},"/s3-obj/{bucket}/{key}":{"get":{"tags":["ks3"],"summary":"download-object ks3","operationId":"ks3#download-object","parameters":[{"name":"bucket","in":"path","description":"bucket name","required":true,"schema":{"type":"string","description":"bucket name","example":"Quaerat architecto."},"example":"Id et sit expedita."},{"name":"key","in":"path","description":"object key","required":true,"schema":{"type":"string","description":"object key","example":"Vero voluptatum perspiciatis omnis qui vel."},"example":"A at dolor soluta molestiae."}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","schema":{"type":"string","description":"Content-Disposition header for downloading","example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","schema":{"type":"integer","description":"Length is the downloaded content length in bytes.","example":4194304,"format":"int64"},"example":4194304}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service"},{"name":"oci","description":"OCI artifacts download service"},{"name":"ks3","description":"OCI artifacts download service"}]} \ No newline at end of file +{"openapi":"3.0.3","info":{"title":"Download OCI artifacts Service","description":"Service for downloading files from OCI artifact","version":"0.0.1"},"servers":[{"url":"http://localhost:8000"}],"paths":{"/healthz":{"get":{"tags":["health"],"summary":"healthz health","operationId":"health#healthz","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"boolean","example":true},"example":false}}}}}},"/livez":{"get":{"tags":["health"],"summary":"livez health","operationId":"health#livez","responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"boolean","example":true},"example":false}}}}}},"/oci-file-sha256/{repository}":{"get":{"tags":["oci"],"summary":"download-file-sha256 oci","operationId":"oci#download-file-sha256","parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"file name in OCI artifact","example":"Vero voluptatum perspiciatis omnis qui vel."},"example":"A at dolor soluta molestiae."},{"name":"tag","in":"query","description":"OCI artifact tag","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"OCI artifact tag","example":"Sequi dolor voluptatem atque."},"example":"Nesciunt eum quia."},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"schema":{"type":"string","description":"OCI artifact repository","example":"Nobis possimus eaque dolor sunt similique."},"example":"Quod nulla nostrum voluptatem soluta reprehenderit reiciendis."}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","schema":{"type":"string","description":"Content-Disposition header for downloading","example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz.sha256"},"example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz.sha256"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","schema":{"type":"integer","description":"Length is the downloaded content length in bytes.","example":4194304,"format":"int64"},"example":4194304}},"content":{"application/plain-text":{"schema":{"type":"string","format":"binary"}}}}}}},"/oci-file/{repository}":{"get":{"tags":["oci"],"summary":"download-file oci","operationId":"oci#download-file","parameters":[{"name":"file","in":"query","description":"file name in OCI artifact","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"file name in OCI artifact","example":"Est et."},"example":"Non magnam a corporis."},{"name":"tag","in":"query","description":"OCI artifact tag","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"OCI artifact tag","example":"Sed nihil autem dolor blanditiis accusamus sit."},"example":"Neque sunt ut repellendus."},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"schema":{"type":"string","description":"OCI artifact repository","example":"Quaerat architecto."},"example":"Id et sit expedita."}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","schema":{"type":"string","description":"Content-Disposition header for downloading","example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","schema":{"type":"integer","description":"Length is the downloaded content length in bytes.","example":4194304,"format":"int64"},"example":4194304}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}}},"/oci-files/{repository}":{"get":{"tags":["oci"],"summary":"list-files oci","operationId":"oci#list-files","parameters":[{"name":"tag","in":"query","description":"OCI artifact tag","allowEmptyValue":true,"required":true,"schema":{"type":"string","description":"OCI artifact tag","example":"Et qui quo."},"example":"Fugiat tempore sapiente dolorem et laborum impedit."},{"name":"repository","in":"path","description":"OCI artifact repository","required":true,"schema":{"type":"string","description":"OCI artifact repository","example":"Vero dolores amet possimus quasi libero nesciunt."},"example":"Debitis nostrum maiores est."}],"responses":{"200":{"description":"OK response.","content":{"application/json":{"schema":{"type":"array","items":{"type":"string","example":"Dolor itaque ullam."},"example":["Id dolorem dolor quasi qui.","Dolore et et fugit officia quia aperiam.","Quam et asperiores."]},"example":["Aut vero et.","Odit rerum at aperiam laboriosam odio.","Quam iusto assumenda."]}}}}}},"/s3-obj/{bucket}/{key}":{"get":{"tags":["ks3"],"summary":"download-object ks3","operationId":"ks3#download-object","parameters":[{"name":"bucket","in":"path","description":"bucket name","required":true,"schema":{"type":"string","description":"bucket name","example":"Ut nulla et itaque."},"example":"Molestiae dolorum."},{"name":"key","in":"path","description":"object key","required":true,"schema":{"type":"string","description":"object key","example":"Cupiditate recusandae qui."},"example":"Iste dolorem quasi eos."}],"responses":{"200":{"description":"OK response.","headers":{"Content-Disposition":{"description":"Content-Disposition header for downloading","schema":{"type":"string","description":"Content-Disposition header for downloading","example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"example":"attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz"},"Content-Length":{"description":"Length is the downloaded content length in bytes.","schema":{"type":"integer","description":"Length is the downloaded content length in bytes.","example":4194304,"format":"int64"},"example":4194304}},"content":{"application/octet-stream":{"schema":{"type":"string","format":"binary"}}}}}}}},"components":{},"tags":[{"name":"health","description":"Health service"},{"name":"oci","description":"OCI artifacts download service"},{"name":"ks3","description":"OCI artifacts download service"}]} \ No newline at end of file diff --git a/dl/gen/http/openapi3.yaml b/dl/gen/http/openapi3.yaml index d5ff94e..5ee0f72 100644 --- a/dl/gen/http/openapi3.yaml +++ b/dl/gen/http/openapi3.yaml @@ -2,7 +2,7 @@ openapi: 3.0.3 info: title: Download OCI artifacts Service description: Service for downloading files from OCI artifact - version: "1.0" + version: 0.0.1 servers: - url: http://localhost:8000 paths: @@ -20,7 +20,7 @@ paths: schema: type: boolean example: true - example: true + example: false /livez: get: tags: @@ -35,7 +35,67 @@ paths: schema: type: boolean example: true - example: true + example: false + /oci-file-sha256/{repository}: + get: + tags: + - oci + summary: download-file-sha256 oci + operationId: oci#download-file-sha256 + parameters: + - name: file + in: query + description: file name in OCI artifact + allowEmptyValue: true + required: true + schema: + type: string + description: file name in OCI artifact + example: Vero voluptatum perspiciatis omnis qui vel. + example: A at dolor soluta molestiae. + - name: tag + in: query + description: OCI artifact tag + allowEmptyValue: true + required: true + schema: + type: string + description: OCI artifact tag + example: Sequi dolor voluptatem atque. + example: Nesciunt eum quia. + - name: repository + in: path + description: OCI artifact repository + required: true + schema: + type: string + description: OCI artifact repository + example: Nobis possimus eaque dolor sunt similique. + example: Quod nulla nostrum voluptatem soluta reprehenderit reiciendis. + responses: + "200": + description: OK response. + headers: + Content-Disposition: + description: Content-Disposition header for downloading + schema: + type: string + description: Content-Disposition header for downloading + example: attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz.sha256 + example: attachment; filename*=UTF-8''tidb-v7.5.0-darwin-arm64.tar.gz.sha256 + Content-Length: + description: Length is the downloaded content length in bytes. + schema: + type: integer + description: Length is the downloaded content length in bytes. + example: 4194304 + format: int64 + example: 4194304 + content: + application/plain-text: + schema: + type: string + format: binary /oci-file/{repository}: get: tags: @@ -51,8 +111,8 @@ paths: schema: type: string description: file name in OCI artifact - example: Eligendi aut vero et neque odit. - example: At aperiam laboriosam odio ut quam. + example: Est et. + example: Non magnam a corporis. - name: tag in: query description: OCI artifact tag @@ -61,8 +121,8 @@ paths: schema: type: string description: OCI artifact tag - example: Assumenda aliquam est et aut. - example: Magnam a corporis. + example: Sed nihil autem dolor blanditiis accusamus sit. + example: Neque sunt ut repellendus. - name: repository in: path description: OCI artifact repository @@ -70,8 +130,8 @@ paths: schema: type: string description: OCI artifact repository - example: Sed nihil autem dolor blanditiis accusamus sit. - example: Neque sunt ut repellendus. + example: Quaerat architecto. + example: Id et sit expedita. responses: "200": description: OK response. @@ -111,8 +171,8 @@ paths: schema: type: string description: OCI artifact tag - example: Dolor itaque ullam. - example: Repellendus id dolorem dolor quasi qui consectetur. + example: Et qui quo. + example: Fugiat tempore sapiente dolorem et laborum impedit. - name: repository in: path description: OCI artifact repository @@ -120,8 +180,8 @@ paths: schema: type: string description: OCI artifact repository - example: Et et fugit. - example: Quia aperiam sunt quam et asperiores cupiditate. + example: Vero dolores amet possimus quasi libero nesciunt. + example: Debitis nostrum maiores est. responses: "200": description: OK response. @@ -131,16 +191,15 @@ paths: type: array items: type: string - example: Qui itaque quos quaerat nulla. + example: Dolor itaque ullam. example: - - Vel nobis asperiores at. - - Dignissimos error et repellendus. - - Nam quibusdam recusandae dolor voluptas. + - Id dolorem dolor quasi qui. + - Dolore et et fugit officia quia aperiam. + - Quam et asperiores. example: - - Et qui quo. - - Fugiat tempore sapiente dolorem et laborum impedit. - - Vero dolores amet possimus quasi libero nesciunt. - - Debitis nostrum maiores est. + - Aut vero et. + - Odit rerum at aperiam laboriosam odio. + - Quam iusto assumenda. /s3-obj/{bucket}/{key}: get: tags: @@ -155,8 +214,8 @@ paths: schema: type: string description: bucket name - example: Quaerat architecto. - example: Id et sit expedita. + example: Ut nulla et itaque. + example: Molestiae dolorum. - name: key in: path description: object key @@ -164,8 +223,8 @@ paths: schema: type: string description: object key - example: Vero voluptatum perspiciatis omnis qui vel. - example: A at dolor soluta molestiae. + example: Cupiditate recusandae qui. + example: Iste dolorem quasi eos. responses: "200": description: OK response. diff --git a/dl/gen/ks3/client.go b/dl/gen/ks3/client.go index 98779ae..f49bbc4 100644 --- a/dl/gen/ks3/client.go +++ b/dl/gen/ks3/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 client // diff --git a/dl/gen/ks3/endpoints.go b/dl/gen/ks3/endpoints.go index b5f57ca..a3fdb44 100644 --- a/dl/gen/ks3/endpoints.go +++ b/dl/gen/ks3/endpoints.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 endpoints // diff --git a/dl/gen/ks3/service.go b/dl/gen/ks3/service.go index ff9d811..03d0457 100644 --- a/dl/gen/ks3/service.go +++ b/dl/gen/ks3/service.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // ks3 service // @@ -20,6 +20,12 @@ type Service interface { DownloadObject(context.Context, *DownloadObjectPayload) (res *DownloadObjectResult, body io.ReadCloser, err error) } +// APIName is the name of the API as defined in the design. +const APIName = "dl" + +// APIVersion is the version of the API as defined in the design. +const APIVersion = "0.0.1" + // ServiceName is the name of the service as defined in the design. This is the // same value that is set in the endpoint request contexts under the ServiceKey // key. diff --git a/dl/gen/oci/client.go b/dl/gen/oci/client.go index b2f26f5..713bfa6 100644 --- a/dl/gen/oci/client.go +++ b/dl/gen/oci/client.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci client // @@ -16,15 +16,17 @@ import ( // Client is the "oci" service client. type Client struct { - ListFilesEndpoint goa.Endpoint - DownloadFileEndpoint goa.Endpoint + ListFilesEndpoint goa.Endpoint + DownloadFileEndpoint goa.Endpoint + DownloadFileSha256Endpoint goa.Endpoint } // NewClient initializes a "oci" service client given the endpoints. -func NewClient(listFiles, downloadFile goa.Endpoint) *Client { +func NewClient(listFiles, downloadFile, downloadFileSha256 goa.Endpoint) *Client { return &Client{ - ListFilesEndpoint: listFiles, - DownloadFileEndpoint: downloadFile, + ListFilesEndpoint: listFiles, + DownloadFileEndpoint: downloadFile, + DownloadFileSha256Endpoint: downloadFileSha256, } } @@ -52,3 +54,19 @@ func (c *Client) DownloadFile(ctx context.Context, p *DownloadFilePayload) (res o := ires.(*DownloadFileResponseData) return o.Result, o.Body, nil } + +// DownloadFileSha256 calls the "download-file-sha256" endpoint of the "oci" +// service. +// DownloadFileSha256 may return the following errors: +// - "invalid_file_path" (type *goa.ServiceError): Could not locate file for download +// - "internal_error" (type *goa.ServiceError): Fault while processing download. +// - error: internal error +func (c *Client) DownloadFileSha256(ctx context.Context, p *DownloadFileSha256Payload) (res *DownloadFileSha256Result, resp io.ReadCloser, err error) { + var ires any + ires, err = c.DownloadFileSha256Endpoint(ctx, p) + if err != nil { + return + } + o := ires.(*DownloadFileSha256ResponseData) + return o.Result, o.Body, nil +} diff --git a/dl/gen/oci/endpoints.go b/dl/gen/oci/endpoints.go index e8d8924..626bb06 100644 --- a/dl/gen/oci/endpoints.go +++ b/dl/gen/oci/endpoints.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci endpoints // @@ -16,8 +16,9 @@ import ( // Endpoints wraps the "oci" service endpoints. type Endpoints struct { - ListFiles goa.Endpoint - DownloadFile goa.Endpoint + ListFiles goa.Endpoint + DownloadFile goa.Endpoint + DownloadFileSha256 goa.Endpoint } // DownloadFileResponseData holds both the result and the HTTP response body @@ -29,11 +30,21 @@ type DownloadFileResponseData struct { Body io.ReadCloser } +// DownloadFileSha256ResponseData holds both the result and the HTTP response +// body reader of the "download-file-sha256" method. +type DownloadFileSha256ResponseData struct { + // Result is the method result. + Result *DownloadFileSha256Result + // Body streams the HTTP response body. + Body io.ReadCloser +} + // NewEndpoints wraps the methods of the "oci" service with endpoints. func NewEndpoints(s Service) *Endpoints { return &Endpoints{ - ListFiles: NewListFilesEndpoint(s), - DownloadFile: NewDownloadFileEndpoint(s), + ListFiles: NewListFilesEndpoint(s), + DownloadFile: NewDownloadFileEndpoint(s), + DownloadFileSha256: NewDownloadFileSha256Endpoint(s), } } @@ -41,6 +52,7 @@ func NewEndpoints(s Service) *Endpoints { func (e *Endpoints) Use(m func(goa.Endpoint) goa.Endpoint) { e.ListFiles = m(e.ListFiles) e.DownloadFile = m(e.DownloadFile) + e.DownloadFileSha256 = m(e.DownloadFileSha256) } // NewListFilesEndpoint returns an endpoint function that calls the method @@ -64,3 +76,16 @@ func NewDownloadFileEndpoint(s Service) goa.Endpoint { return &DownloadFileResponseData{Result: res, Body: body}, nil } } + +// NewDownloadFileSha256Endpoint returns an endpoint function that calls the +// method "download-file-sha256" of service "oci". +func NewDownloadFileSha256Endpoint(s Service) goa.Endpoint { + return func(ctx context.Context, req any) (any, error) { + p := req.(*DownloadFileSha256Payload) + res, body, err := s.DownloadFileSha256(ctx, p) + if err != nil { + return nil, err + } + return &DownloadFileSha256ResponseData{Result: res, Body: body}, nil + } +} diff --git a/dl/gen/oci/service.go b/dl/gen/oci/service.go index e252a2a..47b899b 100644 --- a/dl/gen/oci/service.go +++ b/dl/gen/oci/service.go @@ -1,4 +1,4 @@ -// Code generated by goa v3.14.1, DO NOT EDIT. +// Code generated by goa v3.16.1, DO NOT EDIT. // // oci service // @@ -20,8 +20,16 @@ type Service interface { ListFiles(context.Context, *ListFilesPayload) (res []string, err error) // DownloadFile implements download-file. DownloadFile(context.Context, *DownloadFilePayload) (res *DownloadFileResult, body io.ReadCloser, err error) + // DownloadFileSha256 implements download-file-sha256. + DownloadFileSha256(context.Context, *DownloadFileSha256Payload) (res *DownloadFileSha256Result, body io.ReadCloser, err error) } +// APIName is the name of the API as defined in the design. +const APIName = "dl" + +// APIVersion is the version of the API as defined in the design. +const APIVersion = "0.0.1" + // ServiceName is the name of the service as defined in the design. This is the // same value that is set in the endpoint request contexts under the ServiceKey // key. @@ -30,7 +38,7 @@ const ServiceName = "oci" // MethodNames lists the service method names as defined in the design. These // are the same values that are set in the endpoint request contexts under the // MethodKey key. -var MethodNames = [2]string{"list-files", "download-file"} +var MethodNames = [3]string{"list-files", "download-file", "download-file-sha256"} // DownloadFilePayload is the payload type of the oci service download-file // method. @@ -52,6 +60,26 @@ type DownloadFileResult struct { ContentDisposition string } +// DownloadFileSha256Payload is the payload type of the oci service +// download-file-sha256 method. +type DownloadFileSha256Payload struct { + // OCI artifact repository + Repository string + // OCI artifact tag + Tag string + // file name in OCI artifact + File string +} + +// DownloadFileSha256Result is the result type of the oci service +// download-file-sha256 method. +type DownloadFileSha256Result struct { + // Length is the downloaded content length in bytes. + Length int64 + // Content-Disposition header for downloading + ContentDisposition string +} + // ListFilesPayload is the payload type of the oci service list-files method. type ListFilesPayload struct { // OCI artifact repository diff --git a/dl/go.mod b/dl/go.mod index 5b34425..b6175a1 100644 --- a/dl/go.mod +++ b/dl/go.mod @@ -14,20 +14,17 @@ require ( github.com/AnatolyRugalev/goregen v0.1.0 // indirect github.com/dimfeld/httppath v0.0.0-20170720192232-ee938bf73598 // indirect github.com/go-chi/chi/v5 v5.0.12 // indirect - github.com/gorilla/websocket v1.5.1 // indirect - github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect - github.com/sergi/go-diff v1.3.1 // indirect - golang.org/x/mod v0.17.0 // indirect - golang.org/x/tools v0.20.0 // indirect - gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect -) - -require ( github.com/google/uuid v1.6.0 // indirect + github.com/gorilla/websocket v1.5.1 // indirect github.com/kr/pretty v0.3.1 // indirect + github.com/manveru/faker v0.0.0-20171103152722-9fbc68a78c4d // indirect github.com/opencontainers/go-digest v1.0.0 // indirect github.com/rogpeppe/go-internal v1.11.0 // indirect + github.com/sergi/go-diff v1.3.1 // indirect + golang.org/x/mod v0.17.0 // indirect golang.org/x/net v0.24.0 // indirect golang.org/x/sync v0.7.0 // indirect golang.org/x/text v0.14.0 // indirect + golang.org/x/tools v0.20.0 // indirect + gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c // indirect ) diff --git a/dl/oci.go b/dl/oci.go index 1ac5c49..c9a3d94 100644 --- a/dl/oci.go +++ b/dl/oci.go @@ -5,6 +5,7 @@ import ( "io" "log" "net/url" + "strings" oci "github.com/PingCAP-QE/ee-apps/dl/gen/oci" pkgoci "github.com/PingCAP-QE/ee-apps/dl/pkg/oci" @@ -48,3 +49,19 @@ func (s *ocisrvc) DownloadFile(ctx context.Context, p *oci.DownloadFilePayload) } return res, rc, nil } + +// DownloadFileSha256 implements download-file-sha256. +func (s *ocisrvc) DownloadFileSha256(ctx context.Context, p *oci.DownloadFileSha256Payload) (res *oci.DownloadFileSha256Result, resp io.ReadCloser, err error) { + s.logger.Print("oci.download-file-sha256") + + value, err := pkgoci.GetFileSHA256(ctx, p.Repository, p.Tag, p.File) + if err != nil { + return nil, nil, err + } + + res = &oci.DownloadFileSha256Result{ + Length: int64(len(value)), + ContentDisposition: `attachment; filename*=UTF-8''` + url.QueryEscape(p.File) + ".sha256", + } + return res, io.NopCloser(strings.NewReader(value)), nil +} diff --git a/dl/pkg/oci/download.go b/dl/pkg/oci/download.go index cc85307..a62b16d 100644 --- a/dl/pkg/oci/download.go +++ b/dl/pkg/oci/download.go @@ -5,10 +5,8 @@ import ( "encoding/json" "fmt" "io" - "os" oras "oras.land/oras-go/v2" - "oras.land/oras-go/v2/content" "oras.land/oras-go/v2/registry/remote" ocispec "github.com/opencontainers/image-spec/specs-go/v1" @@ -69,47 +67,20 @@ func NewFileReadCloser(ctx context.Context, repo, tag, filename string) (io.Read return rc, desiredFileDescriptor.Size, nil } -func DownloadFile(ctx context.Context, repo, tag, filename, saveFile string) error { +func GetFileSHA256(ctx context.Context, repo, tag, filename string) (string, error) { repository, err := remote.NewRepository(repo) if err != nil { - return err + return "", err } // 1. get desired file descriptor in the artifact. // destination := strings.Join([]string{repo, tag}, ":") desiredFileDescriptor, err := fetchFileDescriptor(ctx, repository, tag, filename) if err != nil { - return err + return "", err } - // 2. Fetch the blob of the desired file - // blobRef := strings.Join([]string{repo, desiredFileDescriptor.Digest.String()}, "@") - rc, err := repository.Blobs().Fetch(ctx, *desiredFileDescriptor) - if err != nil { - return err - } - defer rc.Close() - - // 3. Create a file to save the desired file - writer, err := os.Create(saveFile) - if err != nil { - return err - } - defer writer.Close() - - // 4. Copy the content the target file. - vr := content.NewVerifyReader(rc, *desiredFileDescriptor) - if _, err = io.Copy(writer, vr); err != nil { - return err - } - - // 5. Handle the downloaded file - if err := vr.Verify(); err != nil { - return err - } - - fmt.Println("File downloaded successfully:", saveFile) - return nil + return desiredFileDescriptor.Digest.Encoded(), nil } func listArtifactLayers(ctx context.Context, target oras.ReadOnlyTarget, ref string) ([]ocispec.Descriptor, error) {