mirror of
https://github.com/OMGeeky/gdriver2.git
synced 2025-12-26 16:07:58 +01:00
Implement applying (some) changes
This commit is contained in:
@@ -1,10 +1,10 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::drive::google_drive::GoogleDrive;
|
||||
use crate::apply_change;
|
||||
use crate::drive::google_drive::{FileData, GoogleDrive};
|
||||
use crate::path_resolver::PathResolver;
|
||||
use chrono::{DateTime, Utc};
|
||||
use gdriver_common::drive_structure::meta::{write_metadata_file, write_metadata_file_to_path};
|
||||
use gdriver_common::ipc::gdriver_service::ReadDirResult;
|
||||
use gdriver_common::drive_structure::meta::{read_metadata_by_id, write_metadata_file, Metadata};
|
||||
use google_drive3::api::Change;
|
||||
use std::collections::HashMap;
|
||||
|
||||
use crate::prelude::*;
|
||||
mod google_drive;
|
||||
@@ -47,16 +47,11 @@ impl Drive {
|
||||
|
||||
self.path_resolver.reset()?;
|
||||
for file in files {
|
||||
for parent in file.parents.clone() {
|
||||
let relation_data = ReadDirResult {
|
||||
id: file.id.clone().into(),
|
||||
name: file.name.clone(),
|
||||
kind: file.kind.clone(),
|
||||
};
|
||||
self.path_resolver
|
||||
.add_relationship(parent.into(), relation_data)?;
|
||||
}
|
||||
let parents = file.parents.clone();
|
||||
let meta = file.into_meta()?;
|
||||
self.path_resolver
|
||||
.add_relationships_for_meta(parents, &meta)?;
|
||||
|
||||
write_metadata_file(&meta)?;
|
||||
}
|
||||
} else {
|
||||
@@ -83,11 +78,81 @@ impl Drive {
|
||||
return Ok(());
|
||||
}
|
||||
for change in changes {
|
||||
dbg!(&change);
|
||||
// dbg!(&change);
|
||||
self.process_change(change)?;
|
||||
}
|
||||
Err("Not implemented".into())
|
||||
Ok(()) //TODO: implement this
|
||||
}
|
||||
#[instrument(skip(self, change))]
|
||||
fn process_change(&mut self, change: Change) -> Result<()> {
|
||||
let file_data =
|
||||
FileData::convert_from_api_file(change.file.ok_or("change had no file data")?);
|
||||
let parents = file_data
|
||||
.parents
|
||||
.clone()
|
||||
.into_iter()
|
||||
.map(Into::into)
|
||||
.collect();
|
||||
let new_meta = file_data.into_meta()?;
|
||||
info!("Processing change: {:?}", new_meta);
|
||||
let id: DriveId = change.file_id.clone().ok_or("No file id in change")?.into();
|
||||
let original_meta = read_metadata_by_id(&id);
|
||||
if original_meta.is_err() {
|
||||
info!("File not found so it has to be new: {:?}", id);
|
||||
self.path_resolver
|
||||
.add_relationships_for_meta(parents, &new_meta)?;
|
||||
write_metadata_file(&new_meta)?;
|
||||
return Ok(());
|
||||
}
|
||||
if change.removed.unwrap_or_default() {
|
||||
info!("File removed: {:?}", id);
|
||||
todo!("Do something when a file is removed from drive");
|
||||
return Ok(());
|
||||
}
|
||||
let mut original_meta = original_meta?;
|
||||
self.process_parents_changes(parents, &id, &new_meta)?;
|
||||
Self::process_meta_changes(new_meta, &mut original_meta)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
// Ok(()) //TODO: implement this
|
||||
fn process_meta_changes(new_meta: Metadata, original_meta: &mut Metadata) -> Result<()> {
|
||||
let mut has_meta_changed = false;
|
||||
|
||||
apply_change!(original_meta, new_meta, last_modified, has_meta_changed, where: {
|
||||
original_meta.last_modified < new_meta.last_modified
|
||||
});
|
||||
apply_change!(original_meta, new_meta, last_accessed, has_meta_changed, where: {
|
||||
original_meta.last_accessed < new_meta.last_accessed
|
||||
});
|
||||
apply_change!(original_meta, new_meta, last_metadata_changed, has_meta_changed, where: {
|
||||
original_meta.last_metadata_changed < new_meta.last_metadata_changed
|
||||
});
|
||||
apply_change!(original_meta, new_meta, name, has_meta_changed);
|
||||
apply_change!(original_meta, new_meta, size, has_meta_changed);
|
||||
apply_change!(original_meta, new_meta, permissions, has_meta_changed);
|
||||
apply_change!(original_meta, new_meta, extra_attributes, has_meta_changed);
|
||||
info!("Has changed: {}", has_meta_changed);
|
||||
if has_meta_changed {
|
||||
write_metadata_file(&original_meta)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn process_parents_changes(
|
||||
&mut self,
|
||||
parents: Vec<DriveId>,
|
||||
id: &DriveId,
|
||||
new_meta: &Metadata,
|
||||
) -> Result<()> {
|
||||
let original_parents = self.path_resolver.get_parents(&id)?.clone();
|
||||
if original_parents != parents {
|
||||
info!("Parents changed: {:?}", id);
|
||||
self.path_resolver
|
||||
.remove_relationships_for_id(&original_parents, &new_meta.id)?;
|
||||
self.path_resolver
|
||||
.add_relationships_for_meta(parents, &new_meta)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
@@ -100,3 +165,4 @@ pub enum TrackingState {
|
||||
Untracked,
|
||||
Tracked(DateTime<Utc>),
|
||||
}
|
||||
mod macros;
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
use const_format::formatcp;
|
||||
use gdriver_common::drive_structure::meta::{FileKind, FileState, Metadata};
|
||||
use gdriver_common::drive_structure::meta::{FileKind, FileState, Metadata, DEFAULT_PERMISSIONS};
|
||||
use gdriver_common::time_utils::datetime_to_timestamp;
|
||||
use gdriver_common::{ipc::gdriver_service::SETTINGS, prelude::*};
|
||||
use google_drive3::api::File;
|
||||
@@ -38,19 +38,20 @@ impl FileData {
|
||||
Ok(Metadata {
|
||||
id: self.id.into(),
|
||||
kind: self.kind,
|
||||
name: self.name,
|
||||
size: self.size.unwrap_or_default() as u64,
|
||||
last_accessed: datetime_to_timestamp(self.viewed_by_me_time.unwrap_or_default())?,
|
||||
last_modified,
|
||||
extra_attributes: Default::default(),
|
||||
state: FileState::MetadataOnly,
|
||||
permissions: 0, //TODO: parse permissions
|
||||
permissions: DEFAULT_PERMISSIONS, //TODO: parse permissions
|
||||
last_metadata_changed: last_modified,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl FileData {
|
||||
fn convert_from_api_file(file: File) -> Self {
|
||||
pub(crate) fn convert_from_api_file(file: File) -> Self {
|
||||
let kind = file.kind.unwrap_or_default();
|
||||
info!(
|
||||
"Converting file with id {:?} with parent: {:?}",
|
||||
@@ -221,7 +222,7 @@ impl GoogleDrive {
|
||||
Err("Did not get expected result on ping".into())
|
||||
}
|
||||
//region changes
|
||||
#[instrument]
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_changes(&mut self) -> Result<Vec<Change>> {
|
||||
info!("Getting changes");
|
||||
let mut page_token = Some(self.get_change_start_token().await?);
|
||||
@@ -260,6 +261,9 @@ impl GoogleDrive {
|
||||
}
|
||||
|
||||
async fn set_change_start_token(&mut self, token: String) -> Result<()> {
|
||||
if self.changes_start_page_token.as_ref() == Some(&token) {
|
||||
return Ok(());
|
||||
}
|
||||
info!("Setting start page token: {}", token);
|
||||
fs::write(SETTINGS.get_changes_file_path(), token.clone()).await?;
|
||||
self.changes_start_page_token = Some(token);
|
||||
@@ -297,7 +301,8 @@ impl GoogleDrive {
|
||||
pub async fn get_local_change_start_token(&mut self) -> Option<String> {
|
||||
self.changes_start_page_token = fs::read_to_string(SETTINGS.get_changes_file_path())
|
||||
.await
|
||||
.ok();
|
||||
.ok()
|
||||
.map(|s| s.trim().to_string());
|
||||
self.changes_start_page_token.clone()
|
||||
}
|
||||
async fn update_change_start_token_from_api(&mut self) -> Result<()> {
|
||||
@@ -342,7 +347,7 @@ impl GoogleDrive {
|
||||
info!("replacing {id} with {}", ROOT_ID.as_ref());
|
||||
*id = ROOT_ID.0.clone();
|
||||
} else {
|
||||
info!("{id} did not match {}", self.root_alt_id);
|
||||
// info!("{id} did not match {}", self.root_alt_id);
|
||||
}
|
||||
}
|
||||
//endregion
|
||||
|
||||
27
gdriver-backend/src/drive/macros.rs
Normal file
27
gdriver-backend/src/drive/macros.rs
Normal file
@@ -0,0 +1,27 @@
|
||||
mod apply_change {
|
||||
#[macro_export]
|
||||
macro_rules! apply_change {
|
||||
($meta:ident, $changed_meta:ident, $field:ident, $has_changed:expr) => {
|
||||
apply_change!($meta, $changed_meta, $field, $has_changed, where:true);
|
||||
};
|
||||
($meta:ident, $changed_meta:ident, $field:ident, $has_changed:expr, where:$extra_condition:expr) => {
|
||||
apply_change!(
|
||||
$meta,
|
||||
$changed_meta,
|
||||
$field,
|
||||
$has_changed,
|
||||
$extra_condition,
|
||||
{
|
||||
::tracing::info!("{} changed from '{:?}' to '{:?}'", stringify!($field), $meta.$field, $changed_meta.$field);
|
||||
$has_changed |= true;
|
||||
$meta.$field = $changed_meta.$field.clone();
|
||||
}
|
||||
);
|
||||
};
|
||||
($meta:ident, $changed_meta:ident, $field:ident, $has_changed:expr, $extra_condition:expr, $action_on_difference:expr) => {
|
||||
if $meta.$field != $changed_meta.$field && $extra_condition {
|
||||
$action_on_difference
|
||||
}
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
use crate::drive::Drive;
|
||||
use crate::prelude::*;
|
||||
use gdriver_common::drive_structure::meta::Metadata;
|
||||
use gdriver_common::ipc::gdriver_service::{ReadDirResult, SETTINGS};
|
||||
use gdriver_common::path_resolve_error::PathResolveError;
|
||||
use gdriver_common::prelude::*;
|
||||
@@ -20,6 +20,9 @@ impl PathResolver {
|
||||
pub(crate) fn get_children(&self, id: &DriveId) -> Result<&Vec<ReadDirResult>> {
|
||||
self.children.get(id).ok_or("Item with ID not found".into())
|
||||
}
|
||||
pub(crate) fn get_parents(&self, id: &DriveId) -> Result<&Vec<DriveId>> {
|
||||
self.parents.get(id).ok_or("Item with ID not found".into())
|
||||
}
|
||||
}
|
||||
|
||||
impl PathResolver {
|
||||
@@ -61,6 +64,21 @@ impl PathResolver {
|
||||
self.write_to_disk()?;
|
||||
Ok(())
|
||||
}
|
||||
pub(crate) fn add_relationships_for_meta(
|
||||
&mut self,
|
||||
parents: Vec<impl Into<DriveId>>,
|
||||
meta: &Metadata,
|
||||
) -> Result<()> {
|
||||
let entry = ReadDirResult {
|
||||
id: meta.id.clone().into(),
|
||||
name: meta.name.to_string(),
|
||||
kind: meta.kind.clone(),
|
||||
};
|
||||
for parent in parents {
|
||||
self.add_relationship(parent.into(), entry.clone())?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Add a relationship between a parent and a child and write to disk
|
||||
pub(crate) fn add_relationship(&mut self, parent: DriveId, entry: ReadDirResult) -> Result<()> {
|
||||
match self.parents.get_mut(&entry.id) {
|
||||
@@ -78,18 +96,23 @@ impl PathResolver {
|
||||
self.write_to_disk()?;
|
||||
Ok(())
|
||||
}
|
||||
/// Remove the relationship between a parent and a child and write to disk
|
||||
pub(crate) fn remove_relationship(
|
||||
|
||||
pub(crate) fn remove_relationships_for_id(
|
||||
&mut self,
|
||||
parent: DriveId,
|
||||
entry: ReadDirResult,
|
||||
parents: &Vec<DriveId>,
|
||||
id: &DriveId,
|
||||
) -> Result<()> {
|
||||
self.parents
|
||||
.get_mut(&entry.id)
|
||||
.map(|x| x.retain(|e| e != &parent));
|
||||
for parent in parents {
|
||||
self.remove_relationship(parent, id)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
/// Remove the relationship between a parent and a child and write to disk
|
||||
pub(crate) fn remove_relationship(&mut self, parent: &DriveId, id: &DriveId) -> Result<()> {
|
||||
self.parents.get_mut(id).map(|x| x.retain(|e| e != parent));
|
||||
self.children
|
||||
.get_mut(&parent)
|
||||
.map(|x| x.retain(|e| e.id != entry.id));
|
||||
.get_mut(parent)
|
||||
.map(|x| x.retain(|e| e.id != *id));
|
||||
self.write_to_disk()?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -248,6 +248,7 @@ pub async fn start() -> Result<()> {
|
||||
}
|
||||
}
|
||||
drive.get_all_file_metas().await?;
|
||||
drive.update().await?;
|
||||
let drive = Arc::new(Mutex::new(drive));
|
||||
|
||||
let server_addr = (config.ip, config.port);
|
||||
|
||||
@@ -13,6 +13,7 @@ pub type TIMESTAMP = (i64, u32);
|
||||
pub struct Metadata {
|
||||
pub id: DriveId,
|
||||
pub state: FileState,
|
||||
pub name: String,
|
||||
pub size: u64,
|
||||
pub last_accessed: TIMESTAMP,
|
||||
pub last_modified: TIMESTAMP,
|
||||
@@ -22,13 +23,15 @@ pub struct Metadata {
|
||||
pub extra_attributes: BTreeMap<Vec<u8>, Vec<u8>>,
|
||||
}
|
||||
|
||||
const PERMISSIONS_RWXRWXRWX: u16 = 0b111_111_111; // 511;
|
||||
pub const PERMISSIONS_RWXRWXRWX: u16 = 0o777;
|
||||
pub const DEFAULT_PERMISSIONS: u16 = PERMISSIONS_RWXRWXRWX;
|
||||
|
||||
impl Metadata {
|
||||
pub fn root() -> Self {
|
||||
Self {
|
||||
id: ROOT_ID.clone(),
|
||||
state: FileState::Root,
|
||||
name: "".to_string(),
|
||||
size: 0,
|
||||
last_accessed: time_now(),
|
||||
last_modified: time_now(),
|
||||
@@ -45,6 +48,10 @@ pub fn read_metadata_file(path: &Path) -> Result<Metadata> {
|
||||
let reader = File::open(path)?;
|
||||
Ok(serde_json::from_reader(reader)?)
|
||||
}
|
||||
pub fn read_metadata_by_id(id: &DriveId) -> Result<Metadata> {
|
||||
let path = SETTINGS.get_metadata_file_path(id);
|
||||
read_metadata_file(&path)
|
||||
}
|
||||
pub fn write_metadata_file(metadata: &Metadata) -> Result<()> {
|
||||
let path = SETTINGS.get_metadata_file_path(&metadata.id);
|
||||
write_metadata_file_to_path(&path, metadata)
|
||||
|
||||
@@ -11,7 +11,7 @@ pub struct GDriverSettings {
|
||||
data_path: PathBuf,
|
||||
}
|
||||
impl GDriverSettings {
|
||||
#[instrument]
|
||||
#[instrument(skip(self))]
|
||||
pub fn initialize_dirs(&self) -> Result<()> {
|
||||
info!("Initializing dirs");
|
||||
let dirs = vec![
|
||||
|
||||
Reference in New Issue
Block a user