Crates.io | ctchi |
lib.rs | ctchi |
version | 0.19.1 |
source | src |
created_at | 2020-05-08 21:17:20.981405 |
updated_at | 2020-12-25 18:40:42.869127 |
description | Home made web framework. |
homepage | https://github.com/glotitude/ctchi |
repository | https://github.com/glotitude/ctchi |
max_upload_size | |
id | 239014 |
size | 41,503 |
What you are looking at is my homemade web framework. It started as pet project and probably continue to be one, but now it has enough features to start simple web page, it even has templates.
Is it ready for production? Not in any case. It doesn't have escaping. It doesn't parse input headers. No middleware. List could go on and on.
But, I have personal page that runs on this framework at http://glotitude.datamonkey.pro/. Feel free to look at it.
concat_idents!
macro[dependencies]
ctchi = "0.18.0"
ctchi_codegen = "0.2.0"
regex = "1"
#![feature(concat_idents)]
#[macro_use]
extern crate ctchi;
use ctchi::core::app::Ctchi;
use ctchi::core::routes::{Routes, Route};
use ctchi_codegen::route;
#[route("/")]
fn index() -> String {
render!("index.html")
}
fn main() {
let mut routes = Routes::new();
// add route to your controller
routes.add_route(routes!(index)());
// create and run local server
let server = Ctchi::new(routes);
let server_result = match server.start() {
Ok(()) => "Ctchi application server is successfully running!".to_string(),
Err(err) => format!("Can't start server! Because '{}'", err)
};
}
cargo run
Ctchi has just a few configuration options:
bind_path
- ip address and port for the server (default is 127.0.0.1:8080
)
base_path
- path to the folder with templates (default is current_dir + /src/pages/
)
static_uri_pref
- url prefix for static files, css/js/images etc (default is static
)
log_path
- path on the file system to the log file.
There are several ways to change configuration of the server:
You should create it at /etc/ctchi/conf.txt
. You can overwrite only 2
properties there bind_path
and base_path
.
You can get ctchi configuration in any place of your program by importing
use ctchi::core::config::get_configuration;
Next you can get a reader and then mutex for configuration:
// get reader
let config_reader = get_configuration();
// get mutex
let config = config_reader.inner.lock().unwrap();
// read some propeties
let prefix = &config.static_uri_pref;
// drop mutex
drop(config);
drop
is very important. You can omit it and it will be automatically called
at the end of the scope, but, if you try to get another config inside the
scope program wouldn't work. So, if you absolutely sure that there wouldn't
be second call for configuration you don't need drop
, if not, better to
call it explicitly.
Ctchi has html templates engine. It isn't sophisticated, but it has all core features you need. What kind of tags it has.
[template]
is root tag, if you have it on the page it is html page with tags,
otherwise ctchi would consider it plane html page.
[for]
tag is for loops. You can pass values (vector of strings) in context and it write
inner part so many time as values length.
[if]
takes boolean value from context and writes inner block if values is true.
It hasn't else
clause. Is can't take expression. So, the whole logic should be
on backend.
[code]
consider everything inside as pure html. Great for long code snippets, since you
don't need to escape every square bracket in it.
[import]
gets page from specified page and import it into current template.
Every rule about tags applies to that page as well.
[[value]]
. Plain value or variable of for loop should be taken in double square brackets.
Every tag except import and value tags, should has closing part.
If you want to write a log of your requests and responses, you should add logger.init into your main function.
use ctchi::log::logger;
fn main() {
logger::init();
// ... other code
}
Configuration has a log_path
field, you can change it either through configuration file,
either through configuration object :)
fn main() {
// ... other code
let config_reader = get_configuration();
let mut config = config_reader.inner.lock().unwrap();
config.log_path = "/Users/glotitude/log/ctchi/server.log".to_string();
drop(config);
// ... other code
}
Remember, all html pages should be in src/pages
folder by default.
Now, say, we have same header for every page. Let's put it into header.html
:
<head>
<meta charset="UTF-8">
<title>Imported Header</title>
<link href="/static/css/main.css" type="text/css" rel="stylesheet">
</head>
And we have index.html:
[template]
<html lang="en">
[import "header.html"/]
<body>
[if authorized]
Hello [[user_name]].
[endif]
Your options for today are:
<ul>
[for option in options]
<li>[[option]]</li>
[endfor]
</ul>
</body>
</html>
[endtemplate]
So, how our controller would look for such template:
#[route("/")]
fn index()-> String {
let mut context = HashMap::<String, Context>::new();
context.insert("authorized".to_string(), Context::BooleanValue(true));
context.insert("user_name".to_string(), Context::SingleValue("Leonid Toshchev".to_string()));
context.insert("options".to_string(), Context::MultiValue(vec!("Eat".to_string(), "Code".to_string(), "Sleep".to_string())));
render!("index.html", context)
}