1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
|
// Package health probes an ori server's GET /healthz endpoint. It is pure Go
// (no GUI dependency) so the connection logic of the desktop client can be
// unit-tested against an httptest server.
package health
import (
"context"
"encoding/json"
"fmt"
"io"
"net/http"
"time"
)
// DefaultTimeout bounds a single probe; a desktop connection screen must fail
// fast when the server is down.
const DefaultTimeout = 3 * time.Second
// Report is the outcome of one probe, shaped to cross the Wails bridge as a
// plain JSON object (no error type, so the JavaScript side never has to
// distinguish a rejected promise from a negative answer).
type Report struct {
// OK is true when /healthz answered with a 2xx status.
OK bool `json:"ok"`
// URL is the exact URL that was probed.
URL string `json:"url"`
// StatusCode is the HTTP status received, or 0 when no response arrived.
StatusCode int `json:"statusCode"`
// Detail is a short human-readable explanation ("ori is reachable",
// the transport error, or the unexpected status).
Detail string `json:"detail"`
}
// Check performs GET <baseURL>/healthz. baseURL must already be normalised
// (scheme + host, no trailing slash). A nil client uses http.DefaultTransport
// with DefaultTimeout.
func Check(ctx context.Context, client *http.Client, baseURL string) Report {
if client == nil {
client = &http.Client{Timeout: DefaultTimeout}
}
target := baseURL + "/healthz"
rep := Report{URL: target}
req, err := http.NewRequestWithContext(ctx, http.MethodGet, target, nil)
if err != nil {
rep.Detail = fmt.Sprintf("invalid URL: %v", err)
return rep
}
resp, err := client.Do(req)
if err != nil {
rep.Detail = fmt.Sprintf("cannot reach ori: %v", err)
return rep
}
defer resp.Body.Close()
rep.StatusCode = resp.StatusCode
body, _ := io.ReadAll(io.LimitReader(resp.Body, 4096))
if resp.StatusCode < 200 || resp.StatusCode > 299 {
rep.Detail = fmt.Sprintf("unexpected status %s from /healthz (is this really an ori server?)", resp.Status)
return rep
}
rep.OK = true
rep.Detail = describe(body)
return rep
}
// describe turns ori's `{"status":"ok"}` body into a one-liner, tolerating
// any other 2xx body so a future ori version cannot break the client.
func describe(body []byte) string {
var payload struct {
Status string `json:"status"`
}
if err := json.Unmarshal(body, &payload); err == nil && payload.Status != "" {
return "ori is reachable (status: " + payload.Status + ")"
}
return "ori is reachable"
}
|