2024-01-06 13:47:47 +00:00
|
|
|
package repo
|
|
|
|
|
|
|
|
import (
|
|
|
|
"fmt"
|
|
|
|
"io"
|
|
|
|
"net/http"
|
|
|
|
"time"
|
|
|
|
|
|
|
|
"code.gitea.io/sdk/gitea"
|
|
|
|
|
|
|
|
"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)
|
|
|
|
|
2024-01-11 19:53:31 +00:00
|
|
|
// Returns the result of a CNAME lookup for @domain.
|
2024-01-06 13:47:47 +00:00
|
|
|
type LookupCNAMEMethod func(domain string) (string, error)
|
|
|
|
|
2024-01-11 19:53:31 +00:00
|
|
|
// Return the repository the domain should point to by looking up the TXT record
|
|
|
|
// "_rio-pages.<domain>".
|
2024-01-06 13:47:47 +00:00
|
|
|
type LookupRepoTXTMethod func(domain string) (string, error)
|
|
|
|
|
2024-01-11 19:53:31 +00:00
|
|
|
// Check of the repository <username>/<repositoryName> contains the specified
|
|
|
|
// branch.
|
2024-01-06 13:47:47 +00:00
|
|
|
type HasBranchMethod func(username, repositoryName, branchName string) bool
|
|
|
|
|
2024-01-11 19:53:31 +00:00
|
|
|
// Check if the specified username exists.
|
2024-01-06 13:47:47 +00:00
|
|
|
type HasUserMethod func(username string) bool
|
|
|
|
|
|
|
|
type Repository struct {
|
|
|
|
Name string
|
|
|
|
}
|
|
|
|
|
|
|
|
type GiteaClient struct {
|
|
|
|
getRepository GetRepositoryMethod
|
|
|
|
hasBranch HasBranchMethod
|
|
|
|
hasUser HasUserMethod
|
|
|
|
GetFile GetFileMethod
|
|
|
|
lookupCNAME LookupCNAMEMethod
|
|
|
|
lookupRepoTXT LookupRepoTXTMethod
|
|
|
|
}
|
|
|
|
|
|
|
|
func NewGiteaClient(giteaUrl string, giteaClient *gitea.Client) GiteaClient {
|
|
|
|
return GiteaClient{
|
|
|
|
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,
|
|
|
|
)
|
|
|
|
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)
|
|
|
|
}
|
|
|
|
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
|
2024-01-11 19:50:48 +00:00
|
|
|
} else if resp.StatusCode == 404 {
|
|
|
|
return []byte{}, false, fmt.Errorf("File does not exist")
|
2024-01-06 13:47:47 +00:00
|
|
|
} 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)
|
|
|
|
},
|
|
|
|
}
|
|
|
|
}
|