This commit is contained in:
parent
4688968a32
commit
0c17944215
7 changed files with 128 additions and 71 deletions
1
Cargo.lock
generated
1
Cargo.lock
generated
|
@ -147,6 +147,7 @@ checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b"
|
||||||
name = "based"
|
name = "based"
|
||||||
version = "0.1.0"
|
version = "0.1.0"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
|
"async-stream",
|
||||||
"bcrypt",
|
"bcrypt",
|
||||||
"chrono",
|
"chrono",
|
||||||
"dashmap",
|
"dashmap",
|
||||||
|
|
|
@ -25,6 +25,7 @@ rand = "0.8.5"
|
||||||
data-encoding = "2.6.0"
|
data-encoding = "2.6.0"
|
||||||
bcrypt = "0.16.0"
|
bcrypt = "0.16.0"
|
||||||
dashmap = "6.1.0"
|
dashmap = "6.1.0"
|
||||||
|
async-stream = "0.3.6"
|
||||||
|
|
||||||
[build-dependencies]
|
[build-dependencies]
|
||||||
reqwest = { version = "0.11", features = ["blocking"] }
|
reqwest = { version = "0.11", features = ["blocking"] }
|
||||||
|
|
|
@ -52,15 +52,12 @@ pub trait AssetRoutes {
|
||||||
|
|
||||||
impl AssetRoutes for rocket::Rocket<Build> {
|
impl AssetRoutes for rocket::Rocket<Build> {
|
||||||
fn mount_assets(self) -> Self {
|
fn mount_assets(self) -> Self {
|
||||||
self.mount(
|
self.mount("/", routes![
|
||||||
"/",
|
|
||||||
routes![
|
|
||||||
crate::asset::htmx_script_route,
|
crate::asset::htmx_script_route,
|
||||||
crate::asset::flowbite_css,
|
crate::asset::flowbite_css,
|
||||||
crate::asset::flowbite_js,
|
crate::asset::flowbite_js,
|
||||||
crate::asset::material_css,
|
crate::asset::material_css,
|
||||||
crate::asset::material_font
|
crate::asset::material_font
|
||||||
],
|
])
|
||||||
)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,16 +1,75 @@
|
||||||
|
use crate::gen_random;
|
||||||
use rocket::Request;
|
use rocket::Request;
|
||||||
use rocket::Response;
|
use rocket::Response;
|
||||||
use rocket::http::Header;
|
use rocket::http::Header;
|
||||||
use rocket::http::Status;
|
use rocket::http::Status;
|
||||||
use rocket::response::Responder;
|
use rocket::response::Responder;
|
||||||
use std::io::Cursor;
|
use std::io::Cursor;
|
||||||
|
use std::io::Read;
|
||||||
use crate::gen_random;
|
use std::os::unix::fs::FileExt;
|
||||||
|
use std::os::unix::fs::MetadataExt;
|
||||||
|
|
||||||
// TODO: Implement file based response
|
// TODO: Implement file based response
|
||||||
|
|
||||||
|
pub struct Data {
|
||||||
|
file: Option<String>,
|
||||||
|
raw: Option<Vec<u8>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Data {
|
||||||
|
pub fn raw(data: Vec<u8>) -> Self {
|
||||||
|
Self {
|
||||||
|
file: None,
|
||||||
|
raw: Some(data),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn file(path: &str) -> Self {
|
||||||
|
Self {
|
||||||
|
file: Some(path.to_string()),
|
||||||
|
raw: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn len(&self) -> usize {
|
||||||
|
if let Some(raw) = &self.raw {
|
||||||
|
raw.len()
|
||||||
|
} else {
|
||||||
|
std::fs::File::open(self.file.as_ref().unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.metadata()
|
||||||
|
.unwrap()
|
||||||
|
.size() as usize
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn index(&self, start: usize, end: usize) -> Vec<u8> {
|
||||||
|
if let Some(raw) = &self.raw {
|
||||||
|
raw[start..=end].to_vec()
|
||||||
|
} else {
|
||||||
|
let file = std::fs::File::open(self.file.as_ref().unwrap()).unwrap();
|
||||||
|
let mut buf: Vec<_> = Vec::with_capacity((end - start) as usize);
|
||||||
|
file.read_exact_at(&mut buf, start as u64).unwrap();
|
||||||
|
buf
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn full(self) -> Vec<u8> {
|
||||||
|
if let Some(raw) = self.raw {
|
||||||
|
raw
|
||||||
|
} else {
|
||||||
|
let mut buf = Vec::with_capacity(self.len());
|
||||||
|
std::fs::File::open(self.file.unwrap())
|
||||||
|
.unwrap()
|
||||||
|
.read_to_end(&mut buf)
|
||||||
|
.unwrap();
|
||||||
|
return buf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub struct DataResponse {
|
pub struct DataResponse {
|
||||||
data: Vec<u8>,
|
data: Data,
|
||||||
content_type: String,
|
content_type: String,
|
||||||
// TODO : Implement better cache control
|
// TODO : Implement better cache control
|
||||||
cache_duration: Option<u64>,
|
cache_duration: Option<u64>,
|
||||||
|
@ -18,9 +77,18 @@ pub struct DataResponse {
|
||||||
|
|
||||||
impl DataResponse {
|
impl DataResponse {
|
||||||
#[must_use]
|
#[must_use]
|
||||||
pub const fn new(data: Vec<u8>, content_type: String, cache_duration: Option<u64>) -> Self {
|
pub fn new(data: Vec<u8>, content_type: String, cache_duration: Option<u64>) -> Self {
|
||||||
Self {
|
Self {
|
||||||
data,
|
data: Data::raw(data),
|
||||||
|
content_type,
|
||||||
|
cache_duration,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[must_use]
|
||||||
|
pub fn new_file(path: &str, content_type: String, cache_duration: Option<u64>) -> Self {
|
||||||
|
Self {
|
||||||
|
data: Data::file(path),
|
||||||
content_type,
|
content_type,
|
||||||
cache_duration,
|
cache_duration,
|
||||||
}
|
}
|
||||||
|
@ -35,7 +103,7 @@ impl<'r> Responder<'r, 'static> for DataResponse {
|
||||||
let ranges = range.split(",").collect::<Vec<_>>();
|
let ranges = range.split(",").collect::<Vec<_>>();
|
||||||
if ranges.len() == 1 {
|
if ranges.len() == 1 {
|
||||||
if let Some((start, end)) = parse_range_header(range, self.data.len()) {
|
if let Some((start, end)) = parse_range_header(range, self.data.len()) {
|
||||||
let sliced_data = &self.data[start..=end];
|
let sliced_data = self.data.index(start, end);
|
||||||
return Ok(Response::build()
|
return Ok(Response::build()
|
||||||
.header(Header::new(
|
.header(Header::new(
|
||||||
"Content-Range",
|
"Content-Range",
|
||||||
|
@ -53,7 +121,7 @@ impl<'r> Responder<'r, 'static> for DataResponse {
|
||||||
|
|
||||||
for range in ranges {
|
for range in ranges {
|
||||||
if let Some((start, end)) = parse_range_header(range, self.data.len()) {
|
if let Some((start, end)) = parse_range_header(range, self.data.len()) {
|
||||||
let sliced_data = &self.data[start..=end];
|
let sliced_data = self.data.index(start, end);
|
||||||
|
|
||||||
let mut body: Vec<u8> = Vec::new();
|
let mut body: Vec<u8> = Vec::new();
|
||||||
|
|
||||||
|
@ -71,7 +139,7 @@ impl<'r> Responder<'r, 'static> for DataResponse {
|
||||||
format!("Content-Type: {}\r\n\r\n", self.content_type.clone())
|
format!("Content-Type: {}\r\n\r\n", self.content_type.clone())
|
||||||
.as_bytes(),
|
.as_bytes(),
|
||||||
);
|
);
|
||||||
body.extend_from_slice(sliced_data);
|
body.extend_from_slice(&sliced_data);
|
||||||
body.extend_from_slice("\r\n".as_bytes());
|
body.extend_from_slice("\r\n".as_bytes());
|
||||||
|
|
||||||
multipart_body.extend_from_slice(&body);
|
multipart_body.extend_from_slice(&body);
|
||||||
|
@ -102,7 +170,7 @@ impl<'r> Responder<'r, 'static> for DataResponse {
|
||||||
.header(cache_control_header)
|
.header(cache_control_header)
|
||||||
.header(Header::new("Accept-Ranges", "bytes"))
|
.header(Header::new("Accept-Ranges", "bytes"))
|
||||||
.header(Header::new("Content-Type", self.content_type))
|
.header(Header::new("Content-Type", self.content_type))
|
||||||
.streamed_body(Cursor::new(self.data))
|
.streamed_body(Cursor::new(self.data.full()))
|
||||||
.finalize())
|
.finalize())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -29,9 +29,7 @@ pub fn Modal<T: UIWidget + 'static, E: UIWidget + 'static, F: FnOnce(String) ->
|
||||||
) -> (String, PreEscaped<String>) {
|
) -> (String, PreEscaped<String>) {
|
||||||
let id = uuid::Uuid::new_v4().to_string();
|
let id = uuid::Uuid::new_v4().to_string();
|
||||||
|
|
||||||
(
|
(format!("modal-{id}"), html! {
|
||||||
format!("modal-{id}"),
|
|
||||||
html! {
|
|
||||||
div id=(format!("modal-{id}")) tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" {
|
div id=(format!("modal-{id}")) tabindex="-1" aria-hidden="true" class="hidden overflow-y-auto overflow-x-hidden fixed top-0 right-0 left-0 z-50 justify-center items-center w-full md:inset-0 h-[calc(100%-1rem)] max-h-full" {
|
||||||
div class="relative p-4 w-full max-w-2xl max-h-full" {
|
div class="relative p-4 w-full max-w-2xl max-h-full" {
|
||||||
|
|
||||||
|
@ -55,6 +53,5 @@ pub fn Modal<T: UIWidget + 'static, E: UIWidget + 'static, F: FnOnce(String) ->
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
}};
|
}};
|
||||||
},
|
})
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -287,13 +287,10 @@ pub fn BottomNavigationTile<T: UIWidget + 'static>(
|
||||||
) -> ClassicWidget<LinkWidget> {
|
) -> ClassicWidget<LinkWidget> {
|
||||||
Classic(
|
Classic(
|
||||||
"inline-flex flex-col items-center justify-center px-5 hover:bg-gray-50 dark:hover:bg-gray-800 group",
|
"inline-flex flex-col items-center justify-center px-5 hover:bg-gray-50 dark:hover:bg-gray-800 group",
|
||||||
Link(
|
Link(reference, html! {
|
||||||
reference,
|
|
||||||
html! {
|
|
||||||
(icon.map(|x| x.render()).unwrap_or_default());
|
(icon.map(|x| x.render()).unwrap_or_default());
|
||||||
span class="text-sm text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500" { (text) };
|
span class="text-sm text-gray-500 dark:text-gray-400 group-hover:text-blue-600 dark:group-hover:text-blue-500" { (text) };
|
||||||
},
|
}),
|
||||||
),
|
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -274,10 +274,7 @@ impl GridElement {
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn span(mut self, value: GridElementValue) -> Self {
|
pub fn span(mut self, value: GridElementValue) -> Self {
|
||||||
self.1.push(format!(
|
self.1.push(format!("{}-span-{}", self.2, match value {
|
||||||
"{}-span-{}",
|
|
||||||
self.2,
|
|
||||||
match value {
|
|
||||||
GridElementValue::_1 => "1",
|
GridElementValue::_1 => "1",
|
||||||
GridElementValue::_2 => "2",
|
GridElementValue::_2 => "2",
|
||||||
GridElementValue::_3 => "3",
|
GridElementValue::_3 => "3",
|
||||||
|
@ -291,8 +288,7 @@ impl GridElement {
|
||||||
GridElementValue::_11 => "11",
|
GridElementValue::_11 => "11",
|
||||||
GridElementValue::_12 => "12",
|
GridElementValue::_12 => "12",
|
||||||
GridElementValue::Auto => "full",
|
GridElementValue::Auto => "full",
|
||||||
}
|
}));
|
||||||
));
|
|
||||||
self
|
self
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue