Add device subcommand

This commit is contained in:
fluo10 2025-07-02 08:32:15 +09:00
parent 2b70b130f2
commit 387c043367
29 changed files with 345 additions and 114 deletions

View file

@ -6,7 +6,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies] [dependencies]
clap.workspace = true
dioxus.workspace = true dioxus.workspace = true
lazy-supplements-desktop.path = "../../lazy-supplements-desktop"
lazy-supplements-examples-core.path = "../core" lazy-supplements-examples-core.path = "../core"
[features] [features]

View file

@ -0,0 +1,16 @@
use clap::{Parser, Subcommand};
use lazy_supplements_desktop::cli::*;
#[derive(Debug, Parser)]
pub struct Cli {
#[command(subcommand)]
command: CliCommand
}
#[derive(Debug, Subcommand)]
pub enum CliCommand {
Config(ConfigCommandArgs),
Device(DeviceCommandArgs),
Log(LogCommandArgs),
Server(ServerCommandArgs),
}

View file

View file

@ -1,3 +1,5 @@
mod cli;
mod ipc;
fn main() { fn main() {
dioxus::launch(lazy_supplements_examples_core::ui::plain::App); dioxus::launch(lazy_supplements_examples_core::ui::plain::App);
} }

View file

View file

@ -0,0 +1,29 @@
pub trait AsyncFrom<T> {
async fn async_from(source: T) -> Self;
}
pub trait AsyncInto<T> {
async fn async_into(self) -> T;
}
impl<T, U> AsyncInto<T> for U
where T: AsyncFrom<U> {
async fn async_into(self) -> T {
T::async_from(self).await
}
}
pub trait AsyncTryFrom<T>: Sized {
type Error: Sized;
async fn async_try_from(source: T) -> Result<Self, Self::Error>;
}
pub trait AsyncTryInto<T>: Sized{
type Error: Sized;
async fn async_try_into(self) -> Result<T, Self::Error>;
}
impl<T, U> AsyncTryInto<T> for U
where T: AsyncTryFrom<U> {
type Error = <T as AsyncTryFrom<U>>::Error;
async fn async_try_into(self) -> Result<T, Self::Error> {
T::async_try_from(self).await
}
}

View file

@ -25,7 +25,7 @@ pub trait PartialConfig: Serialize + Sized + DeserializeOwned
fn is_empty(&self) -> bool; fn is_empty(&self) -> bool;
} }
pub trait ConfigRoot: DeserializeOwned + Serialize { pub trait PartialConfigRoot: DeserializeOwned + Serialize {
fn new() -> Self; fn new() -> Self;
async fn read_or_create<T>(path: T) -> Result<Self, Error> async fn read_or_create<T>(path: T) -> Result<Self, Error>

View file

@ -1,3 +1,4 @@
pub mod async_convert;
pub mod cache; pub mod cache;
pub mod config; pub mod config;
pub mod data; pub mod data;

View file

@ -1,15 +0,0 @@
use serde::{de::DeserializeOwned, Serialize};
pub trait Message: DeserializeOwned + Sized + Serialize {
fn into_writer<W: std::io::Write>(&self, writer: W) -> Result<(), ciborium::ser::Error<std::io::Error>> {
ciborium::into_writer(self, writer)
}
fn into_vec_u8(&self) -> Result<Vec<u8>, ciborium::ser::Error<std::io::Error>> {
let mut buf: Vec<u8> = Vec::new();
self.into_writer(&mut buf)?;
Ok(buf)
}
fn from_reader<R: std::io::Read>(reader: R) -> Result<Self, ciborium::de::Error<std::io::Error>> {
ciborium::from_reader(reader)
}
}

View file

@ -0,0 +1,52 @@
mod node;
use serde::{de::DeserializeOwned, Serialize};
use uuid::Uuid;
use crate::{async_convert::{AsyncTryFrom, AsyncTryInto}, error::Error};
pub trait Message: DeserializeOwned + Sized + Serialize {
fn into_writer<W: std::io::Write>(&self, writer: W) -> Result<(), ciborium::ser::Error<std::io::Error>> {
ciborium::into_writer(self, writer)
}
fn into_vec_u8(&self) -> Result<Vec<u8>, ciborium::ser::Error<std::io::Error>> {
let mut buf: Vec<u8> = Vec::new();
self.into_writer(&mut buf)?;
Ok(buf)
}
fn from_reader<R: std::io::Read>(reader: R) -> Result<Self, ciborium::de::Error<std::io::Error>> {
ciborium::from_reader(reader)
}
}
pub trait Request<T>: Into<T> + From<T> + AsyncTryInto<Self::Response>
where T: Message {
type Response: Response<T, Request = Self>;
async fn send_p2p(self) -> Result<Self::Response, Error>;
}
pub trait Response<T>: Into<T> + From<T> + AsyncTryFrom<Self::Request>
where T: Message{
type Request: Request<T, Response = Self>;
async fn from_request_with_local(req: Self::Request) -> Result<Self,Error>;
async fn from_request_with_p2p(req: Self::Request) -> Result<Self, Error> {
todo!()
}
}
pub trait FromDatabase {
async fn from_storage();
}
pub trait P2pRequest<T>: Into<T> + From<T>
where T: Message {
type P2pResponse: P2pResponse<T, P2pRequest = Self>;
async fn send_p2p(&self) -> Result<Self::P2pResponse, crate::p2p::error::P2pError>{
todo!()
}
}
pub trait P2pResponse<T>: Into<T> + From<T> + AsyncTryFrom<(Self::P2pRequest)>
where T: Message {
type P2pRequest: P2pRequest<T, P2pResponse = Self>;
async fn try_from_p2p_request(source: Self::P2pRequest) -> Result<Self, crate::p2p::error::P2pError>;
}

View file

@ -0,0 +1,10 @@
use serde::{Deserialize, Serialize};
#[derive(Debug, Deserialize, Serialize)]
pub struct ListDeviceRequest;
#[derive(Debug, Deserialize, Serialize)]
pub struct ListDeviceResponse {
node: Vec<crate::data::entity::TrustedNode>
}

View file

@ -0,0 +1,4 @@
#[derive(thiserror::Error)]
pub enum P2pError {
}

View file

@ -1,3 +1,4 @@
pub mod error;
use libp2p::{ identity::Keypair, mdns, ping, swarm}; use libp2p::{ identity::Keypair, mdns, ping, swarm};
use sea_orm::{ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, QueryFilter}; use sea_orm::{ActiveModelTrait, ActiveValue::Set, ColumnTrait, EntityTrait, QueryFilter};

View file

@ -1,23 +1,39 @@
use std::{net::IpAddr, path::PathBuf}; use std::{net::IpAddr, path::PathBuf};
use clap::Args; use clap::Args;
use lazy_supplements_core::config::{PartialConfig, PartialCoreConfig}; use lazy_supplements_core::config::ConfigError;
use crate::config::{PartialP2pConfig, PartialStorageConfig};
#[cfg(unix)]
use crate::config::PartialUnixConfig;
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{config::{desktop::PartialDesktopConfig, CoreConfig}, error::Error, global::{DEFAULT_CONFIG_FILE_PATH, DEFAULT_PARTIAL_CORE_CONFIG,}}; use crate::{
config::PartialDesktopConfig,
error::Error,
global::{DEFAULT_CONFIG_FILE_PATH, DEFAULT_PARTIAL_CORE_CONFIG,}
};
#[derive(Args, Clone, Debug)] #[derive(Args, Clone, Debug)]
pub struct ConfigArgs { pub struct ConfigArgs {
#[arg(long)] #[arg(short = "c", long = "config")]
pub config: Option<PathBuf>, pub file_path: Option<PathBuf>,
#[arg(skip)]
pub file_content: Option<Result<PartialDesktopConfig, ConfigError>>,
#[command(flatten)] #[command(flatten)]
pub core_config: PartialCoreConfig, pub args: PartialDesktopConfig,
#[command(flatten)]
pub desktop_config: PartialDesktopConfig,
} }
impl ConfigArgs { impl ConfigArgs {
pub fn get_file_path_or_default(&self) -> PathBuf {
self.file_path.unwrap_or(DEFAULT_CONFIG_FILE_PATH)
}
pub async fn get_or_read_file_content(&mut self) -> Result<PartialDesktopConfig, ConfigError> {
self.file_content.get_or_insert(
PartialDesktopConfig::read_from(self.get_config_path_or_default()).await
).clone()
}
pub fn get_config_path_or_default(&self) -> PathBuf { pub fn get_config_path_or_default(&self) -> PathBuf {
if let Some(x) = self.config.as_ref() { if let Some(x) = self.config.as_ref() {
x.clone() x.clone()

View file

@ -0,0 +1,12 @@
use clap::Args;
use libp2p::{Multiaddr, PeerId};
use uuid::Uuid;
#[derive(Args, Clone, Debug)]
#[group(multiple = false, required = true)]
pub struct DeviceArgs {
device_number: Option<u32>,
device_id: Option<Uuid>,
peer_id: Option<PeerId>,
multiaddr: Option<Multiaddr>,
}

View file

@ -0,0 +1,7 @@
mod config;
mod device;
mod peer;
pub use config::ConfigArgs;
pub use device::DeviceArgs;
pub use peer::PeerArgs;

View file

@ -0,0 +1,10 @@
use clap::Args;
use libp2p::{Multiaddr, PeerId};
#[derive(Args, Clone, Debug)]
#[group(multiple = false, required = true)]
pub struct PeerArgs {
cache_number: Option<u32>,
peer_id: Option<PeerId>,
multiaddr: Option<Multiaddr>,
}

View file

@ -0,0 +1,23 @@
use clap::Args;
use crate::cli::{ConfigArgs, RunnableCommand};
use crate::cli::PeerArgs;
#[derive(Debug, Args)]
pub struct DeviceAddCommandArgs {
#[command(flatten)]
peer: PeerArgs,
#[arg(short, long)]
passcode: Option<String>,
#[command(flatten)]
config: ConfigArgs
}
impl RunnableCommand for DeviceAddCommandArgs {
async fn run(self) {
todo!()
}
}

View file

@ -0,0 +1,15 @@
use clap::Args;
use crate::cli::{ConfigArgs, RunnableCommand};
#[derive(Debug, Args)]
pub struct DeviceListCommandArgs{
#[command(flatten)]
config: ConfigArgs
}
impl RunnableCommand for DeviceListCommandArgs {
async fn run(self) {
todo!()
}
}

View file

@ -0,0 +1,37 @@
mod add;
mod list;
mod ping;
mod remove;
mod scan;
pub use add::DeviceAddCommandArgs;
use libp2p::{Multiaddr, PeerId};
pub use list::DeviceListCommandArgs;
pub use ping::DevicePingCommandArgs;
pub use remove::DeviceRemoveCommandArgs;
pub use scan::DeviceScanCommandArgs;
use std::{net::IpAddr, ops::Mul, path::PathBuf, str::FromStr};
use clap::{Args, Parser, Subcommand};
use crate::{cli::ServerArgs, error::Error};
use super::ConfigArgs;
#[derive(Debug, Args)]
pub struct DeviceCommandArgs {
#[command(subcommand)]
pub command: DeviceSubcommand
}
#[derive(Debug, Subcommand)]
pub enum DeviceSubcommand {
Add(DeviceAddCommandArgs),
List(DeviceListCommandArgs),
Ping(DevicePingCommandArgs),
Remove(DeviceRemoveCommandArgs),
Scan(DeviceScanCommandArgs),
}

View file

@ -0,0 +1,17 @@
use clap::Args;
use crate::cli::{ConfigArgs, PeerArgs, RunnableCommand};
#[derive(Debug, Args)]
pub struct DevicePingCommandArgs{
#[command(flatten)]
peer: PeerArgs,
#[command(flatten)]
config: ConfigArgs
}
impl RunnableCommand for DevicePingCommandArgs {
async fn run(self) {
todo!()
}
}

View file

@ -0,0 +1,17 @@
use clap::Args;
use crate::cli::{ConfigArgs, DeviceArgs, RunnableCommand};
#[derive(Debug, Args)]
pub struct DeviceRemoveCommandArgs{
#[command(flatten)]
device: DeviceArgs,
#[command(flatten)]
config: ConfigArgs
}
impl RunnableCommand for DeviceRemoveCommandArgs {
async fn run(self) {
todo!()
}
}

View file

@ -0,0 +1,15 @@
use clap::Args;
use crate::cli::{ConfigArgs, RunnableCommand};
#[derive(Debug, Args)]
pub struct DeviceScanCommandArgs{
#[command(flatten)]
config: ConfigArgs
}
impl RunnableCommand for DeviceScanCommandArgs {
async fn run(self) {
todo!()
}
}

View file

@ -0,0 +1,4 @@
#[derive(Args, Debug)]
pub struct LogsCommandArgs {
}

View file

@ -1,9 +1,13 @@
use std::path::PathBuf; use std::path::PathBuf;
mod config; mod args;
mod node; mod device;
mod server; mod server;
pub use config::ConfigArgs; pub use args::*;
pub use node::{ NodeArgs, NodeCommand, PeerArgs , ConsoleNodeArgs}; pub use device::*;
pub use server::ServerArgs; pub use server::*;
pub trait RunnableCommand {
async fn run(self);
}

View file

@ -1,81 +0,0 @@
use std::{net::IpAddr, ops::Mul, path::PathBuf, str::FromStr};
use clap::{Args, Parser, Subcommand};
use libp2p::{
multiaddr::Protocol, noise, ping, swarm::SwarmEvent, tcp, yamux, Multiaddr, PeerId
};
use crate::{cli::ServerArgs, error::Error};
use super::ConfigArgs;
#[derive(Debug, Args)]
pub struct NodeArgs {
#[command(subcommand)]
pub command: NodeCommand
}
#[derive(Debug, Parser)]
pub struct ConsoleNodeArgs {
#[command(flatten)]
pub args: NodeArgs,
}
impl NodeArgs {
pub async fn run(self) -> Result<(), Error> {
println!("{self:?}");
Ok(())
}
}
#[derive(Args, Debug)]
pub struct PeerArgs {
#[arg(value_parser = clap::value_parser!(PeerArg))]
pub peer: PeerArg,
}
#[derive(Clone, Debug)]
pub enum PeerArg {
Addr(Multiaddr),
Id(PeerId),
Number(u32),
}
impl FromStr for PeerArg {
type Err = String;
fn from_str(s: &str) -> Result<Self, Self::Err> {
if let Ok(x) = s.parse::<Multiaddr>() {
Ok(Self::Addr(x))
} else if let Ok(x) = s.parse::<PeerId>() {
Ok(Self::Id(x))
} else if let Ok(x) = s.parse::<u32>() {
Ok(Self::Number(x))
} else {
Err(format!("Invalid value: {s}").to_string())
}
}
}
#[derive(Args, Debug)]
pub struct NodeJoinArgs {
#[command(flatten)]
pub peer: PeerArgs,
pub pass: Option<String>,
}
#[derive(Debug, Subcommand)]
pub enum NodeCommand {
Add(PeerArgs),
Ping(PeerArgs),
Join(PeerArgs),
List,
Delete(PeerArgs),
}
impl PeerArgs {
pub async fn run(self) -> Result<(), Error> {
println!("{self:?}");
todo!()
}
}

View file

@ -3,13 +3,30 @@ pub mod unix;
#[cfg(windows)] #[cfg(windows)]
pub mod windows; pub mod windows;
pub mod desktop;
pub use lazy_supplements_core::config::*; pub use lazy_supplements_core::config::*;
use serde::{Deserialize, Serialize};
#[cfg(unix)] #[cfg(unix)]
pub use unix::*; pub use unix::*;
#[cfg(windows)] #[cfg(windows)]
pub use windows::*; pub use windows::*;
#[derive(Debug, Deserialize, Serialize)]
pub struct PartialDesktopConfig {
p2p: PartialP2pConfig,
storage: PartialStorageConfig,
#[cfg(unix)]
unix: PartialUnixConfig,
}
impl PartialConfigRoot for PartialDesktopConfig {
fn new() -> Self {
Self {
p2p : PartialP2pConfig::empty().with_new_secret(),
storage: PartialStorageConfig::empty(),
unix: PartialUnixConfig::empty(),
}
}
}

View file

@ -40,6 +40,9 @@ impl PartialConfig for PartialUnixConfig {
fn default() -> Self { fn default() -> Self {
todo!() todo!()
} }
fn is_empty(&self) -> bool {
self.socket_path.is_none()
}
fn merge(&mut self, other: Self) { fn merge(&mut self, other: Self) {
if let Some(x) = other.socket_path { if let Some(x) = other.socket_path {
self.socket_path = Some(x); self.socket_path = Some(x);

View file

@ -1,4 +1,17 @@
mod response; mod response;
mod request; mod request;
pub use response::*; pub use response::*;
pub use request::*; pub use request::*;
pub trait IpcRequest {
type IpcResponse: IpcResponse<IpcRequest = Self>;
async fn try_into_p2p_response(&self) -> Result<IpcResponse, Error> {
}
}
pub trait IpcResponse {
type IpcRequest: IpcRequest<IpcResponse = Self>;
async fn try_from_ipc_request(&self) -> Result<IpcRequest, Error>;
}