mirror of
https://github.com/OMGeeky/gdriver2.git
synced 2025-12-27 06:29:37 +01:00
Initial prototype
This prototype has basic IPC working, with starting actions and waiting for actions or just getting information
This commit is contained in:
1
.gitignore
vendored
Normal file
1
.gitignore
vendored
Normal file
@@ -0,0 +1 @@
|
||||
/target
|
||||
1407
Cargo.lock
generated
Normal file
1407
Cargo.lock
generated
Normal file
File diff suppressed because it is too large
Load Diff
20
Cargo.toml
Normal file
20
Cargo.toml
Normal file
@@ -0,0 +1,20 @@
|
||||
[workspace]
|
||||
members = [
|
||||
"gdriver-common",
|
||||
"gdriver-backend",
|
||||
"gdriver-client",
|
||||
]
|
||||
resolver="2"
|
||||
|
||||
[workspace.dependencies]
|
||||
tracing="0.1"
|
||||
tokio={ version = "1.35", features = ["rt-multi-thread", "tracing", "fs", "macros"] }
|
||||
serde={ version = "1.0", features = ["serde_derive"] }
|
||||
tarpc = { version = "0.34", features = ["full"] }
|
||||
futures="0.3"
|
||||
lazy_static="1.4"
|
||||
chrono="0.4"
|
||||
|
||||
[patch.crates-io]
|
||||
#tarpc = {path = "../../Documents/git/OMGeeky/tarpc/tarpc/"}
|
||||
tarpc = {git = "https://github.com/google/tarpc.git"}
|
||||
18
gdriver-backend/Cargo.toml
Normal file
18
gdriver-backend/Cargo.toml
Normal file
@@ -0,0 +1,18 @@
|
||||
[package]
|
||||
name = "gdriver-backend"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
fuser={ version = "0.14", default_features = true, features = ["serializable"] }
|
||||
tracing.workspace = true
|
||||
tokio.workspace = true
|
||||
serde.workspace = true
|
||||
tarpc.workspace = true
|
||||
futures.workspace = true
|
||||
chrono.workspace = true
|
||||
|
||||
[dependencies.gdriver-common]
|
||||
path = "../gdriver-common/"
|
||||
29
gdriver-backend/src/drive.rs
Normal file
29
gdriver-backend/src/drive.rs
Normal file
@@ -0,0 +1,29 @@
|
||||
use std::collections::HashMap;
|
||||
|
||||
use chrono::{DateTime, Utc};
|
||||
use gdriver_common::{drive_structure::drive_id::DriveId, prelude::CONFIGURATION};
|
||||
|
||||
use crate::prelude::*;
|
||||
|
||||
pub struct Drive {
|
||||
tracked_files: HashMap<DriveId, DateTime<Utc>>,
|
||||
}
|
||||
impl Drive {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
tracked_files: HashMap::new(),
|
||||
}
|
||||
}
|
||||
pub fn get_file_tracking_state(&self, id: &DriveId) -> TrackingState {
|
||||
let file = self.tracked_files.get(id);
|
||||
match file {
|
||||
Some(date) => TrackingState::Tracked(*date),
|
||||
None => TrackingState::Untracked,
|
||||
}
|
||||
}
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub enum TrackingState {
|
||||
Untracked,
|
||||
Tracked(DateTime<Utc>),
|
||||
}
|
||||
23
gdriver-backend/src/main.rs
Normal file
23
gdriver-backend/src/main.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
use futures::{future, prelude::*};
|
||||
use std::net::SocketAddr;
|
||||
use tarpc::{
|
||||
context,
|
||||
server::{self, incoming::Incoming, Channel},
|
||||
tokio_serde::formats::Json,
|
||||
};
|
||||
mod prelude;
|
||||
use crate::prelude::*;
|
||||
pub(crate) use gdriver_common::prelude::*;
|
||||
mod drive;
|
||||
mod sample;
|
||||
mod service;
|
||||
|
||||
pub(crate) async fn spawn(fut: impl Future<Output = ()> + Send + 'static) {
|
||||
tokio::spawn(fut);
|
||||
}
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
// sample::main().await?;
|
||||
service::start().await?;
|
||||
Ok(())
|
||||
}
|
||||
2
gdriver-backend/src/prelude.rs
Normal file
2
gdriver-backend/src/prelude.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub(crate) type Result<T> = StdResult<T, Box<dyn Error>>;
|
||||
use std::{error::Error, result::Result as StdResult};
|
||||
38
gdriver-backend/src/sample.rs
Normal file
38
gdriver-backend/src/sample.rs
Normal file
@@ -0,0 +1,38 @@
|
||||
use super::*;
|
||||
use gdriver_common::ipc::sample::World;
|
||||
|
||||
#[derive(Clone)]
|
||||
struct HelloServer(SocketAddr);
|
||||
|
||||
impl World for HelloServer {
|
||||
async fn hello(self, _: context::Context, name: String) -> String {
|
||||
println!("Got Hello request with name: {name}");
|
||||
format!("Hello {}", name)
|
||||
}
|
||||
}
|
||||
pub(super) async fn main() -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
let config = &CONFIGURATION;
|
||||
let server_addr = (config.ip, config.port);
|
||||
let mut listener = tarpc::serde_transport::tcp::listen(&server_addr, Json::default).await?;
|
||||
|
||||
println!("Listening");
|
||||
listener.config_mut().max_frame_length(usize::MAX);
|
||||
listener
|
||||
// Ignore accept errors.
|
||||
.filter_map(|r| future::ready(r.ok()))
|
||||
.map(server::BaseChannel::with_defaults)
|
||||
// Limit channels to 1 per IP.
|
||||
.max_channels_per_key(1, |t| t.transport().peer_addr().unwrap().ip())
|
||||
// serve is generated by the service attribute. It takes as input any type implementing
|
||||
// the generated World trait.
|
||||
.map(|channel| {
|
||||
let server = HelloServer(channel.transport().peer_addr().unwrap());
|
||||
channel.execute(server.serve()).for_each(spawn)
|
||||
})
|
||||
// Max 10 channels.
|
||||
.buffer_unordered(10)
|
||||
.for_each(|_| async {})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
100
gdriver-backend/src/service.rs
Normal file
100
gdriver-backend/src/service.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use std::{sync::Arc, thread};
|
||||
|
||||
use chrono::Duration;
|
||||
use gdriver_common::{
|
||||
drive_structure::drive_id::ROOT_ID,
|
||||
ipc::gdriver_service::{BackendActionError, BackendActionRequest, GDriverService},
|
||||
};
|
||||
use tokio::sync::Mutex;
|
||||
|
||||
use crate::drive::Drive;
|
||||
|
||||
use super::*;
|
||||
#[derive(Clone)]
|
||||
struct GdriverServer {
|
||||
socket_address: SocketAddr,
|
||||
drive: Arc<Mutex<Drive>>,
|
||||
}
|
||||
impl GDriverService for GdriverServer {
|
||||
async fn do_something2(
|
||||
self,
|
||||
_: ::tarpc::context::Context,
|
||||
req: BackendActionRequest,
|
||||
) -> std::result::Result<String, BackendActionError> {
|
||||
println!("You are connected from {}", self.socket_address);
|
||||
|
||||
match req {
|
||||
BackendActionRequest::ShutdownGracefully => {
|
||||
println!("Shutdown request received, but I dont want to.");
|
||||
Err(BackendActionError::CouldNotComplete)
|
||||
//Ok(String::from("OK. Shutting down"))
|
||||
}
|
||||
BackendActionRequest::UpdateChanges => {
|
||||
println!("UpdateChanges request received");
|
||||
let drive = &self.drive;
|
||||
print_sample_tracking_state(drive).await;
|
||||
|
||||
Ok(String::from("OK"))
|
||||
}
|
||||
BackendActionRequest::Ping => {
|
||||
println!("Ping request received");
|
||||
Ok(String::from("Pong"))
|
||||
}
|
||||
BackendActionRequest::RunLong => {
|
||||
println!("RunLong request received");
|
||||
long_running_task(&self.drive).await;
|
||||
Ok(String::from("OK"))
|
||||
}
|
||||
BackendActionRequest::StartLong => {
|
||||
println!("StartLong request received");
|
||||
tokio::spawn(async move { long_running_task(&self.drive).await });
|
||||
Ok(String::from("OK"))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
async fn long_running_task(drive: &Arc<Mutex<Drive>>) {
|
||||
thread::sleep(Duration::seconds(10).to_std().unwrap());
|
||||
print_sample_tracking_state(drive).await;
|
||||
}
|
||||
async fn print_sample_tracking_state(drive: &Arc<Mutex<Drive>>) {
|
||||
let lock = drive.lock();
|
||||
let drive = lock.await;
|
||||
let state = drive.get_file_tracking_state(&ROOT_ID);
|
||||
dbg!(state);
|
||||
}
|
||||
pub async fn start() -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
let config = &CONFIGURATION;
|
||||
println!("Config: {:?}", **config);
|
||||
|
||||
let drive = Drive::new();
|
||||
let m = 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?;
|
||||
listener.config_mut().max_frame_length(usize::MAX);
|
||||
|
||||
println!("Listening");
|
||||
listener
|
||||
// Ignore accept errors.
|
||||
.filter_map(|r| future::ready(r.ok()))
|
||||
.map(server::BaseChannel::with_defaults)
|
||||
// // Limit channels to 1 per IP.
|
||||
.max_channels_per_key(1, |t| t.transport().peer_addr().unwrap().ip())
|
||||
// serve is generated by the service attribute. It takes as input any type implementing
|
||||
// the generated World trait.
|
||||
.map(|channel| {
|
||||
let c = channel.transport().peer_addr().unwrap();
|
||||
let server = GdriverServer {
|
||||
socket_address: c,
|
||||
drive: m.clone(),
|
||||
};
|
||||
channel.execute(server.serve()).for_each(spawn)
|
||||
})
|
||||
// Max 10 channels.
|
||||
.buffer_unordered(10)
|
||||
.for_each(|_| async {})
|
||||
.await;
|
||||
Ok(())
|
||||
}
|
||||
14
gdriver-client/Cargo.toml
Normal file
14
gdriver-client/Cargo.toml
Normal file
@@ -0,0 +1,14 @@
|
||||
[package]
|
||||
name = "gdriver-client"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
tarpc.workspace = true
|
||||
tokio.workspace = true
|
||||
futures-sink = "0.3.30"
|
||||
|
||||
[dependencies.gdriver-common]
|
||||
path = "../gdriver-common/"
|
||||
15
gdriver-client/src/main.rs
Normal file
15
gdriver-client/src/main.rs
Normal file
@@ -0,0 +1,15 @@
|
||||
use std::{error::Error, net::IpAddr, result::Result as StdResult};
|
||||
|
||||
use gdriver_common::{ipc::sample::*, prelude::*};
|
||||
use tarpc::{client, tokio_serde::formats::Json};
|
||||
|
||||
type Result<T> = StdResult<T, Box<dyn Error>>;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<()> {
|
||||
service::start().await?;
|
||||
Ok(())
|
||||
}
|
||||
mod sample;
|
||||
|
||||
mod service;
|
||||
32
gdriver-client/src/sample.rs
Normal file
32
gdriver-client/src/sample.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use gdriver_common::config::CONFIGURATION;
|
||||
|
||||
use super::*;
|
||||
pub async fn start() -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
|
||||
let name = "test1".to_string();
|
||||
let config = &CONFIGURATION;
|
||||
let client: WorldClient = create_client(config.ip, config.port).await?;
|
||||
|
||||
let hello = client
|
||||
.hello(tarpc::context::current(), name.to_string())
|
||||
.await;
|
||||
|
||||
match hello {
|
||||
Ok(hello) => println!("{hello:?}"),
|
||||
Err(e) => println!("{:?}", (e)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub async fn create_client(ip: IpAddr, port: u16) -> Result<WorldClient> {
|
||||
let server_addr = (ip, port);
|
||||
let transport = tarpc::serde_transport::tcp::connect(&server_addr, Json::default)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
println!("Could not connect");
|
||||
e
|
||||
})?;
|
||||
let var_name = WorldClient::new(client::Config::default(), transport);
|
||||
let client = var_name.spawn();
|
||||
Ok(client)
|
||||
}
|
||||
61
gdriver-client/src/service.rs
Normal file
61
gdriver-client/src/service.rs
Normal file
@@ -0,0 +1,61 @@
|
||||
use std::time;
|
||||
|
||||
use gdriver_common::ipc::gdriver_service::{BackendActionRequest, GDriverServiceClient};
|
||||
|
||||
use super::*;
|
||||
|
||||
pub async fn start() -> Result<()> {
|
||||
println!("Hello, world!");
|
||||
let config = &CONFIGURATION;
|
||||
println!("Config: {:?}", **config);
|
||||
let client: GDriverServiceClient = create_client(config.ip, config.port).await?;
|
||||
|
||||
let hello = client
|
||||
.do_something2(tarpc::context::current(), BackendActionRequest::Ping)
|
||||
.await;
|
||||
match hello {
|
||||
Ok(hello) => println!("Yay: {:?}", hello),
|
||||
Err(e) => {
|
||||
println!(":( {:?}", (e));
|
||||
dbg!(e);
|
||||
}
|
||||
}
|
||||
let start = time::SystemTime::now();
|
||||
let hello = client
|
||||
.do_something2(tarpc::context::current(), BackendActionRequest::RunLong)
|
||||
.await;
|
||||
|
||||
let seconds = (time::SystemTime::now().duration_since(start))
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
match hello {
|
||||
Ok(hello) => println!("Run Long returned after {} seconds: {:?}", seconds, hello),
|
||||
Err(e) => println!(":( {:?}", (e)),
|
||||
}
|
||||
let start = time::SystemTime::now();
|
||||
let hello = client
|
||||
.do_something2(tarpc::context::current(), BackendActionRequest::StartLong)
|
||||
.await;
|
||||
let seconds = (time::SystemTime::now().duration_since(start))
|
||||
.unwrap()
|
||||
.as_secs();
|
||||
|
||||
match hello {
|
||||
Ok(hello) => println!("Start Long returned after {} seconds: {:?}", seconds, hello),
|
||||
Err(e) => println!(":( {:?}", (e)),
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
pub async fn create_client(ip: IpAddr, port: u16) -> Result<GDriverServiceClient> {
|
||||
let server_addr = (ip, port);
|
||||
let transport = tarpc::serde_transport::tcp::connect(&server_addr, Json::default)
|
||||
.await
|
||||
.map_err(|e| {
|
||||
println!("Could not connect");
|
||||
e
|
||||
})?;
|
||||
let service = GDriverServiceClient::new(client::Config::default(), transport);
|
||||
let client = service.spawn();
|
||||
Ok(client)
|
||||
}
|
||||
17
gdriver-common/Cargo.toml
Normal file
17
gdriver-common/Cargo.toml
Normal file
@@ -0,0 +1,17 @@
|
||||
[package]
|
||||
name = "gdriver-common"
|
||||
version = "0.1.0"
|
||||
edition = "2021"
|
||||
|
||||
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
|
||||
|
||||
[dependencies]
|
||||
serde.workspace = true
|
||||
tarpc.workspace = true
|
||||
tokio.workspace = true
|
||||
futures.workspace = true
|
||||
lazy_static.workspace = true
|
||||
confique={ version = "0.2" }
|
||||
|
||||
#[patch.crates-io]
|
||||
#confique = {path="~/Documents/git/OMGeeky/confique "}
|
||||
33
gdriver-common/src/config.rs
Normal file
33
gdriver-common/src/config.rs
Normal file
@@ -0,0 +1,33 @@
|
||||
use super::*;
|
||||
use crate::prelude::*;
|
||||
use confique::{Config, Partial};
|
||||
use std::net::{IpAddr, Ipv6Addr};
|
||||
const IP_DEFAULT: IpAddr = IpAddr::V6(Ipv6Addr::LOCALHOST);
|
||||
#[derive(Debug, Serialize, Deserialize, Config, Clone)]
|
||||
pub struct Configuration {
|
||||
#[config(default = 33333)]
|
||||
pub port: u16,
|
||||
// #[config(default = Test)]
|
||||
pub ip: std::net::IpAddr,
|
||||
}
|
||||
pub fn load_config() -> Result<Configuration> {
|
||||
Ok(add_default_locations(Config::builder()).load()?)
|
||||
}
|
||||
pub fn load_config_with_path(path: &Path) -> Result<Configuration> {
|
||||
Ok(add_default_locations(Config::builder().file(path)).load()?)
|
||||
}
|
||||
fn add_default_locations(
|
||||
builder: confique::Builder<Configuration>,
|
||||
) -> confique::Builder<Configuration> {
|
||||
type P = <Configuration as Config>::Partial;
|
||||
let prebuilt = P {
|
||||
ip: Some(IP_DEFAULT),
|
||||
..P::empty()
|
||||
};
|
||||
builder.env().file("config.toml").preloaded(prebuilt)
|
||||
}
|
||||
|
||||
use lazy_static::lazy_static;
|
||||
lazy_static! {
|
||||
pub static ref CONFIGURATION: Configuration = load_config().unwrap();
|
||||
}
|
||||
23
gdriver-common/src/drive_structure.rs
Normal file
23
gdriver-common/src/drive_structure.rs
Normal file
@@ -0,0 +1,23 @@
|
||||
pub mod drive_id {
|
||||
use lazy_static::lazy_static;
|
||||
|
||||
lazy_static! {
|
||||
pub static ref ROOT_ID: DriveId = DriveId(String::from("root"));
|
||||
}
|
||||
#[derive(Debug, Clone, PartialEq, Eq, Hash)]
|
||||
pub struct DriveId(pub String);
|
||||
|
||||
impl<T> From<T> for DriveId
|
||||
where
|
||||
T: Into<String>,
|
||||
{
|
||||
fn from(s: T) -> Self {
|
||||
DriveId(s.into())
|
||||
}
|
||||
}
|
||||
impl AsRef<str> for DriveId {
|
||||
fn as_ref(&self) -> &str {
|
||||
&self.0
|
||||
}
|
||||
}
|
||||
}
|
||||
3
gdriver-common/src/ipc.rs
Normal file
3
gdriver-common/src/ipc.rs
Normal file
@@ -0,0 +1,3 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
pub mod gdriver_service;
|
||||
pub mod sample;
|
||||
21
gdriver-common/src/ipc/gdriver_service.rs
Normal file
21
gdriver-common/src/ipc/gdriver_service.rs
Normal file
@@ -0,0 +1,21 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
#[tarpc::service]
|
||||
pub trait GDriverService {
|
||||
async fn do_something2(
|
||||
req: BackendActionRequest,
|
||||
) -> std::result::Result<String, BackendActionError>;
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum BackendActionRequest {
|
||||
ShutdownGracefully,
|
||||
UpdateChanges,
|
||||
Ping,
|
||||
RunLong,
|
||||
StartLong,
|
||||
}
|
||||
#[derive(Debug, Serialize, Deserialize)]
|
||||
pub enum BackendActionError {
|
||||
Unknown,
|
||||
CouldNotComplete,
|
||||
}
|
||||
5
gdriver-common/src/ipc/sample.rs
Normal file
5
gdriver-common/src/ipc/sample.rs
Normal file
@@ -0,0 +1,5 @@
|
||||
#[tarpc::service]
|
||||
pub trait World {
|
||||
/// Returns a greeting for name.
|
||||
async fn hello(name: String) -> String;
|
||||
}
|
||||
7
gdriver-common/src/lib.rs
Normal file
7
gdriver-common/src/lib.rs
Normal file
@@ -0,0 +1,7 @@
|
||||
use serde::{Deserialize, Serialize};
|
||||
use std::path::Path;
|
||||
pub mod prelude;
|
||||
|
||||
pub mod config;
|
||||
pub mod ipc;
|
||||
pub mod drive_structure;
|
||||
4
gdriver-common/src/prelude.rs
Normal file
4
gdriver-common/src/prelude.rs
Normal file
@@ -0,0 +1,4 @@
|
||||
pub use crate::config::Configuration;
|
||||
pub use crate::config::CONFIGURATION;
|
||||
pub use crate::ipc;
|
||||
pub(crate) type Result<T> = std::result::Result<T, Box<dyn std::error::Error>>;
|
||||
Reference in New Issue
Block a user