Update Runnable and fix errors

This commit is contained in:
fluo10 2025-08-21 07:40:33 +09:00
parent be896aaae3
commit f495af68fc
34 changed files with 158 additions and 109 deletions

View file

@ -206,8 +206,8 @@ pub fn runnable(input: TokenStream) -> TokenStream {
quote!{
impl Runnable for #type_ident {
async fn run(self) {
<#field_type as Runnable>::run(self.#field_ident).await
async fn run(self, app_name: &'static str) {
<#field_type as Runnable>::run(self.#field_ident, app_name).await
}
}
}.into()
@ -216,12 +216,12 @@ pub fn runnable(input: TokenStream) -> TokenStream {
let quote_vec = extract_idents_and_types_from_enum_struct(&variants);
let quote_iter = quote_vec.iter().map(|(variant_ident, variant_type)|{
quote!{
Self::#variant_ident(x) => <#variant_type as Runnable>::run(x).await,
Self::#variant_ident(x) => <#variant_type as Runnable>::run(x, app_name).await,
}
});
quote!{
impl Runnable for #type_ident {
async fn run(self) {
async fn run(self, app_name: &'static str) {
match self {
#(#quote_iter)*
}

View file

@ -4,7 +4,7 @@ use caretta_macros::Runnable;
struct RunnableStruct1;
impl Runnable for RunnableStruct1 {
async fn run(self) {
async fn run(self, app_name: &'static str) {
print!("Run {}", stringify!(RunnableStruct1::run()))
}
}
@ -25,7 +25,7 @@ async fn test() {
let runnable = RunnableStruct2{
runnable: RunnableEnum::Struct1(RunnableStruct1)
};
runnable.run().await;
runnable.run("runnable_app").await;
}

View file

@ -3,7 +3,7 @@ mod storage;
mod p2p;
mod rpc;
use std::path::Path;
use std::{path::Path, default::Default};
use crate::{utils::{emptiable::Emptiable, mergeable::Mergeable}};
pub use error::ConfigError;
use serde::{de::DeserializeOwned, Deserialize, Serialize};
@ -41,6 +41,17 @@ impl AsRef<RpcConfig> for Config {
}
}
impl TryFrom<PartialConfig> for Config {
type Error = crate::error::Error;
fn try_from(value: PartialConfig) -> Result<Self, Self::Error> {
Ok(Self{
rpc: value.rpc.try_into()?,
p2p: value.p2p.try_into()?,
storage: value.storage.try_into()?
})
}
}
#[cfg_attr(feature="desktop", derive(Args))]
#[derive(Clone, Debug, Deserialize, PartialEq, Serialize)]
pub struct PartialConfig {
@ -99,6 +110,14 @@ impl PartialConfig {
file.write_all(toml::to_string(self)?.as_bytes()).await?;
Ok(())
}
#[cfg(not(any(target_os="android", target_os="ios")))]
pub fn default_desktop(app_name: &'static str) -> Self {
Self {
p2p: PartialP2pConfig::default(),
rpc: PartialRpcConfig::default(),
storage: PartialStorageConfig::default(app_name),
}
}
}
impl Emptiable for PartialConfig {
@ -114,3 +133,11 @@ impl Emptiable for PartialConfig {
self.p2p.is_empty() && self.rpc.is_empty() && self.storage.is_empty()
}
}
impl Mergeable for PartialConfig {
fn merge(&mut self, other: Self) {
self.p2p.merge(other.p2p);
self.rpc.merge(other.rpc);
self.storage.merge(other.storage);
}
}

View file

@ -71,7 +71,7 @@ impl P2pConfig {
}
impl TryFrom<PartialP2pConfig> for P2pConfig {
type Error = Error;
type Error = crate::error::Error;
fn try_from(raw: PartialP2pConfig) -> Result<P2pConfig, Self::Error> {
Ok(P2pConfig {
secret: base64_to_keypair(&raw.secret.ok_or(Error::MissingConfig("secret"))?)?,

View file

@ -36,7 +36,7 @@ pub struct PartialStorageConfig {
impl PartialStorageConfig {
#[cfg(not(any(target_os="android", target_os="ios")))]
fn default_desktop(app_name: &'static str) -> Self {
pub fn default(app_name: &'static str) -> Self {
let mut data_dir = dirs::data_local_dir().unwrap();
data_dir.push(app_name);

View file

@ -8,6 +8,8 @@ pub enum Error {
CiborDeserialize(#[from] ciborium::de::Error<std::io::Error>),
#[error(transparent)]
CiborSerialize(#[from] ciborium::ser::Error<std::io::Error>),
#[error("Config error: {0}")]
Config(#[from] crate::config::error::ConfigError),
#[error("DB Error: {0}")]
Db(#[from]sea_orm::DbErr),
#[error("Dial Error: {0}")]

View file

@ -15,10 +15,10 @@ impl GlobalConfig {
inner: OnceCell::const_new()
}
}
pub async fn get_or_init<T>(&'static self, config: T) -> &'static Config where
T: AsRef<Config>{
pub async fn get_or_init<T>(&'static self, config: Config) -> &'static Config where
T: Into<Config>{
self.inner.get_or_init(|| async {
config.as_ref().clone()
config.into()
}).await
}
pub async fn get_or_try_init<T, E>(&'static self, config: T) -> Result<&'static Config, <T as TryInto<Config>>::Error> where

View file

@ -1,12 +1,16 @@
use crate::{config::{Config, P2pConfig, RpcConfig}, error::Error};
pub trait ServerTrait {
async fn serve_p2p(config: &P2pConfig) -> Result<(), Error>;
async fn serve_rpc(config: &RpcConfig) -> Result<(), Error>;
async fn serve_all(config: &Config) -> Result<(), Error> {
async fn serve_p2p<T>(config: &T) -> Result<(), Error>
where T: AsRef<P2pConfig>;
async fn serve_rpc<T>(config: &T) -> Result<(), Error>
where T: AsRef<RpcConfig>;
async fn serve_all<T>(config: &T) -> Result<(), Error>
where
T: AsRef<P2pConfig> + AsRef<RpcConfig> {
tokio::try_join!(
Self::serve_p2p(&config.p2p),
Self::serve_rpc(&config.rpc)
Self::serve_p2p(config),
Self::serve_rpc(config)
)?;
Ok(())
}

View file

@ -2,5 +2,5 @@
pub use caretta_macros::Runnable;
pub trait Runnable {
async fn run(self);
async fn run(self, app_name: &'static str);
}

View file

@ -1,12 +1,13 @@
use std::{net::IpAddr, path::PathBuf};
use std::{net::IpAddr, path::PathBuf, sync::LazyLock};
use clap::Args;
use caretta_core::config::{PartialConfig,PartialP2pConfig, PartialStorageConfig, ConfigError};
use caretta_core::{
config::{Config, ConfigError, PartialConfig, PartialP2pConfig, PartialStorageConfig},
utils::mergeable::Mergeable
};
use serde::{Deserialize, Serialize};
use crate::global::DEFAULT_CONFIG_FILE_PATH;
#[derive(Args, Clone, Debug)]
pub struct ConfigArgs {
#[arg(short = 'c', long = "config")]
@ -19,12 +20,26 @@ pub struct ConfigArgs {
impl ConfigArgs {
pub fn get_file_path_or_default(&self) -> PathBuf {
self.file_path.clone().unwrap_or((*DEFAULT_CONFIG_FILE_PATH).clone())
}
pub async fn get_or_read_file_content(&mut self) -> &mut PartialConfig {
self.file_content.get_or_insert(
PartialConfig::read_from(self.get_file_path_or_default()).await.unwrap()
pub fn get_file_path_or_default(&self, app_name: &'static str) -> PathBuf {
self.file_path.clone().unwrap_or(
dirs::config_local_dir()
.unwrap()
.join(app_name)
.join(app_name.to_string() + ".conf")
)
}
pub async fn get_or_read_file_content(&mut self, app_name: &'static str) -> PartialConfig {
self.file_content.get_or_insert(
PartialConfig::read_from(self.get_file_path_or_default(app_name)).await.unwrap()
).clone()
}
pub async fn into_config_unchecked(mut self, app_name: &'static str) -> Config {
let mut default = PartialConfig::default_desktop(app_name);
let file_content = self.get_or_read_file_content(app_name).await;
let args = self.args;
default.merge(file_content);
default.merge(args);
default.try_into().unwrap()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
#[derive(Debug, Args)]
@ -9,7 +9,7 @@ pub struct ConfigCheckCommandArgs{
}
impl Runnable for ConfigCheckCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
#[derive(Debug, Args)]
@ -11,7 +11,7 @@ pub struct ConfigListCommandArgs{
}
impl Runnable for ConfigListCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -15,8 +15,8 @@ pub struct ConfigCommandArgs {
}
impl Runnable for ConfigCommandArgs {
async fn run(self) {
self.command.run().await
async fn run(self, app_name: &'static str) {
self.command.run(app_name).await
}
}
@ -27,10 +27,10 @@ pub enum ConfigSubcommand {
}
impl Runnable for ConfigSubcommand {
async fn run(self) {
async fn run(self, app_name: &'static str) {
match self {
Self::Check(x) => x.run().await,
Self::List(x) => x.run().await,
Self::Check(x) => x.run(app_name).await,
Self::List(x) => x.run(app_name).await,
}
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
@ -16,7 +16,7 @@ pub struct DeviceAddCommandArgs {
}
impl Runnable for DeviceAddCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
#[derive(Debug, Args)]
@ -9,7 +9,7 @@ pub struct DeviceListCommandArgs{
}
impl Runnable for DeviceListCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -5,7 +5,7 @@ mod remove;
mod scan;
pub use add::DeviceAddCommandArgs;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use libp2p::{Multiaddr, PeerId};
pub use list::DeviceListCommandArgs;
pub use ping::DevicePingCommandArgs;
@ -15,14 +15,19 @@ pub use scan::DeviceScanCommandArgs;
use clap::{Args, Parser, Subcommand};
#[derive(Debug, Args, Runnable)]
#[derive(Debug, Args)]
pub struct DeviceCommandArgs {
#[command(subcommand)]
#[runnable]
pub command: DeviceSubcommand
}
#[derive(Debug, Subcommand, Runnable)]
impl Runnable for DeviceCommandArgs {
async fn run(self, app_name: &'static str) {
self.command.run(app_name).await
}
}
#[derive(Debug, Subcommand)]
pub enum DeviceSubcommand {
Add(DeviceAddCommandArgs),
List(DeviceListCommandArgs),
@ -31,3 +36,15 @@ pub enum DeviceSubcommand {
Scan(DeviceScanCommandArgs),
}
impl Runnable for DeviceSubcommand {
async fn run(self, app_name: &'static str) {
match self {
Self::Add(x) => x.run(app_name).await,
Self::List(x) => x.run(app_name).await,
Self::Ping(x) => x.run(app_name).await,
Self::Remove(x) => x.run(app_name).await,
Self::Scan(x) => x.run(app_name).await,
}
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::{ConfigArgs, PeerArgs};
#[derive(Debug, Args)]
@ -11,7 +11,7 @@ pub struct DevicePingCommandArgs{
}
impl Runnable for DevicePingCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::{ConfigArgs, DeviceArgs};
#[derive(Debug, Args)]
@ -11,7 +11,7 @@ pub struct DeviceRemoveCommandArgs{
}
impl Runnable for DeviceRemoveCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
#[derive(Debug, Args)]
@ -9,7 +9,7 @@ pub struct DeviceScanCommandArgs{
}
impl Runnable for DeviceScanCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -8,7 +8,7 @@ pub struct LogsCommandArgs {
}
impl Runnable for LogsCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::{ConfigArgs, PeerArgs};
#[derive(Debug, Args)]
@ -11,7 +11,7 @@ pub struct PeerInfoCommandArgs{
}
impl Runnable for PeerInfoCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::ConfigArgs;
#[derive(Debug, Args)]
@ -9,7 +9,7 @@ pub struct PeerListCommandArgs{
}
impl Runnable for PeerListCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -17,8 +17,8 @@ pub struct PeerCommandArgs {
}
impl Runnable for PeerCommandArgs {
async fn run(self) {
self.command.run().await
async fn run(self, app_name: &'static str) {
self.command.run(app_name).await
}
}
@ -30,11 +30,11 @@ pub enum PeerSubcommand {
}
impl Runnable for PeerSubcommand {
async fn run(self) {
async fn run(self, app_name: &'static str) {
match self {
Self::Info(x) => x.run().await,
Self::List(x) => x.run().await,
Self::Ping(x) => x.run().await,
Self::Info(x) => x.run(app_name).await,
Self::List(x) => x.run(app_name).await,
Self::Ping(x) => x.run(app_name).await,
}
}
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use crate::utils::runnable::Runnable;
use caretta_core::utils::runnable::Runnable;
use crate::cli::{ConfigArgs, PeerArgs};
#[derive(Debug, Args)]
@ -11,7 +11,7 @@ pub struct PeerPingCommandArgs{
}
impl Runnable for PeerPingCommandArgs {
async fn run(self) {
async fn run(self, app_name: &'static str) {
todo!()
}
}

View file

@ -1,29 +0,0 @@
use std::{path::PathBuf, sync::LazyLock};
pub use caretta_core::global::*;
pub static DEFAULT_DATA_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
let dir = if let Some(x) = dirs::data_local_dir() {
x
} else {
todo!()
};
dir.join(&*PRODUCT_NAME)
});
pub static DEFAULT_CONFIG_DIR_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
let dir = if let Some(x) = dirs::config_local_dir() {
x
} else {
todo!()
};
dir.join(&*PRODUCT_NAME)
});
pub static DEFAULT_CONFIG_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
DEFAULT_CONFIG_DIR_PATH.join(&*DEFAULT_CONFIG_FILE_NAME)
});
pub static DEFAULT_DATABASE_FILE_PATH: LazyLock<PathBuf> = LazyLock::new(|| {
DEFAULT_DATA_DIR_PATH.join(&*DEFAULT_DATABASE_FILE_NAME)
});

View file

@ -1,3 +1 @@
pub mod cli;
pub mod global;
pub mod utils;

View file

@ -1 +0,0 @@
pub use caretta_core::utils::*;

View file

@ -8,3 +8,5 @@ repository.workspace = true
[dependencies]
caretta.path = "../.."
libp2p.workspace = true
tokio.workspace = true

View file

@ -0,0 +1 @@
pub const APP_NAME: &str = "caretta_demo";

View file

@ -1,2 +1,3 @@
pub mod global;
pub mod rpc;
pub mod server;

View file

@ -1,17 +1,20 @@
use caretta::{config::P2pConfig, server::ServerTrait};
pub struct Server{};
use libp2p::{futures::StreamExt, noise, swarm::SwarmEvent, tcp, yamux};
pub struct Server{}
impl ServerTrait for Server {
async fn serve_p2p(config: P2pConfig) -> Result<(), caretta::error::Error> {
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(self.secret)
async fn serve_p2p<T>(config: &T) -> Result<(), caretta::error::Error>
where
T: AsRef<P2pConfig>
{
let mut swarm = libp2p::SwarmBuilder::with_existing_identity(config.as_ref().secret.clone())
.with_tokio()
.with_tcp(
tcp::Config::default(),
noise::Config::new,
yamux::Config::default,
)?
.with_behaviour(|keypair| p2p::Behaviour::try_from(keypair).unwrap())?
.with_behaviour(|keypair| caretta::p2p::Behaviour::try_from(keypair).unwrap())?
.build();
swarm.listen_on("/ip4/0.0.0.0/tcp/0".parse()?)?;
loop{
@ -28,4 +31,9 @@ impl ServerTrait for Server {
});
}
}
async fn serve_rpc<T>(config: &T) -> Result<(), caretta::error::Error>
where T: AsRef<caretta::config::RpcConfig> {
todo!()
}
}

View file

@ -1,20 +1,21 @@
mod server;
use clap::{Parser, Subcommand};
use caretta::cli::*;
use caretta::{cli::*, utils::runnable::Runnable};
pub use server::*;
#[derive(Debug, Parser)]
#[derive(Debug, Parser, Runnable)]
pub struct Cli {
#[command(subcommand)]
#[runnable]
command: CliCommand
}
#[derive(Debug, Subcommand)]
#[derive(Debug, Subcommand, Runnable)]
pub enum CliCommand {
Config(ConfigCommandArgs),
Device(DeviceCommandArgs),
Logs(LogsCommandArgs),
Peer(PeerSubcommand),
Peer(PeerCommandArgs),
Server(ServerCommandArgs),
}

View file

@ -1,5 +1,5 @@
use clap::Args;
use caretta::{error::Error, global::CONFIG, utils::runnable::Runnable};
use caretta::{config::Config, error::Error, global::CONFIG, utils::runnable::Runnable};
use libp2p::{noise, ping, swarm::{NetworkBehaviour, SwarmEvent}, tcp, yamux, Swarm};
use super::ConfigArgs;
@ -10,7 +10,8 @@ pub struct ServerCommandArgs {
config: ConfigArgs,
}
impl Runnable for ServerCommandArgs {
async fn run(self) {
let config = CONFIG.get_or_init(self.config.try_into()?).await;
async fn run(self, app_name: &'static str) {
let config = CONFIG.get_or_init::<Config>(self.config.into_config_unchecked(app_name).await).await;
}
}

View file

@ -1,3 +1,5 @@
use clap::Parser;
use crate::cli::Cli;
mod cli;