From 9afcc7dc1ca1f4cfd9caaa6e636cba8a484f96d3 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 17:44:28 -0500 Subject: [PATCH 01/22] update gitignore to ignore .idea; add device to internal package --- .gitignore | 2 +- internal/device.go | 81 ++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+), 1 deletion(-) create mode 100644 internal/device.go diff --git a/.gitignore b/.gitignore index b4a278d..1c662c5 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .DS_Store *.env - +.idea/ vendor diff --git a/internal/device.go b/internal/device.go new file mode 100644 index 0000000..997fae0 --- /dev/null +++ b/internal/device.go @@ -0,0 +1,81 @@ +package internal + +import ( +"time" +) + +// Device represents the core fields for a LIFX light source +type Device struct { + ID string `json:"json"` + UUID string `json:"uuid"` + Label string `json:"label"` + Connected bool `json:"connected"` + Power string `json:"power"` + Brightness float64 `json:"brightness"` + LastSeen time.Time `json:"last_seen"` + SecondsSinceSeen int `json:"seconds_since_seen"` + Group Group `json:"group"` + Color Color `json:"color"` + Location Location `json:"location"` + Product Product `json:"product"` +} + +// Group represents which group a Device belongs to +type Group struct { + ID string `json:"id"` + Name string `json:"name"` +} + +// Color represents which colors a Device is currently set to +type Color struct { + Hue float64 `json:"hue"` + Saturation float64 `json:"saturation"` + Kelvin float64 `json:"kelvin"` + Name string `json:"name"` +} + +// Location represents what Location a Device belongs to +type Location struct { + ID string `json:"id"` + Name string `json:"name"` +} + +// Product represents the type of LIFX product a Device is +type Product struct { + Name string `json:"name"` + Identifier string `json:"identifier"` + Company string `json:"company"` + Capabilities Capabilities `json:"capabilities"` +} + +// Capabilities represents all of the current features a Device has +type Capabilities struct { + HasColor bool `json:"has_color"` + HasVariableColorTemp bool `json:"has_variable_color_temp"` + HasIR bool `json:"has_ir"` + HasChain bool `json:"has_chain"` + HasMultizone bool `json:"has_multizone"` + MinKelvin float64 `json:"min_kelvin"` + MaxKelvin float64 `json:"max_kelvin"` +} + +// Scene represents currently available scenes for your LIFX bulb +type Scene struct { + UUID string `json:"uuid"` + Name string `json:"name"` + Account map[string]string `json:"account"` + CreatedAt time.Time `json:"created_at"` + UpdatedAt time.Time `json:"updated_at"` + States []State `json:"states"` +} + +// State represents the states of a Scene +type State struct { + Color Color `json:"color"` + Selector string `json:"selector"` + Power string `json:"power"` + Fast bool `json:"fast"` + Brightness float64 `json:"brightness"` + Duration float64 `json:"duration"` + Infrared float64 `json:"infrared"` +} From f3e9acb00203a1256cb044c5865e9b57e9a1200a Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 17:49:04 -0500 Subject: [PATCH 02/22] enable go fmt --- internal/device.go | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/internal/device.go b/internal/device.go index 997fae0..9d49e2f 100644 --- a/internal/device.go +++ b/internal/device.go @@ -1,7 +1,7 @@ package internal import ( -"time" + "time" ) // Device represents the core fields for a LIFX light source @@ -77,5 +77,5 @@ type State struct { Fast bool `json:"fast"` Brightness float64 `json:"brightness"` Duration float64 `json:"duration"` - Infrared float64 `json:"infrared"` + Infrared float64 `json:"infrared"` } From ed4aa3a437210bc7fe5116531ecf982cac172cbc Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 17:56:11 -0500 Subject: [PATCH 03/22] use id tag instead of json --- internal/device.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/device.go b/internal/device.go index 9d49e2f..52d14bc 100644 --- a/internal/device.go +++ b/internal/device.go @@ -6,7 +6,7 @@ import ( // Device represents the core fields for a LIFX light source type Device struct { - ID string `json:"json"` + ID string `json:"id"` UUID string `json:"uuid"` Label string `json:"label"` Connected bool `json:"connected"` From ff999c01fac791e29960467dbfe3d982b7e53a84 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 17:57:03 -0500 Subject: [PATCH 04/22] remove device/filament_device.go --- device/filament_device.go | 81 --------------------------------------- 1 file changed, 81 deletions(-) delete mode 100644 device/filament_device.go diff --git a/device/filament_device.go b/device/filament_device.go deleted file mode 100644 index d8475ab..0000000 --- a/device/filament_device.go +++ /dev/null @@ -1,81 +0,0 @@ -package device - -import ( - "time" -) - -// Device represents the core fields for a LIFX light source -type Device struct { - ID string `json:"json"` - UUID string `json:"uuid"` - Label string `json:"label"` - Connected bool `json:"connected"` - Power string `json:"power"` - Brightness float64 `json:"brightness"` - LastSeen time.Time `json:"last_seen"` - SecondsSinceSeen int `json:"seconds_since_seen"` - Group Group `json:"group"` - Color Color `json:"color"` - Location Location `json:"location"` - Product Product `json:"product"` -} - -// Group represents which group a Device belongs to -type Group struct { - ID string `json:"id"` - Name string `json:"name"` -} - -// Color represents which colors a Device is currently set to -type Color struct { - Hue float64 `json:"hue"` - Saturation float64 `json:"saturation"` - Kelvin float64 `json:"kelvin"` - Name string `json:"name"` -} - -// Location represents what Location a Device belongs to -type Location struct { - ID string `json:"id"` - Name string `json:"name"` -} - -// Product represents the type of LIFX product a Device is -type Product struct { - Name string `json:"name"` - Identifier string `json:"identifier"` - Company string `json:"company"` - Capabilities Capabilities `json:"capabilities"` -} - -// Capabilities represents all of the current features a Device has -type Capabilities struct { - HasColor bool `json:"has_color"` - HasVariableColorTemp bool `json:"has_variable_color_temp"` - HasIR bool `json:"has_ir"` - HasChain bool `json:"has_chain"` - HasMultizone bool `json:"has_multizone"` - MinKelvin float64 `json:"min_kelvin"` - MaxKelvin float64 `json:"max_kelvin"` -} - -// Scene represents currently available scenes for your LIFX bulb -type Scene struct { - UUID string `json:"uuid"` - Name string `json:"name"` - Account map[string]string `json:"account"` - CreatedAt time.Time `json:"created_at"` - UpdatedAt time.Time `json:"updated_at"` - States []State `json:"states"` -} - -// State represents the states of a Scene -type State struct { - Color Color `json:"color"` - Selector string `json:"selector"` - Power string `json:"power"` - Fast bool `json:"fast"` - Brightness float64 `json:"brightnness"` - Duration float64 `json:"duration"` - Infared float64 `json:"infared"` -} From 4370240bea839be052b8e8de1da000a6d7303c8a Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 18:17:14 -0500 Subject: [PATCH 05/22] migrate service/ -> internal/lifx --- .../lifx/http.go | 4 +-- .../lifx/http_test.go | 5 +-- internal/lifx/lifx.go | 33 +++++++++++++++++++ 3 files changed, 35 insertions(+), 7 deletions(-) rename service/filament_service.go => internal/lifx/http.go (98%) rename service/filament_service_test.go => internal/lifx/http_test.go (98%) create mode 100644 internal/lifx/lifx.go diff --git a/service/filament_service.go b/internal/lifx/http.go similarity index 98% rename from service/filament_service.go rename to internal/lifx/http.go index 8d5ae16..9fa684f 100644 --- a/service/filament_service.go +++ b/internal/lifx/http.go @@ -1,4 +1,4 @@ -package service +package lifx import ( "bytes" @@ -6,8 +6,6 @@ import ( "fmt" "io/ioutil" "net/http" - - "github.com/panicpanicpanic/filament/lifx" ) // Get makes a GET request to the LIFX HTTP API and returns []byte or error diff --git a/service/filament_service_test.go b/internal/lifx/http_test.go similarity index 98% rename from service/filament_service_test.go rename to internal/lifx/http_test.go index 1269bff..3e6f7e4 100644 --- a/service/filament_service_test.go +++ b/internal/lifx/http_test.go @@ -1,13 +1,10 @@ -package service_test +package lifx import ( "net/http" "net/http/httptest" "reflect" "testing" - - "github.com/panicpanicpanic/filament/lifx" - "github.com/panicpanicpanic/filament/service" ) func TestServiceGet(t *testing.T) { diff --git a/internal/lifx/lifx.go b/internal/lifx/lifx.go new file mode 100644 index 0000000..d9746f8 --- /dev/null +++ b/internal/lifx/lifx.go @@ -0,0 +1,33 @@ +package lifx + +import "errors" + +const ( + // APIEndpoint is the URL for the latest LIFX HTTP API + APIEndpoint = "https://api.lifx.com/v1" +) + +// Client contains the LIFX access token needed to authenticate +// against the LIFX HTTP API +type Client struct { + accessToken string +} + +// Response is a generic slice of results from LIFX API +type Response struct { + Results []struct { + ID string `json:"id"` + Status string `json:"status"` + Label string `json:"label"` + } `json:"results"` +} + +// NewClient accepts an access token and returns a Client +// If the token is empty, it'll also return an error +func NewClient(token string) (*Client, error) { + if token == "" { + return nil, errors.New("token can't be empty") + } + + return &Client{accessToken: token}, nil +} From 3e18a46d1c3c79619c4c263d25690c206d28d981 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 18:18:02 -0500 Subject: [PATCH 06/22] remove lifx/ --- lifx/filament_lifx.go | 24 ------------------------ 1 file changed, 24 deletions(-) delete mode 100644 lifx/filament_lifx.go diff --git a/lifx/filament_lifx.go b/lifx/filament_lifx.go deleted file mode 100644 index 682cf2d..0000000 --- a/lifx/filament_lifx.go +++ /dev/null @@ -1,24 +0,0 @@ -package lifx - -const ( - // LIFXAPIURL is the URL for the latest LIFX HTTP API - LIFXAPIURL = "https://api.lifx.com/v1" -) - -// Client contains the LIFX AccessToken and URL endpoint needed to reach the LIFX HTTP API -type Client struct { - AccessToken string - Endpoint string -} - -// Response is a generic slice of results from LIFX API -type Response struct { - Results []Result `json:"results"` -} - -// Result returns ID, Status and Label from LIFX API -type Result struct { - ID string `json:"id"` - Status string `json:"status"` - Label string `json:"label"` -} From 766de346eae26954f4320315d50a3d3db4257661 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 18:29:29 -0500 Subject: [PATCH 07/22] refactor client logic to filament package --- client.go | 19 +++++++++++++++++++ filament.go | 22 +++++++++++----------- internal/lifx/lifx.go | 18 ------------------ 3 files changed, 30 insertions(+), 29 deletions(-) create mode 100644 client.go diff --git a/client.go b/client.go new file mode 100644 index 0000000..6865fa4 --- /dev/null +++ b/client.go @@ -0,0 +1,19 @@ +package filament + +import "errors" + +// Client contains the LIFX access token needed to authenticate +// against the LIFX HTTP API +type Client struct { + accessToken string +} + +// NewClient accepts an access token and returns a Client +// If the token is empty, it'll also return an error +func NewClient(token string) (*Client, error) { + if token == "" { + return nil, errors.New("token can't be empty") + } + + return &Client{accessToken: token}, nil +} diff --git a/filament.go b/filament.go index 22646b7..0c50ff9 100644 --- a/filament.go +++ b/filament.go @@ -10,7 +10,7 @@ import ( ) // GetLights returns []device.Device that belong to your LIFX account -func GetLights(client *lifx.Client, selector string) ([]device.Device, error) { +func (c *Client) GetLights(selector string) ([]device.Device, error) { var body []byte var devices []device.Device var err error @@ -38,7 +38,7 @@ func GetLights(client *lifx.Client, selector string) ([]device.Device, error) { } // GetScenes returns []device.Scene that belong to your LIFX account -func GetScenes(client *lifx.Client) ([]device.Scene, error) { +func (c *Client) GetScenes() ([]device.Scene, error) { var body []byte var scenes []device.Scene var err error @@ -61,7 +61,7 @@ func GetScenes(client *lifx.Client) ([]device.Scene, error) { } // ValidateColor returns a device.Color if a valid color string is passed -func ValidateColor(client *lifx.Client, color string) (device.Color, error) { +func (c *Client) ValidateColor(color string) (device.Color, error) { var body []byte var deviceColor device.Color var err error @@ -84,7 +84,7 @@ func ValidateColor(client *lifx.Client, color string) (device.Color, error) { } // SetState sets the state of the lights within the given selector, and returns a LIFX Response -func SetState(client *lifx.Client, selector string, payload interface{}) (lifx.Response, error) { +func (c *Client) SetState(selector string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -112,7 +112,7 @@ func SetState(client *lifx.Client, selector string, payload interface{}) (lifx.R } // SetStates sets multiple states across multiple selectors, and returns a LIFX Response -func SetStates(client *lifx.Client, payload interface{}) (lifx.Response, error) { +func (c *Client) SetStates(payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -135,7 +135,7 @@ func SetStates(client *lifx.Client, payload interface{}) (lifx.Response, error) } // ActivateScene activates a scene from your LIFX account -func ActivateScene(client *lifx.Client, sceneUUID string, payload interface{}) (lifx.Response, error) { +func (c *Client) ActivateScene(sceneUUID string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -158,7 +158,7 @@ func ActivateScene(client *lifx.Client, sceneUUID string, payload interface{}) ( } // Cycle makes the light(s) cycle to the next or previous state in a list of states -func Cycle(client *lifx.Client, selector string, payload interface{}) (lifx.Response, error) { +func (c *Client) Cycle(selector string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -181,7 +181,7 @@ func Cycle(client *lifx.Client, selector string, payload interface{}) (lifx.Resp } // PulseEffect performs a pulse effect by quickly flashing between the given colors -func PulseEffect(client *lifx.Client, selector string, payload interface{}) (lifx.Response, error) { +func (c *Client) PulseEffect(selector string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -204,7 +204,7 @@ func PulseEffect(client *lifx.Client, selector string, payload interface{}) (lif } // BreatheEffect performs a breathe effect by slowly fading between the given colors. -func BreatheEffect(client *lifx.Client, selector string, payload interface{}) (lifx.Response, error) { +func (c *Client) BreatheEffect(selector string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -227,7 +227,7 @@ func BreatheEffect(client *lifx.Client, selector string, payload interface{}) (l } // TogglePower turns off lights if any of them are on, or turns them on if they are all off. -func TogglePower(client *lifx.Client, selector string) (lifx.Response, error) { +func (c *Client) TogglePower(selector string) (lifx.Response, error) { var body []byte var err error var response lifx.Response @@ -254,7 +254,7 @@ func TogglePower(client *lifx.Client, selector string) (lifx.Response, error) { } // StateDelta changes the state of the lights by the amount specified -func StateDelta(client *lifx.Client, selector string, payload interface{}) (lifx.Response, error) { +func (c *Client) StateDelta(selector string, payload interface{}) (lifx.Response, error) { var body []byte var err error var response lifx.Response diff --git a/internal/lifx/lifx.go b/internal/lifx/lifx.go index d9746f8..ec6f4ff 100644 --- a/internal/lifx/lifx.go +++ b/internal/lifx/lifx.go @@ -1,18 +1,10 @@ package lifx -import "errors" - const ( // APIEndpoint is the URL for the latest LIFX HTTP API APIEndpoint = "https://api.lifx.com/v1" ) -// Client contains the LIFX access token needed to authenticate -// against the LIFX HTTP API -type Client struct { - accessToken string -} - // Response is a generic slice of results from LIFX API type Response struct { Results []struct { @@ -21,13 +13,3 @@ type Response struct { Label string `json:"label"` } `json:"results"` } - -// NewClient accepts an access token and returns a Client -// If the token is empty, it'll also return an error -func NewClient(token string) (*Client, error) { - if token == "" { - return nil, errors.New("token can't be empty") - } - - return &Client{accessToken: token}, nil -} From 40c27e0faf00ca61d56129076d31e6f6624ab714 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 19:34:13 -0500 Subject: [PATCH 08/22] remove reference to client --- client.go | 19 ------------------- filament.go | 22 +++++++++++----------- internal/lifx/http.go | 5 +++++ internal/lifx/lifx.go => response.go | 7 +------ 4 files changed, 17 insertions(+), 36 deletions(-) delete mode 100644 client.go rename internal/lifx/lifx.go => response.go (63%) diff --git a/client.go b/client.go deleted file mode 100644 index 6865fa4..0000000 --- a/client.go +++ /dev/null @@ -1,19 +0,0 @@ -package filament - -import "errors" - -// Client contains the LIFX access token needed to authenticate -// against the LIFX HTTP API -type Client struct { - accessToken string -} - -// NewClient accepts an access token and returns a Client -// If the token is empty, it'll also return an error -func NewClient(token string) (*Client, error) { - if token == "" { - return nil, errors.New("token can't be empty") - } - - return &Client{accessToken: token}, nil -} diff --git a/filament.go b/filament.go index 0c50ff9..b29732f 100644 --- a/filament.go +++ b/filament.go @@ -10,7 +10,7 @@ import ( ) // GetLights returns []device.Device that belong to your LIFX account -func (c *Client) GetLights(selector string) ([]device.Device, error) { +func GetLights(selector string) ([]device.Device, error) { var body []byte var devices []device.Device var err error @@ -38,7 +38,7 @@ func (c *Client) GetLights(selector string) ([]device.Device, error) { } // GetScenes returns []device.Scene that belong to your LIFX account -func (c *Client) GetScenes() ([]device.Scene, error) { +func GetScenes() ([]device.Scene, error) { var body []byte var scenes []device.Scene var err error @@ -61,7 +61,7 @@ func (c *Client) GetScenes() ([]device.Scene, error) { } // ValidateColor returns a device.Color if a valid color string is passed -func (c *Client) ValidateColor(color string) (device.Color, error) { +func ValidateColor(color string) (device.Color, error) { var body []byte var deviceColor device.Color var err error @@ -84,7 +84,7 @@ func (c *Client) ValidateColor(color string) (device.Color, error) { } // SetState sets the state of the lights within the given selector, and returns a LIFX Response -func (c *Client) SetState(selector string, payload interface{}) (lifx.Response, error) { +func SetState(selector string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -112,7 +112,7 @@ func (c *Client) SetState(selector string, payload interface{}) (lifx.Response, } // SetStates sets multiple states across multiple selectors, and returns a LIFX Response -func (c *Client) SetStates(payload interface{}) (lifx.Response, error) { +func SetStates(payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -135,7 +135,7 @@ func (c *Client) SetStates(payload interface{}) (lifx.Response, error) { } // ActivateScene activates a scene from your LIFX account -func (c *Client) ActivateScene(sceneUUID string, payload interface{}) (lifx.Response, error) { +func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -158,7 +158,7 @@ func (c *Client) ActivateScene(sceneUUID string, payload interface{}) (lifx.Resp } // Cycle makes the light(s) cycle to the next or previous state in a list of states -func (c *Client) Cycle(selector string, payload interface{}) (lifx.Response, error) { +func Cycle(selector string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -181,7 +181,7 @@ func (c *Client) Cycle(selector string, payload interface{}) (lifx.Response, err } // PulseEffect performs a pulse effect by quickly flashing between the given colors -func (c *Client) PulseEffect(selector string, payload interface{}) (lifx.Response, error) { +func PulseEffect(selector string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -204,7 +204,7 @@ func (c *Client) PulseEffect(selector string, payload interface{}) (lifx.Respons } // BreatheEffect performs a breathe effect by slowly fading between the given colors. -func (c *Client) BreatheEffect(selector string, payload interface{}) (lifx.Response, error) { +func BreatheEffect(selector string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response @@ -227,7 +227,7 @@ func (c *Client) BreatheEffect(selector string, payload interface{}) (lifx.Respo } // TogglePower turns off lights if any of them are on, or turns them on if they are all off. -func (c *Client) TogglePower(selector string) (lifx.Response, error) { +func TogglePower(selector string) (Response, error) { var body []byte var err error var response lifx.Response @@ -254,7 +254,7 @@ func (c *Client) TogglePower(selector string) (lifx.Response, error) { } // StateDelta changes the state of the lights by the amount specified -func (c *Client) StateDelta(selector string, payload interface{}) (lifx.Response, error) { +func StateDelta(selector string, payload interface{}) (Response, error) { var body []byte var err error var response lifx.Response diff --git a/internal/lifx/http.go b/internal/lifx/http.go index 9fa684f..c0afc36 100644 --- a/internal/lifx/http.go +++ b/internal/lifx/http.go @@ -8,6 +8,11 @@ import ( "net/http" ) +const ( + // APIEndpoint is the URL for the latest LIFX HTTP API + APIEndpoint = "https://api.lifx.com/v1" +) + // Get makes a GET request to the LIFX HTTP API and returns []byte or error func Get(client *lifx.Client) ([]byte, error) { var body []byte diff --git a/internal/lifx/lifx.go b/response.go similarity index 63% rename from internal/lifx/lifx.go rename to response.go index ec6f4ff..63789c6 100644 --- a/internal/lifx/lifx.go +++ b/response.go @@ -1,9 +1,4 @@ -package lifx - -const ( - // APIEndpoint is the URL for the latest LIFX HTTP API - APIEndpoint = "https://api.lifx.com/v1" -) +package filament // Response is a generic slice of results from LIFX API type Response struct { From 8f82958586d0f1f77ca5bc1cac64ccdb05ca7891 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 19:37:32 -0500 Subject: [PATCH 09/22] refactor internal lifx http --- internal/device.go => device.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) rename internal/device.go => device.go (99%) diff --git a/internal/device.go b/device.go similarity index 99% rename from internal/device.go rename to device.go index 52d14bc..dee39c3 100644 --- a/internal/device.go +++ b/device.go @@ -1,4 +1,4 @@ -package internal +package filament import ( "time" From 028274e1879075c589662cf4568c02cceb47e485 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 19:38:26 -0500 Subject: [PATCH 10/22] remove Dockerfile --- Dockerfile | 11 ----------- 1 file changed, 11 deletions(-) delete mode 100644 Dockerfile diff --git a/Dockerfile b/Dockerfile deleted file mode 100644 index 9be0404..0000000 --- a/Dockerfile +++ /dev/null @@ -1,11 +0,0 @@ -FROM golang:1.9.2-alpine3.7 - -RUN mkdir -p /go/src/github.com/panicpanicpanic/filament -WORKDIR /go/src/github.com/panicpanicpanic/filament -ADD . /go/src/github.com/panicpanicpanic/filament - -# Install dep and dependancies -RUN apk --no-cache add curl git && \ - curl -fsSL -o /usr/local/bin/dep https://github.com/golang/dep/releases/download/v0.3.2/dep-linux-amd64 && \ - chmod +x /usr/local/bin/dep -RUN dep ensure -vendor-only From fcf9eee94069d83d874483fb3f0f5c8215d47ed5 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 19:39:40 -0500 Subject: [PATCH 11/22] refactor Device structs --- filament.go | 16 ++++++---------- 1 file changed, 6 insertions(+), 10 deletions(-) diff --git a/filament.go b/filament.go index b29732f..f5c5052 100644 --- a/filament.go +++ b/filament.go @@ -3,14 +3,10 @@ package filament import ( "encoding/json" "fmt" - - "github.com/panicpanicpanic/filament/device" - "github.com/panicpanicpanic/filament/lifx" - "github.com/panicpanicpanic/filament/service" ) -// GetLights returns []device.Device that belong to your LIFX account -func GetLights(selector string) ([]device.Device, error) { +// GetLights returns []Device that belong to your LIFX account +func GetLights(selector string) ([]Device, error) { var body []byte var devices []device.Device var err error @@ -37,8 +33,8 @@ func GetLights(selector string) ([]device.Device, error) { return devices, nil } -// GetScenes returns []device.Scene that belong to your LIFX account -func GetScenes() ([]device.Scene, error) { +// GetScenes returns []Scene that belong to your LIFX account +func GetScenes() ([]Scene, error) { var body []byte var scenes []device.Scene var err error @@ -60,8 +56,8 @@ func GetScenes() ([]device.Scene, error) { return scenes, nil } -// ValidateColor returns a device.Color if a valid color string is passed -func ValidateColor(color string) (device.Color, error) { +// ValidateColor returns a Color if a valid color string is passed +func ValidateColor(color string) (Color, error) { var body []byte var deviceColor device.Color var err error From 8a611378fbe9aa3c8a27ec0a69cd80a5855733a1 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sat, 1 Jan 2022 19:57:24 -0500 Subject: [PATCH 12/22] refactor http package --- internal/lifx/errors.go | 7 ++++ internal/lifx/http.go | 72 ++++++++++++++++++++++++----------------- 2 files changed, 49 insertions(+), 30 deletions(-) create mode 100644 internal/lifx/errors.go diff --git a/internal/lifx/errors.go b/internal/lifx/errors.go new file mode 100644 index 0000000..57a10af --- /dev/null +++ b/internal/lifx/errors.go @@ -0,0 +1,7 @@ +package lifx + +import "errors" + +var ( + MissingTokenEndpointError = errors.New("missing access token or valid API endpoint") +) diff --git a/internal/lifx/http.go b/internal/lifx/http.go index c0afc36..184892c 100644 --- a/internal/lifx/http.go +++ b/internal/lifx/http.go @@ -6,6 +6,7 @@ import ( "fmt" "io/ioutil" "net/http" + "os" ) const ( @@ -13,19 +14,26 @@ const ( APIEndpoint = "https://api.lifx.com/v1" ) +var ( + // AccessToken references the LIFX API Access Token + AccessToken = os.Getenv("LIFX_API_ACCESS_TOKEN") +) + // Get makes a GET request to the LIFX HTTP API and returns []byte or error -func Get(client *lifx.Client) ([]byte, error) { - var body []byte - var httpClient http.Client - var err error - var statusCode int +func Get(endpoint string) ([]byte, error) { + var ( + body []byte + err error + httpClient http.Client + statusCode int + ) - if client.AccessToken == "" || client.Endpoint == "" { - return body, fmt.Errorf("In order to access the LIFX API, you must supply a valid AccessToken and Endpoint") + if endpoint == "" || AccessToken == "" { + return body, MissingTokenEndpointError } - request, err := http.NewRequest(http.MethodGet, client.Endpoint, nil) - request.Header.Set("Authorization", "Bearer "+client.AccessToken) + request, err := http.NewRequest(http.MethodGet, endpoint, nil) + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { return body, fmt.Errorf(err.Error()) } @@ -45,30 +53,32 @@ func Get(client *lifx.Client) ([]byte, error) { responseString := string(body) if statusCode > 207 { - return body, fmt.Errorf("Uh oh! You've received a %d status code. Error: %s", statusCode, responseString) + return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) } return body, nil } // Put makes a PUT request to the LIFX HTTP API and returns []byte or error -func Put(client *lifx.Client, payload interface{}) ([]byte, error) { - var body []byte - var httpClient http.Client - var err error - var statusCode int +func Put(endpoint string, payload interface{}) ([]byte, error) { + var ( + body []byte + err error + httpClient http.Client + statusCode int + ) data, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf(err.Error()) } - if client.AccessToken == "" || client.Endpoint == "" { - return nil, fmt.Errorf("In order to access the LIFX API, you must supply a valid AccessToken and Endpoint") + if endpoint == "" || AccessToken == "" { + return body, MissingTokenEndpointError } - request, err := http.NewRequest(http.MethodPut, client.Endpoint, bytes.NewBuffer(data)) - request.Header.Set("Authorization", "Bearer "+client.AccessToken) + request, err := http.NewRequest(http.MethodPut, endpoint, bytes.NewBuffer(data)) + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { return nil, fmt.Errorf(err.Error()) } @@ -88,30 +98,32 @@ func Put(client *lifx.Client, payload interface{}) ([]byte, error) { responseString := string(body) if statusCode > 207 { - return nil, fmt.Errorf("Uh oh! You've received a %d status code. Error: %s", statusCode, responseString) + return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) } return body, nil } // Post makes a POST request to the LIFX HTTP API and returns []byte or error -func Post(client *lifx.Client, payload interface{}) ([]byte, error) { - var body []byte - var httpClient http.Client - var err error - var statusCode int +func Post(endpoint string, payload interface{}) ([]byte, error) { + var ( + body []byte + err error + httpClient http.Client + statusCode int + ) data, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf(err.Error()) } - if client.AccessToken == "" || client.Endpoint == "" { - return nil, fmt.Errorf("In order to access the LIFX API, you must supply a valid AccessToken and Endpoint") + if endpoint == "" || AccessToken == "" { + return body, MissingTokenEndpointError } - request, err := http.NewRequest(http.MethodPost, client.Endpoint, bytes.NewBuffer(data)) - request.Header.Set("Authorization", "Bearer "+client.AccessToken) + request, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(data)) + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { return nil, fmt.Errorf(err.Error()) } @@ -131,7 +143,7 @@ func Post(client *lifx.Client, payload interface{}) ([]byte, error) { responseString := string(body) if statusCode > 207 { - return nil, fmt.Errorf("Uh oh! You've received a %d status code. Error: %s", statusCode, responseString) + return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) } return body, nil From 7332b8da6554adbe10a8c1698cb8cd3849148a7c Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 13:16:46 -0500 Subject: [PATCH 13/22] refactor http_tests --- internal/lifx/http_test.go | 389 +++++-------------------------------- 1 file changed, 46 insertions(+), 343 deletions(-) diff --git a/internal/lifx/http_test.go b/internal/lifx/http_test.go index 3e6f7e4..c3e4617 100644 --- a/internal/lifx/http_test.go +++ b/internal/lifx/http_test.go @@ -1,16 +1,14 @@ package lifx import ( + "fmt" "net/http" "net/http/httptest" - "reflect" + "os" "testing" ) -func TestServiceGet(t *testing.T) { - var client lifx.Client - var err error - +func TestGet(t *testing.T) { payload := []byte(`[ { "id": "123", @@ -51,342 +49,47 @@ func TestServiceGet(t *testing.T) { }] `) - t.Run("when AccessToken is missing from lifx.Client", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(payload) - })) - - client.Endpoint = server.URL - - _, err = service.Get(&client) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an AccessToken, got %d", err) - } - }) - - t.Run("when Endpoint is missing from lifx.Client", func(t *testing.T) { - _ = httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(payload) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = "" - - _, err = service.Get(&client) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an AccessToken, got %d", err) - } - }) - - t.Run("when the LIFX API returns a non-200 HTTP status code for GET request", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - w.Write(payload) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - _, err = service.Get(&client) - if err == nil { - t.Errorf("it should have thrown an error for returning a 500 HTTP status, got %d", err) - } - }) - - t.Run("when the expected response is not []byte", func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(payload) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - body, err := service.Get(&client) - if len(body) == 0 { - t.Errorf("it should have returned 1 empty device, got %d", err) - } - if reflect.TypeOf(body).String() != "[]uint8" { - t.Errorf("it should have returned a []byte, got %d", reflect.TypeOf(body)) - } - }) -} - -func TestServicePut(t *testing.T) { - var client lifx.Client - var err error - - t.Run("when AccessToken is missing from lifx.Client", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMultiStatus) - w.Write(response) - })) - - client.Endpoint = server.URL - - _, err = service.Put(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an AccessToken, got %d", err) - } - }) - - t.Run("when Endpoint is missing from lifx.Client", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMultiStatus) - w.Write(response) - })) - - client.AccessToken = server.URL - client.Endpoint = "" - - _, err = service.Put(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an Endpoint, got %d", err) - } - }) - - t.Run("when the LIFX API returns a non-207 HTTP status code for PUT request", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - w.Write(response) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - _, err = service.Put(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for returning a 500 HTTP status, got %d", err) - } - }) - - t.Run("when the expected response is not []byte", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(response) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - body, err := service.Put(&client, payload) - if len(body) == 0 { - t.Errorf("it should have returned 1 empty device, got %d", err) - } - if reflect.TypeOf(body).String() != "[]uint8" { - t.Errorf("it should have returned a []byte, got %d", reflect.TypeOf(body)) - } - }) -} - -func TestServicePost(t *testing.T) { - var client lifx.Client - var err error - - t.Run("when AccessToken is missing from lifx.Client", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMultiStatus) - w.Write(response) - })) - - client.Endpoint = server.URL - - _, err = service.Post(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an AccessToken, got %d", err) - } - }) - - t.Run("when Endpoint is missing from lifx.Client", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusMultiStatus) - w.Write(response) - })) - - client.AccessToken = server.URL - client.Endpoint = "" - - _, err = service.Post(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for not supplying an Endpoint, got %d", err) - } - }) - - t.Run("when the LIFX API returns a non-207 HTTP status code for POST request", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusInternalServerError) - w.Write(response) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - _, err = service.Post(&client, payload) - if err == nil { - t.Errorf("it should have thrown an error for returning a 500 HTTP status, got %d", err) - } - }) - - t.Run("when the expected response is not []byte", func(t *testing.T) { - response := []byte(` - { - "results": [ - { - "id": "d073d52260ef", - "status": "ok", - "label": "Main" - } - ] - } - `) - - payload := []byte(` - { - "power":"on" - } - `) - - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(response) - })) - - client.AccessToken = "someRandomToken" - client.Endpoint = server.URL - - body, err := service.Post(&client, payload) - if len(body) == 0 { - t.Errorf("it should have returned 1 empty device, got %d", err) - } - if reflect.TypeOf(body).String() != "[]uint8" { - t.Errorf("it should have returned a []byte, got %d", reflect.TypeOf(body)) - } - }) + tests := []struct { + accessToken string + endpoint string + name string + expectedErr bool + }{ + { + name: "when AccessToken is missing", + endpoint: "testEndpoint", + accessToken: "", + expectedErr: true, + }, + { + name: "when endpoint is missing", + endpoint: "", + accessToken: "1234", + expectedErr: true, + }, + { + name: "when the LIFX API returns a non-200 HTTP status code", + endpoint: "testEndpoint", + accessToken: "1234", + expectedErr: true, + }, + } + + for _, tt := range tests { + t.Parallel() + t.Run(tt.name, func(t *testing.T) { + server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { + w.WriteHeader(http.StatusOK) + w.Write(payload) + })) + + os.Setenv("LIFX_API_ACCESS_TOKEN", tt.accessToken) + + url := fmt.Sprintf("%s/%s", server.URL, tt.endpoint) + + if _, err := Get(url); (err != nil) != tt.expectedErr { + t.Errorf("expected to get error %v, got %v", tt.expectedErr, err) + } + }) + } } From db57c433aba8fdcaf2e88c6ce528011e1ff0de94 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 13:58:23 -0500 Subject: [PATCH 14/22] refactor endpoint construction --- filament.go | 202 ++++++++++++++++++++++++------------------ internal/lifx/http.go | 19 +++- 2 files changed, 135 insertions(+), 86 deletions(-) diff --git a/filament.go b/filament.go index f5c5052..b824cbf 100644 --- a/filament.go +++ b/filament.go @@ -2,24 +2,27 @@ package filament import ( "encoding/json" + "errors" "fmt" ) // GetLights returns []Device that belong to your LIFX account func GetLights(selector string) ([]Device, error) { - var body []byte - var devices []device.Device - var err error + var ( + body []byte + devices []Device + err error + ) - // If no selector is passed, default to retrieving all lights for your LIFX account if selector == "" { selector = "all" } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and URL path - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + if endpoint := lifx.returnAPIEndpoint(GetLightsEndpoint, selector); endpoint == "" { + return devices, errors.New("not a valid endpoint") + } - body, err = service.Get(client) + body, err = lifx.Get(endpoint) if err != nil { return devices, fmt.Errorf(err.Error()) } @@ -29,20 +32,22 @@ func GetLights(selector string) ([]Device, error) { return devices, fmt.Errorf(err.Error()) } - // Return []device.Device or return an error return devices, nil } // GetScenes returns []Scene that belong to your LIFX account func GetScenes() ([]Scene, error) { - var body []byte - var scenes []device.Scene - var err error - - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/scenes" + var ( + body []byte + err error + scenes []Scene + ) + + if endpoint := lifx.returnAPIEndpoint(GetScenesEndpoint); endpoint == "" { + return scenes, errors.New("not a valid endpoint") + } - body, err = service.Get(client) + body, err = lifx.Get(endpoint) if err != nil { return scenes, fmt.Errorf(err.Error()) } @@ -52,20 +57,22 @@ func GetScenes() ([]Scene, error) { return scenes, fmt.Errorf(err.Error()) } - // Return []device.Scene or return an error return scenes, nil } // ValidateColor returns a Color if a valid color string is passed func ValidateColor(color string) (Color, error) { - var body []byte - var deviceColor device.Color - var err error - - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/color?string=" + color + var ( + body []byte + deviceColor Color + err error + ) + + if endpoint := lifx.returnAPIEndpoint(ValidateColorEndpoint, color); endpoint == "" { + return deviceColor, errors.New("not a valid endpoint") + } - body, err = service.Get(client) + body, err = lifx.Get(endpoint) if err != nil { return deviceColor, fmt.Errorf(err.Error()) } @@ -75,25 +82,26 @@ func ValidateColor(color string) (Color, error) { return deviceColor, fmt.Errorf(err.Error()) } - // Return device.Color or return error return deviceColor, nil } // SetState sets the state of the lights within the given selector, and returns a LIFX Response func SetState(selector string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) - // If no selector is passed, default to setting state for all lights if selector == "" { selector = "all" } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/state" + if endpoint := lifx.returnAPIEndpoint(SetStateEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Put(client, payload) + body, err = lifx.Put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -103,20 +111,22 @@ func SetState(selector string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // SetStates sets multiple states across multiple selectors, and returns a LIFX Response func SetStates(payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response - - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/states" + var ( + body []byte + err error + response Response + ) + + if endpoint := lifx.returnAPIEndpoint(SetStatesEndpoint); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Put(client, payload) + body, err = lifx.Put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -126,20 +136,22 @@ func SetStates(payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // ActivateScene activates a scene from your LIFX account func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response - - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/scenes/scene_id:" + sceneUUID + "/activate" + var ( + body []byte + err error + response Response + ) + + if endpoint := lifx.returnAPIEndpoint(ActivateSceneEndpoint, sceneUUID); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Put(client, payload) + body, err = lifx.Put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -149,20 +161,26 @@ func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // Cycle makes the light(s) cycle to the next or previous state in a list of states func Cycle(selector string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) + + if selector == "" { + selector = "all" + } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/cycle" + if endpoint := lifx.returnAPIEndpoint(CycleEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Post(client, payload) + body, err = lifx.Post(client, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -172,20 +190,26 @@ func Cycle(selector string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // PulseEffect performs a pulse effect by quickly flashing between the given colors func PulseEffect(selector string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/effects/pulse" + if selector == "" { + selector = "all" + } - body, err = service.Post(client, payload) + if endpoint := lifx.returnAPIEndpoint(PulseEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } + + body, err = lifx.Post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -195,20 +219,26 @@ func PulseEffect(selector string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // BreatheEffect performs a breathe effect by slowly fading between the given colors. func BreatheEffect(selector string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) + + if selector == "" { + selector = "all" + } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/effects/pulse" + if endpoint := lifx.returnAPIEndpoint(BreatheEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Post(client, payload) + body, err = lifx.Post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -218,24 +248,26 @@ func BreatheEffect(selector string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // TogglePower turns off lights if any of them are on, or turns them on if they are all off. func TogglePower(selector string) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) - // If no selector is passed, default to toggle all lights on/off for your LIFX account if selector == "" { selector = "all" } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/toggle" - body, err = service.Post(client, nil) + if endpoint := lifx.returnAPIEndpoint(ToggleEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } + + body, err = lifx.Post(endpoint, nil) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -245,25 +277,26 @@ func TogglePower(selector string) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } // StateDelta changes the state of the lights by the amount specified func StateDelta(selector string, payload interface{}) (Response, error) { - var body []byte - var err error - var response lifx.Response + var ( + body []byte + err error + response Response + ) - // If no selector is passed, default to changing the states on all lights for your LIFX account if selector == "" { selector = "all" } - // In order to access LIFX HTTP API, you must pass a valid AccessToken and Endpoint - client.Endpoint = lifx.LIFXAPIURL + "/lights/" + selector + "/state/delta" + if endpoint := lifx.returnAPIEndpoint(StateDeltaEndpoint, selector); endpoint == "" { + return response, errors.New("not a valid endpoint") + } - body, err = service.Post(client, payload) + body, err = lifx.Post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -273,6 +306,5 @@ func StateDelta(selector string, payload interface{}) (Response, error) { return response, fmt.Errorf(err.Error()) } - // Return lifx.Response or return error return response, nil } diff --git a/internal/lifx/http.go b/internal/lifx/http.go index 184892c..960cfe1 100644 --- a/internal/lifx/http.go +++ b/internal/lifx/http.go @@ -11,7 +11,18 @@ import ( const ( // APIEndpoint is the URL for the latest LIFX HTTP API - APIEndpoint = "https://api.lifx.com/v1" + APIEndpoint = "https://api.lifx.com/v1" + GetScenesEndpoint = "%s/scenes" + ActivateSceneEndpoint = "%s/scenes/scene_id:%s/activate" + ValidateColorEndpoint = "%s/color?string=%s" + GetLightsEndpoint = "%s/lights/%s" + SetStateEndpoint = "%s/lights/%s/state" + SetStatesEndpoint = "%s/lights/states" + StateDeltaEndpoint = "%s/lights/%s/state/delta" + CycleEndpoint = "%s/lights/%s/cycle" + ToggleEndpoint = "%s/lights/%s/toggle" + PulseEndpoint = "%s/lights/%s/effects/pulse" + BreatheEndpoint = "%s/lights/%s/effects/breathe" ) var ( @@ -148,3 +159,9 @@ func Post(endpoint string, payload interface{}) ([]byte, error) { return body, nil } + +// returnAPIEndpoint constructs and returns the appropriate LIFX +// API endpoint +func returnAPIEndpoint(base, args string) string { + return fmt.Sprintf(base, APIEndpoint, args) +} From 54cf33becd668c57ec0e684c1418cbe9c4610033 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 13:59:39 -0500 Subject: [PATCH 15/22] remove godep stuff --- Gopkg.lock | 9 --------- Gopkg.toml | 30 ------------------------------ version.go | 4 ---- 3 files changed, 43 deletions(-) delete mode 100644 Gopkg.lock delete mode 100644 Gopkg.toml delete mode 100644 version.go diff --git a/Gopkg.lock b/Gopkg.lock deleted file mode 100644 index 10ef811..0000000 --- a/Gopkg.lock +++ /dev/null @@ -1,9 +0,0 @@ -# This file is autogenerated, do not edit; changes may be undone by the next 'dep ensure'. - - -[solve-meta] - analyzer-name = "dep" - analyzer-version = 1 - input-imports = [] - solver-name = "gps-cdcl" - solver-version = 1 diff --git a/Gopkg.toml b/Gopkg.toml deleted file mode 100644 index d7072c2..0000000 --- a/Gopkg.toml +++ /dev/null @@ -1,30 +0,0 @@ -# Gopkg.toml example -# -# Refer to https://golang.github.io/dep/docs/Gopkg.toml.html -# for detailed Gopkg.toml documentation. -# -# required = ["github.com/user/thing/cmd/thing"] -# ignored = ["github.com/user/project/pkgX", "bitbucket.org/user/project/pkgA/pkgY"] -# -# [[constraint]] -# name = "github.com/user/project" -# version = "1.0.0" -# -# [[constraint]] -# name = "github.com/user/project2" -# branch = "dev" -# source = "github.com/myfork/project2" -# -# [[override]] -# name = "github.com/x/y" -# version = "2.4.0" -# -# [prune] -# non-go = false -# go-tests = true -# unused-packages = true - - -[prune] - go-tests = true - unused-packages = true diff --git a/version.go b/version.go deleted file mode 100644 index 744e317..0000000 --- a/version.go +++ /dev/null @@ -1,4 +0,0 @@ -package filament - -// Version represents the current version Filament is on -const version = "0.0.1" From 7d870ece0ace1fdc9cab89b1ded067798053be16 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 14:00:14 -0500 Subject: [PATCH 16/22] consolidate response struct within device --- device.go | 9 +++++++++ response.go | 10 ---------- 2 files changed, 9 insertions(+), 10 deletions(-) delete mode 100644 response.go diff --git a/device.go b/device.go index dee39c3..515a175 100644 --- a/device.go +++ b/device.go @@ -79,3 +79,12 @@ type State struct { Duration float64 `json:"duration"` Infrared float64 `json:"infrared"` } + +// Response is a generic slice of results from LIFX API +type Response struct { + Results []struct { + ID string `json:"id"` + Status string `json:"status"` + Label string `json:"label"` + } `json:"results"` +} diff --git a/response.go b/response.go deleted file mode 100644 index 63789c6..0000000 --- a/response.go +++ /dev/null @@ -1,10 +0,0 @@ -package filament - -// Response is a generic slice of results from LIFX API -type Response struct { - Results []struct { - ID string `json:"id"` - Status string `json:"status"` - Label string `json:"label"` - } `json:"results"` -} From e6e520696dc3b872f9a426c5b63bad705eb9caea Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 14:02:08 -0500 Subject: [PATCH 17/22] initialize go mod --- go.mod | 3 +++ 1 file changed, 3 insertions(+) create mode 100644 go.mod diff --git a/go.mod b/go.mod new file mode 100644 index 0000000..2760c2b --- /dev/null +++ b/go.mod @@ -0,0 +1,3 @@ +module github.com/panicpanicpanic/filament + +go 1.14 From 629f656677885c7172cb0bf0b3d8f00d64f418b2 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 14:23:51 -0500 Subject: [PATCH 18/22] fix missing endpoint string issue --- filament.go | 49 +++++++++++++++++++++++++++---------------- internal/lifx/http.go | 4 ++-- 2 files changed, 33 insertions(+), 20 deletions(-) diff --git a/filament.go b/filament.go index b824cbf..edc46b5 100644 --- a/filament.go +++ b/filament.go @@ -4,21 +4,24 @@ import ( "encoding/json" "errors" "fmt" + + "github.com/panicpanicpanic/filament/internal/lifx" ) // GetLights returns []Device that belong to your LIFX account func GetLights(selector string) ([]Device, error) { var ( - body []byte - devices []Device - err error + body []byte + devices []Device + endpoint string + err error ) if selector == "" { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(GetLightsEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.GetLightsEndpoint, selector); endpoint == "" { return devices, errors.New("not a valid endpoint") } @@ -38,12 +41,13 @@ func GetLights(selector string) ([]Device, error) { // GetScenes returns []Scene that belong to your LIFX account func GetScenes() ([]Scene, error) { var ( - body []byte - err error - scenes []Scene + body []byte + endpoint string + err error + scenes []Scene ) - if endpoint := lifx.returnAPIEndpoint(GetScenesEndpoint); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.GetScenesEndpoint, ""); endpoint == "" { return scenes, errors.New("not a valid endpoint") } @@ -65,10 +69,11 @@ func ValidateColor(color string) (Color, error) { var ( body []byte deviceColor Color + endpoint string err error ) - if endpoint := lifx.returnAPIEndpoint(ValidateColorEndpoint, color); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.ValidateColorEndpoint, color); endpoint == "" { return deviceColor, errors.New("not a valid endpoint") } @@ -89,6 +94,7 @@ func ValidateColor(color string) (Color, error) { func SetState(selector string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -97,7 +103,7 @@ func SetState(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(SetStateEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.SetStateEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -118,11 +124,12 @@ func SetState(selector string, payload interface{}) (Response, error) { func SetStates(payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) - if endpoint := lifx.returnAPIEndpoint(SetStatesEndpoint); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.SetStatesEndpoint, ""); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -143,11 +150,12 @@ func SetStates(payload interface{}) (Response, error) { func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) - if endpoint := lifx.returnAPIEndpoint(ActivateSceneEndpoint, sceneUUID); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.ActivateSceneEndpoint, sceneUUID); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -168,6 +176,7 @@ func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { func Cycle(selector string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -176,11 +185,11 @@ func Cycle(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(CycleEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.CycleEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(client, payload) + body, err = lifx.Post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -197,6 +206,7 @@ func Cycle(selector string, payload interface{}) (Response, error) { func PulseEffect(selector string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -205,7 +215,7 @@ func PulseEffect(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(PulseEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.PulseEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -226,6 +236,7 @@ func PulseEffect(selector string, payload interface{}) (Response, error) { func BreatheEffect(selector string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -234,7 +245,7 @@ func BreatheEffect(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(BreatheEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.BreatheEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -255,6 +266,7 @@ func BreatheEffect(selector string, payload interface{}) (Response, error) { func TogglePower(selector string) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -263,7 +275,7 @@ func TogglePower(selector string) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(ToggleEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.ToggleEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } @@ -284,6 +296,7 @@ func TogglePower(selector string) (Response, error) { func StateDelta(selector string, payload interface{}) (Response, error) { var ( body []byte + endpoint string err error response Response ) @@ -292,7 +305,7 @@ func StateDelta(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.returnAPIEndpoint(StateDeltaEndpoint, selector); endpoint == "" { + if endpoint := lifx.ReturnAPIEndpoint(lifx.StateDeltaEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } diff --git a/internal/lifx/http.go b/internal/lifx/http.go index 960cfe1..993223c 100644 --- a/internal/lifx/http.go +++ b/internal/lifx/http.go @@ -160,8 +160,8 @@ func Post(endpoint string, payload interface{}) ([]byte, error) { return body, nil } -// returnAPIEndpoint constructs and returns the appropriate LIFX +// ReturnAPIEndpoint constructs and returns the appropriate LIFX // API endpoint -func returnAPIEndpoint(base, args string) string { +func ReturnAPIEndpoint(base, args string) string { return fmt.Sprintf(base, APIEndpoint, args) } From 1a3634eae571e4534ab04ce3290636818fefb095 Mon Sep 17 00:00:00 2001 From: Angel Martinez Date: Sun, 2 Jan 2022 14:24:26 -0500 Subject: [PATCH 19/22] fix call to t.Parallel --- internal/lifx/http_test.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/internal/lifx/http_test.go b/internal/lifx/http_test.go index c3e4617..b7514ba 100644 --- a/internal/lifx/http_test.go +++ b/internal/lifx/http_test.go @@ -75,8 +75,8 @@ func TestGet(t *testing.T) { }, } + t.Parallel() for _, tt := range tests { - t.Parallel() t.Run(tt.name, func(t *testing.T) { server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { w.WriteHeader(http.StatusOK) From 74d7f0dad21b3f7e92a3dfab740e56a52c7d46cb Mon Sep 17 00:00:00 2001 From: panicpanicpanic Date: Thu, 26 Dec 2024 22:33:26 -0500 Subject: [PATCH 20/22] progress in 2024 --- internal/lifx/errors.go => errors.go | 2 +- filament.go | 107 +++++++++------------ go.mod | 2 +- internal/lifx/http.go => http.go | 28 +++--- internal/lifx/http_test.go => http_test.go | 4 +- requests.go | 22 +++++ 6 files changed, 89 insertions(+), 76 deletions(-) rename internal/lifx/errors.go => errors.go (86%) rename internal/lifx/http.go => http.go (83%) rename internal/lifx/http_test.go => http_test.go (95%) create mode 100644 requests.go diff --git a/internal/lifx/errors.go b/errors.go similarity index 86% rename from internal/lifx/errors.go rename to errors.go index 57a10af..c51eb28 100644 --- a/internal/lifx/errors.go +++ b/errors.go @@ -1,4 +1,4 @@ -package lifx +package filament import "errors" diff --git a/filament.go b/filament.go index edc46b5..0906808 100644 --- a/filament.go +++ b/filament.go @@ -4,42 +4,35 @@ import ( "encoding/json" "errors" "fmt" - - "github.com/panicpanicpanic/filament/internal/lifx" ) -// GetLights returns []Device that belong to your LIFX account -func GetLights(selector string) ([]Device, error) { - var ( - body []byte - devices []Device - endpoint string - err error - ) - - if selector == "" { - selector = "all" - } +const ( + lifxAPIVersion = "v1" +) - if endpoint := lifx.ReturnAPIEndpoint(lifx.GetLightsEndpoint, selector); endpoint == "" { - return devices, errors.New("not a valid endpoint") - } +type Client struct { + token string + version string +} - body, err = lifx.Get(endpoint) - if err != nil { - return devices, fmt.Errorf(err.Error()) +func NewClient(token string) (*Client, error) { + if token == "" { + return nil, errors.New("token can't be empty") } - err = json.Unmarshal(body, &devices) - if err != nil { - return devices, fmt.Errorf(err.Error()) - } + return &Client{ + token: token, + version: lifxAPIVersion, + }, nil +} - return devices, nil +// GetLights returns []Device that belong to your LIFX account +func (c *Client) GetLights(selector string) ([]Device, error) { + return getLights(selector) } // GetScenes returns []Scene that belong to your LIFX account -func GetScenes() ([]Scene, error) { +func (c *Client) GetScenes() ([]Scene, error) { var ( body []byte endpoint string @@ -47,11 +40,11 @@ func GetScenes() ([]Scene, error) { scenes []Scene ) - if endpoint := lifx.ReturnAPIEndpoint(lifx.GetScenesEndpoint, ""); endpoint == "" { + if endpoint := returnAPIEndpoint(GetScenesEndpoint, ""); endpoint == "" { return scenes, errors.New("not a valid endpoint") } - body, err = lifx.Get(endpoint) + body, err = get(endpoint) if err != nil { return scenes, fmt.Errorf(err.Error()) } @@ -65,7 +58,7 @@ func GetScenes() ([]Scene, error) { } // ValidateColor returns a Color if a valid color string is passed -func ValidateColor(color string) (Color, error) { +func (c *Client) ValidateColor(color string) (Color, error) { var ( body []byte deviceColor Color @@ -73,11 +66,11 @@ func ValidateColor(color string) (Color, error) { err error ) - if endpoint := lifx.ReturnAPIEndpoint(lifx.ValidateColorEndpoint, color); endpoint == "" { + if endpoint := returnAPIEndpoint(ValidateColorEndpoint, color); endpoint == "" { return deviceColor, errors.New("not a valid endpoint") } - body, err = lifx.Get(endpoint) + body, err = get(endpoint) if err != nil { return deviceColor, fmt.Errorf(err.Error()) } @@ -91,7 +84,7 @@ func ValidateColor(color string) (Color, error) { } // SetState sets the state of the lights within the given selector, and returns a LIFX Response -func SetState(selector string, payload interface{}) (Response, error) { +func (c *Client) SetState(selector string, payload any) (Response, error) { var ( body []byte endpoint string @@ -103,11 +96,11 @@ func SetState(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.ReturnAPIEndpoint(lifx.SetStateEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(SetStateEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Put(endpoint, payload) + body, err = put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -121,7 +114,7 @@ func SetState(selector string, payload interface{}) (Response, error) { } // SetStates sets multiple states across multiple selectors, and returns a LIFX Response -func SetStates(payload interface{}) (Response, error) { +func (c *Client) SetStates(payload any) (Response, error) { var ( body []byte endpoint string @@ -129,11 +122,11 @@ func SetStates(payload interface{}) (Response, error) { response Response ) - if endpoint := lifx.ReturnAPIEndpoint(lifx.SetStatesEndpoint, ""); endpoint == "" { + if endpoint := returnAPIEndpoint(SetStatesEndpoint, ""); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Put(endpoint, payload) + body, err = put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -147,7 +140,7 @@ func SetStates(payload interface{}) (Response, error) { } // ActivateScene activates a scene from your LIFX account -func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { +func (c *Client) ActivateScene(sceneUUID string, payload any) (Response, error) { var ( body []byte endpoint string @@ -155,11 +148,11 @@ func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { response Response ) - if endpoint := lifx.ReturnAPIEndpoint(lifx.ActivateSceneEndpoint, sceneUUID); endpoint == "" { + if endpoint := returnAPIEndpoint(ActivateSceneEndpoint, sceneUUID); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Put(endpoint, payload) + body, err = put(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -173,7 +166,7 @@ func ActivateScene(sceneUUID string, payload interface{}) (Response, error) { } // Cycle makes the light(s) cycle to the next or previous state in a list of states -func Cycle(selector string, payload interface{}) (Response, error) { +func (c *Client) Cycle(selector string, payload any) (Response, error) { var ( body []byte endpoint string @@ -185,11 +178,11 @@ func Cycle(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.ReturnAPIEndpoint(lifx.CycleEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(CycleEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(endpoint, payload) + body, err = post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -203,7 +196,7 @@ func Cycle(selector string, payload interface{}) (Response, error) { } // PulseEffect performs a pulse effect by quickly flashing between the given colors -func PulseEffect(selector string, payload interface{}) (Response, error) { +func (c *Client) PulseEffect(selector string, payload any) (Response, error) { var ( body []byte endpoint string @@ -215,11 +208,11 @@ func PulseEffect(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.ReturnAPIEndpoint(lifx.PulseEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(PulseEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(endpoint, payload) + body, err = post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -233,7 +226,7 @@ func PulseEffect(selector string, payload interface{}) (Response, error) { } // BreatheEffect performs a breathe effect by slowly fading between the given colors. -func BreatheEffect(selector string, payload interface{}) (Response, error) { +func (c *Client) BreatheEffect(selector string, payload any) (Response, error) { var ( body []byte endpoint string @@ -241,15 +234,11 @@ func BreatheEffect(selector string, payload interface{}) (Response, error) { response Response ) - if selector == "" { - selector = "all" - } - - if endpoint := lifx.ReturnAPIEndpoint(lifx.BreatheEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(BreatheEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(endpoint, payload) + body, err = post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -263,7 +252,7 @@ func BreatheEffect(selector string, payload interface{}) (Response, error) { } // TogglePower turns off lights if any of them are on, or turns them on if they are all off. -func TogglePower(selector string) (Response, error) { +func (c *Client) TogglePower(selector string) (Response, error) { var ( body []byte endpoint string @@ -275,11 +264,11 @@ func TogglePower(selector string) (Response, error) { selector = "all" } - if endpoint := lifx.ReturnAPIEndpoint(lifx.ToggleEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(ToggleEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(endpoint, nil) + body, err = post(endpoint, nil) if err != nil { return response, fmt.Errorf(err.Error()) } @@ -293,7 +282,7 @@ func TogglePower(selector string) (Response, error) { } // StateDelta changes the state of the lights by the amount specified -func StateDelta(selector string, payload interface{}) (Response, error) { +func (c *Client) StateDelta(selector string, payload any) (Response, error) { var ( body []byte endpoint string @@ -305,11 +294,11 @@ func StateDelta(selector string, payload interface{}) (Response, error) { selector = "all" } - if endpoint := lifx.ReturnAPIEndpoint(lifx.StateDeltaEndpoint, selector); endpoint == "" { + if endpoint := returnAPIEndpoint(StateDeltaEndpoint, selector); endpoint == "" { return response, errors.New("not a valid endpoint") } - body, err = lifx.Post(endpoint, payload) + body, err = post(endpoint, payload) if err != nil { return response, fmt.Errorf(err.Error()) } diff --git a/go.mod b/go.mod index 2760c2b..79ba11b 100644 --- a/go.mod +++ b/go.mod @@ -1,3 +1,3 @@ module github.com/panicpanicpanic/filament -go 1.14 +go 1.23.4 diff --git a/internal/lifx/http.go b/http.go similarity index 83% rename from internal/lifx/http.go rename to http.go index 993223c..414b065 100644 --- a/internal/lifx/http.go +++ b/http.go @@ -1,4 +1,4 @@ -package lifx +package filament import ( "bytes" @@ -10,8 +10,8 @@ import ( ) const ( - // APIEndpoint is the URL for the latest LIFX HTTP API - APIEndpoint = "https://api.lifx.com/v1" + // aPIEndpoint is the URL for the latest LIFX HTTP API + aPIEndpoint = "https://api.lifx.com/v1" GetScenesEndpoint = "%s/scenes" ActivateSceneEndpoint = "%s/scenes/scene_id:%s/activate" ValidateColorEndpoint = "%s/color?string=%s" @@ -30,8 +30,8 @@ var ( AccessToken = os.Getenv("LIFX_API_ACCESS_TOKEN") ) -// Get makes a GET request to the LIFX HTTP API and returns []byte or error -func Get(endpoint string) ([]byte, error) { +// get makes a GET request to the LIFX HTTP API and returns []byte or error +func get(endpoint string) ([]byte, error) { var ( body []byte err error @@ -70,8 +70,8 @@ func Get(endpoint string) ([]byte, error) { return body, nil } -// Put makes a PUT request to the LIFX HTTP API and returns []byte or error -func Put(endpoint string, payload interface{}) ([]byte, error) { +// put makes a PUT request to the LIFX HTTP API and returns []byte or error +func put(endpoint string, payload any) ([]byte, error) { var ( body []byte err error @@ -115,8 +115,8 @@ func Put(endpoint string, payload interface{}) ([]byte, error) { return body, nil } -// Post makes a POST request to the LIFX HTTP API and returns []byte or error -func Post(endpoint string, payload interface{}) ([]byte, error) { +// post makes a POST request to the LIFX HTTP API and returns []byte or error +func post(endpoint string, payload any) ([]byte, error) { var ( body []byte err error @@ -160,8 +160,10 @@ func Post(endpoint string, payload interface{}) ([]byte, error) { return body, nil } -// ReturnAPIEndpoint constructs and returns the appropriate LIFX -// API endpoint -func ReturnAPIEndpoint(base, args string) string { - return fmt.Sprintf(base, APIEndpoint, args) +// returnAPIEndpoint constructs and returns the appropriate LIFX API endpoint +func returnAPIEndpoint(base, args string) string { + if args == "" { + args = "all" + } + return fmt.Sprintf(base, aPIEndpoint, args) } diff --git a/internal/lifx/http_test.go b/http_test.go similarity index 95% rename from internal/lifx/http_test.go rename to http_test.go index b7514ba..6ca24c6 100644 --- a/internal/lifx/http_test.go +++ b/http_test.go @@ -1,4 +1,4 @@ -package lifx +package filament import ( "fmt" @@ -87,7 +87,7 @@ func TestGet(t *testing.T) { url := fmt.Sprintf("%s/%s", server.URL, tt.endpoint) - if _, err := Get(url); (err != nil) != tt.expectedErr { + if _, err := get(url); (err != nil) != tt.expectedErr { t.Errorf("expected to get error %v, got %v", tt.expectedErr, err) } }) diff --git a/requests.go b/requests.go new file mode 100644 index 0000000..28df1a4 --- /dev/null +++ b/requests.go @@ -0,0 +1,22 @@ +package filament + +import ( + "encoding/json" + "fmt" +) + +func getLights(selector string) ([]Device, error) { + endpoint := returnAPIEndpoint(GetLightsEndpoint, selector) + + body, err := get(endpoint) + if err != nil { + return []Device{}, fmt.Errorf(err.Error()) + } + + var devices []Device + if err = json.Unmarshal(body, &devices); err != nil { + return devices, fmt.Errorf(err.Error()) + } + + return devices, nil +} From ee3e165b54f910a47c2703fb7e6e1dae14732f25 Mon Sep 17 00:00:00 2001 From: panicpanicpanic Date: Thu, 26 Dec 2024 23:46:50 -0500 Subject: [PATCH 21/22] more progress --- filament.go | 256 +++------------------------------------------------ http.go | 124 +++++++++---------------- http_test.go | 5 +- requests.go | 166 ++++++++++++++++++++++++++++++++- 4 files changed, 222 insertions(+), 329 deletions(-) diff --git a/filament.go b/filament.go index 0906808..86164bd 100644 --- a/filament.go +++ b/filament.go @@ -1,18 +1,19 @@ package filament import ( - "encoding/json" "errors" "fmt" ) const ( + apiEndpoint = "https://api.lifx.com/" lifxAPIVersion = "v1" ) type Client struct { token string version string + apiURL string } func NewClient(token string) (*Client, error) { @@ -23,290 +24,61 @@ func NewClient(token string) (*Client, error) { return &Client{ token: token, version: lifxAPIVersion, + apiURL: fmt.Sprintf("%s%s", apiEndpoint, lifxAPIVersion), }, nil } // GetLights returns []Device that belong to your LIFX account func (c *Client) GetLights(selector string) ([]Device, error) { - return getLights(selector) + return c.getLights(selector) } // GetScenes returns []Scene that belong to your LIFX account func (c *Client) GetScenes() ([]Scene, error) { - var ( - body []byte - endpoint string - err error - scenes []Scene - ) - - if endpoint := returnAPIEndpoint(GetScenesEndpoint, ""); endpoint == "" { - return scenes, errors.New("not a valid endpoint") - } - - body, err = get(endpoint) - if err != nil { - return scenes, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &scenes) - if err != nil { - return scenes, fmt.Errorf(err.Error()) - } - - return scenes, nil + return c.getScenes() } // ValidateColor returns a Color if a valid color string is passed func (c *Client) ValidateColor(color string) (Color, error) { - var ( - body []byte - deviceColor Color - endpoint string - err error - ) - - if endpoint := returnAPIEndpoint(ValidateColorEndpoint, color); endpoint == "" { - return deviceColor, errors.New("not a valid endpoint") - } - - body, err = get(endpoint) - if err != nil { - return deviceColor, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &deviceColor) - if err != nil { - return deviceColor, fmt.Errorf(err.Error()) - } - - return deviceColor, nil + return c.validateColor(color) } // SetState sets the state of the lights within the given selector, and returns a LIFX Response func (c *Client) SetState(selector string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if selector == "" { - selector = "all" - } - - if endpoint := returnAPIEndpoint(SetStateEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = put(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.setState(selector, payload) } // SetStates sets multiple states across multiple selectors, and returns a LIFX Response func (c *Client) SetStates(payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if endpoint := returnAPIEndpoint(SetStatesEndpoint, ""); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = put(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.setStates(payload) } // ActivateScene activates a scene from your LIFX account func (c *Client) ActivateScene(sceneUUID string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if endpoint := returnAPIEndpoint(ActivateSceneEndpoint, sceneUUID); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = put(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.activateScene(sceneUUID, payload) } // Cycle makes the light(s) cycle to the next or previous state in a list of states func (c *Client) Cycle(selector string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if selector == "" { - selector = "all" - } - - if endpoint := returnAPIEndpoint(CycleEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = post(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.cycle(selector, payload) } // PulseEffect performs a pulse effect by quickly flashing between the given colors func (c *Client) PulseEffect(selector string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if selector == "" { - selector = "all" - } - - if endpoint := returnAPIEndpoint(PulseEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = post(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.pulseEffect(selector, payload) } // BreatheEffect performs a breathe effect by slowly fading between the given colors. func (c *Client) BreatheEffect(selector string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if endpoint := returnAPIEndpoint(BreatheEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = post(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.breatheEffect(selector, payload) } // TogglePower turns off lights if any of them are on, or turns them on if they are all off. func (c *Client) TogglePower(selector string) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if selector == "" { - selector = "all" - } - - if endpoint := returnAPIEndpoint(ToggleEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = post(endpoint, nil) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.togglePower(selector) } // StateDelta changes the state of the lights by the amount specified func (c *Client) StateDelta(selector string, payload any) (Response, error) { - var ( - body []byte - endpoint string - err error - response Response - ) - - if selector == "" { - selector = "all" - } - - if endpoint := returnAPIEndpoint(StateDeltaEndpoint, selector); endpoint == "" { - return response, errors.New("not a valid endpoint") - } - - body, err = post(endpoint, payload) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - err = json.Unmarshal(body, &response) - if err != nil { - return response, fmt.Errorf(err.Error()) - } - - return response, nil + return c.stateDelta(selector, payload) } diff --git a/http.go b/http.go index 414b065..4843e3c 100644 --- a/http.go +++ b/http.go @@ -4,166 +4,130 @@ import ( "bytes" "encoding/json" "fmt" - "io/ioutil" + "io" "net/http" - "os" ) const ( - // aPIEndpoint is the URL for the latest LIFX HTTP API - aPIEndpoint = "https://api.lifx.com/v1" - GetScenesEndpoint = "%s/scenes" - ActivateSceneEndpoint = "%s/scenes/scene_id:%s/activate" - ValidateColorEndpoint = "%s/color?string=%s" - GetLightsEndpoint = "%s/lights/%s" - SetStateEndpoint = "%s/lights/%s/state" - SetStatesEndpoint = "%s/lights/states" - StateDeltaEndpoint = "%s/lights/%s/state/delta" - CycleEndpoint = "%s/lights/%s/cycle" - ToggleEndpoint = "%s/lights/%s/toggle" - PulseEndpoint = "%s/lights/%s/effects/pulse" - BreatheEndpoint = "%s/lights/%s/effects/breathe" + getScenesEndpoint = "%s/scenes" + activateSceneEndpoint = "%s/scenes/scene_id:%s/activate" + validateColorEndpoint = "%s/color?string=%s" + getLightsEndpoint = "%s/lights/%s" + setStateEndpoint = "%s/lights/%s/state" + setStatesEndpoint = "%s/lights/states" + stateDeltaEndpoint = "%s/lights/%s/state/delta" + cycleEndpoint = "%s/lights/%s/cycle" + toggleEndpoint = "%s/lights/%s/toggle" + pulseEndpoint = "%s/lights/%s/effects/pulse" + breatheEndpoint = "%s/lights/%s/effects/breathe" ) -var ( - // AccessToken references the LIFX API Access Token - AccessToken = os.Getenv("LIFX_API_ACCESS_TOKEN") -) - -// get makes a GET request to the LIFX HTTP API and returns []byte or error -func get(endpoint string) ([]byte, error) { - var ( - body []byte - err error - httpClient http.Client - statusCode int - ) - - if endpoint == "" || AccessToken == "" { - return body, MissingTokenEndpointError +func get(endpoint string, token string) ([]byte, error) { + if endpoint == "" || token == "" { + return []byte{}, MissingTokenEndpointError } request, err := http.NewRequest(http.MethodGet, endpoint, nil) - request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { - return body, fmt.Errorf(err.Error()) + return []byte{}, err } + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + httpClient := http.Client{} response, err := httpClient.Do(request) if err != nil { - return body, fmt.Errorf(err.Error()) + return []byte{}, fmt.Errorf(err.Error()) } defer response.Body.Close() - body, err = ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if err != nil { - return body, fmt.Errorf(err.Error()) + return []byte{}, fmt.Errorf(err.Error()) } - statusCode = response.StatusCode - responseString := string(body) - - if statusCode > 207 { - return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) + if response.StatusCode > 207 { + return body, fmt.Errorf("received a %d status code. error: %s", response.StatusCode, string(body)) } return body, nil } // put makes a PUT request to the LIFX HTTP API and returns []byte or error -func put(endpoint string, payload any) ([]byte, error) { - var ( - body []byte - err error - httpClient http.Client - statusCode int - ) +func put(endpoint, token string, payload any) ([]byte, error) { + if endpoint == "" || token == "" { + return []byte{}, MissingTokenEndpointError + } data, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf(err.Error()) } - if endpoint == "" || AccessToken == "" { - return body, MissingTokenEndpointError - } - request, err := http.NewRequest(http.MethodPut, endpoint, bytes.NewBuffer(data)) - request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { return nil, fmt.Errorf(err.Error()) } + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + httpClient := http.Client{} response, err := httpClient.Do(request) if err != nil { return nil, fmt.Errorf(err.Error()) } defer response.Body.Close() - body, err = ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if err != nil { - return nil, fmt.Errorf(err.Error()) + return []byte{}, fmt.Errorf(err.Error()) } - statusCode = response.StatusCode - responseString := string(body) - - if statusCode > 207 { - return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) + if response.StatusCode > 207 { + return body, fmt.Errorf("received a %d status code. error: %s", response.StatusCode, string(body)) } return body, nil } // post makes a POST request to the LIFX HTTP API and returns []byte or error -func post(endpoint string, payload any) ([]byte, error) { - var ( - body []byte - err error - httpClient http.Client - statusCode int - ) +func post(endpoint, token string, payload any) ([]byte, error) { + if endpoint == "" || token == "" { + return []byte{}, MissingTokenEndpointError + } data, err := json.Marshal(payload) if err != nil { return nil, fmt.Errorf(err.Error()) } - if endpoint == "" || AccessToken == "" { - return body, MissingTokenEndpointError - } - request, err := http.NewRequest(http.MethodPost, endpoint, bytes.NewBuffer(data)) - request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", AccessToken)) if err != nil { return nil, fmt.Errorf(err.Error()) } + request.Header.Set("Authorization", fmt.Sprintf("Bearer %s", token)) + httpClient := http.Client{} response, err := httpClient.Do(request) if err != nil { return nil, fmt.Errorf(err.Error()) } defer response.Body.Close() - body, err = ioutil.ReadAll(response.Body) + body, err := io.ReadAll(response.Body) if err != nil { return nil, fmt.Errorf(err.Error()) } - statusCode = response.StatusCode - responseString := string(body) - - if statusCode > 207 { - return body, fmt.Errorf("received a %d status code. error: %s", statusCode, responseString) + if response.StatusCode > 207 { + return body, fmt.Errorf("received a %d status code. error: %s", response.StatusCode, string(body)) } return body, nil } // returnAPIEndpoint constructs and returns the appropriate LIFX API endpoint -func returnAPIEndpoint(base, args string) string { +func (c *Client) returnAPIEndpoint(base, args string) string { if args == "" { args = "all" } - return fmt.Sprintf(base, aPIEndpoint, args) + return fmt.Sprintf(base, c.apiURL, args) } diff --git a/http_test.go b/http_test.go index 6ca24c6..d708601 100644 --- a/http_test.go +++ b/http_test.go @@ -4,7 +4,6 @@ import ( "fmt" "net/http" "net/http/httptest" - "os" "testing" ) @@ -83,11 +82,9 @@ func TestGet(t *testing.T) { w.Write(payload) })) - os.Setenv("LIFX_API_ACCESS_TOKEN", tt.accessToken) - url := fmt.Sprintf("%s/%s", server.URL, tt.endpoint) - if _, err := get(url); (err != nil) != tt.expectedErr { + if _, err := get(url, tt.accessToken); (err != nil) != tt.expectedErr { t.Errorf("expected to get error %v, got %v", tt.expectedErr, err) } }) diff --git a/requests.go b/requests.go index 28df1a4..2dbb40b 100644 --- a/requests.go +++ b/requests.go @@ -5,10 +5,10 @@ import ( "fmt" ) -func getLights(selector string) ([]Device, error) { - endpoint := returnAPIEndpoint(GetLightsEndpoint, selector) +func (c *Client) getLights(selector string) ([]Device, error) { + endpoint := c.returnAPIEndpoint(getLightsEndpoint, selector) - body, err := get(endpoint) + body, err := get(endpoint, c.token) if err != nil { return []Device{}, fmt.Errorf(err.Error()) } @@ -20,3 +20,163 @@ func getLights(selector string) ([]Device, error) { return devices, nil } + +func (c *Client) getScenes() ([]Scene, error) { + endpoint := c.returnAPIEndpoint(getScenesEndpoint, "") + + body, err := get(endpoint, c.token) + if err != nil { + return []Scene{}, fmt.Errorf(err.Error()) + } + + var scenes []Scene + if err = json.Unmarshal(body, &scenes); err != nil { + return scenes, fmt.Errorf(err.Error()) + } + + return scenes, nil +} + +func (c *Client) validateColor(color string) (Color, error) { + endpoint := c.returnAPIEndpoint(validateColorEndpoint, color) + + body, err := get(endpoint, c.token) + if err != nil { + return Color{}, fmt.Errorf(err.Error()) + } + + var deviceColor Color + if err = json.Unmarshal(body, &deviceColor); err != nil { + return deviceColor, fmt.Errorf(err.Error()) + } + + return deviceColor, nil +} + +func (c *Client) setState(selector string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(setStateEndpoint, selector) + + body, err := put(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) setStates(payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(setStatesEndpoint, "") + + body, err := put(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) activateScene(sceneUID string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(activateSceneEndpoint, sceneUID) + + body, err := put(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) cycle(selector string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(cycleEndpoint, selector) + + body, err := post(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) pulseEffect(selector string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(pulseEndpoint, selector) + + body, err := post(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) breatheEffect(selector string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(breatheEndpoint, selector) + + body, err := post(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) togglePower(selector string) (Response, error) { + endpoint := c.returnAPIEndpoint(toggleEndpoint, selector) + + body, err := post(endpoint, c.token, nil) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} + +func (c *Client) stateDelta(selector string, payload any) (Response, error) { + endpoint := c.returnAPIEndpoint(stateDeltaEndpoint, selector) + + body, err := post(endpoint, c.token, payload) + if err != nil { + return Response{}, fmt.Errorf(err.Error()) + } + + var response Response + if err = json.Unmarshal(body, &response); err != nil { + return response, fmt.Errorf(err.Error()) + } + + return response, nil +} From 9dd1aab2395ae7c8827666c7a6967bd63beb51e3 Mon Sep 17 00:00:00 2001 From: panicpanicpanic Date: Thu, 26 Dec 2024 23:58:08 -0500 Subject: [PATCH 22/22] these tests are kind of useless --- http_test.go | 92 ---------------------------------------------------- 1 file changed, 92 deletions(-) delete mode 100644 http_test.go diff --git a/http_test.go b/http_test.go deleted file mode 100644 index d708601..0000000 --- a/http_test.go +++ /dev/null @@ -1,92 +0,0 @@ -package filament - -import ( - "fmt" - "net/http" - "net/http/httptest" - "testing" -) - -func TestGet(t *testing.T) { - payload := []byte(`[ - { - "id": "123", - "uuid": "123", - "label": "Main", - "connected": true, - "power": "on", - "color": { - "hue": 240, - "saturation": 1, - "kelvin": 4000 - }, - "brightness": 1, - "group": { - "id": "123", - "name": "My Room" - }, - "location": { - "id": "123", - "name": "My Home" - }, - "product": { - "name": "LIFX BR30", - "identifier": "lifx_br30", - "company": "LIFX", - "capabilities": { - "has_color": true, - "has_variable_color_temp": true, - "has_ir": false, - "has_chain": false, - "has_multizone": false, - "min_kelvin": 2500, - "max_kelvin": 9000 - } - }, - "last_seen": "2018-10-21T04:13:04Z", - "seconds_since_seen": 0 - }] - `) - - tests := []struct { - accessToken string - endpoint string - name string - expectedErr bool - }{ - { - name: "when AccessToken is missing", - endpoint: "testEndpoint", - accessToken: "", - expectedErr: true, - }, - { - name: "when endpoint is missing", - endpoint: "", - accessToken: "1234", - expectedErr: true, - }, - { - name: "when the LIFX API returns a non-200 HTTP status code", - endpoint: "testEndpoint", - accessToken: "1234", - expectedErr: true, - }, - } - - t.Parallel() - for _, tt := range tests { - t.Run(tt.name, func(t *testing.T) { - server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) { - w.WriteHeader(http.StatusOK) - w.Write(payload) - })) - - url := fmt.Sprintf("%s/%s", server.URL, tt.endpoint) - - if _, err := get(url, tt.accessToken); (err != nil) != tt.expectedErr { - t.Errorf("expected to get error %v, got %v", tt.expectedErr, err) - } - }) - } -}