post_archiver/importer/
file_meta.rs1use std::{collections::HashMap, fs::File, hash::Hash, path::PathBuf};
2
3use rusqlite::params;
4use serde_json::Value;
5
6use crate::{
7 error::Result,
8 manager::{PostArchiverConnection, PostArchiverManager, UpdateFileMeta, WritableFileMeta},
9 FileMetaId, Post, PostId,
10};
11
12impl<T> PostArchiverManager<T>
13where
14 T: PostArchiverConnection,
15{
16 pub fn import_file_meta<U>(
25 &self,
26 post: PostId,
27 file_meta: &UnsyncFileMeta<U>,
28 ) -> Result<FileMetaId> {
29 if let Some(id) = self.find_file_meta(post, &file_meta.filename)? {
31 self.bind(id)
33 .update(UpdateFileMeta::default().extra(file_meta.extra.clone()))?;
34 return Ok(id);
35 }
36
37 let mut ins_stmt = self.conn().prepare_cached(
39 "INSERT INTO file_metas (post, filename, mime, extra) VALUES (?, ?, ?, ?) RETURNING id",
40 )?;
41 Ok(ins_stmt.query_row(
42 params![
43 post,
44 file_meta.filename,
45 file_meta.mime,
46 serde_json::to_string(&file_meta.extra).unwrap()
47 ],
48 |row| row.get(0),
49 )?)
50 }
51
52 pub fn import_file_meta_with_content<U>(
62 &self,
63 post: PostId,
64 file_meta: &UnsyncFileMeta<U>,
65 ) -> Result<FileMetaId>
66 where
67 U: WritableFileMeta,
68 {
69 let id = self.import_file_meta(post, file_meta)?;
70
71 let path = self
72 .path
73 .join(Post::directory(post))
74 .join(&file_meta.filename);
75
76 if let Some(parent) = path.parent() {
77 std::fs::create_dir_all(parent)?;
78 }
79
80 let mut file = File::create(&path)?;
81 file_meta.data.write_to_file(&mut file)?;
82
83 Ok(id)
84 }
85
86 pub fn import_file_meta_by_rename(
101 &self,
102 post: PostId,
103 file_meta: &UnsyncFileMeta<PathBuf>,
104 ) -> Result<FileMetaId> {
105 let id = self.import_file_meta(post, file_meta)?;
106
107 let path = self
108 .path
109 .join(Post::directory(post))
110 .join(&file_meta.filename);
111
112 if let Some(parent) = path.parent() {
113 std::fs::create_dir_all(parent)?;
114 }
115
116 std::fs::rename(&file_meta.data, &path)?;
117
118 Ok(id)
119 }
120}
121
122#[derive(Debug, Clone)]
124pub struct UnsyncFileMeta<T> {
125 pub filename: String,
126 pub mime: String,
127 pub extra: HashMap<String, Value>,
128 pub data: T,
129}
130
131impl<T> Hash for UnsyncFileMeta<T> {
132 fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
133 self.filename.hash(state);
134 self.mime.hash(state);
135 }
136}
137
138impl<T> PartialEq for UnsyncFileMeta<T> {
139 fn eq(&self, other: &Self) -> bool {
140 self.filename == other.filename && self.mime == other.mime && self.extra == other.extra
141 }
142}
143
144impl<T> Eq for UnsyncFileMeta<T> {}
145
146impl<T> UnsyncFileMeta<T> {
147 pub fn new(filename: String, mime: String, data: T) -> Self {
148 Self {
149 filename,
150 mime,
151 data,
152 extra: HashMap::new(),
153 }
154 }
155
156 pub fn extra(mut self, extra: HashMap<String, Value>) -> Self {
157 self.extra = extra;
158 self
159 }
160}