diff --git a/app.go b/app.go index 907b63a..4cd6e79 100644 --- a/app.go +++ b/app.go @@ -77,6 +77,12 @@ type NewAppRequest struct { // Used to pull latitude/longitude from Home Assistant // to calculate sunset/sunrise times. HomeZoneEntityId string + + // Optional + // Whether to use secure connections for http and websockets. + // Setting this to `true` will use `https://` instead of `https://` + // and `wss://` instead of `ws://`. + Secure bool } /* @@ -92,13 +98,31 @@ func NewApp(request NewAppRequest) (*App, error) { if port == "" { port = "8123" } - conn, ctx, ctxCancel, err := ws.SetupConnection(request.IpAddress, port, request.HAAuthToken) + + var ( + conn *websocket.Conn + ctx context.Context + ctxCancel context.CancelFunc + err error + ) + + if request.Secure { + conn, ctx, ctxCancel, err = ws.SetupSecureConnection(request.IpAddress, port, request.HAAuthToken) + } else { + conn, ctx, ctxCancel, err = ws.SetupConnection(request.IpAddress, port, request.HAAuthToken) + } if conn == nil { return nil, err } - httpClient := http.NewHttpClient(request.IpAddress, port, request.HAAuthToken) + var httpClient *http.HttpClient + + if request.Secure { + httpClient = http.NewHttpsClient(request.IpAddress, port, request.HAAuthToken) + } else { + httpClient = http.NewHttpClient(request.IpAddress, port, request.HAAuthToken) + } wsWriter := &ws.WebsocketWriter{Conn: conn} service := newService(wsWriter, ctx, httpClient) diff --git a/internal/http/http.go b/internal/http/http.go index 15938a5..2f89643 100644 --- a/internal/http/http.go +++ b/internal/http/http.go @@ -16,8 +16,24 @@ type HttpClient struct { } func NewHttpClient(ip, port, token string) *HttpClient { - url := fmt.Sprintf("http://%s:%s/api", ip, port) - return &HttpClient{url, token} + return ClientFromUri( + fmt.Sprintf("http://%s:%s/api", ip, port), + token, + ) +} + +func NewHttpsClient(ip, port, token string) *HttpClient { + return ClientFromUri( + fmt.Sprintf("https://%s:%s/api", ip, port), + token, + ) +} + +func ClientFromUri(uri, token string) *HttpClient { + return &HttpClient{ + uri, + token, + } } func (c *HttpClient) GetState(entityId string) ([]byte, error) { diff --git a/internal/websocket/websocket.go b/internal/websocket/websocket.go index 70bf7c4..afdf1e4 100644 --- a/internal/websocket/websocket.go +++ b/internal/websocket/websocket.go @@ -50,14 +50,24 @@ func ReadMessage(conn *websocket.Conn, ctx context.Context) ([]byte, error) { } func SetupConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) { + uri := fmt.Sprintf("ws:///%s:%s/api/websocket", ip, port) + return ConnectionFromUri(uri, authToken) +} + +func SetupSecureConnection(ip, port, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) { + uri := fmt.Sprintf("wss://%s:%s/api/websocket", ip, port) + return ConnectionFromUri(uri, authToken) +} + +func ConnectionFromUri(uri, authToken string) (*websocket.Conn, context.Context, context.CancelFunc, error) { ctx, ctxCancel := context.WithTimeout(context.Background(), time.Second*3) // Init websocket connection dialer := websocket.DefaultDialer - conn, _, err := dialer.DialContext(ctx, fmt.Sprintf("ws://%s:%s/api/websocket", ip, port), nil) + conn, _, err := dialer.DialContext(ctx, uri, nil) if err != nil { ctxCancel() - slog.Error("Failed to connect to websocket at ws://%s:%s/api/websocket. Check IP address and port\n", ip, port) + slog.Error("Failed to connect to websocket. Check URI\n", "uri", uri) return nil, nil, nil, err }