Server upload works
This commit is contained in:
@@ -1 +1,2 @@
|
||||
/target
|
||||
.idea
|
||||
Generated
+53
@@ -1581,6 +1581,12 @@ version = "0.4.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70"
|
||||
|
||||
[[package]]
|
||||
name = "hex-literal"
|
||||
version = "1.1.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e712f64ec3850b98572bffac52e2c6f282b29fe6c5fa6d42334b30be438d95c1"
|
||||
|
||||
[[package]]
|
||||
name = "hexf-parse"
|
||||
version = "0.2.1"
|
||||
@@ -2092,6 +2098,7 @@ dependencies = [
|
||||
"criterion",
|
||||
"dirs",
|
||||
"hex",
|
||||
"hex-literal",
|
||||
"iced",
|
||||
"rand",
|
||||
"rayon",
|
||||
@@ -2103,6 +2110,7 @@ dependencies = [
|
||||
"serde_json",
|
||||
"sha2",
|
||||
"tokio",
|
||||
"zstd",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
@@ -2352,6 +2360,16 @@ version = "0.3.17"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "6877bb514081ee2a7ff5ef9de3281f14a4dd4bceac4c09388074a6b5df8a139a"
|
||||
|
||||
[[package]]
|
||||
name = "mime_guess"
|
||||
version = "2.0.5"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "f7c44f8e672c00fe5308fa235f821cb4198414e1c77935c1ab6948d3fd78550e"
|
||||
dependencies = [
|
||||
"mime",
|
||||
"unicase",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "mio"
|
||||
version = "1.1.1"
|
||||
@@ -3447,6 +3465,7 @@ dependencies = [
|
||||
"js-sys",
|
||||
"log",
|
||||
"mime",
|
||||
"mime_guess",
|
||||
"native-tls",
|
||||
"percent-encoding",
|
||||
"pin-project-lite",
|
||||
@@ -4591,6 +4610,12 @@ dependencies = [
|
||||
"winapi",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "unicase"
|
||||
version = "2.9.0"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "dbc4bc3a9f746d862c45cb89d705aa10f187bb96c76001afab07a0d35ce60142"
|
||||
|
||||
[[package]]
|
||||
name = "unicode-bidi"
|
||||
version = "0.3.18"
|
||||
@@ -5936,6 +5961,34 @@ version = "1.0.20"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "4de98dfa5d5b7fef4ee834d0073d560c9ca7b6c46a71d058c48db7960f8cfaf7"
|
||||
|
||||
[[package]]
|
||||
name = "zstd"
|
||||
version = "0.13.3"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "e91ee311a569c327171651566e07972200e76fcfe2242a4fa446149a3881c08a"
|
||||
dependencies = [
|
||||
"zstd-safe",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-safe"
|
||||
version = "7.2.4"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "8f49c4d5f0abb602a93fb8736af2a4f4dd9512e36f7f570d66e65ff867ed3b9d"
|
||||
dependencies = [
|
||||
"zstd-sys",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zstd-sys"
|
||||
version = "2.0.16+zstd.1.5.7"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "91e19ebc2adc8f83e43039e79776e3fda8ca919132d68a1fed6a5faca2683748"
|
||||
dependencies = [
|
||||
"cc",
|
||||
"pkg-config",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "zvariant"
|
||||
version = "5.9.2"
|
||||
|
||||
+4
-2
@@ -12,12 +12,14 @@ serde_json = "1.0.149"
|
||||
rhai = "1.24.0"
|
||||
chrono = "0.4.44"
|
||||
rusqlite = { version = "0.39.0", features = ["chrono"] }
|
||||
reqwest = { version = "0", features = ["json", "stream"] }
|
||||
reqwest = { version = "0", features = ["json", "stream", "multipart"] }
|
||||
rodio = "0.22.2"
|
||||
sha2 = "0.11.0"
|
||||
hex = "0.4.3"
|
||||
tokio = { version = "1.50.0", features = ["rt", "rt-multi-thread", "macros"] }
|
||||
rayon = "1.12.0"
|
||||
hex = "0.4.3"
|
||||
hex-literal = "1.1.0"
|
||||
zstd = "0.13.3"
|
||||
|
||||
[dev-dependencies]
|
||||
criterion = "0.5"
|
||||
|
||||
@@ -2,4 +2,5 @@ pub(crate) mod words;
|
||||
pub(crate) mod card_sets;
|
||||
pub(crate) mod card_stats;
|
||||
pub(crate) mod voice;
|
||||
pub(crate) mod settings;
|
||||
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use rusqlite::fallible_iterator::FallibleIterator;
|
||||
use rusqlite::Connection;
|
||||
|
||||
pub fn get_setting(key: String, connection: &Connection) -> Option<String> {
|
||||
let mut stmt = connection.prepare("SELECT value FROM settings WHERE id = ?1").unwrap();
|
||||
let iter = stmt.query_map((key,), |row| {
|
||||
row.get(0)
|
||||
}).unwrap();
|
||||
|
||||
for row in iter {
|
||||
if let Ok(value) = row {
|
||||
return Some(value);
|
||||
}
|
||||
return None;
|
||||
}
|
||||
None
|
||||
}
|
||||
|
||||
pub fn set_setting(key: String, value: String, connection: &Connection) {
|
||||
let current = get_settings_list(connection);
|
||||
if current.contains(&key) {
|
||||
update_settings(key, value, connection);
|
||||
}else {
|
||||
create_settings(key, value, connection);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn delete_settings(key: String, connection: &Connection) {
|
||||
connection
|
||||
.execute("DELETE FROM settings WHERE id = ?1", (&key,))
|
||||
.unwrap_or_else(|e| {
|
||||
println!("{}", e);
|
||||
0
|
||||
});
|
||||
}
|
||||
|
||||
fn create_settings(key: String, value: String, connection: &Connection) {
|
||||
connection
|
||||
.execute(
|
||||
"INSERT into settings (id, value) VALUES (?1, ?2)",
|
||||
(key, value),
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("{}", e);
|
||||
0
|
||||
});
|
||||
}
|
||||
|
||||
fn update_settings(key: String, value: String, connection: &Connection) {
|
||||
connection
|
||||
.execute(
|
||||
"update settings
|
||||
set value = ?2
|
||||
where id = ?1",
|
||||
(key, value),
|
||||
)
|
||||
.unwrap_or_else(|e| {
|
||||
println!("{}", e);
|
||||
0
|
||||
});}
|
||||
|
||||
fn get_settings_list(connection: &Connection) -> Vec<String> {
|
||||
let mut stmt = connection.prepare("SELECT id FROM settings").unwrap();
|
||||
let iter = stmt.query_map((), |row| {
|
||||
row.get(0)
|
||||
}).unwrap();
|
||||
iter.map(|row| { row.unwrap() }).collect()
|
||||
}
|
||||
|
||||
@@ -16,6 +16,16 @@ pub fn create_db() {
|
||||
}
|
||||
|
||||
fn create_tables(conn: &Connection) {
|
||||
conn.execute(
|
||||
"create table settings
|
||||
(
|
||||
id text primary key,
|
||||
value text
|
||||
);",
|
||||
(),
|
||||
)
|
||||
.unwrap_or_else(|e| 0);
|
||||
|
||||
conn.execute(
|
||||
"create table card_set
|
||||
(
|
||||
@@ -28,7 +38,7 @@ fn create_tables(conn: &Connection) {
|
||||
);",
|
||||
(),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|e| 0);
|
||||
conn.execute(
|
||||
"create table word_group
|
||||
(
|
||||
@@ -38,7 +48,7 @@ fn create_tables(conn: &Connection) {
|
||||
);",
|
||||
(),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|e| 0);
|
||||
conn.execute(
|
||||
"create table words
|
||||
(
|
||||
@@ -55,7 +65,7 @@ fn create_tables(conn: &Connection) {
|
||||
);",
|
||||
(),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|e| 0);
|
||||
conn.execute(
|
||||
"create table card_stats
|
||||
(
|
||||
@@ -72,13 +82,13 @@ fn create_tables(conn: &Connection) {
|
||||
);",
|
||||
(),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|e| 0);
|
||||
conn.execute(
|
||||
"insert into word_group (name)
|
||||
values (\"Слова\");",
|
||||
(),
|
||||
)
|
||||
.unwrap();
|
||||
.unwrap_or_else(|e| 0);
|
||||
}
|
||||
|
||||
pub fn add_word(word: &mut WordData, connection: &Connection) {
|
||||
|
||||
+23
-3
@@ -8,10 +8,12 @@ mod randomizer;
|
||||
mod repetition;
|
||||
mod repetitions;
|
||||
mod selector;
|
||||
mod sync;
|
||||
mod word;
|
||||
mod writing;
|
||||
|
||||
use crate::data_provider::card_sets::load_sets;
|
||||
use crate::data_provider::settings::get_setting;
|
||||
use crate::data_provider::words::{create_db, load_word_groups, load_words};
|
||||
use crate::dictionary::{app_data_dir, DictionaryMessage, DictionaryState};
|
||||
use crate::dictionary_test::{DictionaryQuizMessage, DictionaryQuizState};
|
||||
@@ -21,10 +23,12 @@ use crate::randomizer::randomizer::{RandomizerMessage, RandomizerState};
|
||||
use crate::repetition::{RepetitionMessage, RepetitionState};
|
||||
use crate::repetitions::{CardSetSettings, RepetitionsMessage, RepetitionsState};
|
||||
use crate::selector::*;
|
||||
use crate::sync::{SyncMessage, SyncState};
|
||||
use crate::word::{WordMessage, WordState};
|
||||
use crate::writing::{WritingMessage, WritingState};
|
||||
use crate::Page::{
|
||||
Dictionary, DictionaryQuiz, Quiz, Randomizer, Repetition, Repetitions, Selector, Word, Writing,
|
||||
Dictionary, DictionaryQuiz, Quiz, Randomizer, Repetition, Repetitions, Selector, Sync, Word,
|
||||
Writing,
|
||||
};
|
||||
use crate::RootMessage::Keyboard;
|
||||
use iced::keyboard::Event;
|
||||
@@ -60,6 +64,7 @@ pub enum RootMessage {
|
||||
Repetitions(RepetitionsMessage),
|
||||
Repetition(RepetitionMessage),
|
||||
Word(WordMessage),
|
||||
Sync(SyncMessage),
|
||||
Keyboard(Event),
|
||||
}
|
||||
|
||||
@@ -73,6 +78,7 @@ pub enum Page {
|
||||
Repetitions(RepetitionsState),
|
||||
Repetition(RepetitionState),
|
||||
Word(WordState),
|
||||
Sync(SyncState),
|
||||
PreviousPage,
|
||||
}
|
||||
|
||||
@@ -85,6 +91,7 @@ pub struct AppState {
|
||||
pub card_sets: Vec<CardSetSettings>,
|
||||
pub word_groups: Vec<WordGroup>,
|
||||
pub connection: Connection,
|
||||
pub sync_data: AppSettings,
|
||||
}
|
||||
|
||||
impl Default for ScreenState {
|
||||
@@ -96,12 +103,14 @@ impl Default for ScreenState {
|
||||
let list = load_words(&connection);
|
||||
let sets = load_sets(&connection);
|
||||
let groups = load_word_groups(&connection);
|
||||
let setting = load_settings(&connection);
|
||||
|
||||
let state = Arc::new(Mutex::new(AppState {
|
||||
dictionary: list,
|
||||
card_sets: sets,
|
||||
connection,
|
||||
word_groups: groups,
|
||||
sync_data: setting,
|
||||
}));
|
||||
ScreenState {
|
||||
stack: vec![Selector(SelectorState::new(state.clone()))],
|
||||
@@ -109,6 +118,11 @@ impl Default for ScreenState {
|
||||
}
|
||||
}
|
||||
|
||||
fn load_settings(connection: &Connection) -> AppSettings {
|
||||
let key = get_setting("SYNC_KEY".to_string(), connection);
|
||||
AppSettings { key }
|
||||
}
|
||||
|
||||
impl ScreenState {
|
||||
pub fn boot() -> (ScreenState, Task<RootMessage>) {
|
||||
create_db();
|
||||
@@ -130,7 +144,8 @@ impl ScreenState {
|
||||
Randomizer,
|
||||
Repetitions,
|
||||
Repetition,
|
||||
Word
|
||||
Word,
|
||||
Sync
|
||||
);
|
||||
Task::none()
|
||||
}
|
||||
@@ -145,7 +160,8 @@ impl ScreenState {
|
||||
Randomizer,
|
||||
Repetitions,
|
||||
Repetition,
|
||||
Word
|
||||
Word,
|
||||
Sync
|
||||
)
|
||||
}
|
||||
|
||||
@@ -158,6 +174,10 @@ impl ScreenState {
|
||||
}
|
||||
}
|
||||
|
||||
pub struct AppSettings {
|
||||
key: Option<String>,
|
||||
}
|
||||
|
||||
#[macro_export]
|
||||
macro_rules! view_navigation {
|
||||
($stack:expr, $($e:ident), *) => {
|
||||
|
||||
+1
-1
@@ -193,7 +193,7 @@ impl RepetitionsState {
|
||||
column![
|
||||
text!("Худшие слова"),
|
||||
container(scrollable(self.worst_words_list(&set)).height(200)).style(bordered_box),
|
||||
radio("Начать с плохих слов", SetOrderMode::TrainWorstFirst, Some(set.open_mode), RepetitionsMessage::SetOpenMode),
|
||||
// radio("Начать с плохих слов", SetOrderMode::TrainWorstFirst, Some(set.open_mode), RepetitionsMessage::SetOpenMode),
|
||||
radio("Полностью случайно", SetOrderMode::FullRandom, Some(set.open_mode), RepetitionsMessage::SetOpenMode)
|
||||
]
|
||||
.spacing(DEFAULT_SPACING)
|
||||
|
||||
+7
-1
@@ -9,6 +9,7 @@ use crate::Page::{Quiz, Writing};
|
||||
use crate::{AppState, NavigatedPage, Page, QuizState, RootMessage, DEFAULT_SPACING};
|
||||
use iced::widget::*;
|
||||
use iced::{alignment, Element, Task};
|
||||
use crate::sync::SyncState;
|
||||
|
||||
pub struct SelectorState {
|
||||
pub set: KanaSet,
|
||||
@@ -25,6 +26,7 @@ pub enum SelectorMessage {
|
||||
ToDictionary,
|
||||
ToRandomize,
|
||||
ToRepetitions,
|
||||
ToSync,
|
||||
}
|
||||
|
||||
impl NavigatedPage<SelectorMessage> for SelectorState {
|
||||
@@ -48,6 +50,9 @@ impl NavigatedPage<SelectorMessage> for SelectorState {
|
||||
if let SelectorMessage::ToRepetitions = message {
|
||||
return Some(Page::Repetitions(RepetitionsState::new(self.state.clone())));
|
||||
}
|
||||
if let SelectorMessage::ToSync = message {
|
||||
return Some(Page::Sync(SyncState::new(self.state.clone())));
|
||||
}
|
||||
None
|
||||
}
|
||||
}
|
||||
@@ -80,7 +85,8 @@ impl SelectorState {
|
||||
button("Переключить азбуки").on_press(SelectorMessage::Change),
|
||||
button("Словарь").on_press(SelectorMessage::ToDictionary),
|
||||
button("Рандомайзер").on_press(SelectorMessage::ToRandomize),
|
||||
button("Повторение").on_press(SelectorMessage::ToRepetitions)
|
||||
button("Повторение").on_press(SelectorMessage::ToRepetitions),
|
||||
button("Синхронизация").on_press(SelectorMessage::ToSync)
|
||||
]
|
||||
.spacing(DEFAULT_SPACING),
|
||||
self.rows_selector(),
|
||||
|
||||
+230
@@ -0,0 +1,230 @@
|
||||
use std::io;
|
||||
use crate::data_provider::settings::set_setting;
|
||||
use crate::sync::SyncMessage::NextAnimation;
|
||||
use crate::Page::PreviousPage;
|
||||
use crate::{AppState, NavigatedPage, Page, RootMessage, DEFAULT_SPACING};
|
||||
use iced::widget::container::rounded_box;
|
||||
use iced::widget::{button, column, container, progress_bar, row, space, text};
|
||||
use iced::{Element, Fill, Font, Left, Task};
|
||||
use std::sync::{Arc, Mutex};
|
||||
use std::time::Duration;
|
||||
use zstd::{Encoder, DEFAULT_COMPRESSION_LEVEL};
|
||||
use crate::dictionary::app_data_dir;
|
||||
|
||||
const API_URL: &str = "https://learning.micialware.ru/";
|
||||
/*const API_URL: &str = "http://localhost:8089/";*/
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum SyncMessage {
|
||||
Back,
|
||||
CopyKey,
|
||||
KeyCopied,
|
||||
IdReceived(String),
|
||||
InitSync,
|
||||
GetKey,
|
||||
Send,
|
||||
GetLast,
|
||||
NextAnimation,
|
||||
NetworkFinished,
|
||||
}
|
||||
#[derive(Clone)]
|
||||
pub struct SyncState {
|
||||
state: Arc<Mutex<AppState>>,
|
||||
frozen: bool,
|
||||
progress: f32,
|
||||
}
|
||||
|
||||
impl NavigatedPage<SyncMessage> for SyncState {
|
||||
fn navigate(&self, message: &SyncMessage) -> Option<Page> {
|
||||
if let SyncMessage::Back = message
|
||||
&& !self.frozen
|
||||
{
|
||||
Some(PreviousPage)
|
||||
} else {
|
||||
None
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl SyncState {
|
||||
pub fn new(state: Arc<Mutex<AppState>>) -> SyncState {
|
||||
Self {
|
||||
state,
|
||||
frozen: false,
|
||||
progress: 0.0,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn update(&mut self, message: SyncMessage) -> Task<RootMessage> {
|
||||
match message {
|
||||
SyncMessage::Back => {}
|
||||
SyncMessage::CopyKey => {
|
||||
let state = self.state.lock().unwrap();
|
||||
let key = state.sync_data.key.clone().unwrap();
|
||||
return iced::clipboard::write(key)
|
||||
.map(|_val: String| RootMessage::Sync(SyncMessage::KeyCopied));
|
||||
}
|
||||
SyncMessage::InitSync => {
|
||||
return Task::perform(first_sync(), |id| {
|
||||
RootMessage::Sync(SyncMessage::IdReceived(id))
|
||||
});
|
||||
}
|
||||
SyncMessage::GetKey => {
|
||||
return iced::clipboard::read().map(|key| {
|
||||
RootMessage::Sync(SyncMessage::IdReceived(key.unwrap_or_else(String::new)))
|
||||
});
|
||||
}
|
||||
SyncMessage::KeyCopied => {}
|
||||
SyncMessage::IdReceived(new_id) => {
|
||||
if validate_id(&new_id) == false {
|
||||
return Task::none();
|
||||
}
|
||||
let mut state = self.state.lock().unwrap();
|
||||
state.sync_data.key = Some(new_id.clone());
|
||||
set_setting("SYNC_KEY".to_string(), new_id, &state.connection);
|
||||
}
|
||||
SyncMessage::Send => {
|
||||
self.prepare_to_db_interaction();
|
||||
|
||||
let id = self.state.lock().unwrap().sync_data.key.clone().unwrap();
|
||||
let tasks = Task::batch([
|
||||
Task::perform(
|
||||
async { tokio::time::sleep(Duration::from_millis(200)).await },
|
||||
|_| RootMessage::Sync(NextAnimation),
|
||||
),
|
||||
Task::perform(send_data(id), |_| {
|
||||
RootMessage::Sync(SyncMessage::NetworkFinished)
|
||||
}),
|
||||
]);
|
||||
|
||||
return tasks;
|
||||
}
|
||||
SyncMessage::GetLast => self.prepare_to_db_interaction(),
|
||||
NextAnimation => {
|
||||
self.progress += 1.0;
|
||||
if self.progress > 5.0 {
|
||||
self.progress = 0.0;
|
||||
}
|
||||
if self.frozen {
|
||||
return Task::perform(
|
||||
async { tokio::time::sleep(Duration::from_millis(200)).await },
|
||||
|_| RootMessage::Sync(NextAnimation),
|
||||
);
|
||||
}
|
||||
}
|
||||
SyncMessage::NetworkFinished => {
|
||||
self.frozen = false;
|
||||
}
|
||||
}
|
||||
Task::none()
|
||||
}
|
||||
pub fn view(&self) -> Element<'_, SyncMessage> {
|
||||
container(
|
||||
column![
|
||||
button("Назад").on_press(SyncMessage::Back),
|
||||
row![self.sync_column(), self.app_updater()].spacing(DEFAULT_SPACING)
|
||||
]
|
||||
.align_x(Left)
|
||||
.width(Fill)
|
||||
.height(Fill)
|
||||
.spacing(DEFAULT_SPACING),
|
||||
)
|
||||
.center_x(Fill)
|
||||
.padding(10)
|
||||
.into()
|
||||
}
|
||||
|
||||
fn sync_column(&self) -> Element<'_, SyncMessage> {
|
||||
let network_view: Element<'_, SyncMessage> = if self.frozen {
|
||||
progress_bar(0.0..=5.0, self.progress).into()
|
||||
} else {
|
||||
space().into()
|
||||
};
|
||||
if let Some(key) = self.state.lock().unwrap().sync_data.key.clone() {
|
||||
column![
|
||||
text!("Ваш ключ синхронизации"),
|
||||
container(container(text!("{}", key).size(20).font(Font::MONOSPACE)).padding(3))
|
||||
.style(rounded_box),
|
||||
button("Скопировать в буффер обмена").on_press(SyncMessage::CopyKey),
|
||||
row![
|
||||
button("↑ Отправить").on_press(SyncMessage::Send),
|
||||
button("↓ Скачать").on_press(SyncMessage::GetLast)
|
||||
]
|
||||
.spacing(DEFAULT_SPACING),
|
||||
container(network_view).width(Fill),
|
||||
]
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.width(Fill)
|
||||
.into()
|
||||
} else {
|
||||
column![
|
||||
button("Создать сохранение").on_press(SyncMessage::InitSync),
|
||||
button("Вставить ключ из буффера").on_press(SyncMessage::GetKey),
|
||||
]
|
||||
.spacing(DEFAULT_SPACING)
|
||||
.width(Fill)
|
||||
.into()
|
||||
}
|
||||
}
|
||||
|
||||
fn app_updater(&self) -> Element<'_, SyncMessage> {
|
||||
column![].width(Fill).into()
|
||||
}
|
||||
|
||||
fn prepare_to_db_interaction(&mut self) {
|
||||
if self.frozen {
|
||||
return;
|
||||
}
|
||||
self.frozen = true;
|
||||
self.progress = 0.0;
|
||||
let state = self.state.lock().unwrap();
|
||||
state
|
||||
.connection
|
||||
.query_row("PRAGMA wal_checkpoint(TRUNCATE)", [], |_| Ok(()))
|
||||
.unwrap_or_else(|e| {
|
||||
eprintln!("Ошибка при checkpoint WAL: {e}");
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
async fn send_data(id: String) {
|
||||
let path = app_data_dir();
|
||||
let db_file = path.join("data.db");
|
||||
let data = tokio::fs::read(db_file).await.unwrap();
|
||||
let data = compress(data);
|
||||
|
||||
let api_url = API_URL.to_string();
|
||||
let id_url = format!("{api_url}upload/{id}");
|
||||
|
||||
let form = reqwest::multipart::Form::new().part("db", reqwest::multipart::Part::bytes(data));
|
||||
let client = reqwest::Client::new();
|
||||
client.post(&id_url).multipart(form).send().await.unwrap();
|
||||
}
|
||||
|
||||
fn compress(data: Vec<u8>) -> Vec<u8> {
|
||||
let mut encoder = Encoder::new(Vec::new(), DEFAULT_COMPRESSION_LEVEL).unwrap();
|
||||
io::copy(&mut &data[..], &mut encoder).unwrap();
|
||||
let compressed = encoder.finish().unwrap();
|
||||
compressed
|
||||
}
|
||||
|
||||
async fn first_sync() -> String {
|
||||
let id_url = API_URL.to_string() + "generate";
|
||||
|
||||
let client = reqwest::Client::new();
|
||||
let id = client
|
||||
.get(&id_url)
|
||||
.send()
|
||||
.await
|
||||
.unwrap()
|
||||
.text()
|
||||
.await
|
||||
.unwrap();
|
||||
println!("id: {}", id);
|
||||
id
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn validate_id(id: &str) -> bool {
|
||||
id.len() == 24 && id.chars().all(|c| c.is_ascii_alphanumeric())
|
||||
}
|
||||
Reference in New Issue
Block a user