@@ -13,11 +13,18 @@ import (
1313 "strconv"
1414 "syscall"
1515 "time"
16+
17+ "github.com/babelcloud/gbox/packages/cli/internal/server"
18+ "github.com/babelcloud/gbox/packages/cli/internal/version"
1619)
1720
1821const (
1922 DefaultPort = 29888 // New port for unified gbox server
2023 ServerURL = "http://localhost:29888"
24+
25+ // Version headers returned by server
26+ serverHeaderVersion = "X-GBOX-Version"
27+ serverHeaderBuildID = "X-GBOX-Build-ID"
2128)
2229
2330// Manager handles the gbox server daemon lifecycle
@@ -72,13 +79,25 @@ func (m *Manager) IsServerRunning() bool {
7279
7380// checkHTTPHealth checks if server is responding to HTTP requests
7481func (m * Manager ) checkHTTPHealth () bool {
75- client := & http.Client {Timeout : 500 * time .Millisecond }
82+ client := & http.Client {Timeout : 150 * time .Millisecond }
7683 resp , err := client .Get (fmt .Sprintf ("%s/api/server/info" , m .url ))
7784 if err != nil {
7885 return false
7986 }
8087 defer resp .Body .Close ()
81- return resp .StatusCode == http .StatusOK
88+
89+ if resp .StatusCode != http .StatusOK {
90+ return false
91+ }
92+ serverVersion := resp .Header .Get (serverHeaderVersion )
93+ serverBuildID := resp .Header .Get (serverHeaderBuildID )
94+ clientVersion := version .Version
95+ clientBuildID := server .GetBuildID ()
96+ if (serverVersion != "" && clientVersion != "" && serverVersion != clientVersion ) ||
97+ (serverBuildID != "" && clientBuildID != "" && serverBuildID != clientBuildID ) {
98+ return false
99+ }
100+ return true
82101}
83102
84103// StartServer starts the gbox server daemon
@@ -228,12 +247,58 @@ func (m *Manager) CallAPI(method, endpoint string, body interface{}, result inte
228247 }
229248
230249 client := & http.Client {Timeout : 10 * time .Second }
231- resp , err := client .Do (req )
250+
251+ // perform is a small helper to execute the request
252+ perform := func () (* http.Response , error ) {
253+ return client .Do (req )
254+ }
255+
256+ resp , err := perform ()
232257 if err != nil {
233258 return fmt .Errorf ("API call failed: %v" , err )
234259 }
235260 defer resp .Body .Close ()
236261
262+ // Version/build-id check: compare headers with client values.
263+ serverVersion := resp .Header .Get (serverHeaderVersion )
264+ serverBuildID := resp .Header .Get (serverHeaderBuildID )
265+ clientVersion := version .Version
266+ clientBuildID := server .GetBuildID ()
267+
268+ mismatch := false
269+ if serverVersion != "" && clientVersion != "" && serverVersion != clientVersion {
270+ mismatch = true
271+ }
272+ if serverBuildID != "" && clientBuildID != "" && serverBuildID != clientBuildID {
273+ mismatch = true
274+ }
275+
276+ if mismatch {
277+ _ = m .StopServer ()
278+ if err := m .StartServer (); err != nil {
279+ return fmt .Errorf ("server mismatch (ver:%s!=%s or build:%s!=%s) and restart failed: %v" , serverVersion , clientVersion , serverBuildID , clientBuildID , err )
280+ }
281+ // Retry once with a fresh request object (req body may have been consumed)
282+ if body != nil {
283+ jsonData , _ := json .Marshal (body )
284+ req , err = http .NewRequest (method , url , bytes .NewReader (jsonData ))
285+ if err != nil {
286+ return fmt .Errorf ("failed to create retry request: %v" , err )
287+ }
288+ req .Header .Set ("Content-Type" , "application/json" )
289+ } else {
290+ req , err = http .NewRequest (method , url , nil )
291+ if err != nil {
292+ return fmt .Errorf ("failed to create retry request: %v" , err )
293+ }
294+ }
295+ resp , err = perform ()
296+ if err != nil {
297+ return fmt .Errorf ("API call after restart failed: %v" , err )
298+ }
299+ defer resp .Body .Close ()
300+ }
301+
237302 if resp .StatusCode >= 400 {
238303 body , _ := io .ReadAll (resp .Body )
239304 return fmt .Errorf ("API error (status %d): %s" , resp .StatusCode , string (body ))
0 commit comments