[mirror] Scalable static site server for Git forges (like GitHub Pages)
at main 109 lines 3.1 kB view raw
1package git_pages 2 3import ( 4 "fmt" 5 "slices" 6 "strings" 7 8 "github.com/valyala/fasttemplate" 9) 10 11type WildcardPattern struct { 12 Domain []string 13 CloneURL *fasttemplate.Template 14 IndexRepo *fasttemplate.Template 15 IndexBranch string 16 Authorization bool 17} 18 19func (pattern *WildcardPattern) GetHost() string { 20 parts := []string{"*"} 21 parts = append(parts, pattern.Domain...) 22 return strings.Join(parts, ".") 23} 24 25// Returns `subdomain, found` where if `found == true`, `subdomain` contains the part of `host` 26// corresponding to the * in the domain pattern. 27func (pattern *WildcardPattern) Matches(host string) (string, bool) { 28 hostParts := strings.Split(host, ".") 29 hostLen := len(hostParts) 30 patternLen := len(pattern.Domain) 31 32 // host must have at least one more part than the pattern domain 33 if hostLen <= patternLen { 34 return "", false 35 } 36 37 // break the host parts into <subdomain parts> and <domain parts> 38 mid := hostLen - patternLen 39 prefix := hostParts[:mid] 40 suffix := hostParts[mid:] 41 42 // check if the suffix matches the domain 43 if !slices.Equal(suffix, pattern.Domain) { 44 return "", false 45 } 46 47 // return all the subdomain parts 48 subdomain := strings.Join(prefix, ".") 49 return subdomain, true 50} 51 52func (pattern *WildcardPattern) ApplyTemplate(userName string, projectName string) (string, string) { 53 var repoURL string 54 var branch string 55 repoURLTemplate := pattern.CloneURL 56 if projectName == ".index" { 57 repoURL = repoURLTemplate.ExecuteString(map[string]any{ 58 "user": userName, 59 "project": pattern.IndexRepo.ExecuteString(map[string]any{"user": userName}), 60 }) 61 branch = pattern.IndexBranch 62 } else { 63 repoURL = repoURLTemplate.ExecuteString(map[string]any{ 64 "user": userName, 65 "project": projectName, 66 }) 67 branch = "pages" 68 } 69 return repoURL, branch 70} 71 72func TranslateWildcards(configs []WildcardConfig) ([]*WildcardPattern, error) { 73 var wildcardPatterns []*WildcardPattern 74 for _, config := range configs { 75 cloneURLTemplate, err := fasttemplate.NewTemplate(config.CloneURL, "<", ">") 76 if err != nil { 77 return nil, fmt.Errorf("wildcard pattern: clone URL: %w", err) 78 } 79 80 var indexRepoBranch string = config.IndexRepoBranch 81 indexRepoTemplate, err := fasttemplate.NewTemplate(config.IndexRepo, "<", ">") 82 if err != nil { 83 return nil, fmt.Errorf("wildcard pattern: index repo: %w", err) 84 } 85 86 authorization := false 87 if config.Authorization != "" { 88 if slices.Contains([]string{"gogs", "gitea", "forgejo"}, config.Authorization) { 89 // Currently these are the only supported forges, and the authorization mechanism 90 // is the same for all of them. 91 authorization = true 92 } else { 93 return nil, fmt.Errorf( 94 "wildcard pattern: unknown authorization mechanism: %s", 95 config.Authorization, 96 ) 97 } 98 } 99 100 wildcardPatterns = append(wildcardPatterns, &WildcardPattern{ 101 Domain: strings.Split(config.Domain, "."), 102 CloneURL: cloneURLTemplate, 103 IndexRepo: indexRepoTemplate, 104 IndexBranch: indexRepoBranch, 105 Authorization: authorization, 106 }) 107 } 108 return wildcardPatterns, nil 109}