msgmerge/src/types/project.rs
2024-12-08 09:22:37 +01:00

93 lines
2.6 KiB
Rust

use std::{collections::HashSet, io::{self, Cursor, Read, Write}, path::PathBuf, process::exit};
use serde::{Deserialize, Serialize};
use tokio::{fs::File, io::{AsyncReadExt, AsyncWriteExt, BufWriter}};
use zip::{write::FileOptions, ZipArchive, ZipWriter};
use super::{message::Message, user::User};
#[derive(Serialize, Deserialize, Debug, Clone)]
pub struct Project {
pub users: Vec<User>,
pub messages: Vec<Message>,
pub timestamps: HashSet<usize>,
pub media_index: usize,
}
pub struct ProjectRaw {
pub project: Project,
pub zip: ZipArchive<Cursor<Vec<u8>>>
}
impl Project {
pub async fn load(pathstr: String) -> io::Result<ProjectRaw> {
let path = PathBuf::from(pathstr);
if !path.exists() {
return Err(io::Error::new(io::ErrorKind::NotFound, "File does not exist!"));
}
let mut file = File::open(path).await?;
let mut buffer = Vec::new();
file.read_to_end(&mut buffer).await?;
let cursor = Cursor::new(buffer);
let archive = ZipArchive::new(cursor)?;
let mut copy_archive = archive.clone();
let mut project_file = copy_archive.by_name("project.json").unwrap_or_else(|_| {
eprintln!("Invalid project format!");
exit(1);
});
let mut json_content = String::new();
project_file.read_to_string(&mut json_content)?;
let data: Project = serde_json::from_str(&json_content)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
Ok(ProjectRaw {
project: data,
zip: archive
})
}
pub async fn save(&self, file_path: String) -> io::Result<()> {
let contents = serde_json::to_string(&self)
.map_err(|e| io::Error::new(io::ErrorKind::InvalidData, e))?;
let file = File::create(file_path).await?;
let mut writer = BufWriter::new(file);
let mut buffer = Cursor::new(Vec::new());
{
let mut zip = ZipWriter::new(&mut buffer);
let options = FileOptions::default().unix_permissions(0o755);
zip.add_directory("media/", options)?;
zip.start_file("project.json", options)?;
zip.write_all(contents.as_bytes())?;
zip.finish()?;
}
writer.write_all(&buffer.into_inner()).await?;
writer.flush().await?;
Ok(())
}
pub fn push_msg(&mut self, message: &Message) -> bool {
if self.timestamps.contains(&message.timestamp) {
return false;
}
self.timestamps.insert(message.timestamp);
self.messages.push(message.clone());
return true;
}
}