From 2d3be9dc2cb0c72c4d1a5e572ad3d395d83510a1 Mon Sep 17 00:00:00 2001 From: 6543 <6543@obermui.de> Date: Fri, 15 Jul 2022 18:53:04 +0200 Subject: [PATCH] ... next ... --- go.mod | 10 ++- go.sum | 15 ++++- server/gitea/client.go | 104 +----------------------------- server/gitea/client_fasthttp.go | 111 ++++++++++++++++++++++++++++++++ server/gitea/client_std.go | 89 +++++++++++++++++++++++++ 5 files changed, 222 insertions(+), 107 deletions(-) create mode 100644 server/gitea/client_fasthttp.go create mode 100644 server/gitea/client_std.go diff --git a/go.mod b/go.mod index 13df431..e184ff4 100644 --- a/go.mod +++ b/go.mod @@ -3,9 +3,11 @@ module codeberg.org/codeberg/pages go 1.18 require ( + code.gitea.io/sdk/gitea v0.15.1-0.20220712164508-e5f0c189f2c7 github.com/OrlovEvgeny/go-mcache v0.0.0-20200121124330-1a8195b34f3a github.com/akrylysov/pogreb v0.10.1 github.com/go-acme/lego/v4 v4.5.3 + github.com/joho/godotenv v1.4.0 github.com/reugn/equalizer v0.0.0-20210216135016-a959c509d7ad github.com/rs/zerolog v1.26.0 github.com/stretchr/testify v1.7.0 @@ -38,6 +40,7 @@ require ( github.com/cpu/goacmedns v0.1.1 // indirect github.com/cpuguy83/go-md2man/v2 v2.0.0 // indirect github.com/davecgh/go-spew v1.1.1 // indirect + github.com/davidmz/go-pageant v1.0.2 // indirect github.com/deepmap/oapi-codegen v1.6.1 // indirect github.com/dimchansky/utfbom v1.1.1 // indirect github.com/dnsimple/dnsimple-go v0.70.1 // indirect @@ -45,6 +48,7 @@ require ( github.com/fatih/structs v1.1.0 // indirect github.com/form3tech-oss/jwt-go v3.2.2+incompatible // indirect github.com/go-errors/errors v1.0.1 // indirect + github.com/go-fed/httpsig v1.1.0 // indirect github.com/go-resty/resty/v2 v2.1.1-0.20191201195748-d7b97669fe48 // indirect github.com/gofrs/uuid v3.2.0+incompatible // indirect github.com/golang/groupcache v0.0.0-20200121045136-8c9f03a8e57e // indirect @@ -56,11 +60,11 @@ require ( github.com/gophercloud/utils v0.0.0-20210216074907-f6de111f2eae // indirect github.com/hashicorp/go-cleanhttp v0.5.1 // indirect github.com/hashicorp/go-retryablehttp v0.7.0 // indirect + github.com/hashicorp/go-version v1.5.0 // indirect github.com/iij/doapi v0.0.0-20190504054126-0bbf12d6d7df // indirect github.com/infobloxopen/infoblox-go-client v1.1.1 // indirect github.com/jarcoal/httpmock v1.0.6 // indirect github.com/jmespath/go-jmespath v0.4.0 // indirect - github.com/joho/godotenv v1.4.0 // indirect github.com/json-iterator/go v1.1.7 // indirect github.com/k0kubun/go-ansi v0.0.0-20180517002512-3bf9e2903213 // indirect github.com/klauspost/compress v1.13.4 // indirect @@ -108,8 +112,8 @@ require ( github.com/vultr/govultr/v2 v2.7.1 // indirect go.opencensus.io v0.22.3 // indirect go.uber.org/ratelimit v0.0.0-20180316092928-c15da0234277 // indirect - golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e // indirect - golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d // indirect + golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e // indirect + golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 // indirect golang.org/x/oauth2 v0.0.0-20200107190931-bf48bf16ab8d // indirect golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e // indirect golang.org/x/text v0.3.6 // indirect diff --git a/go.sum b/go.sum index f009f5e..5f74318 100644 --- a/go.sum +++ b/go.sum @@ -22,6 +22,8 @@ cloud.google.com/go/pubsub v1.2.0/go.mod h1:jhfEVHT8odbXTkndysNHCcx0awwzvfOlguIA cloud.google.com/go/storage v1.0.0/go.mod h1:IhtSnM/ZTZV8YYJWCY8RULGVqBDmpoyjwiyrjsg+URw= cloud.google.com/go/storage v1.5.0/go.mod h1:tpKbwo567HUNpVclU5sGELwQWBDZ8gh0ZeosJ0Rtdos= cloud.google.com/go/storage v1.6.0/go.mod h1:N7U0C8pVQ/+NIKOBQyamJIeKQKkZ+mxpohlUTyfDhBk= +code.gitea.io/sdk/gitea v0.15.1-0.20220712164508-e5f0c189f2c7 h1:Gw4MBRV57gFb/xjqmRDgtn705Jn3VIL2f3/ERk7u7qw= +code.gitea.io/sdk/gitea v0.15.1-0.20220712164508-e5f0c189f2c7/go.mod h1:aRmrQC3CAHdJAU1LQt0C9zqzqI8tUB/5oQtNE746aYE= dmitri.shuralyov.com/gpu/mtl v0.0.0-20190408044501-666a987793e9/go.mod h1:H6x//7gZCb22OMCxBHrMx7a5I7Hp++hsVxbQ4BYO7hU= github.com/Azure/azure-sdk-for-go v32.4.0+incompatible h1:1JP8SKfroEakYiQU2ZyPDosh8w2Tg9UopKt88VyQPt4= github.com/Azure/azure-sdk-for-go v32.4.0+incompatible/go.mod h1:9XXNKU+eRnpl9moKnB4QOLf1HestfXbmab5FXxiDBjc= @@ -106,6 +108,8 @@ github.com/cyberdelia/templates v0.0.0-20141128023046-ca7fffd4298c/go.mod h1:GyV github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= +github.com/davidmz/go-pageant v1.0.2 h1:bPblRCh5jGU+Uptpz6LgMZGD5hJoOt7otgT454WvHn0= +github.com/davidmz/go-pageant v1.0.2/go.mod h1:P2EDDnMqIwG5Rrp05dTRITj9z2zpGcD9efWSkTNKLIE= github.com/deepmap/oapi-codegen v1.6.1 h1:2BvsmRb6pogGNtr8Ann+esAbSKFXx2CZN18VpAMecnw= github.com/deepmap/oapi-codegen v1.6.1/go.mod h1:ryDa9AgbELGeB+YEXE1dR53yAjHwFvE9iAUlWl9Al3M= github.com/dgrijalva/jwt-go v3.2.0+incompatible/go.mod h1:E3ru+11k8xSBh+hMPgOLZmtrrCbhqsmaPHjLKYnJCaQ= @@ -136,6 +140,8 @@ github.com/go-chi/chi/v5 v5.0.0/go.mod h1:BBug9lr0cqtdAhsu6R4AAdvufI0/XBzAQSsUqJ github.com/go-cmd/cmd v1.0.5/go.mod h1:y8q8qlK5wQibcw63djSl/ntiHUHXHGdCkPk0j4QeW4s= github.com/go-errors/errors v1.0.1 h1:LUHzmkK3GUKUrL/1gfBUxAHzcev3apQlezX/+O7ma6w= github.com/go-errors/errors v1.0.1/go.mod h1:f4zRHt4oKfwPJE5k8C9vpYG+aDHdBFUsgrm6/TyX73Q= +github.com/go-fed/httpsig v1.1.0 h1:9M+hb0jkEICD8/cAiNqEB66R87tTINszBRTjwjQzWcI= +github.com/go-fed/httpsig v1.1.0/go.mod h1:RCMrTZvN1bJYtofsG4rd5NaO5obxQ5xBkdiS7xsT7bM= github.com/go-gl/glfw v0.0.0-20190409004039-e6da0acd62b1/go.mod h1:vR7hzQXu2zJy9AVAgeJqvqgH9Q5CA+iKCZ2gyEVpxRU= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20191125211704-12ad95a8df72/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= github.com/go-gl/glfw/v3.3/glfw v0.0.0-20200222043503-6f7a984d4dc4/go.mod h1:tQ2UAYgL5IevRw8kRxooKSPJfGvJ9fJQFa0TUsXzTg8= @@ -243,6 +249,8 @@ github.com/hashicorp/go-syslog v1.0.0/go.mod h1:qPfqrKkXGihmCqbJM2mZgkZGvKG1dFdv github.com/hashicorp/go-uuid v1.0.0/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.1/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= github.com/hashicorp/go-uuid v1.0.2/go.mod h1:6SBZvOh/SIDV7/2o3Jml5SYk/TvGqwFJ/bN7x4byOro= +github.com/hashicorp/go-version v1.5.0 h1:O293SZ2Eg+AAYijkVK3jR786Am1bhDEh2GHT0tIVE5E= +github.com/hashicorp/go-version v1.5.0/go.mod h1:fltr4n8CU8Ke44wwGCBoEymUuxUHl09ZGVZPK5anwXA= github.com/hashicorp/go.net v0.0.1/go.mod h1:hjKkEWcCURg++eb33jQU7oqQcI9XDCnUzHA0oac0k90= github.com/hashicorp/golang-lru v0.5.0/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= github.com/hashicorp/golang-lru v0.5.1/go.mod h1:/m3WP610KZHVQ1SGc6re/UDhFvYD7pJ4Ao+sR/qLZy8= @@ -537,8 +545,9 @@ golang.org/x/crypto v0.0.0-20201002170205-7f63de1d35b0/go.mod h1:LzIPMQfyMNhhGPh golang.org/x/crypto v0.0.0-20201016220609-9e8e0b390897/go.mod h1:LzIPMQfyMNhhGPhUkYOs5KpL4U8rLKemX1yGLhDgUto= golang.org/x/crypto v0.0.0-20201221181555-eec23a3978ad/go.mod h1:jdWPYTVW3xRLrWPugEBEK3UY2ZEsg3UU495nc5E+M+I= golang.org/x/crypto v0.0.0-20210513164829-c07d793c2f9a/go.mod h1:P+XmwS30IXTQdn5tA2iutPOUgjI07+tq3H3K9MVA1s8= -golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e h1:gsTQYXdTw2Gq7RBsWvlQ91b+aEQ6bXFUngBGuR8sPpI= golang.org/x/crypto v0.0.0-20210616213533-5ff15b29337e/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e h1:T8NU3HyQ8ClP4SEE+KbFlg6n0NhuTsN4MyznaarGsZM= +golang.org/x/crypto v0.0.0-20220525230936-793ad666bf5e/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= golang.org/x/exp v0.0.0-20190121172915-509febef88a4/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190306152737-a1d7652674e8/go.mod h1:CJ0aWSM057203Lf6IL+f9T1iT9GByDxfZKAQTCR3kQA= golang.org/x/exp v0.0.0-20190510132918-efd6b22b2522/go.mod h1:ZjyILWgesfNpC6sMxTJOJm9Kp84zZh5NQWvqDGG3Qr8= @@ -603,8 +612,9 @@ golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v golang.org/x/net v0.0.0-20210428140749-89ef3d95e781/go.mod h1:OJAsFXCWl8Ukc7SiCT/9KSuxbyM7479/AVlXFRxuMCk= golang.org/x/net v0.0.0-20210510120150-4163338589ed/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/net v0.0.0-20210614182718-04defd469f4e/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= -golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d h1:20cMwl2fHAzkJMEA+8J4JgqBQcQGzbisXo31MIeenXI= golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2 h1:CIJ76btIcR3eFI5EgSo6k1qKw9KJexJuRLI9G7Hp5wE= +golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y= golang.org/x/oauth2 v0.0.0-20180821212333-d2e6202438be/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U= golang.org/x/oauth2 v0.0.0-20190226205417-e64efc72b421/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= golang.org/x/oauth2 v0.0.0-20190604053449-0f29369cfe45/go.mod h1:gOpvHmFTYa4IltrdGE7lF6nIHvwfUNPOp7c8zoXwtLw= @@ -671,6 +681,7 @@ golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBc golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e h1:WUoyKPm6nCo1BnNUvPGnFG3T5DUVem42yDJZZ4CNxMA= golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20201117132131-f5c789dd3221/go.mod h1:Nr5EML6q2oocZ2LXRh80K7BxOlk5/8JxuGnuhpl+muw= +golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1 h1:v+OssWQX+hTHEmOBgwxdZxK4zHq3yOs8F9J7mk0PY8E= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo= golang.org/x/text v0.0.0-20170915032832-14c0d48ead0c/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ= diff --git a/server/gitea/client.go b/server/gitea/client.go index 7b5d009..26cafa4 100644 --- a/server/gitea/client.go +++ b/server/gitea/client.go @@ -2,27 +2,13 @@ package gitea import ( "errors" - "fmt" - "net/url" "strings" - "time" - - "github.com/valyala/fasthttp" - "github.com/valyala/fastjson" ) const giteaAPIRepos = "/api/v1/repos/" var ErrorNotFound = errors.New("not found") -type Client struct { - giteaRoot string - giteaAPIToken string - fastClient *fasthttp.Client - infoTimeout time.Duration - contentTimeout time.Duration -} - type FileResponse struct { Exists bool ETag []byte @@ -44,92 +30,6 @@ func joinURL(baseURL string, paths ...string) string { return baseURL + "/" + strings.Join(p, "/") } -func (f FileResponse) IsEmpty() bool { return len(f.Body) != 0 } - -func NewClient(giteaRoot, giteaAPIToken string) (*Client, error) { - rootURL, err := url.Parse(giteaRoot) - giteaRoot = strings.Trim(rootURL.String(), "/") - - return &Client{ - giteaRoot: giteaRoot, - giteaAPIToken: giteaAPIToken, - infoTimeout: 5 * time.Second, - contentTimeout: 10 * time.Second, - fastClient: getFastHTTPClient(), - }, err -} - -func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) { - url := joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref)) - res, err := client.do(client.contentTimeout, url) - if err != nil { - return nil, err - } - - switch res.StatusCode() { - case fasthttp.StatusOK: - return res.Body(), nil - case fasthttp.StatusNotFound: - return nil, ErrorNotFound - default: - return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) - } -} - -func (client *Client) ServeRawContent(uri string) (*fasthttp.Response, error) { - url := joinURL(client.giteaRoot, giteaAPIRepos, uri) - res, err := client.do(client.contentTimeout, url) - if err != nil { - return nil, err - } - // resp.SetBodyStream(&strings.Reader{}, -1) - - if err != nil { - return nil, err - } - - switch res.StatusCode() { - case fasthttp.StatusOK: - return res, nil - case fasthttp.StatusNotFound: - return nil, ErrorNotFound - default: - return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) - } -} - -func (client *Client) GiteaGetRepoBranchTimestamp(repoOwner, repoName, branchName string) (time.Time, error) { - url := joinURL(client.giteaRoot, giteaAPIRepos, repoOwner, repoName, "branches", branchName) - res, err := client.do(client.infoTimeout, url) - if err != nil { - return time.Time{}, err - } - if res.StatusCode() != fasthttp.StatusOK { - return time.Time{}, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) - } - return time.Parse(time.RFC3339, fastjson.GetString(res.Body(), "commit", "timestamp")) -} - -func (client *Client) GiteaGetRepoDefaultBranch(repoOwner, repoName string) (string, error) { - url := joinURL(client.giteaRoot, giteaAPIRepos, repoOwner, repoName) - res, err := client.do(client.infoTimeout, url) - if err != nil { - return "", err - } - if res.StatusCode() != fasthttp.StatusOK { - return "", fmt.Errorf("unexpected status code '%d'", res.StatusCode()) - } - return fastjson.GetString(res.Body(), "default_branch"), nil -} - -func (client *Client) do(timeout time.Duration, url string) (*fasthttp.Response, error) { - req := fasthttp.AcquireRequest() - - req.SetRequestURI(url) - req.Header.Set(fasthttp.HeaderAuthorization, "token "+client.giteaAPIToken) - res := fasthttp.AcquireResponse() - - err := client.fastClient.DoTimeout(req, res, timeout) - - return res, err +func (f FileResponse) IsEmpty() bool { + return len(f.Body) != 0 } diff --git a/server/gitea/client_fasthttp.go b/server/gitea/client_fasthttp.go new file mode 100644 index 0000000..cd6b159 --- /dev/null +++ b/server/gitea/client_fasthttp.go @@ -0,0 +1,111 @@ +//go:build fasthttp + +package gitea + +import ( + "fmt" + "net/url" + "strings" + "time" + + "github.com/valyala/fasthttp" + "github.com/valyala/fastjson" +) + +type Client struct { + giteaRoot string + giteaAPIToken string + infoTimeout time.Duration + contentTimeout time.Duration + fastClient *fasthttp.Client + fileResponseCache cache.SetGetKey +} + +func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey) (*Client, error) { + rootURL, err := url.Parse(giteaRoot) + giteaRoot = strings.Trim(rootURL.String(), "/") + + return &Client{ + giteaRoot: giteaRoot, + giteaAPIToken: giteaAPIToken, + infoTimeout: 5 * time.Second, + contentTimeout: 10 * time.Second, + fastClient: getFastHTTPClient(), + fileResponseCache: fileResponseCache, + }, err +} + +func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) { + url := joinURL(client.giteaRoot, giteaAPIRepos, targetOwner, targetRepo, "raw", resource+"?ref="+url.QueryEscape(ref)) + res, err := client.do(client.contentTimeout, url) + if err != nil { + return nil, err + } + + switch res.StatusCode() { + case fasthttp.StatusOK: + return res.Body(), nil + case fasthttp.StatusNotFound: + return nil, ErrorNotFound + default: + return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) + } +} + +func (client *Client) ServeRawContent(uri string) (*fasthttp.Response, error) { + url := joinURL(client.giteaRoot, giteaAPIRepos, uri) + res, err := client.do(client.contentTimeout, url) + if err != nil { + return nil, err + } + // resp.SetBodyStream(&strings.Reader{}, -1) + + if err != nil { + return nil, err + } + + switch res.StatusCode() { + case fasthttp.StatusOK: + return res, nil + case fasthttp.StatusNotFound: + return nil, ErrorNotFound + default: + return nil, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) + } +} + +func (client *Client) GiteaGetRepoBranchTimestamp(repoOwner, repoName, branchName string) (time.Time, error) { + url := joinURL(client.giteaRoot, giteaAPIRepos, repoOwner, repoName, "branches", branchName) + res, err := client.do(client.infoTimeout, url) + if err != nil { + return time.Time{}, err + } + if res.StatusCode() != fasthttp.StatusOK { + return time.Time{}, fmt.Errorf("unexpected status code '%d'", res.StatusCode()) + } + return time.Parse(time.RFC3339, fastjson.GetString(res.Body(), "commit", "timestamp")) +} + +func (client *Client) GiteaGetRepoDefaultBranch(repoOwner, repoName string) (string, error) { + url := joinURL(client.giteaRoot, giteaAPIRepos, repoOwner, repoName) + res, err := client.do(client.infoTimeout, url) + if err != nil { + return "", err + } + if res.StatusCode() != fasthttp.StatusOK { + return "", fmt.Errorf("unexpected status code '%d'", res.StatusCode()) + } + return fastjson.GetString(res.Body(), "default_branch"), nil +} + +func (client *Client) do(timeout time.Duration, url string) (*fasthttp.Response, error) { + req := fasthttp.AcquireRequest() + + req.SetRequestURI(url) + req.Header.Set(fasthttp.HeaderAuthorization, "token "+client.giteaAPIToken) + res := fasthttp.AcquireResponse() + + err := client.fastClient.DoTimeout(req, res, timeout) + + return res, err +} diff --git a/server/gitea/client_std.go b/server/gitea/client_std.go new file mode 100644 index 0000000..4bfc480 --- /dev/null +++ b/server/gitea/client_std.go @@ -0,0 +1,89 @@ +//go:build !fasthttp + +package gitea + +import ( + "bytes" + "fmt" + "io" + "net/http" + "net/url" + "strings" + "time" + + "code.gitea.io/sdk/gitea" + "codeberg.org/codeberg/pages/server/cache" +) + +type Client struct { + sdkClient *gitea.Client + fileResponseCache cache.SetGetKey +} + +func NewClient(giteaRoot, giteaAPIToken string, fileResponseCache cache.SetGetKey) (*Client, error) { + rootURL, err := url.Parse(giteaRoot) + giteaRoot = strings.Trim(rootURL.String(), "/") + + stdClient := http.Client{Timeout: 10 * time.Second} + + sdk, err := gitea.NewClient(giteaRoot, gitea.SetHTTPClient(&stdClient), gitea.SetToken(giteaAPIToken)) + return &Client{ + sdkClient: sdk, + fileResponseCache: fileResponseCache, + }, err +} + +func (client *Client) GiteaRawContent(targetOwner, targetRepo, ref, resource string) ([]byte, error) { + rawBytes, resp, err := client.sdkClient.GetFile(targetOwner, targetRepo, ref, resource) + if err != nil { + return nil, err + } + + switch resp.StatusCode { + case http.StatusOK: + return rawBytes, nil + case http.StatusNotFound: + return nil, ErrorNotFound + default: + return nil, fmt.Errorf("unexpected status code '%d'", resp.StatusCode) + } +} + +func (client *Client) ServeRawContent(targetOwner, targetRepo, ref, resource string) (io.ReadCloser, error) { + // TODO: add func that return io.ReadCloser or io.ReadSeekCloser? + rawBytes, resp, err := client.sdkClient.GetFile(targetOwner, targetRepo, ref, resource) + if err != nil { + return nil, err + } + + switch resp.StatusCode { + case http.StatusOK: + return io.NopCloser(bytes.NewReader(rawBytes)), nil + case http.StatusNotFound: + return nil, ErrorNotFound + default: + return nil, fmt.Errorf("unexpected status code '%d'", resp.StatusCode) + } +} + +func (client *Client) GiteaGetRepoBranchTimestamp(repoOwner, repoName, branchName string) (time.Time, error) { + branch, resp, err := client.sdkClient.GetRepoBranch(repoOwner, repoName, branchName) + if err != nil { + return time.Time{}, err + } + if resp.StatusCode != http.StatusOK { + return time.Time{}, fmt.Errorf("unexpected status code '%d'", resp.StatusCode) + } + return branch.Commit.Timestamp, nil +} + +func (client *Client) GiteaGetRepoDefaultBranch(repoOwner, repoName string) (string, error) { + repo, resp, err := client.sdkClient.GetRepo(repoOwner, repoName) + if err != nil { + return "", err + } + if resp.StatusCode != http.StatusOK { + return "", fmt.Errorf("unexpected status code '%d'", resp.StatusCode) + } + return repo.DefaultBranch, nil +}