Skip to content

Commit d05df75

Browse files
committed
wip
1 parent 84d1b33 commit d05df75

File tree

18 files changed

+225
-62
lines changed

18 files changed

+225
-62
lines changed

boilerplate/src/app.rs

+14-12
Original file line numberDiff line numberDiff line change
@@ -1,32 +1,34 @@
1-
use std::sync::Arc;
21
use std::time::Duration;
32

4-
use async_trait::async_trait;
53
use valar::database::Database;
6-
use valar::drivers::cache::MemoryCache;
4+
use valar::services::cache::MemoryCache;
5+
use valar::services::Cache;
76
use valar::Application;
87

98
pub struct App {
109
pub database: Database,
11-
pub cache: MemoryCache,
10+
pub cache: Box<dyn Cache + Send + Sync>,
1211
}
13-
#[async_trait]
12+
1413
impl Application for App {}
1514

1615
impl App {
17-
pub async fn create() -> Arc<Self> {
16+
fn cache() -> impl Cache + Send + Sync {
17+
MemoryCache::with_purge_interval(Duration::from_secs(1))
18+
}
19+
20+
pub async fn create() -> Self {
1821
let database = Database::connect("host=localhost user=erik dbname=valar")
1922
.await
2023
.expect("Unable to connect to the database");
2124

22-
let cache = MemoryCache::with_purge_interval(Duration::from_secs(1));
23-
24-
let app = Self { database, cache };
25-
26-
Arc::new(app)
25+
Self {
26+
database,
27+
cache: Box::new(Self::cache()),
28+
}
2729
}
2830

29-
pub async fn fake() -> Arc<Self> {
31+
pub async fn fake() -> Self {
3032
Self::create().await
3133
}
3234
}

boilerplate/src/http/controllers.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1 +1,2 @@
1+
pub mod counter;
12
pub mod dashboard;
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
use std::sync::Arc;
2+
3+
use valar::http::Request;
4+
use valar::http::Response;
5+
use valar::http::Result;
6+
7+
use crate::App;
8+
9+
pub async fn show(app: Arc<App>, request: Request) -> Result {
10+
let count: i32 = request
11+
.session()?
12+
.get("count")
13+
.on(&app.cache)
14+
.await
15+
.unwrap_or(String::from("0"))
16+
.parse()?;
17+
18+
Response::ok()
19+
.html(format!(
20+
r#"
21+
<h1>Counter</h1>
22+
<p>Count: {count}</p>
23+
<form method="POST">
24+
<button type="submit">Increment</button>
25+
</form>
26+
"#
27+
))
28+
.into_ok()
29+
}
30+
31+
pub async fn increment(app: Arc<App>, request: Request) -> Result {
32+
let session = request.session()?;
33+
34+
let count: i32 = session
35+
.get("count")
36+
.on(&app.cache)
37+
.await
38+
.unwrap_or(String::from("0"))
39+
.parse()?;
40+
41+
session
42+
.set("count", (count + 1).to_string())
43+
.on(&app.cache)
44+
.await?;
45+
46+
Response::redirect("/").into_ok()
47+
}

boilerplate/src/lib.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
1-
pub mod app;
2-
pub mod http;
3-
pub mod routes;
1+
mod app;
2+
mod http;
3+
mod routes;
44

55
pub use app::App;

boilerplate/src/main.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -2,12 +2,15 @@ pub mod app;
22
pub mod http;
33
pub mod routes;
44

5-
pub use app::App;
5+
use std::sync::Arc;
6+
67
use valar::http::Server;
78

9+
use crate::app::App;
10+
811
#[tokio::main]
912
async fn main() {
10-
let app = App::create().await;
13+
let app = Arc::new(App::create().await);
1114
let router = App::router().unwrap();
1215

1316
Server::builder()

boilerplate/src/routes.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -1,22 +1,24 @@
11
use std::sync::Arc;
22

33
use valar::http::middleware::Logger;
4+
use valar::http::middleware::Session;
45
use valar::routing::route::Builder as Route;
56
use valar::routing::router::Compiled;
67
use valar::routing::router::Error;
78
use valar::routing::Router;
89

9-
use crate::http::controllers::dashboard;
10-
use crate::App;
10+
use crate::app::App;
11+
// use crate::http::controllers::dashboard;
12+
use crate::http::controllers::counter;
1113

1214
impl App {
1315
pub fn router() -> Result<Arc<Router<Self, Compiled>>, Error> {
14-
let api = Route::group([
15-
Route::get("/", dashboard::index),
16-
Route::get("/user/:id", dashboard::show).where_parameter("id", "[0-9]+"),
16+
let web = Route::group([
17+
Route::get("/", counter::show),
18+
Route::post("/", counter::increment),
1719
]);
1820

19-
let router = Router::from_iter([api]).middleware(Logger);
21+
let router = Router::from_iter([web.middleware(Session)]).middleware(Logger);
2022
let router = Arc::new(router.compile()?);
2123

2224
Ok(router)
+8-4
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,18 @@
1+
use std::sync::Arc;
2+
13
use boilerplate::App;
24
use valar::http::Request;
35
use valar::http::Uri;
46

57
#[tokio::test]
68
async fn it_has_a_homepage() {
7-
let app = App::fake().await;
9+
let app = App {
10+
..App::fake().await
11+
};
12+
let app = Arc::new(app);
813
let router = App::router().unwrap();
9-
1014
let request = Request::get(Uri::from_static("/"));
11-
let response = router.handle(app.clone(), request).await;
15+
let response = router.handle(app, request).await;
1216

13-
response.assert_ok().assert_is_json();
17+
response.assert_ok();
1418
}

valar/src/app.rs

-3
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,5 @@
11
use std::sync::Arc;
22

3-
use async_trait::async_trait;
4-
5-
#[async_trait]
63
pub trait Application {}
74

85
/// A fake application.

valar/src/database.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -18,8 +18,7 @@ pub struct Database {
1818

1919
impl Database {
2020
pub async fn connect(url: &str) -> Result<Database, PGError> {
21-
let (client, connection) =
22-
tokio_postgres::connect(url, tokio_postgres::NoTls).await?;
21+
let (client, connection) = tokio_postgres::connect(url, tokio_postgres::NoTls).await?;
2322

2423
tokio::spawn(async move {
2524
if let Err(e) = connection.await {

valar/src/drivers.rs

-3
This file was deleted.

valar/src/http/headers.rs

+6
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,12 @@ impl<T> Headers<T> {
194194
self.headers.get_mut(&header.to_lowercase())
195195
}
196196

197+
pub fn iter(&self) -> impl Iterator<Item = (&String, &String)> {
198+
self.headers
199+
.iter()
200+
.flat_map(|(header, values)| values.iter().map(move |value| (header, value)))
201+
}
202+
197203
/// Gets the first value associated
198204
/// with a header name.
199205
///

valar/src/http/response.rs

+65-7
Original file line numberDiff line numberDiff line change
@@ -21,16 +21,9 @@ use crate::utils::TruncatableToFit;
2121
/// to the client.
2222
#[derive(Debug)]
2323
pub struct Response {
24-
/// The response's status
2524
status: StatusCode,
26-
27-
/// The response's version
2825
version: Version,
29-
30-
/// The response's headers
3126
headers: Headers<Self>,
32-
33-
/// The body of the response.
3427
body: String,
3528
}
3629

@@ -67,6 +60,27 @@ impl Response {
6760
Self::builder().ok()
6861
}
6962

63+
pub fn redirect<P>(location: P) -> ResponseBuilder
64+
where
65+
P: Into<String>,
66+
{
67+
Self::builder().redirect(location)
68+
}
69+
70+
pub fn temporary_redirect<P>(location: P) -> ResponseBuilder
71+
where
72+
P: Into<String>,
73+
{
74+
Self::builder().temporary_redirect(location)
75+
}
76+
77+
pub fn permanent_redirect<P>(location: P) -> ResponseBuilder
78+
where
79+
P: Into<String>,
80+
{
81+
Self::builder().permanent_redirect(location)
82+
}
83+
7084
/// Returns a response builder with a created status
7185
/// code.
7286
pub fn created() -> ResponseBuilder {
@@ -377,6 +391,50 @@ impl ResponseBuilder {
377391
self
378392
}
379393

394+
pub fn see_other<L>(mut self, location: L) -> Self
395+
where
396+
L: Into<String>,
397+
{
398+
self.headers.insert("Location", location);
399+
self.status = StatusCode::SEE_OTHER;
400+
401+
self
402+
}
403+
404+
/// Alias to see_other. Use when the redirect is a
405+
/// direct response to a POST / PUT action where the
406+
/// request is intended to go.
407+
pub fn redirect<L>(self, location: L) -> Self
408+
where
409+
L: Into<String>,
410+
{
411+
self.see_other(location)
412+
}
413+
414+
/// Temporary redirect. Use when the resource is now
415+
/// located at a different URI temporarily.
416+
pub fn temporary_redirect<L>(mut self, location: L) -> Self
417+
where
418+
L: Into<String>,
419+
{
420+
self.headers.insert("Location", location);
421+
self.status = StatusCode::TEMPORARY_REDIRECT;
422+
423+
self
424+
}
425+
426+
/// Permanent redirect. Use when the resource is now
427+
/// located at a different URI permanently.
428+
pub fn permanent_redirect<L>(mut self, location: L) -> Self
429+
where
430+
L: Into<String>,
431+
{
432+
self.headers.insert("Location", location);
433+
self.status = StatusCode::PERMANENT_REDIRECT;
434+
435+
self
436+
}
437+
380438
pub fn message<M>(mut self, message: M) -> Self
381439
where
382440
M: Into<String>,

valar/src/http/session.rs

+15-10
Original file line numberDiff line numberDiff line change
@@ -5,9 +5,9 @@ use thiserror::Error;
55
use tokio::time::Instant;
66
use uuid::Uuid;
77

8-
use crate::drivers::cache;
9-
use crate::drivers::Cache;
108
use crate::http::Request;
9+
use crate::services::cache;
10+
use crate::services::Cache;
1111

1212
#[derive(Error, Debug)]
1313
pub enum Error {
@@ -55,27 +55,32 @@ impl Insert {
5555
self
5656
}
5757

58-
pub async fn on<C>(self, cache: &C) -> Result<(), cache::Error>
58+
pub async fn on<C, V>(self, cache: V) -> Result<(), cache::Error>
5959
where
60-
C: Cache,
60+
C: Cache + ?Sized,
61+
V: AsRef<C>,
6162
{
6263
let key = format!("session:{}:{}", self.session.0.as_hyphenated(), self.key);
6364
let expires_at = self
6465
.expires_at
6566
.unwrap_or_else(|| Instant::now() + Duration::from_secs(60 * 60 * 24));
6667

67-
cache.insert_until(key, self.value, expires_at).await
68+
cache
69+
.as_ref()
70+
.insert_until(key, self.value, expires_at)
71+
.await
6872
}
6973
}
7074

7175
impl Obtain {
72-
pub async fn on<C>(self, cache: &C) -> Result<String, cache::Error>
76+
pub async fn on<C, V>(self, cache: V) -> Result<String, cache::Error>
7377
where
74-
C: Cache,
78+
C: Cache + ?Sized,
79+
V: AsRef<C>,
7580
{
7681
let key = format!("session:{}:{}", self.session.0.as_hyphenated(), self.key);
7782

78-
cache.get(&key).await
83+
cache.as_ref().get(&key).await
7984
}
8085
}
8186

@@ -105,8 +110,8 @@ impl Session {
105110
}
106111

107112
impl From<Uuid> for Session {
108-
fn from(session: Uuid) -> Self {
109-
Self(session)
113+
fn from(uuid: Uuid) -> Self {
114+
Self(uuid)
110115
}
111116
}
112117

valar/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
pub mod app;
22
pub mod database;
3-
pub mod drivers;
43
pub mod http;
54
pub mod routing;
5+
pub mod services;
66
pub mod state;
77
mod utils;
88

valar/src/services.rs

+5
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
pub mod cache;
2+
pub mod session;
3+
4+
pub use cache::Cache;
5+
pub use session::Session;

0 commit comments

Comments
 (0)