use tokio::runtime::Runtime;
use std::sync::{Arc};
use std::thread::JoinHandle;
+use std::time::SystemTime;
use tokio::fs;
use tokio::sync::{broadcast, mpsc};
use tokio::sync::broadcast::error::SendError;
use migration::prelude::Utc;
use crate::lockmanager::LockManager;
use crate::note::{create_nodename, randomize_nodename};
-use crate::storage::{get_collection_storage_path, get_file_content, get_note_storage_path, write_file, write_tmp_file};
+use crate::storage::{get_collection_storage_path, get_file_content, get_last_modified, get_note_storage_path, write_file, write_tmp_file};
pub struct Backend {
rt: Arc<Runtime>,
}
pub fn get_note_content<F>(&self, note_id: i32, callback: F)
- where F: FnOnce(Result<Option<notecontent::Model>, DbErr>) + Send + 'static {
+ where F: FnOnce(Result<Option<NoteContentRet>, DbErr>) + Send + 'static {
let backend = self.backend.clone();
let cmd = Box::pin(async move {
// check if the note content is stored in the filesystem or database
let content = fs::read_to_string(path).await;
match content {
Ok(content) => {
- let model = notecontent::Model {
- id: 0,
- note_id: 0,
- content: content,
+ let lastmodified = get_last_modified(path).await;
+ let model = NoteContentRet {
+ content_id: 0,
+ text: content,
+ local_path: Some(PathBuf::from(path)),
+ local_lastmodified: lastmodified
};
callback(Ok(Some(model)));
},
let result = NoteContent::find()
.filter(notecontent::Column::NoteId.eq(note_id))
.order_by_id_asc().one(&backend.db).await;
- callback(result);
+ match result {
+ Ok(Some(model)) => {
+ let ret = NoteContentRet {
+ content_id: model.id,
+ text: model.content,
+ local_path: None,
+ local_lastmodified: None
+ };
+ callback(Ok(Some(ret)));
+ },
+ Ok(None) => {
+ callback(Ok(None));
+ }
+ Err(e) => {
+ callback(Err(e));
+ }
+ }
}
});
let _ = self.tx.send(cmd);
}
+pub struct NoteContentRet {
+ pub content_id: i32,
+ pub text: String,
+ pub local_path: Option<PathBuf>,
+ pub local_lastmodified: Option<SystemTime>
+}
+
pub enum SaveNoteResult {
Ok((entity::note::Model, i32)),
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-
+use std::fs::metadata;
use std::io::ErrorKind;
use std::path::Path;
+use std::time::SystemTime;
use sea_orm::entity::prelude::*;
use sea_orm::{ColumnTrait, DatabaseConnection, DbErr, EntityTrait, QuerySelect, RelationTrait};
use tokio::fs;
.one(db).await
}
+pub async fn get_last_modified(path: &Path) -> Option<SystemTime> {
+ let stat_result = tokio::fs::metadata(path).await;
+ if let Ok(stat) = stat_result {
+ if let Ok(last_modified) = stat.modified() {
+ return Some(last_modified)
+ }
+ }
+ return None
+}
+
pub async fn write_file(path: &Path, content: &str) -> std::io::Result<()> {
let mut file = match File::create(path).await {
Ok(f) => f,
* ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
* POSSIBILITY OF SUCH DAMAGE.
*/
-
+use std::path::PathBuf;
use std::rc::Rc;
use std::sync::atomic::{AtomicU64, Ordering};
+use std::time::SystemTime;
use sea_orm::{NotSet, Set};
use sea_orm::sea_query::prelude::Utc;
-use backend::backend::{BackendHandle, BroadcastMessage, NoteId, NoteTitleUpdate, SaveNoteResult};
+use backend::backend::{BackendHandle, BroadcastMessage, NoteContentRet, NoteId, NoteTitleUpdate, SaveNoteResult};
use backend::lockmanager::NoteLock;
use entity::note::NoteType;
use ui_rs::{action, doc_cast, ui_actions, UiModel};
modified: bool,
+ pub local_path: Option<PathBuf>,
+ pub local_lastmodified: Option<SystemTime>,
+
#[bind("note_type")]
pub note_type: UiInteger,
title_start: -1,
title_end: -1,
modified: false,
+ local_path: None,
+ local_lastmodified: None,
note_type: Default::default(),
text: Default::default(),
self.note_type.set(NoteTypeTabView::TextArea as i64);
}
- pub fn init_content(&mut self, content: &entity::notecontent::Model) {
- self.content_id = content.id;
- self.text.set(content.content.as_str());
- self.update_title(content.content.as_str(), false);
+ pub fn init_content(&mut self, content: NoteContentRet) {
+ self.content_id = content.content_id;
+ self.text.set(content.text.as_str());
+ self.update_title(content.text.as_str(), false);
+ self.local_path = content.local_path;
+ self.local_lastmodified = content.local_lastmodified;
}
pub fn load_content(&mut self) {
match result {
Ok(content) => {
if let Some(content) = content {
- note.init_content(&content);
+ note.init_content(content);
} else {
println!("note {}: no content", note_id);
}
unsafe {
let stmt = dav_parse_statement(cxstr);
+ if stmt.is_null() {
+ return Err(DavError::QlError("dav_parse_statement returned NULL".to_string()));
+ }
let errrorcode = dav_sql_statement_get_errorcode(stmt);
let result = if errrorcode != 0 {
let errrorcode = dav_sql_statement_get_errorcode(stmt);
}
}
+ /// compiles the query to
+ ///
+ /// select {properties} from {from} with depth {depth} where {filter}
fn compile(&self) -> String {
let properties = self
.properties