Skip to content

Commit eb6718a

Browse files
authored
Merge pull request #7 from LubosD/feature/avoid-panic-on-disconnect
Avoid panic on disconnect, provide connection errors
2 parents d61d3c6 + 27ece19 commit eb6718a

File tree

5 files changed

+46
-15
lines changed

5 files changed

+46
-15
lines changed

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ The general flow is
4040
import ga "saml.dev/gome-assistant"
4141

4242
// replace with IP and port of your Home Assistant installation
43-
app := ga.NewApp("0.0.0.0:8123")
43+
app, err := ga.NewApp("0.0.0.0:8123")
4444

4545
// create automations here (see next sections)
4646

app.go

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ import (
1515
ws "saml.dev/gome-assistant/internal/websocket"
1616
)
1717

18+
// Returned by NewApp() if authentication fails
19+
var ErrInvalidToken = ws.ErrInvalidToken
20+
1821
type App struct {
1922
ctx context.Context
2023
ctxCancel context.CancelFunc
@@ -77,15 +80,19 @@ type NewAppRequest struct {
7780
NewApp establishes the websocket connection and returns an object
7881
you can use to register schedules and listeners.
7982
*/
80-
func NewApp(request NewAppRequest) *App {
83+
func NewApp(request NewAppRequest) (*App, error) {
8184
if request.IpAddress == "" || request.HAAuthToken == "" || request.HomeZoneEntityId == "" {
8285
log.Fatalln("IpAddress, HAAuthToken, and HomeZoneEntityId are all required arguments in NewAppRequest.")
8386
}
8487
port := request.Port
8588
if port == "" {
8689
port = "8123"
8790
}
88-
conn, ctx, ctxCancel := ws.SetupConnection(request.IpAddress, port, request.HAAuthToken)
91+
conn, ctx, ctxCancel, err := ws.SetupConnection(request.IpAddress, port, request.HAAuthToken)
92+
93+
if conn == nil {
94+
return nil, err
95+
}
8996

9097
httpClient := http.NewHttpClient(request.IpAddress, port, request.HAAuthToken)
9198

@@ -105,7 +112,7 @@ func NewApp(request NewAppRequest) *App {
105112
intervals: pq.New(),
106113
entityListeners: map[string][]*EntityListener{},
107114
eventListeners: map[string][]*EventListener{},
108-
}
115+
}, nil
109116
}
110117

111118
func (a *App) Cleanup() {
@@ -263,9 +270,12 @@ func (a *App) Start() {
263270
// entity listeners and event listeners
264271
elChan := make(chan ws.ChanMsg)
265272
go ws.ListenWebsocket(a.conn, a.ctx, elChan)
266-
var msg ws.ChanMsg
273+
267274
for {
268-
msg = <-elChan
275+
msg, ok := <-elChan
276+
if !ok {
277+
break
278+
}
269279
if a.entityListenersId == msg.Id {
270280
go callEntityListeners(a, msg.Raw)
271281
} else {

example/example.go

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,11 +10,16 @@ import (
1010
)
1111

1212
func main() {
13-
app := ga.NewApp(ga.NewAppRequest{
13+
app, err := ga.NewApp(ga.NewAppRequest{
1414
IpAddress: "192.168.86.67", // Replace with your Home Assistant IP Address
1515
HAAuthToken: os.Getenv("HA_AUTH_TOKEN"),
1616
HomeZoneEntityId: "zone.home",
1717
})
18+
19+
if err != nil {
20+
log.Fatalln("Error connecting to HASS:", err)
21+
}
22+
1823
defer app.Cleanup()
1924

2025
pantryDoor := ga.

internal/websocket/reader.go

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ package websocket
33
import (
44
"context"
55
"encoding/json"
6+
"log"
67

78
"github.com/gorilla/websocket"
89
)
@@ -20,7 +21,14 @@ type ChanMsg struct {
2021

2122
func ListenWebsocket(conn *websocket.Conn, ctx context.Context, c chan ChanMsg) {
2223
for {
23-
bytes, _ := ReadMessage(conn, ctx)
24+
bytes, err := ReadMessage(conn, ctx)
25+
26+
if err != nil {
27+
log.Default().Println("Error reading from websocket:", err)
28+
close(c)
29+
break
30+
}
31+
2432
base := BaseMessage{}
2533
json.Unmarshal(bytes, &base)
2634
chanMsg := ChanMsg{

internal/websocket/websocket.go

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ import (
1717
i "saml.dev/gome-assistant/internal"
1818
)
1919

20+
var (
21+
ErrInvalidToken = errors.New("invalid authentication token")
22+
)
23+
2024
type AuthMessage struct {
2125
MsgType string `json:"type"`
2226
AccessToken string `json:"access_token"`
@@ -47,39 +51,43 @@ func ReadMessage(conn *websocket.Conn, ctx context.Context) ([]byte, error) {
4751
return msg, nil
4852
}
4953

50-
func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc) {
54+
func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) {
5155
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
5256

5357
// Init websocket connection
5458
dialer := websocket.DefaultDialer
5559
conn, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s:%s/api/websocket", ip, port), nil)
5660
if err != nil {
5761
ctxCancel()
58-
log.Fatalf("ERROR: Failed to connect to websocket at ws://%s:%s/api/websocket. Check IP address and port\n", ip, port)
62+
log.Printf("ERROR: Failed to connect to websocket at ws://%s:%s/api/websocket. Check IP address and port\n", ip, port)
63+
return nil, nil, nil, err
5964
}
6065

6166
// Read auth_required message
6267
_, err = ReadMessage(conn, ctx)
6368
if err != nil {
6469
ctxCancel()
65-
log.Fatalf("Unknown error creating websocket client\n")
70+
log.Printf("Unknown error creating websocket client\n")
71+
return nil, nil, nil, err
6672
}
6773

6874
// Send auth message
6975
err = SendAuthMessage(conn, ctx, authToken)
7076
if err != nil {
7177
ctxCancel()
72-
log.Fatalf("Unknown error creating websocket client\n")
78+
log.Printf("Unknown error creating websocket client\n")
79+
return nil, nil, nil, err
7380
}
7481

7582
// Verify auth message was successful
7683
err = VerifyAuthResponse(conn, ctx)
7784
if err != nil {
7885
ctxCancel()
79-
log.Fatalf("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile\n")
86+
log.Printf("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile\n")
87+
return nil, nil, nil, err
8088
}
8189

82-
return conn, ctx, ctxCancel
90+
return conn, ctx, ctxCancel, nil
8391
}
8492

8593
func SendAuthMessage(conn *websocket.Conn, ctx context.Context, token string) error {
@@ -105,7 +113,7 @@ func VerifyAuthResponse(conn *websocket.Conn, ctx context.Context) error {
105113
json.Unmarshal(msg, &authResp)
106114
// log.Println(authResp.MsgType)
107115
if authResp.MsgType != "auth_ok" {
108-
return errors.New("invalid auth token")
116+
return ErrInvalidToken
109117
}
110118

111119
return nil

0 commit comments

Comments
 (0)