@@ -63,8 +63,6 @@ const SQLITE_URL: &str = "sqlite://data.db";
6363const VIDEO_PATH : & str = "./videos/" ;
6464const DEFAULT_ADMIN_USERNAME : & str = "admin" ;
6565const DEFAULT_ADMIN_PASS_HASH : & str = "$argon2id$v=19$m=19456,t=2,p=1$VE0e3g7DalWHgDwou3nuRA$uC6TER156UQpk0lNQ5+jHM0l5poVjPA1he/Tyn9J4Zw" ;
66- const DEFAULT_GUEST_USERNAME : & str = "guest" ;
67- const DEFAULT_GUEST_PASS_HASH : & str = "$argon2id$v=19$m=19456,t=2,p=1$VE0e3g7DalWHgDwou3nuRA$uC6TER156UQpk0lNQ5+jHM0l5poVjPA1he/Tyn9J4Zw" ;
6866const EXPIRED_SESSION_DELETION_INTERVAL : tokio:: time:: Duration =
6967 tokio:: time:: Duration :: from_secs ( 60 ) ;
7068const SESSION_DURATION : Duration = Duration :: days ( 1 ) ;
@@ -83,6 +81,7 @@ pub struct AppState {
8381 pub mdns_channel : watch:: Sender < MdnsChannelMessage > ,
8482 pub shutdown_token : CancellationToken ,
8583 pub oko_private_socket_addr : Option < SocketAddr > ,
84+ pub db_pool : SqlitePool ,
8685}
8786
8887pub struct App {
@@ -129,6 +128,7 @@ impl App {
129128 } )
130129 }
131130
131+ #[ allow( clippy:: too_many_lines) ] // TODO: Refactor
132132 pub async fn serve ( self ) -> Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > {
133133 // ? Maybe make this optional just in case
134134 let admin_exists = User :: get_using_username ( & self . db , DEFAULT_ADMIN_USERNAME )
@@ -145,21 +145,6 @@ impl App {
145145 admin. create_using_self ( & self . db ) . await ?;
146146 }
147147
148- // ? Maybe make this optional just in case
149- let guest_exists = User :: get_using_username ( & self . db , DEFAULT_GUEST_USERNAME )
150- . await
151- . is_ok ( ) ;
152- if !guest_exists {
153- let mut guest = User {
154- user_id : User :: DEFAULT . user_id ,
155- username : "guest" . to_string ( ) ,
156- password_hash : DEFAULT_GUEST_PASS_HASH . to_owned ( ) ,
157- created_at : User :: DEFAULT . created_at ( ) ,
158- } ;
159-
160- guest. create_using_self ( & self . db ) . await ?;
161- }
162-
163148 // Session layer.
164149 //
165150 // This uses `tower-sessions` to establish a layer that will provide the session
@@ -185,7 +170,7 @@ impl App {
185170 //
186171 // This combines the session layer with our backend to establish the auth
187172 // service which will provide the auth session as a request extension.
188- let backend = Backend :: new ( self . db ) ;
173+ let backend = Backend :: new ( self . db . clone ( ) ) ;
189174 let auth_layer = AuthManagerLayerBuilder :: new ( backend, session_layer) . build ( ) ;
190175
191176 let embedded_assets_service = ServeEmbed :: < EmbeddedAssets > :: new ( ) ;
@@ -209,6 +194,7 @@ impl App {
209194 mdns_channel : mdns_channel. clone ( ) ,
210195 shutdown_token : shutdown_token. clone ( ) ,
211196 oko_private_socket_addr : self . oko_private_socket_addr ,
197+ db_pool : self . db ,
212198 } ) ;
213199
214200 let mdns_task = tokio:: spawn ( async move {
@@ -238,6 +224,7 @@ impl App {
238224
239225 let main_router = Router :: new ( )
240226 . route ( "/api/ws" , axum:: routing:: any ( ws_handler) )
227+ . route ( "/api/guest_exists" , axum:: routing:: get ( guest_exists_route) )
241228 . with_state ( app_state. clone ( ) ) ;
242229
243230 // TODO: Order of merge matters here, make sure the correct routes are protected and that fallback works as intended.
@@ -269,6 +256,15 @@ impl App {
269256 }
270257}
271258
259+ pub async fn guest_exists_route ( state : State < Arc < AppState > > ) -> impl IntoResponse {
260+ let guest_user_result = User :: get_using_username ( & state. db_pool , "guest" ) . await ;
261+ if guest_user_result. is_err ( ) {
262+ return http:: StatusCode :: INTERNAL_SERVER_ERROR . into_response ( ) ;
263+ }
264+
265+ http:: StatusCode :: OK . into_response ( )
266+ }
267+
272268// ? Maybe move all functions below into App impl block, then use `self` for db pool
273269
274270async fn shutdown_signal (
@@ -397,7 +393,7 @@ async fn handle_socket(
397393 // TODO: Maybe find a better way to handle this
398394 if camera_any_port {
399395 let Ok ( db_camera) =
400- Camera :: get_using_ip ( & auth_session . backend . db , who. ip ( ) . to_string ( ) + ":*" ) . await
396+ Camera :: get_using_ip ( & state . db_pool , who. ip ( ) . to_string ( ) + ":*" ) . await
401397 else {
402398 // TODO: Inform client/db if camera not found (both web user and ws connection), also find better way to exit here?
403399 error ! ( "Camera (any port) not found in DB, aborting..." ) ;
@@ -406,9 +402,7 @@ async fn handle_socket(
406402
407403 camera_id = db_camera. camera_id ;
408404 } else {
409- let Ok ( db_camera) =
410- Camera :: get_using_ip ( & auth_session. backend . db , who. to_string ( ) ) . await
411- else {
405+ let Ok ( db_camera) = Camera :: get_using_ip ( & state. db_pool , who. to_string ( ) ) . await else {
412406 // TODO: Inform client/db if camera not found (both web user and ws connection), also find better way to exit here?
413407 error ! ( "Camera not found in DB, aborting..." ) ;
414408 return ;
@@ -417,8 +411,7 @@ async fn handle_socket(
417411 camera_id = db_camera. camera_id ;
418412 }
419413
420- let Ok ( camera_settings) =
421- CameraSetting :: get_for_camera ( & auth_session. backend . db , camera_id) . await
414+ let Ok ( camera_settings) = CameraSetting :: get_for_camera ( & state. db_pool , camera_id) . await
422415 else {
423416 error ! ( "Error getting initial camera settings for camera {camera_id}, aborting..." ) ;
424417 return ;
@@ -434,8 +427,7 @@ async fn handle_socket(
434427
435428 user_id = Some ( user. user_id ) ;
436429
437- let Ok ( i_cameras) =
438- Camera :: list_accessible_to_user ( & auth_session. backend . db , user. user_id ) . await
430+ let Ok ( i_cameras) = Camera :: list_accessible_to_user ( & state. db_pool , user. user_id ) . await
439431 else {
440432 error ! ( "Error listing cameras for user..." ) ;
441433 return ;
@@ -454,7 +446,7 @@ async fn handle_socket(
454446 // ! Camera restart does not guarantee new recording, frames will keep going to the same video unless socket times out?
455447 let mut recording_task: JoinHandle < Result < ( ) , Box < dyn std:: error:: Error + Send + Sync > > > =
456448 if is_camera {
457- let auth_session_clone = auth_session . clone ( ) ;
449+ let state_clone = state . clone ( ) ;
458450 // TODO: Check if errors are returned properly here, had some issues with the ? operator being silent
459451 tracker. spawn ( async move {
460452 let now = Video :: DEFAULT . start_time ( ) ;
@@ -473,9 +465,7 @@ async fn handle_socket(
473465 } ;
474466
475467 // ? Maybe don't create video until first frame (or maybe doing this is actually a good approach)?
476- video
477- . create_using_self ( & auth_session_clone. backend . db )
478- . await ?;
468+ video. create_using_self ( & state_clone. db_pool ) . await ?;
479469
480470 let ( frame_width, frame_height, framerate) = match initial_camera_settings_clone {
481471 #[ allow( clippy:: match_same_arms) ] // readability
@@ -547,9 +537,7 @@ async fn handle_socket(
547537 video. end_time = Some ( OffsetDateTime :: now_utc ( ) ) ;
548538 video. file_size = Some ( total_bytes. try_into ( ) ?) ;
549539
550- video
551- . update_using_self ( & auth_session_clone. backend . db )
552- . await ?;
540+ video. update_using_self ( & state_clone. db_pool ) . await ?;
553541 info ! ( "Recording finished for {who}..." ) ;
554542
555543 Ok ( ( ) )
@@ -781,11 +769,9 @@ async fn handle_socket(
781769 error ! ( "Error sending API WebSocket message to {who}: {e:?}" ) ;
782770 }
783771
784- let Ok ( new_cameras) = Camera :: list_accessible_to_user (
785- & auth_session. backend . db ,
786- user_id_some,
787- )
788- . await
772+ let Ok ( new_cameras) =
773+ Camera :: list_accessible_to_user ( & state. db_pool , user_id_some)
774+ . await
789775 else {
790776 // TODO: prevent potential endless loop here from the DB call always failing
791777 error ! ( "Error listing new cameras for {who}..." ) ;
0 commit comments