-
Notifications
You must be signed in to change notification settings - Fork 67
/
with_shell.rs
175 lines (146 loc) · 4.86 KB
/
with_shell.rs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
mod shared {
use crux_core::macros::Effect;
use crux_core::render::Render;
use crux_http::Http;
use serde::{Deserialize, Serialize};
#[derive(Default)]
pub(crate) struct App;
#[derive(Serialize, Deserialize)]
pub enum Event {
Get,
GetJson,
// events local to the core
#[serde(skip)]
Set(crux_http::Result<crux_http::Response<Vec<u8>>>),
#[serde(skip)]
SetJson(crux_http::Result<crux_http::Response<String>>),
}
#[derive(Default, Serialize, Deserialize)]
pub struct Model {
pub status: u16,
pub body: Vec<u8>,
pub json_body: String,
}
#[derive(Serialize, Deserialize, Default)]
pub struct ViewModel {
pub result: String,
}
impl crux_core::App for App {
type Event = Event;
type Model = Model;
type ViewModel = ViewModel;
type Capabilities = Capabilities;
fn update(&self, event: Event, model: &mut Model, caps: &Capabilities) {
match event {
Event::Get => {
caps.http.get("http://example.com").send(Event::Set);
}
Event::GetJson => {
caps.http
.get("http://example.com")
.expect_json::<String>()
.send(Event::SetJson);
}
Event::Set(response) => {
let mut response = response.unwrap();
model.status = response.status().into();
model.body = response.take_body().unwrap();
caps.render.render()
}
Event::SetJson(response) => {
model.json_body = response.unwrap().take_body().unwrap();
caps.render.render()
}
}
}
fn view(&self, model: &Self::Model) -> Self::ViewModel {
ViewModel {
result: format!(
"Status: {}, Body: {}, Json Body: {}",
model.status,
String::from_utf8_lossy(&model.body),
&model.json_body
),
}
}
}
#[derive(Effect)]
pub(crate) struct Capabilities {
pub http: Http<Event>,
pub render: Render<Event>,
}
}
mod shell {
use super::shared::{App, Effect, Event};
use anyhow::Result;
use crux_core::Core;
use crux_http::protocol::{HttpRequest, HttpResponse, HttpResult};
use std::collections::VecDeque;
enum Task {
Event(Event),
Effect(Effect),
}
pub(crate) fn run(core: &Core<Effect, App>, event: Event) -> Result<Vec<HttpRequest>> {
let mut queue: VecDeque<Task> = VecDeque::new();
queue.push_back(Task::Event(event));
let mut received: Vec<HttpRequest> = vec![];
while !queue.is_empty() {
let task = queue.pop_front().expect("an event");
match task {
Task::Event(event) => {
enqueue_effects(&mut queue, core.process_event(event));
}
Task::Effect(effect) => match effect {
Effect::Render(_) => (),
Effect::Http(mut request) => {
let http_request = &request.operation;
received.push(http_request.clone());
let response = HttpResponse::ok().json("Hello").build();
enqueue_effects(
&mut queue,
core.resolve(&mut request, HttpResult::Ok(response)),
);
}
},
};
}
Ok(received)
}
fn enqueue_effects(queue: &mut VecDeque<Task>, effects: Vec<Effect>) {
queue.append(&mut effects.into_iter().map(Task::Effect).collect())
}
}
mod tests {
use crate::{
shared::{App, Effect, Event},
shell::run,
};
use anyhow::Result;
use crux_core::Core;
use crux_http::protocol::HttpRequest;
#[test]
pub fn test_http() -> Result<()> {
let core: Core<Effect, App> = Core::default();
let received = run(&core, Event::Get)?;
assert_eq!(
received,
vec![HttpRequest::get("http://example.com/").build()]
);
assert_eq!(
core.view().result,
"Status: 200, Body: \"Hello\", Json Body: "
);
Ok(())
}
#[test]
pub fn test_http_json() -> Result<()> {
let core: Core<Effect, App> = Core::default();
let received = run(&core, Event::GetJson)?;
assert_eq!(
received,
vec![HttpRequest::get("http://example.com/").build()]
);
assert_eq!(core.view().result, "Status: 0, Body: , Json Body: Hello");
Ok(())
}
}