updates.go 1.9 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879
  1. package main
  2. import (
  3. "encoding/json"
  4. "io/ioutil"
  5. "net/http"
  6. "regexp"
  7. "time"
  8. "golang.org/x/mod/semver"
  9. )
  10. const updateCheckURL = "https://api.github.com/repos/knadh/listmonk/releases/latest"
  11. type remoteUpdateResp struct {
  12. Version string `json:"tag_name"`
  13. URL string `json:"html_url"`
  14. }
  15. // AppUpdate contains information of a new update available to the app that
  16. // is sent to the frontend.
  17. type AppUpdate struct {
  18. Version string `json:"version"`
  19. URL string `json:"url"`
  20. }
  21. var reSemver = regexp.MustCompile(`-(.*)`)
  22. // checkUpdates is a blocking function that checks for updates to the app
  23. // at the given intervals. On detecting a new update (new semver), it
  24. // sets the global update status that renders a prompt on the UI.
  25. func checkUpdates(curVersion string, interval time.Duration, app *App) {
  26. // Strip -* suffix.
  27. curVersion = reSemver.ReplaceAllString(curVersion, "")
  28. time.Sleep(time.Second * 1)
  29. ticker := time.NewTicker(interval)
  30. defer ticker.Stop()
  31. for range ticker.C {
  32. resp, err := http.Get(updateCheckURL)
  33. if err != nil {
  34. app.log.Printf("error checking for remote update: %v", err)
  35. continue
  36. }
  37. if resp.StatusCode != 200 {
  38. app.log.Printf("non 200 response on remote update check: %d", resp.StatusCode)
  39. continue
  40. }
  41. b, err := ioutil.ReadAll(resp.Body)
  42. if err != nil {
  43. app.log.Printf("error reading remote update payload: %v", err)
  44. continue
  45. }
  46. resp.Body.Close()
  47. var up remoteUpdateResp
  48. if err := json.Unmarshal(b, &up); err != nil {
  49. app.log.Printf("error unmarshalling remote update payload: %v", err)
  50. continue
  51. }
  52. // There is an update. Set it on the global app state.
  53. if semver.IsValid(up.Version) {
  54. v := reSemver.ReplaceAllString(up.Version, "")
  55. if semver.Compare(v, curVersion) > 0 {
  56. app.Lock()
  57. app.update = &AppUpdate{
  58. Version: up.Version,
  59. URL: up.URL,
  60. }
  61. app.Unlock()
  62. app.log.Printf("new update %s found", up.Version)
  63. }
  64. }
  65. }
  66. }