refactored communication into sendMessage function

This commit is contained in:
milarin 2024-02-14 16:36:12 +01:00
parent 305cc6ce13
commit 103b4c37a8
13 changed files with 240 additions and 122 deletions

View File

@ -1,7 +1,11 @@
package sway
import (
"encoding/binary"
"encoding/json"
"errors"
"fmt"
"io"
"net"
"os"
"sync"
@ -41,3 +45,48 @@ func (c *Client) Close() error {
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
}

13
get_bar_config.go Normal file
View File

@ -0,0 +1,13 @@
package sway
import (
"context"
)
func (c *Client) GetBarIDs(ctx context.Context) ([]string, error) {
return sendMessage[[]string](c, 6, "")
}
func (c *Client) GetBarConfig(ctx context.Context, barID string) (*BarConfig, error) {
return sendMessage[*BarConfig](c, 6, barID)
}

9
get_binding_modes.go Normal file
View File

@ -0,0 +1,9 @@
package sway
import (
"context"
)
func (c *Client) GetBindingModes(ctx context.Context) ([]string, error) {
return sendMessage[[]string](c, 8, "")
}

13
get_config.go Normal file
View File

@ -0,0 +1,13 @@
package sway
import (
"context"
)
func (c *Client) GetConfig(ctx context.Context) (string, error) {
cfg, err := sendMessage[config](c, 9, "")
if err != nil {
return "", err
}
return cfg.Config, nil
}

View File

@ -0,0 +1,13 @@
package sway
import (
"context"
)
func (c *Client) GetCurrentBindingMode(ctx context.Context) (string, error) {
mode, err := sendMessage[name](c, 12, "")
if err != nil {
return "", err
}
return mode.Name, nil
}

9
get_marks.go Normal file
View File

@ -0,0 +1,9 @@
package sway
import (
"context"
)
func (c *Client) GetMarks(ctx context.Context) ([]string, error) {
return sendMessage[[]string](c, 5, "")
}

View File

@ -2,46 +2,8 @@ package sway
import (
"context"
"encoding/binary"
"encoding/json"
"fmt"
"io"
)
func (c *Client) GetOutputs(ctx context.Context) ([]Output, error) {
c.Lock()
defer c.Unlock()
if _, err := fmt.Fprint(c.conn, "i3-ipc"); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(0)); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(3)); err != nil {
return nil, err
}
if _, err := c.conn.Read(make([]byte, 6)); err != nil {
return nil, err
}
var length uint32
if err := binary.Read(c.conn, binary.LittleEndian, &length); err != nil {
return nil, err
}
var messageType uint32
if err := binary.Read(c.conn, binary.LittleEndian, &messageType); err != nil {
return nil, err
}
results := []Output{}
if err := json.NewDecoder(io.LimitReader(c.conn, int64(length))).Decode(&results); err != nil {
return nil, err
}
return results, nil
return sendMessage[[]Output](c, 3, "")
}

9
get_tree.go Normal file
View File

@ -0,0 +1,9 @@
package sway
import (
"context"
)
func (c *Client) GetTree(ctx context.Context) (*Node, error) {
return sendMessage[*Node](c, 4, "")
}

9
get_version.go Normal file
View File

@ -0,0 +1,9 @@
package sway
import (
"context"
)
func (c *Client) GetVersion(ctx context.Context) (*Version, error) {
return sendMessage[*Version](c, 7, "")
}

View File

@ -2,46 +2,8 @@ package sway
import (
"context"
"encoding/binary"
"encoding/json"
"fmt"
"io"
)
func (c *Client) GetWorkspaces(ctx context.Context) ([]Workspace, error) {
c.Lock()
defer c.Unlock()
if _, err := fmt.Fprint(c.conn, "i3-ipc"); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(0)); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(1)); err != nil {
return nil, err
}
if _, err := c.conn.Read(make([]byte, 6)); err != nil {
return nil, err
}
var length uint32
if err := binary.Read(c.conn, binary.LittleEndian, &length); err != nil {
return nil, err
}
var messageType uint32
if err := binary.Read(c.conn, binary.LittleEndian, &messageType); err != nil {
return nil, err
}
results := []Workspace{}
if err := json.NewDecoder(io.LimitReader(c.conn, int64(length))).Decode(&results); err != nil {
return nil, err
}
return results, nil
return sendMessage[[]Workspace](c, 1, "")
}

View File

@ -2,50 +2,13 @@ package sway
import (
"context"
"encoding/binary"
"encoding/json"
"fmt"
"io"
"git.milar.in/milarin/slices"
)
func (c *Client) RunCommand(ctx context.Context, cmd string) ([]error, error) {
c.Lock()
defer c.Unlock()
if _, err := fmt.Fprint(c.conn, "i3-ipc"); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(len(cmd))); err != nil {
return nil, err
}
if err := binary.Write(c.conn, binary.LittleEndian, uint32(0)); err != nil {
return nil, err
}
if _, err := fmt.Fprint(c.conn, cmd); err != nil {
return nil, err
}
if _, err := c.conn.Read(make([]byte, 6)); err != nil {
return nil, err
}
var length uint32
if err := binary.Read(c.conn, binary.LittleEndian, &length); err != nil {
return nil, err
}
var messageType uint32
if err := binary.Read(c.conn, binary.LittleEndian, &messageType); err != nil {
return nil, err
}
results := []commandResult{}
if err := json.NewDecoder(io.LimitReader(c.conn, int64(length))).Decode(&results); err != nil {
results, err := sendMessage[[]commandResult](c, 0, cmd)
if err != nil {
return nil, err
}

18
send_tick.go Normal file
View File

@ -0,0 +1,18 @@
package sway
import (
"context"
)
func (c *Client) SendTick(ctx context.Context, payload string) error {
result, err := sendMessage[commandResult](c, 10, payload)
if err != nil {
return err
}
if result.HasError() {
return result.GetError()
}
return nil
}

View File

@ -56,6 +56,27 @@ func (o Output) String() string {
return string(data)
}
type BarConfig struct {
ID string `json:"id"`
Mode BarMode `json:"mode"`
Position BarPosition `json:"position"`
StatusCommand string `json:"status_command"`
Font string `json:"font"`
WorkspaceButtons bool `json:"workspace_buttons"`
WorkspaceMinWidth int `json:"workspace_min_width"`
BindingModeIndicator bool `json:"binding_mode_indicator"`
Colors BarColors `json:"colors"`
Gaps BarGaps `json:"gaps"`
BarHeight int `json:"bar_height"`
StatusPadding int `json:"status_padding"`
StatusEdgePadding int `json:"status_edge_padding"`
}
func (bc BarConfig) String() string {
data, _ := json.MarshalIndent(bc, "", "\t")
return string(data)
}
type WindowProperties struct {
Title string `json:"title"`
Instance string `json:"instance"`
@ -84,9 +105,9 @@ type Node struct {
Geometry Rectangle `json:"geometry"`
Urgent bool `json:"urgent"`
Sticky bool `json:"sticky"`
Marks []interface{} `json:"marks"` // TODO type
Marks []string `json:"marks"`
Focused bool `json:"focused"`
Focus []Node `json:"focus"`
Focus []NodeID `json:"focus"`
Nodes []Node `json:"nodes"`
FloatingNodes []Node `json:"floating_nodes"`
Representation string `json:"representation"`
@ -99,9 +120,10 @@ type Node struct {
Window int `json:"window"`
WindowProperties WindowProperties `json:"window_properties"`
// Undocumented fields. Use with caution!
Num int `json:"num"`
Output string `json:"output"`
// The following fields are undocumented. Use with caution!
// They are included in sway as well as in i3 for years though
Num int `json:"num"` // workspace number
Output string `json:"output"` // output port name
}
func (n Node) String() string {
@ -218,6 +240,21 @@ const (
TransformFlipped270 Transform = "flipped-270"
)
type BarMode = string
const (
BarModeDock BarMode = "dock"
BarModeHide BarMode = "hide"
barModeInvisible BarMode = "invisible"
)
type BarPosition = string
const (
BarPositionTop BarPosition = "top"
BarPositionBottom BarPosition = "bottom"
)
type commandResult struct {
Success bool `json:"success"`
ParseError bool `json:"parse_error"`
@ -242,3 +279,55 @@ type Mode struct {
Height int `json:"height"`
Refresh int `json:"refresh"`
}
type BarColors struct {
Background string `json:"background"`
Statusline string `json:"statusline"`
Separator string `json:"separator"`
FocusedBackground string `json:"focused_background"`
FocusedStatusline string `json:"focused_statusline"`
FocusedSeparator string `json:"focused_separator"`
FocusedWorkspaceText string `json:"focused_workspace_text"`
FocusedWorkspaceBackground string `json:"focused_workspace_bg"`
FocusedWorkspaceBorder string `json:"focused_workspace_border"`
ActiveWorkspaceText string `json:"active_workspace_text"`
ActiveWorkspaceBackground string `json:"active_workspace_bg"`
ActiveWorkspaceBorder string `json:"active_workspace_border"`
InactiveWorkspaceText string `json:"inactive_workspace_text"`
InactiveWorkspaceBackground string `json:"inactive_workspace_bg"`
InactiveWorkspaceBorder string `json:"inactive_workspace_border"`
UrgentWorkspaceText string `json:"urgent_workspace_text"`
UrgentWorkspaceBackground string `json:"urgent_workspace_bg"`
UrgentWorkspaceBorder string `json:"urgent_workspace_border"`
BindingModeText string `json:"binding_mode_text"`
BindingModeBackground string `json:"binding_mode_bg"`
BindingModeBorder string `json:"binding_mode_border"`
}
type BarGaps struct {
Top int `json:"top"`
Right int `json:"right"`
Bottom int `json:"bottom"`
Left int `json:"left"`
}
type Version struct {
Major int `json:"major"`
Minor int `json:"minor"`
Patch int `json:"patch"`
HumanReadable string `json:"human_readable"`
LoadedConfigFileName string `json:"loaded_config_file_name"`
}
func (v Version) String() string {
data, _ := json.MarshalIndent(v, "", "\t")
return string(data)
}
type config struct {
Config string `json:"config"`
}
type name struct {
Name string `json:"name"`
}