A second start of the program opens the server of the first, and does not start another. And the browser opens the address without the token in a command line, because every user of the machine can read the argument list of a process (decision 35).
- A start takes the lock in the user's runtime directory.
- Running finds the record of a server that runs, and whose socket is the user's: open that one, and stop.
- Otherwise listen, Publish the address, and let go of the lock.
- The Opener writes the address to a file that only the user can read, and opens that file.
The Opener writes the address to a file that only the user can read, and opens that file.
runtimeDir, _ := os.MkdirTemp("", "run-") // $XDG_RUNTIME_DIR in a program
defer func() { _ = os.RemoveAll(runtimeDir) }()
ctx := context.Background() // the context of the command in a program
inst, err := launch.Acquire(ctx, runtimeDir, "prog")
if err != nil {
fmt.Println(err)
return
}
defer inst.Release()
if r, ok := inst.Running(); ok {
fmt.Println("prog ui is already running:", r.URL)
return
}
// Listen, then publish the address with the token.
if err := inst.Publish("http://127.0.0.1:7374/?token=T"); err != nil {
fmt.Println(err)
return
}
defer func() { _ = inst.Retire(ctx) }()
fmt.Println("prog ui: http://127.0.0.1:7374/?token=T")prog ui: http://127.0.0.1:7374/?token=Tlocalweb/launch/example_test.go. CI runs it and checks its output.| Name | What it does |
|---|---|
launch.Acquire, launch.Instance | the lock, and the record of the server that runs |
launch.Instance.Running, launch.Instance.Publish, launch.Instance.Retire | find, write and remove the record |
launch.Opener | opens the browser through a private file; Skip where no browser of the user’s can |
launch.Detached | starts a program that outlives this one |
The kit reads no environment: the program passes the runtime directory,
such as $XDG_RUNTIME_DIR/prog, and its name.