126 lines
3.4 KiB
Rust
126 lines
3.4 KiB
Rust
use chrono::offset::Utc;
|
|
use curl::{easy, easy::Easy2};
|
|
use rand::prelude::*;
|
|
use ring_compat::signature::ed25519::SigningKey;
|
|
use rusqlite::{Connection, DatabaseName};
|
|
use tauri::{Manager, State};
|
|
use tokio::sync::Mutex;
|
|
|
|
use crate::server::app_state::AppState;
|
|
|
|
#[derive(Debug)]
|
|
struct Collector(Vec<u8>, Vec<u8>, usize);
|
|
|
|
impl easy::Handler for Collector {
|
|
fn write(&mut self, data: &[u8]) -> Result<usize, easy::WriteError> {
|
|
self.0.extend_from_slice(data);
|
|
Ok(data.len())
|
|
}
|
|
|
|
fn read(&mut self, data: &mut [u8]) -> Result<usize, easy::ReadError> {
|
|
let p = self.2;
|
|
let src: &[u8] = self.1.as_ref();
|
|
let n = usize::min(src.len() - p, data.len());
|
|
data[..n].copy_from_slice(&src[p..(p + n)]);
|
|
self.2 = n + p;
|
|
Ok(n)
|
|
}
|
|
|
|
fn seek(&mut self, whence: std::io::SeekFrom) -> easy::SeekResult {
|
|
use std::io::SeekFrom::{Current, End, Start};
|
|
match whence {
|
|
Start(p) => {
|
|
self.2 = p as usize;
|
|
easy::SeekResult::Ok
|
|
}
|
|
End(d) => {
|
|
let p = self.1.len() as i64;
|
|
if p + d < 0 {
|
|
easy::SeekResult::Fail
|
|
} else {
|
|
self.2 = (p + d) as usize;
|
|
easy::SeekResult::Ok
|
|
}
|
|
}
|
|
Current(d) => {
|
|
let p = self.2 as i64;
|
|
if p + d < 0 {
|
|
easy::SeekResult::Fail
|
|
} else {
|
|
self.2 = (p + d) as usize;
|
|
easy::SeekResult::Ok
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
fn data_client(file: &str) -> Result<Easy2<Collector>, ()> {
|
|
let mut client = Easy2::new(Collector(Vec::new(), Vec::new(), 0));
|
|
let url = format!(
|
|
"https://cloud.seebruecke.org/public.php/webdav/data/{}",
|
|
file
|
|
);
|
|
client.url(&url).map_err(|_| ())?;
|
|
client.username(include_str!("cloud_user.txt"))
|
|
.map_err(|_| ())?;
|
|
client.http_auth(easy::Auth::new().auto(true))
|
|
.map_err(|_| ())?;
|
|
client.ssl_cainfo_blob(include_bytes!("isrg-root-x1.pem"))
|
|
.map_err(|_| ())?;
|
|
Ok(client)
|
|
}
|
|
|
|
fn put_client(file: &str, payload: &[u8]) -> Result<Easy2<Collector>, ()> {
|
|
let mut client = data_client(&file)?;
|
|
client.put(true).map_err(|_| ())?;
|
|
client.get_mut().1.extend_from_slice(payload);
|
|
client.in_filesize(payload.len() as u64)
|
|
.map_err(|e| println!("{:?}", e))?;
|
|
client.upload(true).map_err(|e| println!("{:?}", e))?;
|
|
Ok(client)
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn pull_data(
|
|
_state: State<'_, Mutex<AppState>>,
|
|
) -> Result<String, ()> {
|
|
let mut client = data_client("")?;
|
|
client.custom_request("PROPFIND").map_err(|_| ())?;
|
|
client.perform().map_err(|_| ())?;
|
|
let content = &client.get_ref().0;
|
|
Ok(String::from_utf8_lossy(content).to_string())
|
|
}
|
|
|
|
async fn push_key(id: &u64, key: &SigningKey) -> Result<(), ()> {
|
|
let file = format!("{:016X}.key", id);
|
|
let v_key = key.verifying_key();
|
|
let client = put_client(&file, v_key.as_ref())?;
|
|
let _perf = client.perform().map_err(|e| println!("{:?}", e))?;
|
|
Ok(())
|
|
}
|
|
|
|
fn push_db(id: &u64, db: &Connection, app: tauri::AppHandle) -> Result<(), ()> {
|
|
let filename = format!("{:016X}.sqlite", id);
|
|
let path = app
|
|
.path()
|
|
.resolve(&filename, tauri::path::BaseDirectory::Temp)
|
|
.map_err(|e| println!("{:?}", e))?;
|
|
db.backup(DatabaseName::Main, &path, None)
|
|
.map_err(|e| println!("{:?}", e))?;
|
|
let buf = std::fs::read(&path).map_err(|e| println!("{:?}", e))?;
|
|
let client = put_client(&filename, buf.as_ref())?;
|
|
let _perf = client.perform().map_err(|e| println!("{:?}", e))?;
|
|
Ok(())
|
|
}
|
|
|
|
#[tauri::command]
|
|
pub async fn push_data(
|
|
app: tauri::AppHandle,
|
|
state: State<'_, Mutex<AppState>>,
|
|
) -> Result<(), ()> {
|
|
let state = state.lock().await;
|
|
push_key(&state.id, &state.key).await?;
|
|
push_db(&state.id, &state.db, app)?;
|
|
Ok(())
|
|
}
|