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 / exists, false if it // does not. type GetRepositoryMethod func(username, repositoryName string) (Repository, error) // Returns , nil if the file exists at path (relative to the repository) in // /@ exists. If not, returns "", error. type GetFileMethod func(username, repositoryName, branch, path string, since *time.Time) ([]byte, bool, error) type LookupCNAMEMethod func(domain string) (string, error) type LookupRepoTXTMethod func(domain string) (string, error) type HasBranchMethod func(username, repositoryName, branchName string) bool 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 } 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) }, } }