Skip to content

Commit

Permalink
request: remove RequestClient.Validate
Browse files Browse the repository at this point in the history
After the last changes this would not affect performance. Not that it
matters too much anyway, while parsing the Result is kind slow, it is
not by far the impactful thing for performance, unless you are doing
maybe thousands of commands, but I think the IPC interface will be a
bottleneck much earlier than parsing the results.
  • Loading branch information
thiagokokada committed Jul 25, 2024
1 parent fa4304e commit 44e3a40
Show file tree
Hide file tree
Showing 3 changed files with 29 additions and 37 deletions.
34 changes: 13 additions & 21 deletions request.go
Original file line number Diff line number Diff line change
Expand Up @@ -134,16 +134,12 @@ func parseResponse(raw RawResponse) (response []Response, err error) {
return response, nil
}

func validateResponse(validate bool, params []string, response []Response) ([]Response, error) {
func validateResponse(params []string, response []Response) ([]Response, error) {
// Empty response, something went terrible wrong
if len(response) == 0 {
return []Response{""}, errors.New("empty response")
}

if !validate {
return response, nil
}

want := len(params)
if want == 0 {
// commands without parameters will have at least one return
Expand All @@ -169,12 +165,12 @@ func validateResponse(validate bool, params []string, response []Response) ([]Re
return response, nil
}

func parseAndValidateResponse(validate bool, params []string, raw RawResponse) ([]Response, error) {
func parseAndValidateResponse(params []string, raw RawResponse) ([]Response, error) {
response, err := parseResponse(raw)
if err != nil {
return response, err
}
return validateResponse(validate, params, response)
return validateResponse(params, response)
}

func unmarshalResponse(response RawResponse, v any) (err error) {
Expand Down Expand Up @@ -237,7 +233,6 @@ func MustClient() *RequestClient {
// '$XDG_RUNTIME_DIR/hypr/$HYPRLAND_INSTANCE_SIGNATURE/.socket.sock'.
func NewClient(socket string) *RequestClient {
return &RequestClient{
Validate: true,
conn: &net.UnixAddr{
Net: "unix",
Name: socket,
Expand Down Expand Up @@ -402,13 +397,13 @@ func (c *RequestClient) Devices() (d Devices, err error) {
// Accept multiple commands at the same time, in this case it will use batch
// mode, similar to 'hyprctl dispatch --batch'.
// Returns a [Response] list for each parameter, that may be useful for further
// validations, especially when [RequestClient] 'Validation' is set to false.
// validations.
func (c *RequestClient) Dispatch(params ...string) (r []Response, err error) {
raw, err := c.doRequest("dispatch", params...)
if err != nil {
return nil, err
}
return parseAndValidateResponse(c.Validate, params, raw)
return parseAndValidateResponse(params, raw)
}

// Get option command, similar to 'hyprctl getoption'.
Expand All @@ -425,26 +420,25 @@ func (c *RequestClient) GetOption(name string) (o Option, err error) {
// Accept multiple commands at the same time, in this case it will use batch
// mode, similar to 'hyprctl keyword --batch'.
// Returns a [Response] list for each parameter, that may be useful for further
// validations, especially when [RequestClient] 'Validation' is set to false.
// validations.
func (c *RequestClient) Keyword(params ...string) (r []Response, err error) {
raw, err := c.doRequest("keyword", params...)
if err != nil {
return nil, err
}
return parseAndValidateResponse(c.Validate, params, raw)
return parseAndValidateResponse(params, raw)
}

// Kill command, similar to 'hyprctl kill'.
// Kill an app by clicking on it, can exit with ESCAPE. Will NOT wait until the
// user to click in the window.
// Returns a [Response], that may be useful for further validations, especially
// when [RequestClient] 'Validation' is set to false.
// Returns a [Response], that may be useful for further validations.
func (c *RequestClient) Kill() (r Response, err error) {
raw, err := c.doRequest("kill")
if err != nil {
return "", err
}
response, err := parseAndValidateResponse(c.Validate, nil, raw)
response, err := parseAndValidateResponse(nil, raw)
return response[0], err // should return only one response
}

Expand All @@ -469,26 +463,24 @@ func (c *RequestClient) Monitors() (m []Monitor, err error) {
}

// Reload command, similar to 'hyprctl reload'.
// Returns a [Response], that may be useful for further validations, especially
// when [RequestClient] 'Validation' is set to false.
// Returns a [Response], that may be useful for further validations.
func (c *RequestClient) Reload() (r Response, err error) {
raw, err := c.doRequest("reload")
if err != nil {
return "", err
}
response, err := parseAndValidateResponse(c.Validate, nil, raw)
response, err := parseAndValidateResponse(nil, raw)
return response[0], err // should return only one response
}

// Set cursor command, similar to 'hyprctl setcursor'.
// Returns a [Response] object, that may be useful for further validations,
// especially when [RequestClient] 'Validation' is set to false.
// Returns a [Response], that may be useful for further validations
func (c *RequestClient) SetCursor(theme string, size int) (r Response, err error) {
raw, err := c.doRequest("setcursor", fmt.Sprintf("%s %d", theme, size))
if err != nil {
return "", err
}
response, err := parseAndValidateResponse(c.Validate, nil, raw)
response, err := parseAndValidateResponse(nil, raw)
return response[0], err // should return only one response
}

Expand Down
27 changes: 15 additions & 12 deletions request_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -164,32 +164,35 @@ func TestParseResponse(t *testing.T) {
}
}

func BenchmarkParseResponse(b *testing.B) {
response := []byte(strings.Repeat("ok\r\n", 1000))

for i := 0; i < b.N; i++ {
parseResponse(response)
}
}

func TestValidateResponse(t *testing.T) {
tests := []struct {
validate bool
params []string
response []Response
want []Response
wantErr bool
}{
// empty response should error
{true, genParams("param", 1), []Response{}, []Response{""}, true},
{genParams("param", 1), []Response{}, []Response{""}, true},
// happy path
{true, genParams("param", 1), []Response{"ok"}, []Response{"ok"}, false},
{genParams("param", 1), []Response{"ok"}, []Response{"ok"}, false},
// happy path
{true, genParams("param", 2), []Response{"ok", "ok"}, []Response{"ok", "ok"}, false},
{genParams("param", 2), []Response{"ok", "ok"}, []Response{"ok", "ok"}, false},
// missing response
{true, genParams("param", 2), []Response{"ok"}, []Response{"ok"}, true},
// disable validation
{false, genParams("param", 2), []Response{"ok"}, []Response{"ok"}, false},
{genParams("param", 2), []Response{"ok"}, []Response{"ok"}, true},
// non-ok response
{true, genParams("param", 2), []Response{"ok", "Invalid command"}, []Response{"ok", "Invalid command"}, true},
// disable validation
{false, genParams("param", 2), []Response{"ok", "Invalid command"}, []Response{"ok", "Invalid command"}, false},
{genParams("param", 2), []Response{"ok", "Invalid command"}, []Response{"ok", "Invalid command"}, true},
}
for _, tt := range tests {
t.Run(fmt.Sprintf("tests_%v-%v-%v", tt.validate, tt.params, tt.response), func(t *testing.T) {
response, err := validateResponse(tt.validate, tt.params, tt.response)
t.Run(fmt.Sprintf("tests_%v-%v", tt.params, tt.response), func(t *testing.T) {
response, err := validateResponse(tt.params, tt.response)
assert.DeepEqual(t, response, tt.want)
if tt.wantErr {
assert.Error(t, err)
Expand Down
5 changes: 1 addition & 4 deletions request_types.go
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,8 @@ type RawResponse []byte
type Response string

// RequestClient is the main struct from hyprland-go.
// You may want to set 'Validate' as false to avoid (possibly costly)
// validations, at the expense of not reporting some errors in the IPC.
type RequestClient struct {
Validate bool
conn *net.UnixAddr
conn *net.UnixAddr
}

// Unmarshal structs for requests.
Expand Down

0 comments on commit 44e3a40

Please sign in to comment.