piper: pipe cleanup on early return, write error; misc error hygiene
piper_handler: close stdin/stdout pipes on Start() failure and on WriteString error instead of leaking fds. Propagate WriteString error. worker/client: log SetDeadline errors instead of discarding them. voice/session: pushAudio marshals params inline and returns the marshal error instead of swallowing it via mustParams (removed). tool/matcher: log ListTools errors instead of silently returning an empty allowlist that refuses every act. config: applyDefaults now sets RouterThreshold and ToolTimeout defaults so consumers self-contained defaults are belt-and-suspenders.
This commit is contained in:
@@ -56,17 +56,26 @@ func (h *piperHandler) Synthesize(ctx context.Context, req worker.SynthesizeReq)
|
||||
|
||||
stdout, err := cmd.StdoutPipe()
|
||||
if err != nil {
|
||||
stdin.Close()
|
||||
return worker.SynthesizeResp{}, fmt.Errorf("piper: stdout pipe: %w", err)
|
||||
}
|
||||
|
||||
if err := cmd.Start(); err != nil {
|
||||
stdin.Close()
|
||||
stdout.Close()
|
||||
return worker.SynthesizeResp{}, fmt.Errorf("piper: start: %w", err)
|
||||
}
|
||||
|
||||
_, _ = io.WriteString(stdin, req.Text)
|
||||
if _, err := io.WriteString(stdin, req.Text); err != nil {
|
||||
stdin.Close()
|
||||
stdout.Close()
|
||||
_ = cmd.Wait()
|
||||
return worker.SynthesizeResp{}, fmt.Errorf("piper: write text: %w", err)
|
||||
}
|
||||
stdin.Close()
|
||||
|
||||
rawPCM, readErr := io.ReadAll(stdout)
|
||||
stdout.Close()
|
||||
|
||||
waitErr := cmd.Wait()
|
||||
if waitErr != nil {
|
||||
|
||||
@@ -223,6 +223,7 @@ const (
|
||||
DefaultRepeatInterval = 5 * time.Minute
|
||||
DefaultAutotuneInterval = 10 * time.Minute
|
||||
DefaultRouterThreshold = 0.35
|
||||
DefaultToolTimeout = 30 * time.Second
|
||||
)
|
||||
|
||||
// Load reads the JSON config at path and applies defaults. A missing file is
|
||||
@@ -274,6 +275,15 @@ func (c *Config) applyDefaults() {
|
||||
c.SocketPath = filepath.Join(defaultRuntimeDir(), "mavend.sock")
|
||||
}
|
||||
}
|
||||
|
||||
if c.Voice != nil {
|
||||
if c.Voice.RouterThreshold <= 0 {
|
||||
c.Voice.RouterThreshold = DefaultRouterThreshold
|
||||
}
|
||||
if c.Voice.ToolTimeout <= 0 {
|
||||
c.Voice.ToolTimeout = Duration(DefaultToolTimeout)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Config) validate() error {
|
||||
|
||||
@@ -24,6 +24,7 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
"fmt"
|
||||
"log"
|
||||
"os/exec"
|
||||
"strings"
|
||||
"time"
|
||||
@@ -117,6 +118,7 @@ func NewMatcher(api API) *Matcher { return &Matcher{api: api} }
|
||||
func (m *Matcher) names() []string {
|
||||
ts, err := m.api.ListTools(context.Background(), "enabled")
|
||||
if err != nil {
|
||||
log.Printf("tool: list enabled tools: %v", err)
|
||||
return nil
|
||||
}
|
||||
names := make([]string, len(ts))
|
||||
|
||||
@@ -69,7 +69,11 @@ func (s *Session) pushAudio(p AudioNudgePush) error {
|
||||
if s.closed || s.conn == nil {
|
||||
return fmt.Errorf("voice: session %d closed: %w", s.ID, ErrNoSession)
|
||||
}
|
||||
return writeFrame(s.conn, Push{Kind: PushKindAudioNudge, Params: mustParams(p)})
|
||||
params, err := json.Marshal(p)
|
||||
if err != nil {
|
||||
return fmt.Errorf("voice: marshal push params: %w", err)
|
||||
}
|
||||
return writeFrame(s.conn, Push{Kind: PushKindAudioNudge, Params: params})
|
||||
}
|
||||
|
||||
func (s *Session) shutdown() {
|
||||
@@ -167,11 +171,3 @@ func (r *Sessions) PushToMostRecent(ctx context.Context, p AudioNudgePush) error
|
||||
return best.pushAudio(p)
|
||||
}
|
||||
|
||||
// helper that returns a fixed nil-error marshal so the push call site is short.
|
||||
func mustParams(v any) json.RawMessage {
|
||||
if v == nil {
|
||||
return nil
|
||||
}
|
||||
b, _ := jsonMarshal(v)
|
||||
return b
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"sync"
|
||||
"time"
|
||||
@@ -95,9 +96,13 @@ func (c *Client) call(ctx context.Context, m Method, params any, out any) error
|
||||
// half-sent frame would desync the stream. Teardown is the clean
|
||||
// recovery; the next call re-dials.
|
||||
if dl, ok := ctx.Deadline(); ok {
|
||||
_ = c.c.SetDeadline(dl)
|
||||
if err := c.c.SetDeadline(dl); err != nil {
|
||||
log.Printf("worker: set deadline: %v", err)
|
||||
}
|
||||
} else {
|
||||
_ = c.c.SetDeadline(time.Now().Add(defaultCallTimeout))
|
||||
if err := c.c.SetDeadline(time.Now().Add(defaultCallTimeout)); err != nil {
|
||||
log.Printf("worker: set deadline: %v", err)
|
||||
}
|
||||
}
|
||||
defer c.c.SetDeadline(time.Time{})
|
||||
|
||||
|
||||
Reference in New Issue
Block a user