package main import ( "code.gitea.io/sdk/gitea" "fmt" "github.com/kpango/glg" "github.com/labstack/echo/v4" "github.com/labstack/echo/v4/middleware" "github.com/rs/zerolog" "github.com/rs/zerolog/log" "github.com/rs/zerolog/pkgerrors" "os" "strconv" "sync" "time" ) type Channel int const ( Stable Channel = iota Prerelease ) type Attachement struct { User string Repo string Tag string Filename string Channel Channel } type RegionCounter struct { RegionCount map[string]int sync.RWMutex } var giteaURL string func getAttachementURL(attachement Attachement) (string, error) { client, err := gitea.NewClient(giteaURL) if err != nil { return "", fmt.Errorf("Failed to create gitea client: %v") } var release *gitea.Release if attachement.Tag != "" { release, _, err = client.GetReleaseByTag(attachement.User, attachement.Repo, attachement.Tag) if err != nil { return "", fmt.Errorf("Failed to get release by tag: %v") } } else { isPrerelease := false if attachement.Channel == Prerelease { isPrerelease = true } releases, _, err := client.ListReleases(attachement.User, attachement.Repo, gitea.ListReleasesOptions{IsPreRelease: &isPrerelease}) if err != nil { return "", fmt.Errorf("Failed to get releases: %v") } if len(releases) == 0 { return "", fmt.Errorf("no release found") } release = releases[0] } for _, a := range release.Attachments { if a.Name == attachement.Filename { return a.DownloadURL, nil } } return "", fmt.Errorf("no matching attachement found") } func (r *RegionCounter) countRegion(region string) { log.Debug().Msgf("Region %s", region) r.Lock() defer r.Unlock() if region == "" { return } r.RegionCount[region]++ } func main() { zerolog.TimeFieldFormat = time.RFC1123Z consoleWriter := zerolog.ConsoleWriter{Out: os.Stdout, TimeFormat: time.RFC1123Z} log.Logger = log.Output(consoleWriter).With().Timestamp().Logger() giteaURL = os.Getenv("GITEA_URL") logLevel, err := strconv.Atoi(os.Getenv("LOG_LEVEL")) if err != nil { logLevel = 1 } log.Logger.Level(zerolog.Level(logLevel)) if log.Logger.GetLevel() == zerolog.DebugLevel { log.Logger = log.Output(consoleWriter).With().Timestamp().Caller().Logger() zerolog.ErrorStackMarshaler = pkgerrors.MarshalStack } regionCounter := &RegionCounter{ RegionCount: make(map[string]int), } app := echo.New() app.Use(middleware.Recover()) app.GET("/:user/:repo/releases/download/latest/:name", func(c echo.Context) error { log.Debug().Msgf("%+v", map[string]string{"user": c.Param("user"), "repo": c.Param("repo"), "name": c.Param("name")}) attachement := Attachement{ User: c.Param("user"), Repo: c.Param("repo"), Filename: c.Param("name"), Channel: Stable, } url, err := getAttachementURL(attachement) if err != nil { glg.Debug(err) c.String(404, err.Error()) return nil } go regionCounter.countRegion(c.Request().Header.Get("Fly-Region")) c.Redirect(307, url) return nil }) app.GET("/:user/:repo/releases/download/latest\\::channel/:name", func(c echo.Context) error { log.Debug().Msgf("%+v", map[string]string{"user": c.Param("user"), "repo": c.Param("repo"), "name": c.Param("name"), "channel": c.Param("channel")}) channel := Stable if c.Param("channel") == "prerelease" { channel = Prerelease } attachement := Attachement{ User: c.Param("user"), Repo: c.Param("repo"), Filename: c.Param("name"), Channel: channel, } url, err := getAttachementURL(attachement) if err != nil { glg.Debug(err) c.String(404, err.Error()) return nil } go regionCounter.countRegion(c.Request().Header.Get("Fly-Region")) c.Redirect(307, url) return nil }) app.GET("/:user/:repo/releases/download/tag\\::tag/:name", func(c echo.Context) error { log.Debug().Msgf("%+v", map[string]string{"user": c.Param("user"), "repo": c.Param("repo"), "name": c.Param("name"), "tag": c.Param("tag")}) attachement := Attachement{ User: c.Param("user"), Repo: c.Param("repo"), Filename: c.Param("name"), Tag: c.Param("tag"), } url, err := getAttachementURL(attachement) if err != nil { glg.Debug(err) c.String(404, err.Error()) return nil } go regionCounter.countRegion(c.Request().Header.Get("Fly-Region")) c.Redirect(307, url) return nil }) app.GET("/regions", func(c echo.Context) error { regionCounter.RLock() defer regionCounter.RUnlock() return c.JSON(200, regionCounter.RegionCount) }) log.Error().Err(app.Start(":8080")) }