mirror of
https://github.com/OMGeeky/gdriver2.git
synced 2025-12-27 06:29:37 +01:00
start implementing getting meta for structure
This commit is contained in:
@@ -10,6 +10,7 @@ pub struct Drive {
|
||||
tracked_files: HashMap<DriveId, DateTime<Utc>>,
|
||||
pub path_resolver: PathResolver,
|
||||
google_drive: GoogleDrive,
|
||||
pub offline_mode: bool,
|
||||
}
|
||||
impl Drive {
|
||||
#[instrument()]
|
||||
@@ -18,8 +19,12 @@ impl Drive {
|
||||
tracked_files: HashMap::new(),
|
||||
path_resolver: PathResolver::new(),
|
||||
google_drive: GoogleDrive::new().await?,
|
||||
offline_mode: false,
|
||||
})
|
||||
}
|
||||
pub fn set_offline_mode(&mut self, offline_mode: bool) {
|
||||
self.offline_mode = offline_mode;
|
||||
}
|
||||
#[instrument(skip(self))]
|
||||
pub fn get_file_tracking_state(&self, id: &DriveId) -> TrackingState {
|
||||
let file = self.tracked_files.get(id);
|
||||
@@ -28,20 +33,46 @@ impl Drive {
|
||||
None => TrackingState::Untracked,
|
||||
}
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn get_all_file_metas(&mut self) -> Result<()> {
|
||||
if self.offline_mode {
|
||||
info!("Offline mode, skipping get_all_file_metas");
|
||||
//TODO: load from local storage
|
||||
return Ok(());
|
||||
}
|
||||
let has_existing_token = self.google_drive.has_local_change_token().await;
|
||||
if !has_existing_token {
|
||||
//only get start token & data if we shouldn't have it
|
||||
self.google_drive.get_change_start_token().await?;
|
||||
let x = self.google_drive.get_all_file_metas().await?;
|
||||
dbg!(&x);
|
||||
} else {
|
||||
//TODO: get file metas from local storage
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn update(&mut self) -> Result<()> {
|
||||
if self.offline_mode {
|
||||
info!("Offline mode, skipping update");
|
||||
return Ok(());
|
||||
}
|
||||
let changes = self.google_drive.get_changes().await?;
|
||||
if changes.is_empty() {
|
||||
info!("No changes");
|
||||
return Ok(());
|
||||
}
|
||||
for change in changes {
|
||||
dbg!(change);
|
||||
dbg!(&change);
|
||||
}
|
||||
Err("Not implemented".into())
|
||||
|
||||
// Ok(()) //TODO: implement this
|
||||
}
|
||||
|
||||
#[instrument(skip(self))]
|
||||
pub async fn ping(&self) -> Result<()> {
|
||||
self.google_drive.ping().await
|
||||
|
||||
@@ -1,19 +1,55 @@
|
||||
use crate::prelude::*;
|
||||
use chrono::{DateTime, Utc};
|
||||
use const_format::formatcp;
|
||||
use gdriver_common::{ipc::gdriver_service::SETTINGS, prelude::*};
|
||||
use google_drive3::api::File;
|
||||
use google_drive3::{
|
||||
api::{Change, Scope},
|
||||
hyper::{client::HttpConnector, Client},
|
||||
hyper_rustls::{self, HttpsConnector},
|
||||
oauth2, DriveHub,
|
||||
};
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::any::type_name;
|
||||
use std::fmt::{Debug, Display, Formatter};
|
||||
use tokio::fs;
|
||||
|
||||
const FIELDS_FILE: &'static str = "id, name, size, mimeType, kind, md5Checksum, parents, trashed, createdTime, modifiedTime, viewedByMeTime";
|
||||
#[derive(Ord, PartialOrd, Eq, PartialEq, Debug, Serialize, Deserialize, Clone, Hash)]
|
||||
pub struct FileData {
|
||||
pub id: String,
|
||||
pub name: String,
|
||||
pub size: Option<i64>,
|
||||
pub mime_type: String,
|
||||
pub kind: String,
|
||||
pub md5_checksum: Option<String>,
|
||||
pub parents: Option<Vec<String>>,
|
||||
pub trashed: Option<bool>,
|
||||
pub created_time: Option<DateTime<Utc>>,
|
||||
pub modified_time: Option<DateTime<Utc>>,
|
||||
pub viewed_by_me_time: Option<DateTime<Utc>>,
|
||||
}
|
||||
|
||||
impl FileData {
|
||||
fn convert_from_api_file(file: File) -> Self {
|
||||
Self {
|
||||
id: file.id.unwrap_or_default(),
|
||||
name: file.name.unwrap_or_default(),
|
||||
size: file.size,
|
||||
mime_type: file.mime_type.unwrap_or_default(),
|
||||
kind: file.kind.unwrap_or_default(),
|
||||
md5_checksum: file.md5_checksum,
|
||||
parents: file.parents,
|
||||
trashed: file.trashed,
|
||||
created_time: file.created_time,
|
||||
modified_time: file.modified_time,
|
||||
viewed_by_me_time: file.viewed_by_me_time,
|
||||
}
|
||||
}
|
||||
}
|
||||
const FIELDS_CHANGE: &str = formatcp!(
|
||||
"nextPageToken, newStartPageToken, changes(removed, fileId, changeType, file({FIELDS_FILE}))"
|
||||
"nextPageToken, newStartPageToken, changes(removed, fileId, changeType, file({}))",
|
||||
FIELDS_FILE
|
||||
);
|
||||
#[derive(Clone)]
|
||||
pub struct GoogleDrive {
|
||||
@@ -21,6 +57,43 @@ pub struct GoogleDrive {
|
||||
changes_start_page_token: Option<String>,
|
||||
}
|
||||
|
||||
impl GoogleDrive {
|
||||
#[instrument]
|
||||
pub(crate) async fn get_all_file_metas(&self) -> Result<Vec<FileData>> {
|
||||
let mut page_token: Option<String> = None;
|
||||
let mut files = Vec::new();
|
||||
loop {
|
||||
let (response, body) = self
|
||||
.hub
|
||||
.files()
|
||||
.list()
|
||||
.supports_all_drives(false)
|
||||
.spaces("drive")
|
||||
.page_token(&page_token.unwrap_or_default())
|
||||
.param("fields", &format!("nextPageToken, files({})", FIELDS_FILE))
|
||||
.doit()
|
||||
.await?;
|
||||
page_token = body.next_page_token;
|
||||
if response.status().is_success() {
|
||||
files.extend(
|
||||
body.files
|
||||
.unwrap_or_default()
|
||||
.into_iter()
|
||||
.map(FileData::convert_from_api_file),
|
||||
);
|
||||
} else {
|
||||
error!("Could not get files: {:?}", response);
|
||||
return Err("Could not get files".into());
|
||||
}
|
||||
if page_token.is_none() {
|
||||
info!("No more pages");
|
||||
break;
|
||||
}
|
||||
}
|
||||
Ok(files)
|
||||
}
|
||||
}
|
||||
|
||||
impl GoogleDrive {
|
||||
#[instrument]
|
||||
pub(crate) async fn new() -> Result<Self> {
|
||||
@@ -82,7 +155,7 @@ impl GoogleDrive {
|
||||
#[instrument]
|
||||
pub async fn get_changes(&mut self) -> Result<Vec<Change>> {
|
||||
info!("Getting changes");
|
||||
let mut page_token = Some(self.change_start_token().await?);
|
||||
let mut page_token = Some(self.get_change_start_token().await?);
|
||||
let mut changes = Vec::new();
|
||||
while let Some(current_page_token) = page_token {
|
||||
info!("Getting changes with page token: {}", current_page_token);
|
||||
@@ -100,7 +173,7 @@ impl GoogleDrive {
|
||||
.doit()
|
||||
.await?;
|
||||
if let Some(token) = body.new_start_page_token {
|
||||
self.changes_start_page_token = Some(token);
|
||||
self.set_change_start_token(token).await?;
|
||||
}
|
||||
if response.status().is_success() {
|
||||
changes.extend(body.changes.unwrap_or_default());
|
||||
@@ -113,19 +186,21 @@ impl GoogleDrive {
|
||||
trace!("Got {} changes", changes.len());
|
||||
Ok(changes)
|
||||
}
|
||||
async fn set_change_start_token(&mut self, token: String) -> Result<()> {
|
||||
info!("Setting start page token: {}", token);
|
||||
fs::write(SETTINGS.get_changes_file_path(), token.clone()).await?;
|
||||
self.changes_start_page_token = Some(token);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn change_start_token(&mut self) -> Result<String> {
|
||||
pub async fn get_change_start_token(&mut self) -> Result<String> {
|
||||
Ok(match &self.changes_start_page_token {
|
||||
None => {
|
||||
info!("Getting start page token");
|
||||
let token = fs::read_to_string(SETTINGS.get_changes_file_path())
|
||||
.await
|
||||
.unwrap_or_default();
|
||||
self.changes_start_page_token = if !token.is_empty() {
|
||||
Some(token)
|
||||
} else {
|
||||
Some(self.get_changes_start_token_from_api().await?)
|
||||
};
|
||||
let has_local_token = self.has_local_change_token().await;
|
||||
if !has_local_token {
|
||||
self.update_change_start_token_from_api().await?;
|
||||
}
|
||||
info!("Got start page token: {:?}", self.changes_start_page_token);
|
||||
self.changes_start_page_token
|
||||
.clone()
|
||||
@@ -137,7 +212,22 @@ impl GoogleDrive {
|
||||
}
|
||||
})
|
||||
}
|
||||
async fn get_changes_start_token_from_api(&self) -> Result<String> {
|
||||
|
||||
pub(crate) async fn has_local_change_token(&mut self) -> bool {
|
||||
!self
|
||||
.get_local_change_start_token()
|
||||
.await
|
||||
.unwrap_or_default()
|
||||
.is_empty()
|
||||
}
|
||||
|
||||
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();
|
||||
self.changes_start_page_token.clone()
|
||||
}
|
||||
async fn update_change_start_token_from_api(&mut self) -> Result<()> {
|
||||
info!("Getting start page token from API");
|
||||
let (response, body) = self
|
||||
.hub
|
||||
@@ -147,8 +237,9 @@ impl GoogleDrive {
|
||||
.doit()
|
||||
.await?;
|
||||
if response.status().is_success() {
|
||||
let start_page_token = body.start_page_token.unwrap_or_default();
|
||||
Ok(start_page_token)
|
||||
let token = body.start_page_token.clone().unwrap_or_default();
|
||||
self.set_change_start_token(token).await?;
|
||||
Ok(())
|
||||
} else {
|
||||
Err("Could not get start page token".into())
|
||||
}
|
||||
|
||||
@@ -1,14 +1,16 @@
|
||||
use crate::drive::Drive;
|
||||
use crate::prelude::*;
|
||||
use gdriver_common::ipc::gdriver_service::ReadDirResult;
|
||||
use gdriver_common::path_resolve_error::PathResolveError;
|
||||
use gdriver_common::prelude::*;
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::collections::HashMap;
|
||||
use std::path::Path;
|
||||
|
||||
#[derive(Eq, PartialEq, Debug, Clone)]
|
||||
pub struct PathResolver {
|
||||
/// A map of children to their parents
|
||||
parents: HashMap<DriveId, Vec<DriveId>>,
|
||||
/// A map of parents to their children with id, name and type (folder/file/symlink)
|
||||
children: HashMap<DriveId, Vec<ReadDirResult>>,
|
||||
}
|
||||
|
||||
@@ -19,20 +21,22 @@ impl PathResolver {
|
||||
children: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub async fn get_id_from_path(&mut self, path: &Path, drive: &Drive) -> Result<DriveId> {
|
||||
pub async fn get_id_from_path(
|
||||
&mut self,
|
||||
path: &Path,
|
||||
) -> StdResult<Option<DriveId>, PathResolveError> {
|
||||
let segments: Vec<_> = path
|
||||
.to_str()
|
||||
.ok_or(PathResolveError::InvalidPath)?
|
||||
.split('/')
|
||||
.collect();
|
||||
let mut current = ROOT_ID.clone();
|
||||
self.update_from_drive(drive).await?;
|
||||
for segment in segments {
|
||||
current = self
|
||||
.get_id_from_parent_and_name(segment, ¤t)
|
||||
.ok_or("path-segment not found")?;
|
||||
current = self.get_id_from_parent_and_name(segment, ¤t).ok_or(
|
||||
PathResolveError::Other("path-segment not found".to_string()),
|
||||
)?;
|
||||
}
|
||||
return Ok(current);
|
||||
return Ok(Some(current));
|
||||
}
|
||||
pub fn get_id_from_parent_and_name(&self, name: &str, parent: &DriveId) -> Option<DriveId> {
|
||||
if let Some(children) = self.children.get(parent) {
|
||||
@@ -46,16 +50,28 @@ impl PathResolver {
|
||||
async fn update_from_drive(&mut self, drive: &Drive) -> Result<()> {
|
||||
todo!()
|
||||
}
|
||||
/// Add a relationship between a parent and a child
|
||||
pub(crate) fn add_relationship(&mut self, parent: DriveId, entry: ReadDirResult) {
|
||||
todo!()
|
||||
match self.parents.get_mut(&entry.id) {
|
||||
Some(x) => x.push(parent.clone()),
|
||||
None => {
|
||||
self.parents.insert(entry.id.clone(), vec![parent.clone()]);
|
||||
}
|
||||
};
|
||||
match self.children.get_mut(&parent) {
|
||||
Some(x) => x.push(entry.clone()),
|
||||
None => {
|
||||
self.children.insert(parent.clone(), vec![entry.clone()]);
|
||||
}
|
||||
}
|
||||
}
|
||||
/// Remove the relationship between a parent and a child
|
||||
pub(crate) fn remove_relationship(&mut self, parent: DriveId, entry: ReadDirResult) {
|
||||
todo!()
|
||||
self.parents
|
||||
.get_mut(&entry.id)
|
||||
.map(|x| x.retain(|e| e != &parent));
|
||||
self.children
|
||||
.get_mut(&parent)
|
||||
.map(|x| x.retain(|e| e.id != entry.id));
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum PathResolveError {
|
||||
#[error("The path provided was invalid")]
|
||||
InvalidPath,
|
||||
}
|
||||
|
||||
@@ -16,9 +16,14 @@ struct GdriverServer {
|
||||
drive: Arc<Mutex<Drive>>,
|
||||
}
|
||||
impl GDriverService for GdriverServer {
|
||||
// async fn get_settings(self, context: Context) -> StdResult<GDriverSettings, GetSettingsError> {
|
||||
// todo!()
|
||||
// }
|
||||
async fn set_offline_mode(
|
||||
self,
|
||||
_context: Context,
|
||||
offline_mode: bool,
|
||||
) -> StdResult<(), GDriverServiceError> {
|
||||
self.drive.lock().await.set_offline_mode(offline_mode);
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn get_file_by_name(
|
||||
self,
|
||||
@@ -42,7 +47,12 @@ impl GDriverService for GdriverServer {
|
||||
context: Context,
|
||||
path: PathBuf,
|
||||
) -> StdResult<DriveId, GetFileByPathError> {
|
||||
Err(GetFileByPathError::Other)
|
||||
let mut drive_lock = self.drive.lock().await;
|
||||
let x = drive_lock.path_resolver.get_id_from_path(&path).await?;
|
||||
match x {
|
||||
None => Err(GetFileByPathError::NotFound),
|
||||
Some(id) => Ok(id),
|
||||
}
|
||||
}
|
||||
|
||||
async fn write_local_change(
|
||||
@@ -191,7 +201,7 @@ pub async fn start() -> Result<()> {
|
||||
let config = &CONFIGURATION;
|
||||
info!("Config: {:?}", **config);
|
||||
|
||||
let drive = Drive::new().await?;
|
||||
let mut drive = Drive::new().await?;
|
||||
match drive.ping().await {
|
||||
Ok(_) => {
|
||||
info!("Can reach google drive api.");
|
||||
@@ -201,7 +211,8 @@ pub async fn start() -> Result<()> {
|
||||
return Err(e);
|
||||
}
|
||||
}
|
||||
let m = Arc::new(Mutex::new(drive));
|
||||
drive.get_all_file_metas().await?;
|
||||
let drive = Arc::new(Mutex::new(drive));
|
||||
|
||||
let server_addr = (config.ip, config.port);
|
||||
let mut listener = tarpc::serde_transport::tcp::listen(&server_addr, Json::default).await?;
|
||||
@@ -220,7 +231,7 @@ pub async fn start() -> Result<()> {
|
||||
let c = channel.transport().peer_addr().unwrap();
|
||||
let server = GdriverServer {
|
||||
socket_address: c,
|
||||
drive: m.clone(),
|
||||
drive: drive.clone(),
|
||||
};
|
||||
channel.execute(server.serve()).for_each(spawn)
|
||||
})
|
||||
|
||||
@@ -4,6 +4,7 @@ use tokio::sync::mpsc::{channel, Sender};
|
||||
|
||||
use crate::filesystem::{Filesystem, ShutdownRequest};
|
||||
use gdriver_common::{ipc::sample::*, prelude::*};
|
||||
use tarpc::context::Context;
|
||||
use tarpc::{client, tokio_serde::formats::Json};
|
||||
use tokio::task::JoinHandle;
|
||||
|
||||
@@ -15,10 +16,11 @@ async fn main() -> Result<()> {
|
||||
// service::start().await?;
|
||||
let mount_options = &[MountOption::RW];
|
||||
let (tx, rx) = channel(1);
|
||||
let f = Filesystem::new(
|
||||
service::create_client(CONFIGURATION.ip, CONFIGURATION.port).await?,
|
||||
rx,
|
||||
);
|
||||
let gdriver_client = service::create_client(CONFIGURATION.ip, CONFIGURATION.port).await?;
|
||||
gdriver_client
|
||||
.set_offline_mode(Context::current(), true) //TODO make this configurable
|
||||
.await??;
|
||||
let f = Filesystem::new(gdriver_client, rx);
|
||||
mount(f, &"/var/tmp/gdriver2_mount", mount_options, tx)
|
||||
.await?
|
||||
.await?;
|
||||
|
||||
@@ -10,6 +10,7 @@ use std::path::PathBuf;
|
||||
|
||||
#[tarpc::service]
|
||||
pub trait GDriverService {
|
||||
async fn set_offline_mode(offline_mode: bool) -> StdResult<(), GDriverServiceError>;
|
||||
async fn get_file_by_name(
|
||||
name: OsString,
|
||||
parent: DriveId,
|
||||
@@ -52,6 +53,7 @@ lazy_static! {
|
||||
|
||||
pub mod errors {
|
||||
use super::*;
|
||||
use crate::path_resolve_error::PathResolveError;
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum GDriverServiceError {
|
||||
#[error("Error getting the settings: {0}")]
|
||||
@@ -102,6 +104,8 @@ pub mod errors {
|
||||
NotFound,
|
||||
#[error("Could not update drive info")]
|
||||
Update(String),
|
||||
#[error("Could not resolve path")]
|
||||
PathResolve(#[from] PathResolveError),
|
||||
}
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
|
||||
@@ -5,5 +5,6 @@ pub mod prelude;
|
||||
pub mod config;
|
||||
pub mod drive_structure;
|
||||
pub mod ipc;
|
||||
pub mod path_resolve_error;
|
||||
pub mod project_dirs;
|
||||
pub mod tracing_setup;
|
||||
|
||||
9
gdriver-common/src/path_resolve_error.rs
Normal file
9
gdriver-common/src/path_resolve_error.rs
Normal file
@@ -0,0 +1,9 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[derive(Debug, Serialize, Deserialize, thiserror::Error)]
|
||||
pub enum PathResolveError {
|
||||
#[error("The path provided was invalid")]
|
||||
InvalidPath,
|
||||
#[error("Some other error occurred")]
|
||||
Other(String),
|
||||
}
|
||||
Reference in New Issue
Block a user