package main import ( "errors" "strings" "time" "code.gitea.io/sdk/gitea" "github.com/patrickmn/go-cache" log "github.com/sirupsen/logrus" ) var ( pathCache = cache.New(1 * time.Hour, 1 * time.Hour) ) type PageCacheEntry struct { Repository *gitea.Repository Path string } func makePageCacheKey(domain, path string) string { return domain + "/" + path } /// Try to find the repository with name @reponame of the user @username. If @cname /// is not "", then it also verifies that the repository contains a "CNAME" with /// the value of @cname as its content. @host, @domain, and @path are passed for /// caching on success. func lookupRepositoryAndCache(username, reponame, host, domain, path, cname string, giteaClient *gitea.Client) (*gitea.Repository, error) { log.Debugf("Looking up repository %s/%s", username, reponame) repo, _, err := giteaClient.GetRepo(username, reponame) if err != nil { return nil, err } // Check if the CNAME file matches if cname != "" { file, _, err := giteaClient.GetFile( username, repo.Name, PagesBranch, "CNAME", false, ) if err != nil { log.Errorf("Could not verify CNAME of %s/%s: %v\n", username, repo.Name, err) return nil, err } cnameContent := strings.Trim( string(file[:]), "\n", ) if cnameContent != cname { return nil, errors.New("CNAME mismatch") } } // Cache data pathCache.Set( makePageCacheKey(domain, path), PageCacheEntry{ repo, path, }, cache.DefaultExpiration, ) return repo, nil } func RepoFromPath(username, host, cname, path string, giteaClient *gitea.Client) (*gitea.Repository, string, error) { domain := host // Guess the repository key := makePageCacheKey(domain, path) entry, found := pathCache.Get(key) if found { pageEntry := entry.(PageCacheEntry) return pageEntry.Repository, pageEntry.Path, nil } pathParts := strings.Split(path, "/") if len(pathParts) > 1 { log.Debugf("Trying repository %s", pathParts[0]) modifiedPath := strings.Join(pathParts[1:], "/") repo, err := lookupRepositoryAndCache( username, pathParts[0], host, domain, modifiedPath, cname, giteaClient, ) if err == nil { return repo, modifiedPath, nil } } // Allow specifying the repository name in the TXT record reponame := domain lookupDomain := domain if cname != "" { lookupDomain = cname } repoLookup, err := lookupRepoTXT(lookupDomain) if err != nil || repoLookup != "" { log.Infof( "TXT lookup for %s resulted in choosing repository %s", lookupDomain, repoLookup, ) reponame = repoLookup } // Allow naming the repository "example.org" (But give the TXT record preference) if cname != "" && repoLookup == "" && err == nil { reponame = cname; } log.Debugf("Trying repository %s/%s", username, reponame) repo, err := lookupRepositoryAndCache( username, reponame, host, domain, path, cname, giteaClient, ) return repo, path, err }