Skip to content

Commit fcf75d9

Browse files
committed
add code for 45 and ending. also update clap to rc.5
1 parent 4c31bbb commit fcf75d9

File tree

10 files changed

+227
-2
lines changed

10 files changed

+227
-2
lines changed

04_httpie/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@ name = "cli_get"
1616

1717
[dependencies]
1818
anyhow = "1" # 错误处理
19-
clap = "3.0.0-beta.5" # 命令行解析
19+
clap = { version = "3.0.0-rc.5", features = ["derive"] } # 命令行解析
2020
colored = "2" # 命令终端多彩显示
2121
jsonxf = "1.1" # JSON pretty print 格式化
2222
mime = "0.3" # 处理 mime 类型

45_arch/Cargo.toml

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
[package]
2+
name = "arch"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
anyhow = "1"
10+
async-trait = "0.1"
11+
thiserror = "1"
12+
tokio = { version = "1", features = ["full"] }

45_arch/examples/pipeline.rs

Lines changed: 184 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,184 @@
1+
use std::fmt;
2+
3+
pub use async_trait::async_trait;
4+
pub type BoxedError = Box<dyn std::error::Error>;
5+
6+
/// rerun 超过 5 次,就视为失败
7+
const MAX_RERUN: usize = 5;
8+
9+
/// plug 执行的结果
10+
#[must_use]
11+
pub enum PlugResult<Ctx> {
12+
Continue,
13+
Rerun,
14+
Terminate,
15+
NewPipe(Vec<Box<dyn Plug<Ctx>>>),
16+
Err(BoxedError),
17+
}
18+
19+
/// plug trait,任何 pipeline 中的组件需要实现这个 trait
20+
#[async_trait]
21+
pub trait Plug<Ctx>: fmt::Display {
22+
async fn call(&self, ctx: &mut Ctx) -> PlugResult<Ctx>;
23+
}
24+
25+
/// pipeline 结构
26+
#[derive(Default)]
27+
pub struct Pipeline<Ctx> {
28+
plugs: Vec<Box<dyn Plug<Ctx>>>,
29+
pos: usize,
30+
rerun: usize,
31+
executed: Vec<String>,
32+
}
33+
34+
impl<Ctx> Pipeline<Ctx> {
35+
/// 创建一个新的 pipeline
36+
pub fn new(plugs: Vec<Box<dyn Plug<Ctx>>>) -> Self {
37+
Self {
38+
plugs,
39+
pos: 0,
40+
rerun: 0,
41+
executed: Vec::with_capacity(16),
42+
}
43+
}
44+
45+
/// 执行整个 pipeline,要么执行完毕,要么出错
46+
pub async fn execute(&mut self, ctx: &mut Ctx) -> Result<(), BoxedError> {
47+
while self.pos < self.plugs.len() {
48+
self.add_execution_log();
49+
let plug = &self.plugs[self.pos];
50+
51+
match plug.call(ctx).await {
52+
PlugResult::Continue => {
53+
self.pos += 1;
54+
self.rerun = 0;
55+
}
56+
PlugResult::Rerun => {
57+
// pos 不往前走,重新执行现有组件,rerun 开始累加
58+
self.rerun += 1;
59+
}
60+
PlugResult::Terminate => {
61+
break;
62+
}
63+
PlugResult::NewPipe(v) => {
64+
self.pos = 0;
65+
self.rerun = 0;
66+
self.plugs = v;
67+
}
68+
PlugResult::Err(e) => return Err(e),
69+
}
70+
71+
// 如果 rerun 5 次,返回错误
72+
if self.rerun >= MAX_RERUN {
73+
return Err(anyhow::anyhow!("max rerun").into());
74+
}
75+
}
76+
77+
Ok(())
78+
}
79+
80+
pub fn get_execution_log(&self) -> &[String] {
81+
&self.executed
82+
}
83+
84+
fn add_execution_log(&mut self) {
85+
self.executed.push(self.plugs[self.pos].to_string());
86+
}
87+
}
88+
89+
// 示例代码
90+
use thiserror::Error;
91+
92+
struct Context;
93+
94+
#[derive(Debug, Error)]
95+
enum MyError {
96+
#[error("Not found: {0}")]
97+
NotFound(&'static str),
98+
}
99+
100+
#[derive(Debug)]
101+
struct Normalizer;
102+
struct SecurityChecker;
103+
struct CacheLoader;
104+
struct CacheWriter;
105+
struct DataLoader;
106+
107+
impl fmt::Display for Normalizer {
108+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
109+
write!(f, "Normalizer")
110+
}
111+
}
112+
113+
impl fmt::Display for SecurityChecker {
114+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
115+
write!(f, "SecurityChecker")
116+
}
117+
}
118+
119+
impl fmt::Display for CacheLoader {
120+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
121+
write!(f, "CacheLoader")
122+
}
123+
}
124+
125+
impl fmt::Display for CacheWriter {
126+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
127+
write!(f, "CacheWriter")
128+
}
129+
}
130+
131+
impl fmt::Display for DataLoader {
132+
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
133+
write!(f, "DataLoader")
134+
}
135+
}
136+
137+
#[async_trait]
138+
impl Plug<Context> for Normalizer {
139+
async fn call(&self, _ctx: &mut Context) -> PlugResult<Context> {
140+
PlugResult::Continue
141+
}
142+
}
143+
144+
#[async_trait]
145+
impl Plug<Context> for SecurityChecker {
146+
async fn call(&self, _ctx: &mut Context) -> PlugResult<Context> {
147+
PlugResult::NewPipe(vec![
148+
Box::new(CacheLoader),
149+
Box::new(DataLoader),
150+
Box::new(CacheWriter),
151+
])
152+
}
153+
}
154+
155+
#[async_trait]
156+
impl Plug<Context> for CacheLoader {
157+
async fn call(&self, _ctx: &mut Context) -> PlugResult<Context> {
158+
PlugResult::Continue
159+
}
160+
}
161+
162+
#[async_trait]
163+
impl Plug<Context> for CacheWriter {
164+
async fn call(&self, _ctx: &mut Context) -> PlugResult<Context> {
165+
PlugResult::Continue
166+
}
167+
}
168+
169+
#[async_trait]
170+
impl Plug<Context> for DataLoader {
171+
async fn call(&self, _ctx: &mut Context) -> PlugResult<Context> {
172+
PlugResult::Err(Box::new(MyError::NotFound("something")))
173+
}
174+
}
175+
176+
#[tokio::main]
177+
async fn main() -> Result<(), Box<dyn std::error::Error>> {
178+
let mut pipeline = Pipeline::new(vec![Box::new(SecurityChecker), Box::new(Normalizer)]);
179+
let mut ctx = Context;
180+
let result = pipeline.execute(&mut ctx).await;
181+
println!("{:?}", pipeline.get_execution_log());
182+
println!("{:?}", result);
183+
Ok(())
184+
}

45_arch/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// see examples

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,5 +43,7 @@ members = [
4343
"42_kv",
4444
"43_docdoc",
4545
"44_data_processing",
46+
"45_arch",
4647
"46_kv",
48+
"ending",
4749
]

ending/.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
/target

ending/Cargo.toml

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
[package]
2+
name = "ending"
3+
version = "0.1.0"
4+
edition = "2021"
5+
6+
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
7+
8+
[dependencies]
9+
tracing = "0.1"
10+
tracing-subscriber = { version = "0.3", features = ["env-filter"] }
11+
reqwest = { version = "0.11", default-features = false, features = ["rustls-tls", "blocking"]}

ending/examples/http2.rs

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
use tracing::info;
2+
use tracing_subscriber::EnvFilter;
3+
4+
fn main() {
5+
tracing_subscriber::fmt::fmt()
6+
.with_env_filter(EnvFilter::from_default_env())
7+
.init();
8+
9+
let url = "https://www.rust-lang.org/";
10+
11+
let _body = reqwest::blocking::get(url).unwrap().text().unwrap();
12+
info!("Fetching url: {}", url);
13+
}

ending/src/lib.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
// see examples

mid_term_rgrep/Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ edition = "2021"
77

88
[dependencies]
99
anyhow = "1"
10-
clap = "3.0.0-beta.5"
10+
clap = { version = "3.0.0-rc.5", features = ["derive"] }
1111
colored = "2"
1212
glob = "0.3"
1313
itertools = "0.10"

0 commit comments

Comments
 (0)