mirror of
https://github.com/Xevion/go-ha.git
synced 2025-12-07 01:15:15 -06:00
moved websocket code to websocket package
This commit is contained in:
4
app.go
4
app.go
@@ -7,7 +7,7 @@ import (
|
|||||||
"time"
|
"time"
|
||||||
|
|
||||||
"github.com/saml-dev/gome-assistant/internal/http"
|
"github.com/saml-dev/gome-assistant/internal/http"
|
||||||
"github.com/saml-dev/gome-assistant/internal/setup"
|
ws "github.com/saml-dev/gome-assistant/internal/websocket"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -30,7 +30,7 @@ you can use to register schedules and listeners.
|
|||||||
*/
|
*/
|
||||||
func App(connString string) app {
|
func App(connString string) app {
|
||||||
token := os.Getenv("AUTH_TOKEN")
|
token := os.Getenv("AUTH_TOKEN")
|
||||||
conn, ctx, ctxCancel := setup.SetupConnection(connString)
|
conn, ctx, ctxCancel := ws.SetupConnection(connString)
|
||||||
|
|
||||||
httpClient := http.NewHttpClient(connString, token)
|
httpClient := http.NewHttpClient(connString, token)
|
||||||
|
|
||||||
|
|||||||
@@ -4,7 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
|
|
||||||
"github.com/saml-dev/gome-assistant/internal/http"
|
"github.com/saml-dev/gome-assistant/internal/http"
|
||||||
"github.com/saml-dev/gome-assistant/internal/setup"
|
ws "github.com/saml-dev/gome-assistant/internal/websocket"
|
||||||
"nhooyr.io/websocket"
|
"nhooyr.io/websocket"
|
||||||
)
|
)
|
||||||
|
|
||||||
@@ -28,12 +28,12 @@ type LightRequest struct {
|
|||||||
|
|
||||||
func (l Light) TurnOn(entityId string) {
|
func (l Light) TurnOn(entityId string) {
|
||||||
req := newLightOnRequest(entityId)
|
req := newLightOnRequest(entityId)
|
||||||
setup.WriteMessage(req, l.conn, l.ctx)
|
ws.WriteMessage(req, l.conn, l.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (l Light) TurnOff(entityId string) {
|
func (l Light) TurnOff(entityId string) {
|
||||||
req := newLightOffRequest(entityId)
|
req := newLightOffRequest(entityId)
|
||||||
setup.WriteMessage(req, l.conn, l.ctx)
|
ws.WriteMessage(req, l.conn, l.ctx)
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Internal */
|
/* Internal */
|
||||||
|
|||||||
@@ -1,104 +0,0 @@
|
|||||||
package setup
|
|
||||||
|
|
||||||
import (
|
|
||||||
"context"
|
|
||||||
"encoding/json"
|
|
||||||
"errors"
|
|
||||||
"fmt"
|
|
||||||
"log"
|
|
||||||
"os"
|
|
||||||
"time"
|
|
||||||
|
|
||||||
"nhooyr.io/websocket"
|
|
||||||
)
|
|
||||||
|
|
||||||
type AuthMessage struct {
|
|
||||||
MsgType string `json:"type"`
|
|
||||||
AccessToken string `json:"access_token"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func WriteMessage[T any](msg T, conn *websocket.Conn, ctx context.Context) error {
|
|
||||||
msgJson, err := json.Marshal(msg)
|
|
||||||
// fmt.Println(string(msgJson))
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
err = conn.Write(ctx, websocket.MessageText, msgJson)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func ReadMessage(conn *websocket.Conn, ctx context.Context) (string, error) {
|
|
||||||
_, msg, err := conn.Read(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return "", err
|
|
||||||
}
|
|
||||||
return string(msg), nil
|
|
||||||
}
|
|
||||||
|
|
||||||
func SetupConnection(connString string) (*websocket.Conn, context.Context, context.CancelFunc) {
|
|
||||||
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
|
|
||||||
|
|
||||||
// Init websocket connection
|
|
||||||
conn, _, err := websocket.Dial(ctx, fmt.Sprintf("ws://%s/api/websocket", connString), nil)
|
|
||||||
if err != nil {
|
|
||||||
ctxCancel()
|
|
||||||
log.Fatalf("ERROR: Failed to connect to websocket at ws://%s/api/websocket. Check IP address and port\n", connString)
|
|
||||||
}
|
|
||||||
|
|
||||||
// Read auth_required message
|
|
||||||
_, err = ReadMessage(conn, ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctxCancel()
|
|
||||||
log.Fatalln("Unknown error creating websocket client")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Send auth message
|
|
||||||
err = SendAuthMessage(conn, ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctxCancel()
|
|
||||||
log.Fatalln("Unknown error creating websocket client")
|
|
||||||
}
|
|
||||||
|
|
||||||
// Verify auth message
|
|
||||||
err = VerifyAuthResponse(conn, ctx)
|
|
||||||
if err != nil {
|
|
||||||
ctxCancel()
|
|
||||||
log.Fatalln("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile")
|
|
||||||
}
|
|
||||||
|
|
||||||
return conn, ctx, ctxCancel
|
|
||||||
}
|
|
||||||
|
|
||||||
func SendAuthMessage(conn *websocket.Conn, ctx context.Context) error {
|
|
||||||
token := os.Getenv("AUTH_TOKEN")
|
|
||||||
err := WriteMessage(AuthMessage{MsgType: "auth", AccessToken: token}, conn, ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
|
|
||||||
type authResponse struct {
|
|
||||||
MsgType string `json:"type"`
|
|
||||||
Message string `json:"message"`
|
|
||||||
}
|
|
||||||
|
|
||||||
func VerifyAuthResponse(conn *websocket.Conn, ctx context.Context) error {
|
|
||||||
_, msg, err := conn.Read(ctx)
|
|
||||||
if err != nil {
|
|
||||||
return err
|
|
||||||
}
|
|
||||||
|
|
||||||
var authResp authResponse
|
|
||||||
json.Unmarshal(msg, &authResp)
|
|
||||||
if authResp.MsgType != "auth_ok" {
|
|
||||||
return errors.New("invalid auth token")
|
|
||||||
}
|
|
||||||
|
|
||||||
return nil
|
|
||||||
}
|
|
||||||
@@ -1,7 +1,108 @@
|
|||||||
// websocket is used to interact with the Home Assistant
|
// Package websocket is used to interact with the Home Assistant
|
||||||
// websocket API. All HA interaction is done via websocket
|
// websocket API. All HA interaction is done via websocket
|
||||||
// except for cases explicitly called out in http package
|
// except for cases explicitly called out in http package
|
||||||
// documentation.
|
// documentation.
|
||||||
package websocket
|
package websocket
|
||||||
|
|
||||||
// TODO: move existing websocket code here
|
import (
|
||||||
|
"context"
|
||||||
|
"encoding/json"
|
||||||
|
"errors"
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
|
||||||
|
"nhooyr.io/websocket"
|
||||||
|
)
|
||||||
|
|
||||||
|
type AuthMessage struct {
|
||||||
|
MsgType string `json:"type"`
|
||||||
|
AccessToken string `json:"access_token"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func WriteMessage[T any](msg T, conn *websocket.Conn, ctx context.Context) error {
|
||||||
|
msgJson, err := json.Marshal(msg)
|
||||||
|
// fmt.Println(string(msgJson))
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
err = conn.Write(ctx, websocket.MessageText, msgJson)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func ReadMessage(conn *websocket.Conn, ctx context.Context) (string, error) {
|
||||||
|
_, msg, err := conn.Read(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return "", err
|
||||||
|
}
|
||||||
|
return string(msg), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func SetupConnection(connString string) (*websocket.Conn, context.Context, context.CancelFunc) {
|
||||||
|
ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3)
|
||||||
|
|
||||||
|
// Init websocket connection
|
||||||
|
conn, _, err := websocket.Dial(ctx, fmt.Sprintf("ws://%s/api/websocket", connString), nil)
|
||||||
|
if err != nil {
|
||||||
|
ctxCancel()
|
||||||
|
log.Fatalf("ERROR: Failed to connect to websocket at ws://%s/api/websocket. Check IP address and port\n", connString)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read auth_required message
|
||||||
|
_, err = ReadMessage(conn, ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctxCancel()
|
||||||
|
log.Fatalln("Unknown error creating websocket client")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Send auth message
|
||||||
|
err = SendAuthMessage(conn, ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctxCancel()
|
||||||
|
log.Fatalln("Unknown error creating websocket client")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Verify auth message
|
||||||
|
err = VerifyAuthResponse(conn, ctx)
|
||||||
|
if err != nil {
|
||||||
|
ctxCancel()
|
||||||
|
log.Fatalln("ERROR: Auth token is invalid. Please double check it or create a new token in your Home Assistant profile")
|
||||||
|
}
|
||||||
|
|
||||||
|
return conn, ctx, ctxCancel
|
||||||
|
}
|
||||||
|
|
||||||
|
func SendAuthMessage(conn *websocket.Conn, ctx context.Context) error {
|
||||||
|
token := os.Getenv("AUTH_TOKEN")
|
||||||
|
err := WriteMessage(AuthMessage{MsgType: "auth", AccessToken: token}, conn, ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
type authResponse struct {
|
||||||
|
MsgType string `json:"type"`
|
||||||
|
Message string `json:"message"`
|
||||||
|
}
|
||||||
|
|
||||||
|
func VerifyAuthResponse(conn *websocket.Conn, ctx context.Context) error {
|
||||||
|
_, msg, err := conn.Read(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return err
|
||||||
|
}
|
||||||
|
|
||||||
|
var authResp authResponse
|
||||||
|
json.Unmarshal(msg, &authResp)
|
||||||
|
if authResp.MsgType != "auth_ok" {
|
||||||
|
return errors.New("invalid auth token")
|
||||||
|
}
|
||||||
|
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user