103 lines
2.6 KiB
Go
103 lines
2.6 KiB
Go
package gitrpc
|
|
|
|
import (
|
|
"context"
|
|
"fmt"
|
|
"io"
|
|
"net/http"
|
|
"net/url"
|
|
"time"
|
|
|
|
"connectrpc.com/connect"
|
|
|
|
"simplegit/gitrpc/v1/v1connect"
|
|
)
|
|
|
|
type GitRpcClient struct {
|
|
baseURL string
|
|
http *http.Client
|
|
svc v1connect.GitServiceClient
|
|
}
|
|
|
|
func NewClient(baseURL string) *GitRpcClient {
|
|
httpClient := &http.Client{Timeout: 30 * time.Second}
|
|
svc := v1connect.NewGitServiceClient(
|
|
httpClient,
|
|
baseURL,
|
|
connect.WithInterceptors(tokenInterceptor()),
|
|
)
|
|
return &GitRpcClient{
|
|
baseURL: baseURL,
|
|
http: httpClient,
|
|
svc: svc,
|
|
}
|
|
}
|
|
|
|
func (c *GitRpcClient) GitService() v1connect.GitServiceClient { return c.svc }
|
|
|
|
type tokenCtxKey struct{}
|
|
|
|
func WithToken(ctx context.Context, token string) context.Context {
|
|
return context.WithValue(ctx, tokenCtxKey{}, token)
|
|
}
|
|
|
|
func tokenFromContext(ctx context.Context) (string, bool) {
|
|
t, ok := ctx.Value(tokenCtxKey{}).(string)
|
|
return t, ok
|
|
}
|
|
|
|
func tokenInterceptor() connect.UnaryInterceptorFunc {
|
|
return func(next connect.UnaryFunc) connect.UnaryFunc {
|
|
return func(ctx context.Context, req connect.AnyRequest) (connect.AnyResponse, error) {
|
|
if token, ok := tokenFromContext(ctx); ok {
|
|
req.Header().Set("Authorization", "Bearer "+token)
|
|
}
|
|
return next(ctx, req)
|
|
}
|
|
}
|
|
}
|
|
|
|
func IsNotFound(err error) bool {
|
|
return err != nil && connect.CodeOf(err) == connect.CodeNotFound
|
|
}
|
|
|
|
func (c *GitRpcClient) GetRaw(ctx context.Context, repo, ref, path string) (io.ReadCloser, error) {
|
|
return c.getBinary(ctx, "/raw", repo, url.Values{"ref": {ref}, "file": {path}})
|
|
}
|
|
|
|
func (c *GitRpcClient) GetPatch(ctx context.Context, repo, sha string) (io.ReadCloser, error) {
|
|
return c.getBinary(ctx, "/patch", repo, url.Values{"sha": {sha}})
|
|
}
|
|
|
|
func (c *GitRpcClient) GetArchive(ctx context.Context, repo, ref, format string) (io.ReadCloser, error) {
|
|
v := url.Values{"ref": {ref}}
|
|
if format != "" {
|
|
v.Set("format", format)
|
|
}
|
|
return c.getBinary(ctx, "/archive", repo, v)
|
|
}
|
|
|
|
func (c *GitRpcClient) getBinary(ctx context.Context, endpoint, repo string, extra url.Values) (io.ReadCloser, error) {
|
|
v := url.Values{"repo": {repo}}
|
|
for k, vs := range extra {
|
|
v[k] = vs
|
|
}
|
|
req, err := http.NewRequestWithContext(ctx, http.MethodGet, c.baseURL+endpoint+"?"+v.Encode(), nil)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if token, ok := tokenFromContext(ctx); ok {
|
|
req.Header.Set("Authorization", "Bearer "+token)
|
|
}
|
|
resp, err := c.http.Do(req)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
if resp.StatusCode >= 400 {
|
|
body, _ := io.ReadAll(resp.Body)
|
|
resp.Body.Close()
|
|
return nil, fmt.Errorf("gitrpc %s: %s: %s", endpoint, resp.Status, body)
|
|
}
|
|
return resp.Body, nil
|
|
}
|