Documentation
¶
Overview ¶
Package apprun is the single owner of the long-lived process boot sequence shared by `gadak serve` and gadak-desktop.
This is a move, not a redesign: each step is the same work the two mains already did. Caller-specific surfaces stay with the caller (serve: addr bind, GuardBrowser, /healthz; desktop: wails window, deeplink, Origin-strip mux). Intentional order differences are options, not a merged sequence:
- GDK-468: serve checks for a live same-profile serve (AfterConfig) before taking the persist lock.
- GDK-658: desktop runs wails SingleInstance (application.New) before AcquireStandalone / StartOriginPassthrough.
Process-start workspace selection (GDK-644) is SelectWorkspace, called from each main before flags. Persist flush on the CLI process is still cmd/gadak main (every verb, os.Exit(1) on failure); desktop sets FlushOnClose so Runtime.Close does that flush.
Index ¶
Constants ¶
This section is empty.
Variables ¶
This section is empty.
Functions ¶
func PublishAdvertise ¶
PublishAdvertise writes serve-origin.json for a standalone workspace and returns a cleanup that removes it. Connected workspaces and a missing profile dir are no-ops.
A write failure is fatal (GDK-343 / F6): this process holds the persist lock, so without the advertise file every concurrent CLI write becomes a hard "workspace busy" error instead of routing here. Failing loud at startup beats a warning nobody reads.
serve calls this after bind (the final address, including port fallback). Desktop does not: it advertises an origin-only listener via StartOriginPassthrough ("no forced server/port").
func SelectWorkspace ¶
func SelectWorkspace()
SelectWorkspace is the process-start workspace pick (GDK-644). Both mains call this before flags (CLI) or early-exit probes (desktop). Importing internal/config no longer selects a workspace.
func StartOriginPassthrough ¶
StartOriginPassthrough gives a standalone desktop app the advertise surface `gadak serve` has (GDK-333), so a concurrent CLI routes writes here instead of opening a second embedded issuetap graph over the same persist file (GDK-340). The app itself has no TCP listener by design — this one is loopback-only, an OS-picked port, and serves exactly two paths, both forwarded to api (which carries the browser guard and the X-Gadak identity headers):
GET origin.ProbePath — the port_fallback / probeMatches probe origin.RESTPrefix/... — the origin passthrough a CLI write takes
Everything else is 404: this is not a UI/API server ("no forced server/port" invariant). Returns a cleanup that withdraws the advertise file and closes the listener. Connected workspaces are a no-op.
Failure is fatal (GDK-343): the persist lock is taken here — before the advertise write — so a second owner dies at startup instead of stealing routing; and once this process holds the lock, a missing advertise file would turn every concurrent CLI write into a hard "workspace busy" error instead of a route, so a failed listener or advertise write aborts too.
The desktop caller invokes this after application.New so wails SingleInstance can os.Exit the second process before persist is taken (GDK-658). Lock-before-advertise inside this function is unchanged.
Types ¶
type Options ¶
type Options struct {
// Version stamps server.Version. Empty leaves the current value.
Version string
// Log receives watch-loop status lines. Default is log.Print. Never
// pass secrets.
Log func(string)
// OpenStore, if set, replaces store.Open(config.DBPath()). serve
// passes cmd/gadak openStore so rejectUnknownProfile stays there.
OpenStore func() (*store.DB, error)
// AfterConfig runs after config.Load and before the store opens (and
// before persist acquire). serve uses this for the live-serve handoff
// (GDK-468), which must happen before the persist lock.
AfterConfig func(*config.Config) error
// DeferStandalone skips persist acquire during Open. Desktop sets this
// so wails SingleInstance (application.New) can os.Exit a second
// instance before persist is taken (GDK-658).
DeferStandalone bool
// FlushOnClose runs origin.Close from Runtime.Close. Desktop sets this
// (GDK-342/348). serve leaves it false: cmd/gadak main flushes every
// verb and os.Exit(1)s on failure.
FlushOnClose bool
}
Options configures caller-specific boot differences. Zero value is the serve-shaped path: persist is taken during Open (after AfterConfig).
type Runtime ¶
type Runtime struct {
Cfg *config.Config
DB *store.DB
API *server.Handler
Reg *workspace.Registry
// contains filtered or unexported fields
}
Runtime is the opened app surface both mains hold. Callers own when to Close (LIFO with their own resources: signal ctx, HTTP listener, wails).
func Open ¶
Open loads config, opens the mirror, builds the API handler (attachment cache + server.New), and creates the workspace registry. Version stamp is first when Options.Version is set. Persist acquire for standalone runs here unless DeferStandalone is set.
func (*Runtime) Close ¶
Close stops an origin-passthrough listener (if this Runtime started one), flushes standalone persist when FlushOnClose is set or persist was acquired here, then closes the registry, API handler, and store — API before DB (GDK-270). Safe on a partial Open.
func (*Runtime) StartOriginPassthrough ¶
StartOriginPassthrough takes persist (if not already held) and advertises an origin-only listener. Desktop calls this after application.New (GDK-658).
func (*Runtime) StartWatch ¶
StartWatch starts the optional update check and the incremental sync loops (primary profile + workspace mounts). Order and log strings match the previous inlined cmdServe / desktop ApplicationStarted body.
Watch re-entry is syncer.WatchLoop, not Watch (GDK-663): Watch returns on fatal auth and would leave the process alive with sync permanently stopped.
noSync skips the watch loops but still starts the update check (serve --no-sync). Desktop always passes false.