forked from franciscoBSalgueiro/en-croissant
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathpuzzle.rs
112 lines (94 loc) · 3.1 KB
/
puzzle.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
use std::{collections::VecDeque, path::PathBuf, sync::Mutex};
use diesel::{dsl::sql, sql_types::Bool, Connection, ExpressionMethods, QueryDsl, RunQueryDsl};
use once_cell::sync::Lazy;
use serde::Serialize;
use specta::Type;
use tauri::{path::BaseDirectory, Manager};
use crate::{
db::{puzzles, Puzzle},
error::Error,
};
#[derive(Debug)]
struct PuzzleCache {
cache: VecDeque<Puzzle>,
counter: usize,
min_rating: u16,
max_rating: u16,
}
impl PuzzleCache {
fn new() -> Self {
Self {
cache: VecDeque::new(),
counter: 0,
min_rating: 0,
max_rating: 0,
}
}
fn get_puzzles(&mut self, file: &str, min_rating: u16, max_rating: u16) -> Result<(), Error> {
if self.cache.is_empty()
|| self.min_rating != min_rating
|| self.max_rating != max_rating
|| self.counter >= 20
{
self.cache.clear();
self.counter = 0;
let mut db = diesel::SqliteConnection::establish(file).expect("open database");
let new_puzzles = puzzles::table
.filter(puzzles::rating.le(max_rating as i32))
.filter(puzzles::rating.ge(min_rating as i32))
.order(sql::<Bool>("RANDOM()"))
.limit(20)
.load::<Puzzle>(&mut db)?;
self.cache = new_puzzles.into_iter().collect();
self.min_rating = min_rating;
self.max_rating = max_rating;
}
Ok(())
}
fn get_next_puzzle(&mut self) -> Option<Puzzle> {
if let Some(puzzle) = self.cache.get(self.counter) {
self.counter += 1;
Some(puzzle.clone())
} else {
None
}
}
}
#[tauri::command]
#[specta::specta]
pub fn get_puzzle(file: String, min_rating: u16, max_rating: u16) -> Result<Puzzle, Error> {
static PUZZLE_CACHE: Lazy<Mutex<PuzzleCache>> = Lazy::new(|| Mutex::new(PuzzleCache::new()));
let mut cache = PUZZLE_CACHE.lock().unwrap();
cache.get_puzzles(&file, min_rating, max_rating)?;
cache.get_next_puzzle().ok_or(Error::NoPuzzles)
}
#[derive(Serialize, Type)]
#[serde(rename_all = "camelCase")]
pub struct PuzzleDatabaseInfo {
title: String,
description: String,
puzzle_count: i32,
storage_size: i32,
path: String,
}
#[tauri::command]
#[specta::specta]
pub async fn get_puzzle_db_info(
file: PathBuf,
app: tauri::AppHandle,
) -> Result<PuzzleDatabaseInfo, Error> {
let db_path = PathBuf::from("puzzles").join(file);
let path = app.path().resolve(db_path, BaseDirectory::AppData)?;
let mut db =
diesel::SqliteConnection::establish(&path.to_string_lossy()).expect("open database");
let puzzle_count = puzzles::table.count().get_result::<i64>(&mut db)? as i32;
let storage_size = path.metadata()?.len() as i32;
let filename = path.file_name().expect("get filename").to_string_lossy();
Ok(PuzzleDatabaseInfo {
title: filename.to_string(),
description: "".to_string(),
puzzle_count,
storage_size,
path: path.to_string_lossy().to_string(),
})
}