Small HTTP server that redirects to artifacts from the latest github release for a project
Du kannst nicht mehr als 25 Themen auswählen Themen müssen mit entweder einem Buchstaben oder einer Ziffer beginnen. Sie können Bindestriche („-“) enthalten und bis zu 35 Zeichen lang sein.

main.go 2.7KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127
  1. package main
  2. import (
  3. "context"
  4. "flag"
  5. "fmt"
  6. "github.com/google/go-github/github"
  7. "log"
  8. "net/http"
  9. "os"
  10. "os/signal"
  11. "strings"
  12. "syscall"
  13. "time"
  14. )
  15. var (
  16. owner string
  17. repo string
  18. redirect *string
  19. ctx context.Context
  20. client *github.Client
  21. release *github.RepositoryRelease
  22. )
  23. func fetchLatest() {
  24. latest, _, err := client.Repositories.GetLatestRelease(ctx, owner, repo)
  25. if err != nil {
  26. log.Println("Error retrieving latest release", err)
  27. return
  28. }
  29. release = latest
  30. }
  31. func temporaryRedirect(w http.ResponseWriter, url string) {
  32. w.Header().Add("Location", url)
  33. w.WriteHeader(http.StatusTemporaryRedirect)
  34. }
  35. func serve(w http.ResponseWriter, request *http.Request) {
  36. if "/" == request.RequestURI && len(*redirect) > 0 {
  37. temporaryRedirect(w, *redirect)
  38. return
  39. }
  40. if release == nil {
  41. w.WriteHeader(http.StatusInternalServerError)
  42. _, _ = fmt.Fprint(w, "Unknown release")
  43. return
  44. }
  45. for _, asset := range release.Assets {
  46. if "/" + *asset.Name == request.RequestURI {
  47. temporaryRedirect(w, *asset.BrowserDownloadURL)
  48. return
  49. }
  50. }
  51. w.WriteHeader(http.StatusNotFound)
  52. _, _ = fmt.Fprint(w, "Asset not found in release ", *release.Name)
  53. }
  54. func parseRepo(fullRepo *string) error {
  55. if len(*fullRepo) == 0 {
  56. return fmt.Errorf("the repository option must be specified")
  57. }
  58. if strings.Count(*fullRepo, "/") != 1 {
  59. return fmt.Errorf("the repository must be specified in `user/repo` format")
  60. }
  61. repoParts := strings.Split(*fullRepo, "/")
  62. owner = repoParts[0]
  63. repo = repoParts[1]
  64. return nil
  65. }
  66. func main() {
  67. redirect = flag.String("redirect", "", "if specified, requests for / will be redirected to this url")
  68. var fullRepo = flag.String("repo", "", "the repository to redirect releases for, in user/repo format [required]")
  69. var port = flag.Int("port", 8080, "the port to listen on for HTTP requests")
  70. flag.Parse()
  71. if err := parseRepo(fullRepo); err != nil {
  72. _, _ = fmt.Fprintf(os.Stderr, "Error: %s\n\n", err.Error())
  73. flag.Usage()
  74. return
  75. }
  76. client = github.NewClient(nil)
  77. ticker := time.NewTicker(time.Hour)
  78. go func() {
  79. fetchLatest()
  80. for range ticker.C {
  81. fetchLatest()
  82. }
  83. }()
  84. var cancel context.CancelFunc
  85. ctx, cancel = context.WithCancel(context.Background())
  86. c := make(chan os.Signal, 1)
  87. signal.Notify(c, os.Interrupt)
  88. signal.Notify(c, syscall.SIGTERM)
  89. go func() {
  90. for sig := range c {
  91. cancel()
  92. ticker.Stop()
  93. log.Printf("Received %s, exiting.", sig.String())
  94. os.Exit(0)
  95. }
  96. }()
  97. log.Printf("Listing on :%d", *port)
  98. server := &http.Server{
  99. Addr: fmt.Sprintf(":%d", *port),
  100. Handler: http.HandlerFunc(serve),
  101. }
  102. err := server.ListenAndServe()
  103. if err != nil {
  104. log.Println("Error listening for requests on port ", port, err)
  105. }
  106. }