web added!

This commit is contained in:
Tim-Paik 2021-08-13 00:56:54 +08:00
parent 0b8c2909a9
commit 2806bf5119
3 changed files with 223 additions and 37 deletions

View File

@ -5,6 +5,7 @@ extern crate rocket;
use colored::*;
use rocket::fairing::{Fairing, Info, Kind};
use rocket::response::Redirect;
use rocket::{config::TlsConfig, fs::NamedFile};
use rocket_dyn_templates::Template;
use std::net::IpAddr;
@ -20,10 +21,28 @@ async fn file_server(path: std::path::PathBuf) -> Option<NamedFile> {
NamedFile::open(path).await.ok()
}
#[derive(rocket::serde::Serialize)]
#[serde(crate = "rocket::serde")]
struct Dir {
name: String,
modified: String,
}
#[derive(rocket::serde::Serialize)]
#[serde(crate = "rocket::serde")]
struct File {
name: String,
size: u64,
modified: String,
}
#[derive(rocket::serde::Serialize)]
#[serde(crate = "rocket::serde")]
struct IndexContext<'r> {
title: &'r String,
title: &'r str,
paths: Vec<&'r str>,
dirs: Vec<Dir>,
files: Vec<File>,
}
#[derive(Responder)]
@ -31,9 +50,11 @@ enum Resp {
#[response(status = 200)]
Index(Template),
#[response(status = 404)]
NotFound(String),
NotFound(&'static str),
#[response(status = 200)]
File(NamedFile),
File(Option<NamedFile>),
#[response(status = 302)]
Redirect(Redirect),
}
#[catch(404)]
@ -48,19 +69,61 @@ async fn not_found(request: &rocket::Request<'_>) -> Resp {
if root.join("index.html").is_file()
&& std::env::var("SPA").unwrap_or("false".to_string()) == "true"
{
return Resp::File(
NamedFile::open(&root.join("index.html"))
.await
.ok()
.unwrap(),
);
return Resp::File(NamedFile::open(&root.join("index.html")).await.ok());
}
// Show dotfiles, std::path::PathBuf does not match the url beginning with the dot
if localpath.is_file() && std::env::var("DOTFILES").unwrap_or("false".to_string()) == "true" {
return Resp::File(NamedFile::open(localpath).await.ok());
}
if !localpath.is_dir() {
return Resp::NotFound("".to_string());
// Need to have file 404.tera as a placeholder
return Resp::NotFound("");
}
if !request.uri().path().ends_with("/") {
println!("ok");
return Resp::Redirect(Redirect::to(request.uri().path().to_string() + "/"));
}
let context = &IndexContext {
title: &"title?".to_string(),
title: "title?",
paths: vec!["target", "debug"],
dirs: vec![
Dir {
name: ".fingerprint".to_string(),
modified: chrono::Local::now().to_string(),
},
Dir {
name: "build".to_string(),
modified: chrono::Local::now().to_string(),
},
Dir {
name: "deps".to_string(),
modified: chrono::Local::now().to_string(),
},
Dir {
name: "examples".to_string(),
modified: chrono::Local::now().to_string(),
},
Dir {
name: "incremental".to_string(),
modified: chrono::Local::now().to_string(),
},
],
files: vec![
File {
name: ".cargo-lock".to_string(),
size: 0,
modified: chrono::Local::now().to_string(),
},
File {
name: "web".to_string(),
size: 142606336,
modified: chrono::Local::now().to_string(),
},
File {
name: "web.d".to_string(),
size: 88,
modified: chrono::Local::now().naive_local().to_string(),
},
],
};
Resp::Index(Template::render("index", context))
}
@ -140,6 +203,7 @@ async fn main() {
(@arg nocolor: --nocolor "Disable cli colors")
(@arg cors: --cors "Enable CORS")
(@arg spa: --spa "Enable Single-Page Application mode (always serve /index.html when the file is not found)")
(@arg dotfiles: --dotfiles "Show dotfiles")
(@arg open: -o --open "Open the page in the default browser")
(@arg ROOT: default_value["."] {
|path| match std::fs::metadata(path) {
@ -206,10 +270,11 @@ async fn main() {
std::env::set_var(
"ROOT",
display_path(Path::new(matches.value_of("ROOT").unwrap())),
display_path(Path::new(matches.value_of("ROOT").unwrap_or("."))),
);
std::env::set_var("SPA", matches.is_present("spa").to_string());
std::env::set_var("DOTFILES", matches.is_present("dotfiles").to_string());
if matches.is_present("nocolor") {
colored::control::set_override(false);
@ -218,16 +283,15 @@ async fn main() {
let figment = rocket::Config::figment()
.merge((
"address",
IpAddr::from_str(matches.value_of("address").unwrap())
.unwrap_or(IpAddr::from([127, 0, 0, 1])),
IpAddr::from_str(matches.value_of("address").unwrap_or("127.0.0.1")).unwrap(),
))
.merge((
"port",
matches
.value_of("port")
.unwrap()
.unwrap_or("8000")
.parse::<u16>()
.unwrap_or(8000),
.unwrap(),
))
.merge((
"ident",
@ -254,8 +318,11 @@ async fn main() {
} else {
"http://".to_string()
},
matches.value_of("address").unwrap().to_string(),
matches.value_of("port").unwrap().to_string()
matches
.value_of("address")
.unwrap_or("127.0.0.1")
.to_string(),
matches.value_of("port").unwrap_or("8000").to_string()
);
if cfg!(target_os = "windows") {
std::process::Command::new("explorer").arg(url).spawn().ok();

View File

View File

@ -1,20 +1,139 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="renderer" content="webkit" />
<meta name="force-rendering" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }}</title>
<style>
* {
padding: 0;
margin: 0;
}
</style>
</head>
<body>
<header style="padding: 1.5rem 5% 1rem; background-color: #f2f2f2"></header>
</body>
</html>
<head>
<meta charset="UTF-8" />
<meta name="renderer" content="webkit" />
<meta name="force-rendering" content="webkit" />
<meta http-equiv="X-UA-Compatible" content="IE=edge" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>{{ title }}</title>
<!--[if lt IE 9
]><script src="https://cdn.jsdelivr.net/npm/html5shiv/dist/html5shiv.min.js"></script
><![endif]-->
<style>
* {
padding: 0;
margin: 0;
border-spacing: 0;
}
a {
text-decoration: none;
color: #116fce;
}
th,
td {
text-align: left;
padding: 0.4rem 0;
white-space: nowrap;
font-size: 1rem;
border-bottom: 1px dashed #cccccc;
}
</style>
</head>
<body>
{% set paths_length = paths | length %}
<header style="padding: 1.5rem 5% 1rem; background-color: #f2f2f2">
<h1 style="font-size: 1.25rem; font-weight: normal">
<nav>
<span>
<a href="/"> / </a>
</span>
{% for path in paths %}
<span>
<a href="./{% for i in range(end=paths | length - loop.index) %}../{% endfor %}">{{ path }} /
</a>
</span>
{% endfor %}
</nav>
</h1>
</header>
<main>
<div id="meta" style="font-size: 0.75rem; padding: 1.05rem 5%">
<span style="margin-right: 1rem"><b>{{ dirs | length }}</b> directories</span>
<span><b>{{ files | length }}</b> files</span>
</div>
<div id="listing">
<table style="border-top: 1px dashed #cccccc">
<thead style="height: 3rem">
<tr>
<th style="width: 5%"></th>
<th style="width: 80%">Name</th>
<th style="padding: 0 1.25rem">Size</th>
<th class="hideable" style="text-align: right">Modified</th>
<th class="hideable" style="width: 5%"></th>
</tr>
</thead>
<tbody>
<tr>
<td style="width: 5%"></td>
<td style="width: 80%">
<a href="../"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 50 50" width="1.5rem" height="100%"
style="vertical-align: middle">
<path
d="M 25 7.21875 L 23.59375 8.65625 L 13.6875 18.53125 C 12.902344 19.316406 12.902344 20.589844 13.6875 21.375 C 14.472656 22.160156 15.746094 22.160156 16.53125 21.375 L 23 14.875 L 23 40 C 22.988281 40.722656 23.367188 41.390625 23.992188 41.753906 C 24.613281 42.121094 25.386719 42.121094 26.007813 41.753906 C 26.632813 41.390625 27.011719 40.722656 27 40 L 27 14.875 L 33.46875 21.375 C 34.253906 22.160156 35.527344 22.160156 36.3125 21.375 C 37.097656 20.589844 37.097656 19.316406 36.3125 18.53125 L 26.40625 8.65625 Z">
</path>
</svg>
<span>Go up</span></a>
</td>
<td data-order="-1" style="padding: 0 1.25rem">-</td>
<td class="hideable" style="text-align: right">-</td>
<td style="width: 5%"></td>
</tr>
{% for dir in dirs %}
<tr class="dir">
<td style="width: 5%"></td>
<td style="width: 80%">
<a href="./{{ dir.name }}"><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 48 48" width="1.5rem"
height="100%" style="vertical-align: middle">
<path fill="#FFA000" d="M40,12H22l-4-4H8c-2.2,0-4,1.8-4,4v8h40v-4C44,13.8,42.2,12,40,12z" />
<path fill="#FFCA28"
d="M40,12H8c-2.2,0-4,1.8-4,4v20c0,2.2,1.8,4,4,4h32c2.2,0,4-1.8,4-4V16C44,13.8,42.2,12,40,12z" />
</svg>
<span>{{ dir.name }}</span></a>
</td>
<td data-order="-1" style="padding: 0 1.25rem">-</td>
<td class="hideable" style="text-align: right">
{{ dir.modified }}
</td>
<td class="hideable" style="width: 5%"></td>
</tr>
{% endfor %} {% for file in files %}
<tr class="file">
<td style="width: 5%"></td>
<td style="width: 80%">
<a href="./{{ file.name }}"><svg fill="#000000" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"
width="1.5rem" height="100%" style="vertical-align: middle">
<path
d="M 6 2 C 4.9057453 2 4 2.9057453 4 4 L 4 20 C 4 21.094255 4.9057453 22 6 22 L 18 22 C 19.094255 22 20 21.094255 20 20 L 20 8 L 14 2 L 6 2 z M 6 4 L 13 4 L 13 9 L 18 9 L 18 20 L 6 20 L 6 4 z" />
</svg>
<span>{{ file.name }}</span></a>
</td>
<td data-order="-1" style="padding: 0 1.25rem">
{{ file.size | filesizeformat |
replace(from="KB", to="KiB") |
replace(from="MB", to="MiB") |
replace(from="GB", to="GiB") |
replace(from="TB", to="TiB") |
replace(from="PB", to="PiB") |
replace(from="EB", to="EiB") |
replace(from="ZB", to="ZiB") |
replace(from="YB", to="YiB") }}
</td>
<td class="hideable" style="text-align: right">
{{ file.modified }}
</td>
<td class="hideable" style="width: 5%"></td>
</tr>
{% endfor %}
<tr></tr>
</tbody>
</table>
</div>
</main>
</body>
</html>