package sway import ( "encoding/binary" "encoding/json" "errors" "fmt" "io" "net" "os" "sync" ) type Client struct { sync.Mutex socket string conn net.Conn } func GetDefaultClient() (*Client, error) { socket, ok := os.LookupEnv("SWAYSOCK") if !ok { return nil, errors.New("could not find sway socket. is $SWAYSOCK set properly?") } return GetClientBySocket(socket) } func GetClientBySocket(socket string) (*Client, error) { conn, err := net.Dial("unix", socket) if err != nil { return nil, err } return &Client{ socket: socket, conn: conn, }, nil } func (c *Client) Close() error { c.Lock() defer c.Unlock() return c.conn.Close() } func sendMessage[T any](client *Client, messageType uint32, payload string) (T, error) { client.Lock() defer client.Unlock() if _, err := fmt.Fprint(client.conn, "i3-ipc"); err != nil { return *new(T), err } if err := binary.Write(client.conn, binary.LittleEndian, uint32(len(payload))); err != nil { return *new(T), err } if err := binary.Write(client.conn, binary.LittleEndian, messageType); err != nil { return *new(T), err } if _, err := fmt.Fprint(client.conn, payload); err != nil { return *new(T), err } if _, err := client.conn.Read(make([]byte, 6)); err != nil { return *new(T), err } var length uint32 if err := binary.Read(client.conn, binary.LittleEndian, &length); err != nil { return *new(T), err } var responseType uint32 if err := binary.Read(client.conn, binary.LittleEndian, &responseType); err != nil { return *new(T), err } // io.Copy(os.Stdout, client.conn) // return *new(T), nil result := new(T) if err := json.NewDecoder(io.LimitReader(client.conn, int64(length))).Decode(result); err != nil { return *new(T), err } return *result, nil }