1package common
2
3import (
4 "encoding/json"
5 "fmt"
6 "io"
7 "log"
8 "net/http"
9 "runtime"
10 "time"
11
12 "github.com/bnema/gordon/pkg/docker"
13)
14
15type CurrentVersion struct {
16 isContainer bool
17 Version string `json:"version"`
18}
19
20type ArchVersion struct {
21 Name string `json:"name"`
22}
23
24type VersionInfo struct {
25 Name string `json:"name"`
26}
27
28type VersionsResponse struct {
29 AMD64 string `json:"amd64"`
30 ARM64 string `json:"arm64"`
31}
32
33func GetCurrentBuildVersionInfo(c *Config) CurrentVersion {
34 return CurrentVersion{
35 isContainer: docker.IsRunningInContainer(),
36 Version: c.GetVersion(),
37 }
38}
39
40func CheckForNewVersion(localVersion, remoteVersion string) string {
41 if localVersion != remoteVersion {
42 return "A new version is available"
43 }
44 return ""
45}
46
47func getArch() string {
48 return runtime.GOARCH
49}
50
51func checkAndUpdateVersion(c *Config) (string, error) {
52 localVersion := GetCurrentBuildVersionInfo(c)
53 remoteVersions, err := getRemoteVersion(c)
54 if err != nil {
55 return "", err
56 }
57
58 var remoteVersion string
59 switch getArch() {
60 case "amd64":
61 remoteVersion = remoteVersions.AMD64
62 case "arm64":
63 remoteVersion = remoteVersions.ARM64
64 default:
65 return "", fmt.Errorf("unsupported architecture: %s", getArch())
66 }
67
68 // Check if remoteVersion is empty
69 if remoteVersion == "" {
70 return "", fmt.Errorf("remote version not available for architecture %s", getArch())
71 }
72
73 message := CheckForNewVersion(localVersion.Version, remoteVersion)
74
75 // Return the message without an error, even if it's empty
76 return message, nil
77}
78
79func CheckVersionPeriodically(c *Config) (string, error) {
80 // Check if version is "devel"
81 if c.GetVersion() == "devel" {
82 return "", nil
83 }
84
85 // Perform an immediate check.
86 newVersionMessage, err := checkAndUpdateVersion(c)
87
88 if err != nil {
89 return "", err
90 }
91
92 if newVersionMessage != "" {
93 fmt.Println(newVersionMessage)
94 return "", nil
95 }
96
97 // Set up a ticker to check every 5 minutes.
98 timer := time.NewTicker(5 * time.Minute)
99 defer timer.Stop()
100
101 for range timer.C {
102 newVersionMessage, err = checkAndUpdateVersion(c)
103 if err != nil {
104 log.Printf("Error fetching remote version: %s", err)
105 continue
106 }
107
108 if newVersionMessage != "" {
109 fmt.Println(newVersionMessage)
110 return "", nil //We return so the loop stops in case of a new version
111 }
112 }
113
114 return "", nil
115}
116
117func getRemoteVersion(c *Config) (VersionsResponse, error) {
118 proxyURL := c.Build.ProxyURL
119 if proxyURL == "" {
120 return VersionsResponse{}, fmt.Errorf("proxy URL is empty")
121 }
122
123 checkVersionEndpoint := proxyURL + "/version"
124 resp, err := http.Get(checkVersionEndpoint)
125 if err != nil {
126 return VersionsResponse{}, err
127 }
128
129 defer resp.Body.Close()
130
131 body, err := io.ReadAll(resp.Body)
132 if err != nil {
133 return VersionsResponse{}, err
134 }
135
136 var remoteVersionInfo VersionsResponse
137 err = json.Unmarshal(body, &remoteVersionInfo)
138 if err != nil {
139 return VersionsResponse{}, err
140 }
141
142 return remoteVersionInfo, nil
143}