소스 검색

Fix bugs in the websocket implementation

Lee Morgan 4 주 전
부모
커밋
93acd3e402
5개의 변경된 파일40개의 추가작업 그리고 8개의 파일을 삭제
  1. 1 0
      Cargo.lock
  2. 1 0
      Cargo.toml
  3. 3 2
      src/main.rs
  4. 33 4
      src/websocket.rs
  5. 2 2
      ui/index.js

+ 1 - 0
Cargo.lock

@@ -621,6 +621,7 @@ dependencies = [
 name = "ha_permissions"
 version = "0.1.0"
 dependencies = [
+ "actix-codec",
  "actix-web",
  "awc",
  "dotenvy",

+ 1 - 0
Cargo.toml

@@ -4,6 +4,7 @@ version = "0.1.0"
 edition = "2024"
 
 [dependencies]
+actix-codec = "0.5.2"
 actix-web = "4.14.0"
 awc = "3.8.2"
 dotenvy = "0.15.7"

+ 3 - 2
src/main.rs

@@ -1,4 +1,4 @@
-use actix_web::{HttpServer, App, middleware, web};
+use actix_web::{HttpServer, App, middleware, web, rt};
 use std::sync::Mutex;
 
 mod routes;
@@ -19,9 +19,10 @@ async fn main() -> Result<(), std::io::Error> {
     let data = web::Data::new(users);
 
     //Connect to HA
-    websocket::connect_to_ha(ha_ip, ha_token)
+    let ha_connection = websocket::connect_to_ha(ha_ip, ha_token)
         .await
         .expect("Failed to start websocket");
+    rt::spawn(websocket::listen(ha_connection));
 
     //Create HTTP server
     HttpServer::new(move || {

+ 33 - 4
src/websocket.rs

@@ -1,14 +1,17 @@
-use awc::{Client, ws::{Frame, Message}};
+use awc::{Client, BoxedSocket, ws::{Frame, Message, Codec}};
+use actix_codec::Framed;
 use futures_util::{SinkExt, StreamExt};
 use serde_json::{Value, from_str, json};
 
-pub async fn connect_to_ha(ip: String, token: String) -> Result<(), Box<dyn std::error::Error>> {
+pub async fn connect_to_ha(
+    ip: String,
+    token: String
+) -> Result<Framed<BoxedSocket, Codec>, Box<dyn std::error::Error>> {
     let client = Client::new();
     let (_resp, mut connection) = client
         .ws(format!("ws://{}:8123/api/websocket", ip))
         .connect()
         .await?;
-    let mut message_id = 1;
 
     while let Some(Ok(msg)) = connection.next().await {
         if let Frame::Text(bytes) = msg {
@@ -36,14 +39,40 @@ pub async fn connect_to_ha(ip: String, token: String) -> Result<(), Box<dyn std:
                 /*let entities_msg = json!({"type": "config/entity_registry/list", "id": message_id});
                 connection.send(Message::Text(entities_msg.to_string().into())).await?;
                 message_id += 1;*/
+                return Ok(connection);
+            }
+
+            if parsed["type"] == "auth_invalid" {
+                return Err("HA authentication.failed".into());
             }
+        }
+    }
+
+    Err("Websocket closed before authentication completed".into())
+}
+
+pub async fn listen(mut connection: Framed<BoxedSocket, Codec>) {
+    let mut message_id = 1;
+
+    while let Some(Ok(msg)) = connection.next().await {
+        if let Frame::Text(bytes) = msg {
+            let text = match String::from_utf8(bytes.to_vec()) {
+                Ok(t) => t,
+                Err(_) => continue
+            };
+            let parsed: Value = match from_str(&text) {
+                Ok(v) => v,
+                Err(_) => continue
+            };
 
             if parsed["type"] == "result" {
                 println!("result");
                 println!("{:#?}", parsed);
             }
+
+            let _ = message_id;
         }
     }
 
-    Ok(())
+    println!("HA websocket connection closed");
 }

+ 2 - 2
ui/index.js

@@ -2,7 +2,7 @@ import loginPage from "./login/index.js";
 import dashboardPage from "./dashboard/index.js";
 import adminCreatePage from "./adminCreate/index.js";
 
-window.areUsers = true;
+window.adminExists = true;
 
 let pages = document.querySelectorAll(".page");
 
@@ -22,7 +22,7 @@ let openPage = (page)=>{
 }
 
 //Check for login
-if(!window.areUsers){
+if(!window.adminExists){
     adminCreatePage.display();
 }else if(localStorage.getItem("loggedIn") === "true"){
     dashboardPage.display();