Add server and update cli

This commit is contained in:
fluo10 2025-04-27 08:36:57 +09:00
parent ec28d1d467
commit f19037f243
13 changed files with 191 additions and 34 deletions

11
Cargo.lock generated
View file

@ -22,6 +22,17 @@ dependencies = [
"thiserror",
]
[[package]]
name = "achievement-counter-server"
version = "0.1.0"
dependencies = [
"achievement-counter-core",
"anyhow",
"chrono",
"clap",
"thiserror",
]
[[package]]
name = "android-tzdata"
version = "0.1.1"

View file

@ -2,10 +2,10 @@
members = [
"cli",
"core",
"core", "server",
]
[workspace.dependencies]
anyhow = "1.0.98"
chrono = "0.4.40"
thiserror = "2.0.12"
thiserror = "2.0.12"

18
cli/src/error.rs Normal file
View file

@ -0,0 +1,18 @@
#[derive(thiserror::Error, Debug)]
pub enum Error {
#[error("Parser error")]
Clap(#[from] clap::Error),
#[error("Parse int error")]
ParseIntError(#[from] std::num::ParseIntError),
#[error("IO Error")]
IoError(#[from] std::io::Error),
}
impl Error {
pub fn print(&self) -> Result<(), Error> {
match self {
Error::Clap(x) => Ok(x.print()?),
_ => unimplemented!(),
}
}
}

View file

@ -1,33 +1,56 @@
pub mod error;
//mod label;
mod record;
//use label::LabelArgs;
use error::Error;
use record::{RecordArgs,RecordAddArgs};
use clap::{Parser, Subcommand};
use clap::{Args, CommandFactory, Parser, Subcommand};
use std::ffi::OsString;
#[derive(Parser)]
#[command(version, about, long_about = None)]
#[command(propagate_version=true)]
struct Cli {
#[command(flatten)]
add_args: Option<RecordAddArgs>,
#[command(subcommand)]
command: Option<Command>,
command: Command,
}
#[derive(Subcommand)]
#[derive(Clone, Debug, Subcommand)]
enum Command {
//Add(RecordAddArgs),
//Label(LabelArgs),
Record(RecordArgs),
}
fn main() {
let cli = Cli::parse();
match &cli.command {
//Some(Commands::Add(x)) => x.run(),
//Some(Commands::Label(x)) => x.run(),
Some(Command::Record(x)) => x.run(),
None => {unimplemented!()},
}
fn try_parse() -> Result<Cli, Error> {
Ok(try_parse_from(std::env::args_os())?)
}
fn try_parse_from<I, T>(itr: I) -> Result<Cli, Error>
where I: IntoIterator<Item=T>,
T: Into<OsString> + Clone,
{
let os_string_vec: Vec<OsString> = itr.into_iter().map(|x| Into::<OsString>::into(x)).collect();
Cli::try_parse_from(os_string_vec.clone()).or_else(|err| match err.kind() {
clap::error::ErrorKind::InvalidSubcommand => {
try_parse_from(vec![OsString::from("record"), OsString::from("add")].into_iter().chain(os_string_vec.clone().into_iter()))
},
_ => Err(err)?,
})
}
fn main() -> Result<(), Error> {
let cli = try_parse();
match cli {
Err(_) => Ok(Cli::command().print_help()?),
Ok(x) => match x.command {
//Some(Commands::Add(x)) => x.run(),
//Some(Commands::Label(x)) => x.run(),
Command::Record(x) => x.run(),
}
}
}

View file

@ -1,37 +1,56 @@
use achievement_counter_core::Record;
use chrono::prelude::*;
use clap::{Args, Subcommand};
use crate::Error;
use std::str::FromStr;
#[derive(Args)]
pub struct RecordAddArgs {
#[derive(Args, Clone, Debug)]
pub struct AchievementArgValues {
pub label: String,
pub value: i8,
}
impl FromStr for AchievementArgValues {
type Err = Error;
fn from_str(s: &str) -> Result<Self, Error> {
let strvec: Vec<&str> = s.split(':').collect();
Ok(AchievementArgValues{
label: strvec.get(0).unwrap().to_string(),
value: strvec.get(1).unwrap().parse()?
})
}
}
#[derive(Args, Clone, Debug)]
pub struct RecordAddArgs {
#[arg(short, long)]
pub comment: Option<String>,
#[arg(short, long)]
pub time: Option<DateTime<Utc>>,
#[arg(default_value_t = 1)]
pub count: u8,
//pub achievements: Vec<String>,
}
impl RecordAddArgs {
pub fn run(&self) {
pub fn run(self) -> Result<(), Error> {
unimplemented!();
}
}
#[derive(Subcommand)]
#[derive(Clone, Debug, Subcommand)]
pub enum RecordCommand {
Add(RecordAddArgs),
}
#[derive(Args)]
#[derive(Args, Clone, Debug)]
pub struct RecordArgs {
#[command(subcommand)]
command: RecordCommand,
}
impl RecordArgs {
pub fn run(&self) {
match &self.command {
pub fn run(self) -> Result<(), Error> {
match self.command {
RecordCommand::Add(x) => x.run(),
}
}

View file

@ -0,0 +1,10 @@
use super::id::*;
pub struct Achievement<T, U>
where T: MayId,
U: MayId,
{
id: T,
lavel: U,
count: i8,
}

55
core/src/data/id.rs Normal file
View file

@ -0,0 +1,55 @@
#[derive(Debug)]
pub struct IdNumber(usize);
#[derive(Debug)]
pub struct IdString(String);
#[derive(Debug)]
pub struct NoId();
#[derive(Debug, PartialEq)]
pub enum IdValue {
Number(usize),
String(String)
}
pub trait MayId {
fn is_id() -> bool;
fn get_value(&self) -> Option<IdValue>;
}
impl MayId for IdNumber {
fn is_id() -> bool {
true
}
fn get_value(&self) -> Option<IdValue> {
Some(IdValue::Number(self.0))
}
}
impl MayId for IdString {
fn is_id() -> bool {
true
}
fn get_value(&self) -> Option<IdValue> {
Some(IdValue::String(self.0.clone()))
}
}
impl MayId for NoId {
fn is_id() -> bool {
false
}
fn get_value(&self) -> Option<IdValue> {
None
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn parse_values() {
assert_eq!(Some(IdValue::Number(1)), IdNumber(1).get_value());
assert_eq!(Some(IdValue::String("Test".to_string())), IdString("Test".to_string()).get_value());
assert_eq!(None, NoId().get_value());
}
}

9
core/src/data/mod.rs Normal file
View file

@ -0,0 +1,9 @@
mod id;
mod label;
mod record;
mod achievement;
pub use id::*;
pub use label::*;
pub use record::*;
pub use achievement::*;

View file

@ -1,10 +1,9 @@
use crate::label::Label;
use chrono::prelude::*;
use std::collections::HashMap;
#[derive(Debug)]
#[derive(Clone, Debug)]
pub struct Record {
pub label: String,
pub comment: String,
pub count: u8,
pub date: DateTime<Utc>,
pub achievements: HashMap<String, i8>,
}

View file

@ -1,7 +1,6 @@
pub mod label;
pub mod record;
pub use self::label::Label;
pub use self::record::Record;
pub mod data;
pub use self::data::Label;
pub use self::data::Record;
pub fn add(left: u64, right: u64) -> u64 {
left + right

11
server/Cargo.toml Normal file
View file

@ -0,0 +1,11 @@
[package]
name = "achievement-counter-server"
version = "0.1.0"
edition = "2024"
[dependencies]
achievement-counter-core = { path = "../core" }
anyhow = {workspace = true}
chrono = {workspace = true}
clap = {version = "4.5.37", features=["derive"]}
thiserror = {workspace = true}

3
server/src/main.rs Normal file
View file

@ -0,0 +1,3 @@
fn main() {
println!("Hello, world!");
}