Implement applying (some) changes

This commit is contained in:
OMGeeky
2024-04-16 18:08:30 +02:00
parent 7f67afa229
commit 89c0123f3c
7 changed files with 164 additions and 35 deletions

View File

@@ -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;

View File

@@ -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

View 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
}
};
}
}

View File

@@ -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(())
}

View File

@@ -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);

View File

@@ -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)

View File

@@ -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![