ollie/toolsrv/spawn.go

77 lines
2.1 KiB
Go

package toolsrv
import (
"context"
"fmt"
)
// Process represents a running toolsrv subprocess.
// The session owns this and calls Close() when the session ends.
type Process struct {
// Socket is the Unix socket path clients should Dial().
Socket string
// Info holds host environment details (platform, git repo status).
Info HostInfo
// cleanup shuts down the subprocess and removes the socket.
cleanup func()
}
// Close shuts down the toolsrv subprocess and removes the socket file.
func (p *Process) Close() {
if p.cleanup != nil {
p.cleanup()
}
}
// Spawn starts a local ollie-remote subprocess listening on a Unix socket.
// The returned Process owns the subprocess lifecycle. Callers connect
// via Dial(LocalAddr(proc.Socket)).
func Spawn(ctx context.Context, cwd string, opts ...Option) (*Process, error) {
StreamOutput(ctx, "[toolsrv] spawning local toolsrv...\n")
t, err := localDial(ctx, cwd, opts...)
if err != nil {
return nil, err
}
// Verify the server is responsive via the initial connection.
conn := NewConnSplit(t.r, t.w, func() {})
var info HostInfo
if hi, err := conn.FetchHostInfo(); err == nil {
info = hi
}
StreamOutput(ctx, fmt.Sprintf("[toolsrv] local ready: %s (socket %s)\n", cwd, t.sockPath))
return &Process{
Socket: t.sockPath,
Info: info,
cleanup: t.cleanup,
}, nil
}
// SpawnRemote starts ollie-remote on a remote host via SSH, sets up Unix
// socket forwarding, and returns a Process with the local forwarded socket.
func SpawnRemote(ctx context.Context, cfg RemoteConfig) (*Process, error) {
StreamOutput(ctx, fmt.Sprintf("[toolsrv] dialing %s (cwd: %s)...\n", cfg.SSHTarget, cfg.CWD))
t, err := sshDial(ctx, cfg)
if err != nil {
return nil, fmt.Errorf("spawn remote: %w", err)
}
conn := NewConnSplit(t.r, t.w, func() {})
var info HostInfo
if hi, err := conn.FetchHostInfo(); err == nil {
info = hi
}
StreamOutput(ctx, fmt.Sprintf("[toolsrv] remote ready: %s → %s (%s/%s)\n", cfg.SSHTarget, t.sockPath, info.Platform, info.Arch))
return &Process{
Socket: t.sockPath,
Info: info,
cleanup: t.cleanup,
}, nil
}