69 lines
1.9 KiB
Go
69 lines
1.9 KiB
Go
package ipc
|
|
|
|
import (
|
|
"bufio"
|
|
"encoding/json"
|
|
"fmt"
|
|
"os"
|
|
"path/filepath"
|
|
"time"
|
|
|
|
"github.com/bjarneo/cliamp/internal/appdir"
|
|
)
|
|
|
|
// DefaultSocketPath returns the default IPC socket path (~/.config/cliamp/cliamp.sock).
|
|
func DefaultSocketPath() string {
|
|
dir, err := appdir.Dir()
|
|
if err != nil {
|
|
return filepath.Join(os.TempDir(), "cliamp.sock")
|
|
}
|
|
return filepath.Join(dir, "cliamp.sock")
|
|
}
|
|
|
|
// Send connects to the IPC socket, sends a request, and returns the response.
|
|
// The connection is closed after a single request/response exchange.
|
|
func Send(sockPath string, req Request) (Response, error) {
|
|
return SendWithDeadline(sockPath, req, 5*time.Second)
|
|
}
|
|
|
|
// SendWithDeadline is like Send but lets the caller override the exchange
|
|
// deadline. Plugin commands can legitimately run for minutes (downloads), so
|
|
// the generic 5s cap is too short for them.
|
|
func SendWithDeadline(sockPath string, req Request, deadline time.Duration) (Response, error) {
|
|
conn, err := dialSocket(sockPath, 3*time.Second)
|
|
if err != nil {
|
|
if isSocketUnavailable(err) {
|
|
return Response{}, fmt.Errorf("cliamp is not running (no socket at %s)", sockPath)
|
|
}
|
|
return Response{}, fmt.Errorf("connect: %w", err)
|
|
}
|
|
defer conn.Close()
|
|
|
|
conn.SetDeadline(time.Now().Add(deadline))
|
|
|
|
// Encode and send the request as a single JSON line.
|
|
data, err := json.Marshal(req)
|
|
if err != nil {
|
|
return Response{}, fmt.Errorf("marshal request: %w", err)
|
|
}
|
|
data = append(data, '\n')
|
|
if _, err := conn.Write(data); err != nil {
|
|
return Response{}, fmt.Errorf("write: %w", err)
|
|
}
|
|
|
|
// Read the response line.
|
|
scanner := bufio.NewScanner(conn)
|
|
if !scanner.Scan() {
|
|
if err := scanner.Err(); err != nil {
|
|
return Response{}, fmt.Errorf("read response: %w", err)
|
|
}
|
|
return Response{}, fmt.Errorf("no response from server")
|
|
}
|
|
|
|
var resp Response
|
|
if err := json.Unmarshal(scanner.Bytes(), &resp); err != nil {
|
|
return Response{}, fmt.Errorf("unmarshal response: %w", err)
|
|
}
|
|
return resp, nil
|
|
}
|