Persistent daemon + thin networked client #9

Open
harry wants to merge 14 commits from feat/daemon-client-split into main
2 changed files with 16 additions and 1 deletions
Showing only changes of commit 95b1967e9b - Show all commits

View File

@@ -232,6 +232,14 @@ func handleDaemonAttach(ctx context.Context, registry *ProjectRegistry, t protoc
_ = sendSnapshot(t, project, view.FocusedID)
}
// Close the transport when the daemon context is cancelled (shutdown or
// `daemon stop`). Without this the t.Recv() loop below blocks forever on a
// still-connected client and the accept loop's wg.Wait() never returns.
go func() {
<-ctx.Done()
_ = t.Close()
}()
done := make(chan struct{})
go func() {
defer close(done)

View File

@@ -7,6 +7,7 @@ import (
"fmt"
"io"
"net"
"sync"
)
var ErrTransportClosed = errors.New("protocol: transport closed")
@@ -18,10 +19,14 @@ type Transport interface {
Close() error
}
// ConnTransport is a JSON-lines implementation over a stream connection.
// ConnTransport is a JSON-lines implementation over a stream connection. Send
// is guarded by a mutex so the daemon can push frames from its subscriber pump
// and its command handlers concurrently; Close may be called from any goroutine
// (e.g. on context cancellation) to unblock a pending Recv.
type ConnTransport struct {
conn net.Conn
r *bufio.Reader
wmu sync.Mutex
w *bufio.Writer
}
@@ -41,6 +46,8 @@ func (t *ConnTransport) Send(f Frame) error {
if err != nil {
return fmt.Errorf("protocol: encode frame: %w", err)
}
t.wmu.Lock()
defer t.wmu.Unlock()
if _, err := t.w.Write(append(b, '\n')); err != nil {
return err
}