Skip to content

Commit e4660f2

Browse files
authored
Merge pull request #1 from TuuKeZu/v2
V2
2 parents f2eec8a + 0d06c80 commit e4660f2

14 files changed

+655
-1016
lines changed

Cargo.lock

+42-684
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2-1
Original file line numberDiff line numberDiff line change
@@ -17,10 +17,11 @@ handlebars = "5.1.2"
1717
serde = "1.0.197"
1818
serde_json = "1.0.115"
1919
warp = "0.3.7"
20-
sqlx = { version = "0.7.4", features = [ "postgres" ]}
2120
urlencoding = "2.1.3"
2221
minify-js = { version = "0.6.0", optional = true }
2322
minify-html = "0.15.0"
23+
log = "0.4.22"
24+
http = "1.1.0"
2425

2526
[dependencies.macros]
2627
path = "./macros"

README.md

+71-5
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,74 @@
11
# Potion-rs
2-
## IN DEVELOPMENT, DO NOT DEPLOY TO PRODUCTION
2+
> [!CAUTION]
3+
> Should not be used in production, under development
34
4-
## Documentation
5-
For now documentation only exists for `potion::Error`.
5+
Flask inspired general purpose fullstack web-framework with file-system based routing with support for server-side rendered template-based pages. For client side hydration and responsiveness potion includes build-in Typescript bundler *(as it is our philosophy that Typescript should be strictly used for simple DOM manipulation and)*
66

7-
## Features
8-
**DO NOT** enable `features = ["router"]`, as it does not currently compile
7+
### Features
8+
- [x] File-system based compile-time generated routing
9+
- [x] Robust state management between routers
10+
- [x] Support for accessing files both in router's own dir and in static folder.
11+
- [x] typescriot support for post-render DOM-manipulation
12+
- [x] .ts files both in /static and /routing directories are automatically compiled and linked *(sourcemaps included)*
13+
- [x] Optimised for fast rendering
14+
- [x] Minified generated HTML
15+
- [x] Minified .js bundles
16+
- [ ] Compressed HTML
17+
18+
19+
## Example
20+
21+
`src/main.rs`
22+
```rust
23+
// Derive `potion::IntoContext` for global state
24+
#[derive(Clone, potion::IntoContext)]
25+
pub struct RouterContext {
26+
pub hb: Arc<Handlebars<'static>>,
27+
pub db: Pool<Postgres>
28+
}
29+
30+
// Generate routing during compilation phase. All .rs files are automatically included during compilation
31+
potion::routing!();
32+
33+
#[tokio::main]
34+
async fn main() -> Result<(), Box<dyn Error>> {
35+
dotenv::dotenv().ok();
36+
37+
// Initialize file-system routing
38+
let (mut hb, static_router) = potion::initialize_routing(
39+
&std::env::var("POTION_PROJECT_DIR").expect("Tried to read misconfigured .env file"),
40+
true,
41+
)?;
42+
43+
// Create postgres connection-pool
44+
let pool = sqlx::postgres::PgPoolOptions::new()
45+
.max_connections(5)
46+
.connect(&std::env::var("POSTGRES_URL").expect("Tried to read misconfigured .env file"))
47+
.await?;
48+
49+
// Initialize context
50+
let context = Box::new(RsContext { hb: Arc::new(hb), db: pool.clone() });
51+
52+
// Generate and server routing
53+
let routes = router(context)
54+
.or(static_router);
55+
56+
warp::serve(routes).run(([0, 0, 0, 0], 3030)).await;
57+
58+
Ok(())
59+
}
60+
```
61+
62+
`src/routing/hello/index.rs`
63+
```rust
64+
pub fn initialize(router: potion::Router) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone {
65+
// Access global state
66+
let context = router.downcast::<RouterContext>();
67+
68+
let routing = warp::path("hello")
69+
.and(warp::get())
70+
.map(|| "Hello World");
71+
72+
routing
73+
}
74+
```

macros/Cargo.lock

+37
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

macros/Cargo.toml

+3-1
Original file line numberDiff line numberDiff line change
@@ -12,4 +12,6 @@ channel = "nightly"
1212
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
1313

1414
[dependencies]
15-
dotenv = "0.15.0"
15+
dotenv = "0.15.0"
16+
quote = "1"
17+
syn = "2.0"

macros/src/lib.rs

+37-1
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
use proc_macro::{Span, TokenStream};
1+
use proc_macro::TokenStream;
22
use routing::construct_routing_system;
3+
use syn::{parse_macro_input, DataStruct, DeriveInput};
4+
use syn::Data::Struct;
5+
36

47
mod file_system;
58
mod routing;
@@ -27,3 +30,36 @@ pub fn routing(_p: TokenStream) -> TokenStream {
2730

2831
ts.parse().unwrap()
2932
}
33+
34+
#[proc_macro_derive(IntoContext)]
35+
pub fn hello_derive(item: TokenStream) -> TokenStream {
36+
let ast = parse_macro_input!(item as DeriveInput);
37+
let name = ast.ident;
38+
39+
match ast.data {
40+
Struct(DataStruct { .. }) => {},
41+
_ => unimplemented!("Only works for structs"),
42+
};
43+
44+
quote::quote!{
45+
impl potion::Context for #name {
46+
fn as_any(&self) -> &dyn Any {
47+
self
48+
}
49+
50+
fn as_any_mut(&mut self) -> &mut dyn Any {
51+
self
52+
}
53+
54+
fn box_clone(&self) -> Box<dyn potion::Context + Send + Sync> {
55+
Box::new((*self).clone())
56+
}
57+
}
58+
}.into()
59+
}
60+
61+
#[test]
62+
fn test_router() {
63+
let a = construct_routing_system("D:\\potion-test\\src\\routing");
64+
dbg!(a);
65+
}

macros/src/routing.rs

+4-7
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,6 @@ pub fn construct_import_tree(
3232
if path.extension().unwrap() == "rs" {
3333
let file = entry.file_name().to_str().unwrap().replace(".rs", "");
3434
*s += &format!(" pub mod {}; ", &file);
35-
dbg!(&path);
3635
l.push(resolve_relative_path(path, true)?);
3736
}
3837
}
@@ -42,21 +41,20 @@ pub fn construct_import_tree(
4241
}
4342

4443
pub fn construct_router_tree(l: &mut Vec<VecDeque<String>>) -> io::Result<String> {
45-
let mut ts = String::from("fn router(hb: Arc<Handlebars<'static>>, pool: Pool<Postgres>) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone { ");
44+
let mut ts = String::from("fn router(context: Box<dyn potion::Context + Send + Sync>) -> impl Filter<Extract = (impl warp::Reply,), Error = warp::Rejection> + Clone { ");
4645

4746
let mut tree_list: Vec<&VecDeque<String>> = l.iter().filter(|tree| tree.iter().last().unwrap() == "index").collect();
48-
47+
4948
if let Some(tree) = tree_list.pop() {
5049
if tree.len() <= 0 {
5150
panic!("Failed to construct router tree. Tried to link file with invalid path")
5251
}
5352
if tree.iter().last().unwrap() == "index" {
5453
for (i, route) in tree.iter().enumerate() {
55-
dbg!(&route, &i);
5654
if i == 0 {
5755
ts += &format!("warp::path(\"{}\").and(", route)
5856
} else if i == tree.len() - 1 {
59-
ts += &format!("routing::{}::initialize( potion::Context::new(hb.clone(), pool.clone(), &[{}]) )", resolve_import_path(tree.clone()), tree.iter().map(|r| format!("\"{r}\"")).collect::<Vec<String>>().join(", "));
57+
ts += &format!("routing::{}::initialize( potion::Router::new(context.clone(), &[{}]))", resolve_import_path(tree.clone()), tree.iter().map(|r| format!("\"{r}\"")).collect::<Vec<String>>().join(", "));
6058
} else {
6159
ts += &format!("warp::path(\"{}\").and(", route)
6260
}
@@ -69,13 +67,12 @@ pub fn construct_router_tree(l: &mut Vec<VecDeque<String>>) -> io::Result<String
6967
}
7068

7169
for tree in tree_list {
72-
dbg!(&tree);
7370
if tree.iter().last().unwrap() == "index" {
7471
for (i, route) in tree.iter().enumerate() {
7572
if i == 0 {
7673
ts += &format!(".or(warp::path(\"{}\").and(", route)
7774
} else if i == tree.len() - 1 {
78-
ts += &format!("routing::{}::initialize( potion::Context::new(hb.clone(), pool.clone(), &[{}]) )", resolve_import_path(tree.clone()), tree.iter().map(|r| format!("\"{r}\"")).collect::<Vec<String>>().join(", "));
75+
ts += &format!("routing::{}::initialize( potion::Router::new(context.clone(), &[{}]))", resolve_import_path(tree.clone()), tree.iter().map(|r| format!("\"{r}\"")).collect::<Vec<String>>().join(", "));
7976
} else {
8077
ts += &format!("warp::path(\"{}\").and(", route)
8178
}

0 commit comments

Comments
 (0)