nandi/oripublic Fork 0
f5c963af3c1597c0274ce4a99705dbd92a7d1cba
Commits
Clone
git clone https://git.rickub.com/nandi/ori.git
git clone ssh://git@rickub.com/nandi/ori.git

Host key fingerprint (ed25519): SHA256:iycHnxEyq0Q7uyVpB7JlznP0G7JrTPXLYRcAU5CSLhc — verify it before your first connect.

forked from bots-garden/ori

app.go · 125 lines · 3.8 KBGo Blame HistoryRaw
✨ Workspace panel, selectors, previews, desktop app, sandbox template, resizable file tree, light/dark theme 76d62ac k33g yesterday1package main
2
3import (
4 "context"
5 "fmt"
6 "net/http"
7
8 "github.com/wailsapp/wails/v2/pkg/runtime"
9
10 "rickub.com/bots-garden/ori-desktop/internal/health"
11 "rickub.com/bots-garden/ori-desktop/internal/settings"
12)
13
14// App holds the state shared by the Go-bound methods exposed to the frontend.
15// Every exported method on App is callable from JavaScript as
16// window.go.main.App.<Method>(...) and returns a Promise.
17type App struct {
18 ctx context.Context
19 settingsPath string
20 client *http.Client
21}
22
23// NewApp creates the application state. The settings location is resolved
24// once here; if the platform exposes no user config directory the path is
25// left empty and SaveConfig reports the problem instead of guessing.
26func NewApp() *App {
27 path, err := settings.DefaultPath()
28 if err != nil {
29 path = ""
30 }
31 return &App{
32 settingsPath: path,
33 client: &http.Client{Timeout: health.DefaultTimeout},
34 }
35}
36
37// startup is the Wails OnStartup hook; it keeps the runtime context needed by
38// runtime.* calls such as BrowserOpenURL.
39func (a *App) startup(ctx context.Context) {
40 a.ctx = ctx
41}
42
43// GetConfig returns the remembered settings (defaults on a first run).
44func (a *App) GetConfig() (settings.Settings, error) {
45 if a.settingsPath == "" {
46 return settings.Default(), nil
47 }
48 return settings.Load(a.settingsPath)
49}
50
51// SaveConfig normalises the server URL and persists the settings.
52func (a *App) SaveConfig(s settings.Settings) error {
53 if a.settingsPath == "" {
54 return fmt.Errorf("no user configuration directory available on this platform")
55 }
56 normalized, err := settings.NormalizeURL(s.ServerURL)
57 if err != nil {
58 return err
59 }
60 s.ServerURL = normalized
61 return settings.Save(a.settingsPath, s)
62}
63
64// CheckHealth probes GET <url>/healthz and reports the outcome. It never
65// fails the Promise: a malformed URL or an unreachable server both come back
66// as a Report with OK=false and an explanatory Detail.
67func (a *App) CheckHealth(rawURL string) health.Report {
68 base, err := settings.NormalizeURL(rawURL)
69 if err != nil {
70 return health.Report{URL: rawURL, Detail: err.Error()}
71 }
72 return health.Check(a.context(), a.client, base)
73}
74
75// Connect is the one-call happy path used by the connection screen: it
76// normalises the URL, checks /healthz, remembers the URL on success and
77// returns the normalised base URL the frontend should load. On failure the
78// Promise rejects with the health Detail so the screen can show it.
79func (a *App) Connect(rawURL string) (string, error) {
80 base, err := settings.NormalizeURL(rawURL)
81 if err != nil {
82 return "", err
83 }
84 rep := health.Check(a.context(), a.client, base)
85 if !rep.OK {
86 return "", fmt.Errorf("%s", rep.Detail)
87 }
88 if a.settingsPath != "" {
89 if err := settings.Save(a.settingsPath, settings.Settings{ServerURL: base}); err != nil {
90 // Not fatal for the session: the user is connected, only the
91 // memory of the URL is lost. Surface it in the returned error?
92 // No — the frontend treats an error as "not connected"; log it.
93 fmt.Println("ori-desktop: warning:", err)
94 }
95 }
96 return base, nil
97}
98
99// OpenInBrowser opens the given URL (normalised first) in the system's
100// default browser — the fallback when embedding is not wanted.
101func (a *App) OpenInBrowser(rawURL string) error {
102 base, err := settings.NormalizeURL(rawURL)
103 if err != nil {
104 return err
105 }
106 if a.ctx == nil {
107 return fmt.Errorf("application runtime not ready")
108 }
109 runtime.BrowserOpenURL(a.ctx, base)
110 return nil
111}
112
113// SettingsPath tells the frontend where the settings live, for display.
114func (a *App) SettingsPath() string {
115 return a.settingsPath
116}
117
118// context returns the runtime context, or a background one before startup
119// (bound methods are only reachable after startup, this is belt and braces).
120func (a *App) context() context.Context {
121 if a.ctx != nil {
122 return a.ctx
123 }
124 return context.Background()
125}