Skip to content

Commit

Permalink
feat: 添加update及utils
Browse files Browse the repository at this point in the history
  • Loading branch information
Cnotech committed May 1, 2024
1 parent 8231847 commit d1e4a9b
Show file tree
Hide file tree
Showing 4 changed files with 329 additions and 267 deletions.
83 changes: 54 additions & 29 deletions src/entrances/mirror.rs
Original file line number Diff line number Diff line change
@@ -1,29 +1,54 @@
use std::fs::write;

use anyhow::{anyhow, Result};
use reqwest::blocking::get;
use toml::{to_string_pretty, Value};

use crate::{
types::mirror::MirrorHello,
utils::{fs::ensure_dir_exist, get_path_mirror},
};

pub fn mirror_add(url: &String) -> Result<()> {
// 请求 url
let res: MirrorHello = get(url)?.json()?;

// 写 mirror 目录
let p = get_path_mirror()?.join(&res.name);
ensure_dir_exist(&p)?;
let value = Value::try_from(res)?;
let text = to_string_pretty(&value)?;
write(p.join("meta.toml"), text)?;

Ok(())
}

#[test]
fn test_mirror_add() {
mirror_add(&"http://localhost:3000/api/hello".to_string()).unwrap();
}
use std::fs::write;

use anyhow::{anyhow, Result};
use reqwest::blocking::get;
use toml::{to_string_pretty, Value};

use crate::{
types::mirror::{MirrorHello, ServiceKeys},
utils::{
fs::ensure_dir_exist,
get_path_mirror,
mirror::{filter_service_from_meta, read_local_mirror_meta},
},
};

pub fn mirror_add(url: &String, should_match_name: Option<String>) -> Result<()> {
// 请求 url
let res: MirrorHello = get(url)?.json()?;

// 检查名称是否符合
if let Some(n) = should_match_name {
if res.name != n {
return Err(anyhow!("Error:Mirror has changed its registry name (from '{n}' to '{m}'), use 'ept mirror remove {n}' to remove the old mirror first",m=res.name));
}
}

// 写 mirror 目录
let p = get_path_mirror()?.join(&res.name);
ensure_dir_exist(&p)?;
let value = Value::try_from(res)?;
let text = to_string_pretty(&value)?;
write(p.join("meta.toml"), text)?;

Ok(())
}

pub fn mirror_update(name: &String) -> Result<()> {
// 读取 meta 文件
let meta = read_local_mirror_meta(name)?;
// 筛选出 hello 服务
let (hello_path, _) = filter_service_from_meta(meta, ServiceKeys::Hello)?;
// 调用 add
mirror_add(&hello_path, Some(name.to_string()))
}

#[test]
fn test_mirror_add() {
mirror_add(&"http://localhost:3000/api/hello".to_string(), None).unwrap();
}

#[test]
fn test_mirror_update() {
mirror_update(&"official".to_string()).unwrap();
}
193 changes: 98 additions & 95 deletions src/types/mirror.rs
Original file line number Diff line number Diff line change
@@ -1,95 +1,98 @@
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Debug, PartialEq, Clone)]
pub enum Locale {
ZhCn,
EnUs,
Multi,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ServiceKeys {
EptToolchain,
PkgSoftware,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct MirrorHello {
pub name: String,
pub locale: Locale,
pub description: String,
pub maintainer: String,
pub protocol: String,
pub root_url: String,
pub property: Property,
pub service: Vec<Service>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Property {
pub deploy_region: Locale,
pub proxy_storage: bool,
pub upload_bandwidth: u64,
pub sync_interval: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Service {
pub key: ServiceKeys,
pub path: String,
}

impl Serialize for Locale {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
Locale::ZhCn => "zh-CN",
Locale::EnUs => "en-US",
Locale::Multi => "Multi",
};
serializer.serialize_str(s)
}
}

impl<'de> Deserialize<'de> for Locale {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"zh-CN" => Ok(Locale::ZhCn),
"en-US" => Ok(Locale::EnUs),
"Multi" => Ok(Locale::Multi),
_ => Err(serde::de::Error::custom("invalid locale variant")),
}
}
}
impl Serialize for ServiceKeys {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
ServiceKeys::EptToolchain => "EPT_TOOLCHAIN",
ServiceKeys::PkgSoftware => "PKG_SOFTWARE",
};
serializer.serialize_str(s)
}
}

impl<'de> Deserialize<'de> for ServiceKeys {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"EPT_TOOLCHAIN" => Ok(ServiceKeys::EptToolchain),
"PKG_SOFTWARE" => Ok(ServiceKeys::PkgSoftware),
_ => Err(serde::de::Error::custom("invalid service key")),
}
}
}
use serde::{Deserialize, Deserializer, Serialize, Serializer};

#[derive(Debug, PartialEq, Clone)]
pub enum Locale {
ZhCn,
EnUs,
Multi,
}

#[derive(Debug, PartialEq, Clone)]
pub enum ServiceKeys {
Hello,
EptToolchain,
PkgSoftware,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct MirrorHello {
pub name: String,
pub locale: Locale,
pub description: String,
pub maintainer: String,
pub protocol: String,
pub root_url: String,
pub property: Property,
pub service: Vec<Service>,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Property {
pub deploy_region: Locale,
pub proxy_storage: bool,
pub upload_bandwidth: u64,
pub sync_interval: u64,
}

#[derive(Serialize, Deserialize, Debug, PartialEq, Clone)]
pub struct Service {
pub key: ServiceKeys,
pub path: String,
}

impl Serialize for Locale {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
Locale::ZhCn => "zh-CN",
Locale::EnUs => "en-US",
Locale::Multi => "Multi",
};
serializer.serialize_str(s)
}
}

impl<'de> Deserialize<'de> for Locale {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"zh-CN" => Ok(Locale::ZhCn),
"en-US" => Ok(Locale::EnUs),
"Multi" => Ok(Locale::Multi),
_ => Err(serde::de::Error::custom("invalid locale variant")),
}
}
}
impl Serialize for ServiceKeys {
fn serialize<S>(&self, serializer: S) -> Result<S::Ok, S::Error>
where
S: Serializer,
{
let s = match self {
ServiceKeys::Hello => "HELLO",
ServiceKeys::EptToolchain => "EPT_TOOLCHAIN",
ServiceKeys::PkgSoftware => "PKG_SOFTWARE",
};
serializer.serialize_str(s)
}
}

impl<'de> Deserialize<'de> for ServiceKeys {
fn deserialize<D>(deserializer: D) -> Result<Self, D::Error>
where
D: Deserializer<'de>,
{
let s = String::deserialize(deserializer)?;
match s.as_str() {
"HELLO" => Ok(ServiceKeys::Hello),
"EPT_TOOLCHAIN" => Ok(ServiceKeys::EptToolchain),
"PKG_SOFTWARE" => Ok(ServiceKeys::PkgSoftware),
_ => Err(serde::de::Error::custom("invalid service key")),
}
}
}
33 changes: 33 additions & 0 deletions src/utils/mirror.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
use anyhow::{anyhow, Result};
use fs_extra::file::read_to_string;
use toml::from_str;

use crate::{
p2s,
types::mirror::{MirrorHello, Service, ServiceKeys},
utils::get_path_mirror,
};

// 读取 meta
pub fn read_local_mirror_meta(name: &String) -> Result<MirrorHello> {
let p = get_path_mirror()?.join(name).join("meta.toml");
if !p.exists() {
return Err(anyhow!("Error:Mirror '{name}' hasn't been added"));
}
let text = read_to_string(&p)?;
let meta: MirrorHello = from_str(&text)
.map_err(|e| anyhow!("Error:Invalid meta content at '{fp}' : {e}", fp = p2s!(p)))?;
Ok(meta)
}

// 从 meta 中筛选出服务,返回的第一个参数是拼接了 root_url 后的路径
pub fn filter_service_from_meta(hello: MirrorHello, key: ServiceKeys) -> Result<(String, Service)> {
let res = hello.service.iter().find(|s| s.key == key);
if let Some(r) = res {
Ok((format!("{r}{p}", r = hello.root_url, p = r.path), r.clone()))
} else {
Err(anyhow!(
"Error:Failed to find service '{key:?}' in current mirror meta"
))
}
}
Loading

0 comments on commit d1e4a9b

Please sign in to comment.