gitea-attachements-proxy/main.go

177 lines
4.5 KiB
Go

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"))
}