parent
5ace6fbdfb
commit
f12e1ffc8f
18
Cargo.toml
18
Cargo.toml
|
@ -1,12 +1,10 @@
|
||||||
[package]
|
[workspace]
|
||||||
name = "vanten-s"
|
|
||||||
version = "0.1.0"
|
|
||||||
edition = "2021"
|
|
||||||
|
|
||||||
[dependencies]
|
resolver = "2"
|
||||||
log = "0.4.22"
|
|
||||||
wasm-logger = "0.2.0"
|
|
||||||
web-sys = "0.3.76"
|
|
||||||
# this is the development version of Yew
|
|
||||||
yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] }
|
|
||||||
|
|
||||||
|
default-members = [ "backend" ]
|
||||||
|
|
||||||
|
members = [
|
||||||
|
"backend",
|
||||||
|
"frontend"
|
||||||
|
]
|
||||||
|
|
10
backend/Cargo.toml
Normal file
10
backend/Cargo.toml
Normal file
|
@ -0,0 +1,10 @@
|
||||||
|
[package]
|
||||||
|
name = "backend"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
actix-files = "0.6.6"
|
||||||
|
actix-web = "4.9.0"
|
||||||
|
env_logger = "0.11.6"
|
||||||
|
tokio = { version = "1.42.0", features = ["full"] }
|
16
backend/src/main.rs
Normal file
16
backend/src/main.rs
Normal file
|
@ -0,0 +1,16 @@
|
||||||
|
use actix_files::Files;
|
||||||
|
use actix_web::{middleware::Logger, App, HttpServer};
|
||||||
|
|
||||||
|
#[actix_web::main]
|
||||||
|
async fn main() -> std::io::Result<()> {
|
||||||
|
env_logger::init_from_env(env_logger::Env::new().default_filter_or("info"));
|
||||||
|
HttpServer::new(|| {
|
||||||
|
App::new()
|
||||||
|
.wrap(Logger::default())
|
||||||
|
.service(Files::new("/fs", "fs").index_file("index.html"))
|
||||||
|
.service(Files::new("/", "dist").index_file("index.html"))
|
||||||
|
})
|
||||||
|
.bind(("127.0.0.1", 8080))?
|
||||||
|
.run()
|
||||||
|
.await
|
||||||
|
}
|
14
frontend/Cargo.toml
Normal file
14
frontend/Cargo.toml
Normal file
|
@ -0,0 +1,14 @@
|
||||||
|
[package]
|
||||||
|
name = "vanten-s"
|
||||||
|
version = "0.1.0"
|
||||||
|
edition = "2021"
|
||||||
|
|
||||||
|
[dependencies]
|
||||||
|
log = "0.4.22"
|
||||||
|
wasm-logger = "0.2.0"
|
||||||
|
web-sys = "0.3.76"
|
||||||
|
yew = { git = "https://github.com/yewstack/yew/", features = ["csr"] }
|
||||||
|
serde-wasm-bindgen = "0.6.5"
|
||||||
|
wasm-bindgen-futures = "0.4.49"
|
||||||
|
futures = "0.3.31"
|
||||||
|
|
|
@ -16,6 +16,7 @@ body {
|
||||||
font: inherit;
|
font: inherit;
|
||||||
padding: 0;
|
padding: 0;
|
||||||
border: none;
|
border: none;
|
||||||
|
width: max;
|
||||||
}
|
}
|
||||||
|
|
||||||
.input:focus {
|
.input:focus {
|
78
frontend/src/commands/cat.rs
Normal file
78
frontend/src/commands/cat.rs
Normal file
|
@ -0,0 +1,78 @@
|
||||||
|
use std::sync::Arc;
|
||||||
|
|
||||||
|
use wasm_bindgen_futures::{spawn_local, JsFuture};
|
||||||
|
use web_sys::{console, wasm_bindgen::UnwrapThrowExt, window, Response};
|
||||||
|
use super::{Environment, Handle, Rader};
|
||||||
|
|
||||||
|
#[derive(Clone)]
|
||||||
|
struct Fetcher {
|
||||||
|
next: Option<Arc<Fetcher>>,
|
||||||
|
filename: String,
|
||||||
|
previous_text: String,
|
||||||
|
rader: Rader,
|
||||||
|
handle: Handle
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cat(mut env: Environment) {
|
||||||
|
if env.arguments.len() == 1 {
|
||||||
|
env.rader.push("cat: no filename provided\n".to_string());
|
||||||
|
env.handle.set(env.rader);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut previous_fetcher = None;
|
||||||
|
for filename in env.arguments[1..].iter().rev() {
|
||||||
|
let next_fetcher = Fetcher {
|
||||||
|
next: previous_fetcher,
|
||||||
|
filename: filename.to_string(),
|
||||||
|
previous_text: String::new(),
|
||||||
|
rader: env.rader.clone(),
|
||||||
|
handle: env.handle.clone(),
|
||||||
|
};
|
||||||
|
previous_fetcher = Some(Arc::new(next_fetcher));
|
||||||
|
}
|
||||||
|
|
||||||
|
spawn_local(fetch((*previous_fetcher.unwrap_throw()).clone()));
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch(mut fetcher: Fetcher) {
|
||||||
|
let text = fetch_single_file(fetcher.filename).await;
|
||||||
|
|
||||||
|
let text = fetcher.previous_text + &text;
|
||||||
|
|
||||||
|
if let Some(fetcher) = fetcher.next {
|
||||||
|
let mut fetcher = (*fetcher).clone();
|
||||||
|
fetcher.previous_text = text;
|
||||||
|
Box::pin(fetch(fetcher.clone())).await
|
||||||
|
} else {
|
||||||
|
fetcher.rader.push(text.clone());
|
||||||
|
fetcher.handle.set(fetcher.rader);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async fn fetch_single_file(filename: String) -> String {
|
||||||
|
let resource = format!("/fs/{filename}");
|
||||||
|
|
||||||
|
let window = window().unwrap_throw();
|
||||||
|
|
||||||
|
console::log_1(&"Got Window".into());
|
||||||
|
|
||||||
|
let future: JsFuture = window.fetch_with_str(&resource).into();
|
||||||
|
let response = future.await.unwrap_throw();
|
||||||
|
let response = Response::from(response);
|
||||||
|
|
||||||
|
if response.status() == 404 {
|
||||||
|
return format!("cat: {filename}: No such file or directory\n");
|
||||||
|
}
|
||||||
|
|
||||||
|
console::log_1(&"Got Response".into());
|
||||||
|
|
||||||
|
let text: JsFuture = response.text().unwrap_throw().into();
|
||||||
|
let text = text.await.unwrap_throw();
|
||||||
|
let text = text.as_string().unwrap_throw();
|
||||||
|
|
||||||
|
console::log_1(&"Got Text".into());
|
||||||
|
|
||||||
|
text
|
||||||
|
}
|
5
frontend/src/commands/clear.rs
Normal file
5
frontend/src/commands/clear.rs
Normal file
|
@ -0,0 +1,5 @@
|
||||||
|
use super::Environment;
|
||||||
|
|
||||||
|
pub fn clear(env: Environment) {
|
||||||
|
env.handle.set(vec![]);
|
||||||
|
}
|
12
frontend/src/commands/echo.rs
Normal file
12
frontend/src/commands/echo.rs
Normal file
|
@ -0,0 +1,12 @@
|
||||||
|
use super::Environment;
|
||||||
|
|
||||||
|
pub fn echo(mut env: Environment) {
|
||||||
|
let mut text = "".to_string();
|
||||||
|
for argument in &env.arguments[1..] {
|
||||||
|
text += argument;
|
||||||
|
text += " ";
|
||||||
|
};
|
||||||
|
text += "\n";
|
||||||
|
env.rader.push(text);
|
||||||
|
env.handle.set(env.rader);
|
||||||
|
}
|
45
frontend/src/commands/mod.rs
Normal file
45
frontend/src/commands/mod.rs
Normal file
|
@ -0,0 +1,45 @@
|
||||||
|
use log::{error, info};
|
||||||
|
use yew::UseStateHandle;
|
||||||
|
|
||||||
|
mod clear;
|
||||||
|
mod cat;
|
||||||
|
mod echo;
|
||||||
|
|
||||||
|
pub type Rader = Vec<String>;
|
||||||
|
pub type Handle = UseStateHandle<Rader>;
|
||||||
|
|
||||||
|
struct Environment<'a> {
|
||||||
|
pub rader: Rader,
|
||||||
|
pub handle: Handle,
|
||||||
|
pub arguments: Vec<&'a str>,
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn run(command: String, rader: Rader, handle: Handle) {
|
||||||
|
let arguments = command.trim().split_whitespace().collect::<Vec<_>>();
|
||||||
|
|
||||||
|
info!("{:?}", arguments);
|
||||||
|
|
||||||
|
if arguments.len() == 0 {
|
||||||
|
handle.set(rader);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
let environment = Environment {
|
||||||
|
rader,
|
||||||
|
handle,
|
||||||
|
arguments,
|
||||||
|
};
|
||||||
|
|
||||||
|
match environment.arguments[0] {
|
||||||
|
"clear" => clear::clear(environment),
|
||||||
|
"cat" => cat::cat(environment),
|
||||||
|
"echo" => echo::echo(environment),
|
||||||
|
_ => unrecognized_command(environment),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn unrecognized_command(mut env: Environment) {
|
||||||
|
env.rader.push(format!("vsh: {}: command not found\n", env.arguments[0]));
|
||||||
|
env.handle.set(env.rader);
|
||||||
|
error!("Unrecognized Command");
|
||||||
|
}
|
|
@ -20,9 +20,8 @@ fn App() -> Html {
|
||||||
info!("{}", rad);
|
info!("{}", rad);
|
||||||
let handle = rader_handle.clone();
|
let handle = rader_handle.clone();
|
||||||
let mut val = (*handle).clone();
|
let mut val = (*handle).clone();
|
||||||
val.push(get_prompt() + &rad);
|
val.push(get_prompt() + &rad + "\n");
|
||||||
val = commands::run(rad, val);
|
commands::run(rad, val, handle);
|
||||||
rader_handle.set(val);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
html! {
|
html! {
|
||||||
|
@ -73,8 +72,7 @@ fn Terminal(props: &TerminalProps) -> Html {
|
||||||
.map(|rad| {
|
.map(|rad| {
|
||||||
html! {
|
html! {
|
||||||
<>
|
<>
|
||||||
<code><wbr /> { rad } </code>
|
<code> { rad } </code>
|
||||||
<br />
|
|
||||||
</>
|
</>
|
||||||
}
|
}
|
||||||
})
|
})
|
1
fs/hihi.txt
Normal file
1
fs/hihi.txt
Normal file
|
@ -0,0 +1 @@
|
||||||
|
:3
|
|
@ -3,7 +3,10 @@
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8" />
|
<meta charset="utf-8" />
|
||||||
<title>Yew App</title>
|
<title>Yew App</title>
|
||||||
<link data-trunk rel="css" href="main.css"/>
|
<link data-trunk rel="css" href="frontend/main.css"/>
|
||||||
</head>
|
</head>
|
||||||
<body></body>
|
<body>
|
||||||
|
<link data-trunk rel="rust" data-type="main" href="frontend/Cargo.toml"/>
|
||||||
|
<link data-trunk rel="copy-dir" href="fs/"/>
|
||||||
|
</body>
|
||||||
</html>
|
</html>
|
||||||
|
|
|
@ -1,3 +0,0 @@
|
||||||
pub fn clear(_rader: Vec<String>) -> Vec<String> {
|
|
||||||
return vec![];
|
|
||||||
}
|
|
|
@ -1,17 +0,0 @@
|
||||||
use log::error;
|
|
||||||
|
|
||||||
mod clear;
|
|
||||||
|
|
||||||
pub fn run(command: String, rader: Vec<String>) -> Vec<String> {
|
|
||||||
match command.as_str() {
|
|
||||||
"" => rader,
|
|
||||||
"clear" => clear::clear(rader),
|
|
||||||
unrecognized => unrecognized_command(unrecognized, rader),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn unrecognized_command(command: &str, mut rader: Vec<String>) -> Vec<String> {
|
|
||||||
rader.push(format!("Unrecognized Command \"{command}\""));
|
|
||||||
error!("Unrecognized Command");
|
|
||||||
rader
|
|
||||||
}
|
|
Loading…
Reference in a new issue