1- use crate :: db:: { Drawing , Snapshot , RoomSettings , DB } ;
1+ use crate :: db:: { Drawing , RoomSettings , Snapshot , DB } ;
22use std:: time:: { SystemTime , UNIX_EPOCH } ;
33
4+ const AUTOSAVE_CREATED_BY : & str = "__autosave__" ;
5+ const AUTOSAVE_DEFAULT_NAME : & str = "Latest autosave snapshot" ;
6+ const AUTOSAVE_DEFAULT_DESCRIPTION : & str = "Automatically saved by Excalidraw" ;
7+
48#[ tauri:: command]
59pub fn save_drawing ( name : String , data : String ) -> Result < String , String > {
610 let timestamp = SystemTime :: now ( )
711 . duration_since ( UNIX_EPOCH )
812 . unwrap ( )
913 . as_secs ( ) as i64 ;
10-
14+
1115 let id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
12-
16+
1317 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
14-
18+
1519 conn. execute (
1620 "INSERT INTO drawings (id, name, data, created_at, updated_at) VALUES (?1, ?2, ?3, ?4, ?5)" ,
1721 rusqlite:: params![ & id, & name, & data, timestamp, timestamp] ,
1822 )
1923 . map_err ( |e| e. to_string ( ) ) ?;
20-
24+
2125 Ok ( id)
2226}
2327
@@ -27,22 +31,22 @@ pub fn update_drawing(id: String, name: String, data: String) -> Result<(), Stri
2731 . duration_since ( UNIX_EPOCH )
2832 . unwrap ( )
2933 . as_secs ( ) as i64 ;
30-
34+
3135 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
32-
36+
3337 conn. execute (
3438 "UPDATE drawings SET name = ?1, data = ?2, updated_at = ?3 WHERE id = ?4" ,
3539 rusqlite:: params![ & name, & data, timestamp, & id] ,
3640 )
3741 . map_err ( |e| e. to_string ( ) ) ?;
38-
42+
3943 Ok ( ( ) )
4044}
4145
4246#[ tauri:: command]
4347pub fn load_drawing ( id : String ) -> Result < Drawing , String > {
4448 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
45-
49+
4650 let drawing = conn
4751 . query_row (
4852 "SELECT id, name, data, created_at, updated_at FROM drawings WHERE id = ?1" ,
@@ -58,18 +62,20 @@ pub fn load_drawing(id: String) -> Result<Drawing, String> {
5862 } ,
5963 )
6064 . map_err ( |e| e. to_string ( ) ) ?;
61-
65+
6266 Ok ( drawing)
6367}
6468
6569#[ tauri:: command]
6670pub fn list_drawings ( ) -> Result < Vec < Drawing > , String > {
6771 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
68-
72+
6973 let mut stmt = conn
70- . prepare ( "SELECT id, name, data, created_at, updated_at FROM drawings ORDER BY updated_at DESC" )
74+ . prepare (
75+ "SELECT id, name, data, created_at, updated_at FROM drawings ORDER BY updated_at DESC" ,
76+ )
7177 . map_err ( |e| e. to_string ( ) ) ?;
72-
78+
7379 let drawings = stmt
7480 . query_map ( [ ] , |row| {
7581 Ok ( Drawing {
@@ -83,17 +89,17 @@ pub fn list_drawings() -> Result<Vec<Drawing>, String> {
8389 . map_err ( |e| e. to_string ( ) ) ?
8490 . collect :: < Result < Vec < _ > , _ > > ( )
8591 . map_err ( |e| e. to_string ( ) ) ?;
86-
92+
8793 Ok ( drawings)
8894}
8995
9096#[ tauri:: command]
9197pub fn delete_drawing ( id : String ) -> Result < ( ) , String > {
9298 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
93-
99+
94100 conn. execute ( "DELETE FROM drawings WHERE id = ?1" , rusqlite:: params![ & id] )
95101 . map_err ( |e| e. to_string ( ) ) ?;
96-
102+
97103 Ok ( ( ) )
98104}
99105
@@ -112,14 +118,14 @@ pub fn save_snapshot(
112118 . duration_since ( UNIX_EPOCH )
113119 . unwrap ( )
114120 . as_secs ( ) as i64 ;
115-
121+
116122 let id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
117-
123+
118124 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
119-
125+
120126 // Get room settings to check max snapshots
121127 let settings = get_room_settings_internal ( & conn, & room_id) ?;
122-
128+
123129 // Count existing snapshots
124130 let count: i32 = conn
125131 . query_row (
@@ -128,7 +134,7 @@ pub fn save_snapshot(
128134 |row| row. get ( 0 ) ,
129135 )
130136 . map_err ( |e| e. to_string ( ) ) ?;
131-
137+
132138 // If at limit, delete oldest snapshot
133139 if count >= settings. max_snapshots {
134140 conn. execute (
@@ -137,25 +143,25 @@ pub fn save_snapshot(
137143 )
138144 . map_err ( |e| e. to_string ( ) ) ?;
139145 }
140-
146+
141147 // Insert new snapshot
142148 conn. execute (
143149 "INSERT INTO snapshots (id, room_id, name, description, thumbnail, created_by, created_at, data) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)" ,
144150 rusqlite:: params![ & id, & room_id, & name, & description, & thumbnail, & created_by, timestamp, & data] ,
145151 )
146152 . map_err ( |e| e. to_string ( ) ) ?;
147-
153+
148154 Ok ( id)
149155}
150156
151157#[ tauri:: command]
152158pub fn list_snapshots ( room_id : String ) -> Result < Vec < Snapshot > , String > {
153159 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
154-
160+
155161 let mut stmt = conn
156162 . prepare ( "SELECT id, room_id, name, description, thumbnail, created_by, created_at, '' as data FROM snapshots WHERE room_id = ?1 ORDER BY created_at DESC" )
157163 . map_err ( |e| e. to_string ( ) ) ?;
158-
164+
159165 let snapshots = stmt
160166 . query_map ( rusqlite:: params![ & room_id] , |row| {
161167 Ok ( Snapshot {
@@ -172,14 +178,14 @@ pub fn list_snapshots(room_id: String) -> Result<Vec<Snapshot>, String> {
172178 . map_err ( |e| e. to_string ( ) ) ?
173179 . collect :: < Result < Vec < _ > , _ > > ( )
174180 . map_err ( |e| e. to_string ( ) ) ?;
175-
181+
176182 Ok ( snapshots)
177183}
178184
179185#[ tauri:: command]
180186pub fn load_snapshot ( id : String ) -> Result < Snapshot , String > {
181187 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
182-
188+
183189 let snapshot = conn
184190 . query_row (
185191 "SELECT id, room_id, name, description, thumbnail, created_by, created_at, data FROM snapshots WHERE id = ?1" ,
@@ -198,36 +204,111 @@ pub fn load_snapshot(id: String) -> Result<Snapshot, String> {
198204 } ,
199205 )
200206 . map_err ( |e| e. to_string ( ) ) ?;
201-
207+
202208 Ok ( snapshot)
203209}
204210
205211#[ tauri:: command]
206212pub fn delete_snapshot ( id : String ) -> Result < ( ) , String > {
207213 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
208-
209- conn. execute ( "DELETE FROM snapshots WHERE id = ?1" , rusqlite:: params![ & id] )
210- . map_err ( |e| e. to_string ( ) ) ?;
211-
214+
215+ conn. execute (
216+ "DELETE FROM snapshots WHERE id = ?1" ,
217+ rusqlite:: params![ & id] ,
218+ )
219+ . map_err ( |e| e. to_string ( ) ) ?;
220+
212221 Ok ( ( ) )
213222}
214223
215224#[ tauri:: command]
216- pub fn update_snapshot_metadata ( id : String , name : String , description : String ) -> Result < ( ) , String > {
225+ pub fn update_snapshot_metadata (
226+ id : String ,
227+ name : String ,
228+ description : String ,
229+ ) -> Result < ( ) , String > {
217230 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
218-
231+
219232 conn. execute (
220233 "UPDATE snapshots SET name = ?1, description = ?2 WHERE id = ?3" ,
221234 rusqlite:: params![ & name, & description, & id] ,
222235 )
223236 . map_err ( |e| e. to_string ( ) ) ?;
224-
237+
225238 Ok ( ( ) )
226239}
227240
241+ #[ tauri:: command]
242+ pub fn save_autosave_snapshot (
243+ room_id : String ,
244+ name : Option < String > ,
245+ description : Option < String > ,
246+ thumbnail : Option < String > ,
247+ data : String ,
248+ ) -> Result < String , String > {
249+ let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
250+
251+ let timestamp = SystemTime :: now ( )
252+ . duration_since ( UNIX_EPOCH )
253+ . unwrap ( )
254+ . as_secs ( ) as i64 ;
255+
256+ let final_name = name. unwrap_or_else ( || AUTOSAVE_DEFAULT_NAME . to_string ( ) ) ;
257+ let final_description = description. unwrap_or_else ( || AUTOSAVE_DEFAULT_DESCRIPTION . to_string ( ) ) ;
258+ let final_thumbnail = thumbnail. unwrap_or_default ( ) ;
259+
260+ let existing_id_result: Result < String , rusqlite:: Error > = conn. query_row (
261+ "SELECT id FROM snapshots WHERE room_id = ?1 AND created_by = ?2 LIMIT 1" ,
262+ rusqlite:: params![ & room_id, AUTOSAVE_CREATED_BY ] ,
263+ |row| row. get ( 0 ) ,
264+ ) ;
265+
266+ match existing_id_result {
267+ Ok ( existing_id) => {
268+ conn. execute (
269+ "UPDATE snapshots SET name = ?1, description = ?2, thumbnail = ?3, data = ?4, created_at = ?5 WHERE id = ?6" ,
270+ rusqlite:: params![
271+ & final_name,
272+ & final_description,
273+ & final_thumbnail,
274+ & data,
275+ timestamp,
276+ & existing_id,
277+ ] ,
278+ )
279+ . map_err ( |e| e. to_string ( ) ) ?;
280+
281+ Ok ( existing_id)
282+ }
283+ Err ( rusqlite:: Error :: QueryReturnedNoRows ) => {
284+ let id = uuid:: Uuid :: new_v4 ( ) . to_string ( ) ;
285+ conn. execute (
286+ "INSERT INTO snapshots (id, room_id, name, description, thumbnail, created_by, created_at, data) VALUES (?1, ?2, ?3, ?4, ?5, ?6, ?7, ?8)" ,
287+ rusqlite:: params![
288+ & id,
289+ & room_id,
290+ & final_name,
291+ & final_description,
292+ & final_thumbnail,
293+ AUTOSAVE_CREATED_BY ,
294+ timestamp,
295+ & data,
296+ ] ,
297+ )
298+ . map_err ( |e| e. to_string ( ) ) ?;
299+
300+ Ok ( id)
301+ }
302+ Err ( err) => Err ( err. to_string ( ) ) ,
303+ }
304+ }
305+
228306// Room settings commands
229307
230- fn get_room_settings_internal ( conn : & rusqlite:: Connection , room_id : & str ) -> Result < RoomSettings , String > {
308+ fn get_room_settings_internal (
309+ conn : & rusqlite:: Connection ,
310+ room_id : & str ,
311+ ) -> Result < RoomSettings , String > {
231312 conn. query_row (
232313 "SELECT room_id, max_snapshots, auto_save_interval FROM room_settings WHERE room_id = ?1" ,
233314 rusqlite:: params![ room_id] ,
@@ -244,7 +325,7 @@ fn get_room_settings_internal(conn: &rusqlite::Connection, room_id: &str) -> Res
244325 Ok ( RoomSettings {
245326 room_id : room_id. to_string ( ) ,
246327 max_snapshots : 10 ,
247- auto_save_interval : 300 ,
328+ auto_save_interval : 60 ,
248329 } )
249330 } )
250331}
@@ -256,15 +337,19 @@ pub fn get_room_settings(room_id: String) -> Result<RoomSettings, String> {
256337}
257338
258339#[ tauri:: command]
259- pub fn update_room_settings ( room_id : String , max_snapshots : i32 , auto_save_interval : i32 ) -> Result < ( ) , String > {
340+ pub fn update_room_settings (
341+ room_id : String ,
342+ max_snapshots : i32 ,
343+ auto_save_interval : i32 ,
344+ ) -> Result < ( ) , String > {
260345 let conn = DB . lock ( ) . map_err ( |e| e. to_string ( ) ) ?;
261-
346+
262347 conn. execute (
263348 "INSERT INTO room_settings (room_id, max_snapshots, auto_save_interval) VALUES (?1, ?2, ?3)
264349 ON CONFLICT(room_id) DO UPDATE SET max_snapshots = ?2, auto_save_interval = ?3" ,
265350 rusqlite:: params![ & room_id, max_snapshots, auto_save_interval] ,
266351 )
267352 . map_err ( |e| e. to_string ( ) ) ?;
268-
353+
269354 Ok ( ( ) )
270355}
0 commit comments