rio/internal/gitea/client.go

131 lines
3.6 KiB
Go

package gitea
import (
"fmt"
"io"
"net/http"
"time"
"code.gitea.io/sdk/gitea"
log "github.com/sirupsen/logrus"
"git.polynom.me/rio/internal/dns"
)
// Returns true if the repository at <username>/<repository> exists, false if it
// does not.
type GetRepositoryMethod func(username, repositoryName string) (Repository, error)
// Returns <file content>, nil if the file exists at path <path> (relative to the repository) in
// <username>/<repository>@<branch> exists. If not, returns "", error.
type GetFileMethod func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error)
// Returns the result of a CNAME lookup for @domain.
type LookupCNAMEMethod func(domain string) (string, error)
// Return the repository the domain should point to by looking up the TXT record
// "_rio-pages.<domain>".
type LookupRepoTXTMethod func(domain string) (string, error)
// Check of the repository <username>/<repositoryName> contains the specified
// branch.
type HasBranchMethod func(username, repositoryName, branchName string) bool
// Check if the specified username exists.
type HasUserMethod func(username string) bool
type Repository struct {
Name string
}
type GiteaClient struct {
Token string
GetRepository GetRepositoryMethod
HasBranch HasBranchMethod
HasUser HasUserMethod
GetFile GetFileMethod
LookupCNAME LookupCNAMEMethod
LookupRepoTXT LookupRepoTXTMethod
}
func NewGiteaClient(giteaUrl string, token string, giteaClient *gitea.Client) GiteaClient {
return GiteaClient{
Token: token,
GetRepository: func(username, repositoryName string) (Repository, error) {
repo, _, err := giteaClient.GetRepo(username, repositoryName)
if err != nil {
return Repository{}, err
}
return Repository{
Name: repo.Name,
}, nil
},
HasBranch: func(username, repositoryName, branchName string) bool {
res, _, err := giteaClient.ListRepoBranches(username, repositoryName, gitea.ListRepoBranchesOptions{})
if err != nil {
return false
}
for _, branch := range res {
if branch.Name == branchName {
return true
}
}
return false
},
HasUser: func(username string) bool {
_, _, err := giteaClient.GetUserInfo(username)
return err == nil
},
GetFile: func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) {
// We have to do the raw request manually because the Gitea SDK does not allow
// passing the If-Modfied-Since header.
apiUrl := fmt.Sprintf(
"%s/api/v1/repos/%s/%s/raw/%s?ref=%s",
giteaUrl,
username,
repositoryName,
path,
branch,
)
log.Debugf("GetFile: Requesting '%s'", apiUrl)
client := &http.Client{}
req, err := http.NewRequest("GET", apiUrl, nil)
if since != nil {
sinceFormat := since.Format(time.RFC1123)
req.Header.Add("If-Modified-Since", sinceFormat)
}
// Add authentication, if we have a token
if token != "" {
req.Header.Add("Authorization", "token "+token)
}
resp, err := client.Do(req)
if err != nil {
return []byte{}, true, err
}
defer resp.Body.Close()
content, err := io.ReadAll(resp.Body)
if err != nil {
return []byte{}, true, err
} else if resp.StatusCode == 302 {
return []byte{}, false, nil
} else if resp.StatusCode == 404 {
return []byte{}, false, fmt.Errorf("File does not exist")
} else {
return content, true, err
}
},
LookupCNAME: func(domain string) (string, error) {
return dns.LookupCNAME(domain)
},
LookupRepoTXT: func(domain string) (string, error) {
return dns.LookupRepoTXT(domain)
},
}
}