Skip to content

Commit 11f8af8

Browse files
authored
Merge pull request #34 from piotrpdev/OKO-108-User-Accounts
2 parents cc20a41 + b7af18c commit 11f8af8

File tree

7 files changed

+223
-133
lines changed

7 files changed

+223
-133
lines changed

backend/src/web.rs

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,18 @@
11
pub use app::App;
22
pub use app::AppState;
3-
pub use app::ImageContainer;
43
use serde::Deserialize;
54
use serde::Serialize;
65

76
use crate::CameraSettingNoMeta;
87

8+
#[derive(Serialize, Deserialize, Clone)]
9+
pub struct ImageContainer {
10+
pub camera_id: i64,
11+
pub timestamp: i64,
12+
#[serde(with = "serde_bytes")]
13+
pub image_bytes: Vec<u8>,
14+
}
15+
916
// TODO: Use single shared definition for both camera and backend
1017
#[derive(Serialize, Deserialize, Debug, Clone)]
1118
pub enum CameraMessage {

backend/src/web/app.rs

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,6 @@ use opencv::{
2020
videoio::{VideoWriter, VideoWriterTrait},
2121
};
2222
use rust_embed::RustEmbed;
23-
use serde::{Deserialize, Serialize};
2423
use sqlx::{sqlite::SqliteConnectOptions, SqlitePool};
2524
use time::{Duration, OffsetDateTime};
2625
use tokio::{
@@ -55,7 +54,7 @@ use crate::{
5554
User, Video,
5655
};
5756

58-
use super::MdnsChannelMessage;
57+
use super::{ImageContainer, MdnsChannelMessage};
5958

6059
// TODO: Maybe use `std::future::pending::<()>();` instead of sleeping forever
6160

@@ -74,16 +73,6 @@ const EMPTY_TASK_SLEEP_DURATION: tokio::time::Duration = tokio::time::Duration::
7473
#[folder = "static/"]
7574
struct EmbeddedAssets;
7675

77-
// ? Maybe move this somewhere better
78-
// TODO: Probably change to Protobuf or bincode instead of JSON
79-
#[derive(Serialize, Deserialize, Clone)]
80-
pub struct ImageContainer {
81-
pub camera_id: i64,
82-
pub timestamp: i64,
83-
#[serde(with = "serde_bytes")]
84-
pub image_bytes: Vec<u8>,
85-
}
86-
8776
pub struct AppState {
8877
pub images_tx: watch::Sender<ImageContainer>,
8978
pub video_path: PathBuf,
@@ -669,11 +658,11 @@ async fn handle_socket(
669658
});
670659

671660
let api_channel = state.api_channel.clone();
661+
let sender_mutex_clone = sender_mutex.clone();
672662
let mut first_received = false;
673663

674664
let mut api_listener_task: JoinHandle<Result<(), Box<dyn std::error::Error + Send + Sync>>> =
675665
if is_camera {
676-
let sender_mutex_clone = sender_mutex.clone();
677666
tokio::spawn(async move {
678667
if let Some(some_camera_settings) = initial_camera_settings {
679668
let some_initial_camera_settings = CameraSettingNoMeta {
@@ -757,14 +746,23 @@ async fn handle_socket(
757746
#[allow(clippy::single_match)] // will change in the future
758747
match api_msg {
759748
// TODO: every user task performing this is wasteful, global camera list mutex shared with api would be better
760-
ApiChannelMessage::CameraListChanged(_) => {
749+
ApiChannelMessage::CameraListChanged(change) => {
761750
info!("API channel message received for camera list changed for {who}...");
762751

763752
let Some(user_id_some) = user_id else {
764753
error!("Camera list changed but user was not found in auth_session. How is this even possible?");
765754
break;
766755
};
767756

757+
if let Err(e) = sender_mutex_clone
758+
.lock()
759+
.await
760+
.send(Message::Text(serde_json::to_string(&change)?))
761+
.await
762+
{
763+
error!("Error sending API WebSocket message to {who}: {e:?}");
764+
}
765+
768766
let Ok(new_cameras) = Camera::list_accessible_to_user(
769767
&auth_session.backend.db,
770768
user_id_some,

frontend/src/lib/components/CameraAndVideos.svelte

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -8,14 +8,28 @@
88
import { onDestroy, onMount } from "svelte";
99
import * as Table from "$lib/components/ui/table/index.js";
1010
import { socket } from "$lib/stores/socketStore";
11-
import { isImageContainer, type VideoCameraView } from "../../types";
12-
13-
export let cameraId: number;
14-
export let cameraName: string;
11+
import {
12+
isImageContainer,
13+
type ImageContainer,
14+
type VideoCameraView,
15+
} from "../../types";
1516
1617
let frameCount = 0;
1718
let imgSrc: string = "";
1819
20+
export let cameraId: number;
21+
export let cameraName: string;
22+
export const processImage = (image_bytes: ImageContainer["image_bytes"]) => {
23+
frameCount++;
24+
const bytes = new Uint8Array(image_bytes);
25+
const blob = new Blob([bytes], { type: "image/jpeg" });
26+
const url = URL.createObjectURL(blob);
27+
if (imgSrc !== "") {
28+
URL.revokeObjectURL(imgSrc);
29+
}
30+
imgSrc = url;
31+
};
32+
1933
// Needed to reset the frame count and image source when the camera changes
2034
$: ((_cameraId) => {
2135
frameCount = 0;
@@ -37,39 +51,6 @@
3751
throw new Error("Failed to fetch videos");
3852
}
3953
}
40-
41-
function onMessage(event: MessageEvent) {
42-
const data = event.data;
43-
44-
try {
45-
const parsed_msg = JSON.parse(data);
46-
47-
if (isImageContainer(parsed_msg)) {
48-
if (parsed_msg.camera_id !== cameraId) {
49-
return;
50-
}
51-
52-
frameCount++;
53-
const bytes = new Uint8Array(parsed_msg.image_bytes);
54-
const blob = new Blob([bytes], { type: "image/jpeg" });
55-
const url = URL.createObjectURL(blob);
56-
if (imgSrc !== "") {
57-
URL.revokeObjectURL(imgSrc);
58-
}
59-
imgSrc = url;
60-
}
61-
} catch (e) {
62-
console.error("Failed to parse WebSocket message JSON");
63-
}
64-
}
65-
66-
onMount(() => {
67-
$socket?.addEventListener("message", onMessage);
68-
});
69-
70-
onDestroy(() => {
71-
$socket?.removeEventListener("message", onMessage);
72-
});
7354
</script>
7455

7556
<Card.Root>

0 commit comments

Comments
 (0)