mirror of
https://github.com/GopeedLab/gopeed.git
synced 2026-11-04 07:45:30 +00:00
91 lines
2.6 KiB
Go
91 lines
2.6 KiB
Go
// Package githubmirror rewrites GitHub URLs and executes mirrored operations.
|
|
package githubmirror
|
|
|
|
import (
|
|
"fmt"
|
|
"net/url"
|
|
"strings"
|
|
)
|
|
|
|
type Mirror struct {
|
|
Type string `json:"type"`
|
|
URL string `json:"url"`
|
|
IsBuiltIn bool `json:"isBuiltIn"`
|
|
IsDeleted bool `json:"isDeleted"`
|
|
}
|
|
type Config struct {
|
|
Enabled bool `json:"enabled"`
|
|
Mirrors []Mirror `json:"mirrors"`
|
|
}
|
|
|
|
func DefaultConfig() *Config {
|
|
return &Config{Enabled: true, Mirrors: []Mirror{
|
|
{Type: "jsdelivr", URL: "https://fastly.jsdelivr.net/gh", IsBuiltIn: true},
|
|
{Type: "ghProxy", URL: "https://fastgit.cc", IsBuiltIn: true},
|
|
{Type: "ghProxy", URL: "https://gh-proxy.com", IsBuiltIn: true},
|
|
{Type: "ghProxy", URL: "https://ghfast.top", IsBuiltIn: true},
|
|
}}
|
|
}
|
|
func (c *Config) Validate() error {
|
|
if len(c.Mirrors) > 32 {
|
|
return fmt.Errorf("too many GitHub mirrors")
|
|
}
|
|
for _, mirror := range c.Mirrors {
|
|
u, err := url.Parse(mirror.URL)
|
|
if err != nil || u == nil || (u.Scheme != "http" && u.Scheme != "https") || u.Host == "" || u.User != nil || u.RawQuery != "" || u.Fragment != "" {
|
|
return fmt.Errorf("invalid GitHub mirror URL")
|
|
}
|
|
if mirror.Type != "jsdelivr" && mirror.Type != "ghProxy" {
|
|
return fmt.Errorf("invalid GitHub mirror type: %s", mirror.Type)
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// Kind describes what a candidate endpoint must support.
|
|
type Kind uint8
|
|
|
|
const (
|
|
Resource Kind = iota
|
|
Repository
|
|
)
|
|
|
|
// Candidates preserves the official URL first. jsDelivr is only eligible for
|
|
// raw source resources; Git operations use mirrors supporting Git Smart HTTP.
|
|
// GitHub API URLs are never mirrored.
|
|
func Candidates(c *Config, raw string, kind Kind) []string {
|
|
result := []string{raw}
|
|
u, err := url.Parse(raw)
|
|
if err != nil || c == nil || !c.Enabled || u.User != nil || (u.Scheme != "https" && u.Scheme != "http") {
|
|
return result
|
|
}
|
|
if u.Host != "github.com" && u.Host != "raw.githubusercontent.com" {
|
|
return result
|
|
}
|
|
seen := map[string]bool{raw: true}
|
|
for _, mirror := range c.Mirrors {
|
|
if mirror.IsDeleted {
|
|
continue
|
|
}
|
|
var candidate string
|
|
switch mirror.Type {
|
|
case "ghProxy":
|
|
candidate = strings.TrimRight(mirror.URL, "/") + "/" + raw
|
|
case "jsdelivr":
|
|
if kind == Repository || u.Host != "raw.githubusercontent.com" {
|
|
continue
|
|
}
|
|
parts := strings.SplitN(strings.TrimPrefix(u.EscapedPath(), "/"), "/", 4)
|
|
if len(parts) != 4 {
|
|
continue
|
|
}
|
|
candidate = strings.TrimRight(mirror.URL, "/") + "/" + parts[0] + "/" + parts[1] + "@" + parts[2] + "/" + parts[3]
|
|
}
|
|
if candidate != "" && !seen[candidate] {
|
|
result = append(result, candidate)
|
|
seen[candidate] = true
|
|
}
|
|
}
|
|
return result
|
|
}
|