Skip to content

Commit

Permalink
stash
Browse files Browse the repository at this point in the history
stash
  • Loading branch information
ityuany committed Jul 15, 2024
1 parent 4027196 commit 0c75d0e
Show file tree
Hide file tree
Showing 5 changed files with 166 additions and 102 deletions.
58 changes: 3 additions & 55 deletions crates/snm_core/src/model/dispatch_manage.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,20 +23,17 @@ impl DispatchManage {
// 分配
impl DispatchManage {
pub async fn list(&self) -> Result<(), SnmError> {
let dir_tuple = self.read_runtime_dir_name_vec()?;
self.manager.show_list(&dir_tuple).await;
self.manager.show_list().await?;
Ok(())
}

pub async fn list_offline(&self) -> Result<(), SnmError> {
let dir_tuple = self.read_runtime_dir_name_vec()?;
self.manager.show_list_offline(&dir_tuple).await;
self.manager.show_list_offline().await?;
Ok(())
}

pub async fn list_remote(&self, all: bool) -> Result<(), SnmError> {
let dir_tuple = self.read_runtime_dir_name_vec()?;
self.manager.show_list_remote(&dir_tuple, all).await?;
self.manager.show_list_remote(all).await?;
Ok(())
}

Expand Down Expand Up @@ -112,55 +109,6 @@ impl DispatchManage {
Ok(())
}

fn read_runtime_dir_name_vec(&self) -> Result<(Vec<String>, Option<String>), SnmError> {
let runtime_dir_path_buf = self.manager.get_runtime_base_dir_path_buf()?;

let mut default_dir = None;

if runtime_dir_path_buf.exists().not() {
// TODO here create not suitable , should be find a better way
fs::create_dir_all(&runtime_dir_path_buf).expect(
format!(
"read_runtime_dir_name_vec create_dir_all error {:?}",
&runtime_dir_path_buf.display()
)
.as_str(),
);
}

let dir_name_vec = runtime_dir_path_buf
.read_dir()
.expect(
format!(
"read_runtime_dir_name_vec read_dir error {:?}",
&runtime_dir_path_buf.display()
)
.as_str(),
)
.filter_map(|dir_entry| dir_entry.ok())
.filter(|dir_entry| dir_entry.path().is_dir())
.filter_map(|dir_entry| {
let file_name = dir_entry.file_name().into_string().ok()?;

if file_name.eq("default") {
if let Some(o) = fs::read_link(dir_entry.path()).ok() {
if let Some(last) =
o.components().last().and_then(|x| x.as_os_str().to_str())
{
default_dir = Some(String::from(last));
}
}

return None;
}

return Some(file_name);
})
.collect::<Vec<String>>();

Ok((dir_name_vec, default_dir))
}

async fn download(&self, v: &str) -> Result<(), SnmError> {
let download_url = self.manager.get_download_url(v);
let downloaded_file_path_buf = self.manager.get_downloaded_file_path_buf(v)?;
Expand Down
20 changes: 11 additions & 9 deletions crates/snm_core/src/traits/atom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,19 +24,14 @@ pub trait AtomTrait {
downloaded_file_path_buf: &'a PathBuf,
) -> Pin<Box<dyn Future<Output = Option<String>> + Send + 'a>>;

fn show_list<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
fn show_list<'a>(&'a self) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>>;

fn show_list_offline<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>>;
) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>>;

fn show_list_remote<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
all: bool,
) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>>;

Expand Down Expand Up @@ -77,8 +72,15 @@ pub trait AtomTrait {
.filter_map(|dir_entry| {
let file_name = dir_entry.file_name().into_string().ok()?;

if file_name.ends_with("-default") {
default_dir = Some(file_name.trim_end_matches("-default").to_string());
if file_name.eq("default") {
if let Some(o) = fs::read_link(dir_entry.path()).ok() {
if let Some(last) =
o.components().last().and_then(|x| x.as_os_str().to_str())
{
default_dir = Some(String::from(last));
}
}

return None;
}

Expand Down
1 change: 1 addition & 0 deletions crates/snm_node/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ snm_utils = { path = "../snm_utils" }
snm_config = { path = "../snm_config" }
snm_node_version = { path = "../snm_node_version" }
snm_tarball = { path = "../snm_tarball" }
snm_download_builder = { path = "../snm_download_builder" }
xz2 = {version = "0.1.7" , features = ["static"]}
tar = "0.4"
num-format = "0.4.0"
Expand Down
173 changes: 145 additions & 28 deletions crates/snm_node/src/snm_node.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,57 +16,177 @@ use sha2::Sha256;
use snm_config::InstallStrategy;
use snm_config::SnmConfig;
use snm_core::traits::atom::AtomTrait;
use snm_download_builder::{DownloadBuilder, WriteStrategy};
use snm_tarball::decompress;
use snm_utils::snm_error::SnmError;
use snm_utils::to_ok::ToOk;
use std::collections::HashMap;
use std::fs;
use std::ops::Not;
use std::pin::Pin;
use std::time::Duration;
use std::{
fs::File,
io::{BufReader, Read},
path::PathBuf,
};
use tokio::try_join;

pub struct SnmNode {
snm_config: SnmConfig,
}

impl SnmNode {
async fn download(&self, version: &str) -> Result<(), SnmError> {
let download_url = self.get_download_url(version);
let downloaded_file_path_buf = self.get_downloaded_file_path_buf(version)?;

DownloadBuilder::new()
.retries(3)
.write_strategy(WriteStrategy::Nothing)
.download(&download_url, &downloaded_file_path_buf)
.await?;

let runtime = self.get_runtime_dir_path_buf(version)?;

if runtime.exists() {
fs::remove_dir_all(&runtime)?;
}

self.decompress_download_file(&downloaded_file_path_buf, &runtime)?;

fs::remove_file(&downloaded_file_path_buf)?;

Ok(())
}

pub async fn set_default(&self, version: &str) -> Result<(), SnmError> {
if self.get_anchor_file_path_buf(version)?.exists().not() {
let msg = format!(
"🤔 v{} is not installed, do you want to install it ?",
version
);
if Confirm::new().with_prompt(msg).interact()? {
self.install(version).await?;
}
} else {
let default_dir = self.get_runtime_dir_for_default_path_buf()?;
if default_dir.exists() {
fs::remove_dir_all(&default_dir)?;
}

let from_dir = self.get_runtime_dir_path_buf(version)?;

#[cfg(unix)]
{
std::os::unix::fs::symlink(&from_dir, &default_dir)?;
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_dir(&version_dir, &default_dir)?;
}
}

Ok(())
}

pub async fn un_install(&self, version: &str) -> Result<(), SnmError> {
let default_dir = self.get_runtime_dir_for_default_path_buf()?;
let version_dir = self.get_runtime_dir_path_buf(&version)?;
if fs::read_link(&default_dir)?.eq(&version_dir) {
let msg = format!(
"🤔 {} is default instance, do you want to uninstall it ?",
version
);
if Confirm::new().with_prompt(msg).interact()? {
fs::remove_file(&default_dir)?;
fs::remove_dir_all(version_dir)?;
}
} else {
fs::remove_dir_all(version_dir)?;
}
Ok(())
}

pub async fn install(&self, version: &str) -> Result<(), SnmError> {
let anchor_file = self.get_anchor_file_path_buf(&version)?;
let version_dir = self.get_runtime_dir_path_buf(&version)?;

if anchor_file.exists().not() {
self.download(version).await?;
} else {
let confirm = Confirm::new()
.with_prompt(format!(
"🤔 v{} is already installed, do you want to reinstall it ?",
&version
))
.interact()
.expect("install Confirm error");

if confirm {
fs::remove_dir_all(&version_dir)?;
self.download(version).await?;
}

let default_dir = self.get_runtime_dir_for_default_path_buf()?;

if default_dir.exists().not() {
#[cfg(unix)]
{
std::os::unix::fs::symlink(&version_dir, &default_dir)?;
}
#[cfg(windows)]
{
std::os::windows::fs::symlink_dir(&version_dir, &default_dir)?;
}
}
}

Ok(())
}

pub fn new(snm_config: SnmConfig) -> Self {
Self { snm_config }
}

async fn get_node_list_remote(&self) -> Vec<NodeModel> {
async fn get_node_list_remote(&self) -> Result<Vec<NodeModel>, SnmError> {
let host = self.snm_config.get_node_dist_url();
let node_list_url = format!("{}/index.json", host);
let node_vec: Vec<NodeModel> = reqwest::get(&node_list_url)
.await
.expect(format!("fetch {} failed", &node_list_url).as_str())

let client = reqwest::Client::new();

let node_vec: Vec<NodeModel> = client
.get(&node_list_url)
.timeout(Duration::from_secs(10))
.send()
.await?
.json::<Vec<NodeModel>>()
.await
.expect(format!("parse {} response to json failed", &node_list_url).as_str());
node_vec
.await?;
Ok(node_vec)
}

async fn get_node_schedule(&self) -> Vec<NodeSchedule> {
async fn get_node_schedule(&self) -> Result<Vec<NodeSchedule>, SnmError> {
let host = self.snm_config.get_node_github_resource_host();

let node_schedule_url = format!("{}/nodejs/Release/main/schedule.json", host);

let node_schedule_vec: Vec<NodeSchedule> = reqwest::get(&node_schedule_url)
.await
.expect(format!("fetch {} failed", node_schedule_url).as_str())
let client = reqwest::Client::new();

let node_schedule_vec: Vec<NodeSchedule> = client
.get(&node_schedule_url)
.timeout(Duration::from_secs(10))
.send()
.await?
.json::<std::collections::HashMap<String, NodeSchedule>>()
.await
.expect(format!("parse {} response to json failed", node_schedule_url).as_str())
.await?
.into_iter()
.map(|(v, mut schedule)| {
schedule.version = Some(v[1..].to_string());
schedule
})
.collect();

node_schedule_vec
Ok(node_schedule_vec)
}

async fn get_node_sha256_hashmap(&self, node_version: &str) -> HashMap<String, String> {
Expand Down Expand Up @@ -285,12 +405,9 @@ impl AtomTrait for SnmNode {
})
}

fn show_list<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
fn show_list<'a>(&'a self) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>> {
Box::pin(async move {
let (dir_vec, default_v) = dir_tuple;
let (dir_vec, default_v) = self.read_runtime_dir_name_vec()?;
if dir_vec.is_empty() {
let msg = format!(
"Node list is empty, please use {} to get the latest version.",
Expand All @@ -301,7 +418,7 @@ impl AtomTrait for SnmNode {

let now = Utc::now().date_naive();
let (remote_node_vec, node_schedule_vec) =
join!(self.get_node_list_remote(), self.get_node_schedule());
try_join!(self.get_node_list_remote(), self.get_node_schedule())?;

let version_req_vec = node_schedule_vec
.into_iter()
Expand Down Expand Up @@ -362,7 +479,7 @@ impl AtomTrait for SnmNode {

if let Some(v) = default_v {
self.show_node_list(node_vec, |node_v| {
if node_v == v {
if *node_v == v {
return "⛳️";
} else {
return "";
Expand All @@ -373,15 +490,15 @@ impl AtomTrait for SnmNode {
return "";
});
}
Ok(())
})
}

fn show_list_offline<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
) -> Pin<Box<dyn Future<Output = ()> + Send + 'a>> {
) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>> {
Box::pin(async move {
let (dir_vec, default_v) = dir_tuple;
let (dir_vec, default_v) = self.read_runtime_dir_name_vec()?;
if dir_vec.is_empty() {
let msg = format!(
"Node list is empty, please use {} to get the latest version.",
Expand All @@ -397,20 +514,20 @@ impl AtomTrait for SnmNode {
" "
};
println!("{:<2} {}", prefix, item);
})
});
Ok(())
})
}

fn show_list_remote<'a>(
&'a self,
dir_tuple: &'a (Vec<String>, Option<String>),
all: bool,
) -> Pin<Box<dyn Future<Output = Result<(), SnmError>> + Send + 'a>> {
Box::pin(async move {
let (dir_vec, _default_v) = dir_tuple;
let (dir_vec, _default_v) = self.read_runtime_dir_name_vec()?;

let (mut node_vec, node_schedule_vec) =
join!(self.get_node_list_remote(), self.get_node_schedule());
try_join!(self.get_node_list_remote(), self.get_node_schedule())?;

let now = Utc::now().date_naive();

Expand Down
Loading

0 comments on commit 0c75d0e

Please sign in to comment.