Create a web server to begin the Visions VTT application #110

Merged
savanni merged 4 commits from visions into main 2023-12-04 02:42:05 +00:00
13 changed files with 2246 additions and 13 deletions

6
.gitignore vendored
View File

@ -5,7 +5,7 @@ dist
result result
*.tgz *.tgz
*.tar.gz *.tar.gz
file-service/*.sqlite *.sqlite
file-service/*.sqlite-shm *.sqlite-shm
file-service/*.sqlite-wal *.sqlite-wal
file-service/var file-service/var

43
Cargo.lock generated
View File

@ -937,7 +937,7 @@ dependencies = [
"cool_asserts", "cool_asserts",
"futures-util", "futures-util",
"hex-string", "hex-string",
"http", "http 0.2.9",
"image 0.23.14", "image 0.23.14",
"log 0.4.20", "log 0.4.20",
"logger", "logger",
@ -1597,7 +1597,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-sink", "futures-sink",
"futures-util", "futures-util",
"http", "http 0.2.9",
"indexmap 1.9.3", "indexmap 1.9.3",
"slab", "slab",
"tokio", "tokio",
@ -1648,7 +1648,7 @@ dependencies = [
"base64 0.21.4", "base64 0.21.4",
"bytes", "bytes",
"headers-core", "headers-core",
"http", "http 0.2.9",
"httpdate", "httpdate",
"mime 0.3.17", "mime 0.3.17",
"sha1", "sha1",
@ -1660,7 +1660,7 @@ version = "0.2.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429" checksum = "e7f66481bfee273957b1f20485a4ff3362987f85b2c236580d81b4eb7a326429"
dependencies = [ dependencies = [
"http", "http 0.2.9",
] ]
[[package]] [[package]]
@ -1741,6 +1741,17 @@ dependencies = [
"itoa", "itoa",
] ]
[[package]]
name = "http"
version = "1.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "b32afd38673a8016f7c9ae69e5af41a58f81b1d31689040f2f1959594ce194ea"
dependencies = [
"bytes",
"fnv",
"itoa",
]
[[package]] [[package]]
name = "http-body" name = "http-body"
version = "0.4.5" version = "0.4.5"
@ -1748,7 +1759,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1" checksum = "d5f38f16d184e36f2408a55281cd658ecbd3ca05cce6d6510a176eca393e26d1"
dependencies = [ dependencies = [
"bytes", "bytes",
"http", "http 0.2.9",
"pin-project-lite", "pin-project-lite",
] ]
@ -1800,7 +1811,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.9",
"http-body", "http-body",
"httparse", "httparse",
"httpdate", "httpdate",
@ -2337,7 +2348,7 @@ dependencies = [
"bytes", "bytes",
"encoding_rs", "encoding_rs",
"futures-util", "futures-util",
"http", "http 0.2.9",
"httparse", "httparse",
"log 0.4.20", "log 0.4.20",
"memchr", "memchr",
@ -3204,7 +3215,7 @@ dependencies = [
"futures-core", "futures-core",
"futures-util", "futures-util",
"h2", "h2",
"http", "http 0.2.9",
"http-body", "http-body",
"hyper 0.14.27", "hyper 0.14.27",
"hyper-tls", "hyper-tls",
@ -4296,7 +4307,7 @@ dependencies = [
"byteorder", "byteorder",
"bytes", "bytes",
"data-encoding", "data-encoding",
"http", "http 0.2.9",
"httparse", "httparse",
"log 0.4.20", "log 0.4.20",
"rand 0.8.5", "rand 0.8.5",
@ -4541,6 +4552,18 @@ version = "0.9.4"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f"
[[package]]
name = "visions"
version = "0.1.0"
dependencies = [
"authdb",
"http 1.0.0",
"serde 1.0.188",
"serde_json",
"tokio",
"warp",
]
[[package]] [[package]]
name = "void" name = "void"
version = "1.0.2" version = "1.0.2"
@ -4584,7 +4607,7 @@ dependencies = [
"futures-channel", "futures-channel",
"futures-util", "futures-util",
"headers", "headers",
"http", "http 0.2.9",
"hyper 0.14.27", "hyper 0.14.27",
"log 0.4.20", "log 0.4.20",
"mime 0.3.17", "mime 0.3.17",

View File

@ -24,4 +24,5 @@ members = [
"screenplay", "screenplay",
"sgf", "sgf",
"tree", "tree",
"visions/server",
] ]

14
visions/server/Cargo.toml Normal file
View File

@ -0,0 +1,14 @@
[package]
name = "visions"
version = "0.1.0"
edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
authdb = { path = "../../authdb/" }
http = { version = "1" }
serde_json = { version = "*" }
serde = { version = "1" }
tokio = { version = "1", features = [ "full" ] }
warp = { version = "0.3" }

View File

@ -0,0 +1,24 @@
use authdb::{AuthDB, AuthToken};
use http::{response::Response, status::StatusCode, Error};
pub async fn handle_auth(
auth_ctx: &AuthDB,
auth_token: AuthToken,
) -> Result<http::Response<String>, Error> {
match auth_ctx.authenticate(auth_token).await {
Ok(Some(session)) => match serde_json::to_string(&session) {
Ok(session_token) => Response::builder()
.status(StatusCode::OK)
.body(session_token),
Err(_) => Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body("".to_owned()),
},
Ok(None) => Response::builder()
.status(StatusCode::UNAUTHORIZED)
.body("".to_owned()),
Err(_) => Response::builder()
.status(StatusCode::INTERNAL_SERVER_ERROR)
.body("".to_owned()),
}
}

105
visions/server/src/main.rs Normal file
View File

@ -0,0 +1,105 @@
use authdb::{AuthDB, AuthError, AuthToken, SessionToken, Username};
use std::{
convert::Infallible,
net::{IpAddr, Ipv4Addr, SocketAddr},
path::PathBuf,
sync::Arc,
};
use warp::{
header,
http::StatusCode,
reply::{Json, Reply},
Filter,
};
mod handlers;
use handlers::handle_auth;
#[derive(Debug)]
struct Unauthorized;
impl warp::reject::Reject for Unauthorized {}
#[derive(Debug)]
struct AuthDBError(AuthError);
impl warp::reject::Reject for AuthDBError {}
fn with_session(
auth_ctx: Arc<AuthDB>,
) -> impl Filter<Extract = (Username,), Error = warp::Rejection> + Clone {
header("authentication").and_then({
move |value: String| {
let auth_ctx = auth_ctx.clone();
async move {
match auth_ctx.validate_session(SessionToken::from(value)).await {
Ok(Some(username)) => Ok(username),
Ok(None) => Err(warp::reject::custom(Unauthorized)),
Err(err) => Err(warp::reject::custom(AuthDBError(err))),
}
}
}
})
}
fn route_echo_unauthenticated() -> impl Filter<Extract = (Json,), Error = warp::Rejection> + Clone {
warp::path!("api" / "v1" / "echo" / String).map(|param: String| {
println!("param: {}", param);
warp::reply::json(&vec!["unauthenticated", param.as_str()])
})
}
fn route_authenticate(
auth_ctx: Arc<AuthDB>,
) -> impl Filter<Extract = (Json,), Error = warp::Rejection> + Clone {
let auth_ctx = auth_ctx.clone();
warp::path!("api" / "v1" / "auth")
.and(warp::post())
.and(warp::body::json())
.map(move |param: AuthToken| {
let res = handle_auth(&auth_ctx, param.clone());
warp::reply::json(&param)
})
}
fn route_echo_authenticated(
auth_ctx: Arc<AuthDB>,
) -> impl Filter<Extract = (Json,), Error = warp::Rejection> + Clone {
warp::path!("api" / "v1" / "echo" / String)
.and(with_session(auth_ctx.clone()))
.map(move |param: String, username: Username| {
println!("param: {:?}", username);
println!("param: {}", param);
warp::reply::json(&vec!["authenticated", username.as_str(), param.as_str()])
})
}
async fn handle_rejection(err: warp::Rejection) -> Result<impl Reply, Infallible> {
if let Some(Unauthorized) = err.find() {
Ok(warp::reply::with_status(
"".to_owned(),
StatusCode::UNAUTHORIZED,
))
} else {
Ok(warp::reply::with_status(
"".to_owned(),
StatusCode::INTERNAL_SERVER_ERROR,
))
}
}
#[tokio::main]
pub async fn main() {
let auth_db = AuthDB::new(PathBuf::from("./auth_db.sqlite"))
.await
.expect("AuthDB should initialize");
let auth_ctx: Arc<AuthDB> = Arc::new(auth_db);
let filter = route_echo_authenticated(auth_ctx.clone())
.or(route_authenticate(auth_ctx.clone()))
.or(route_echo_unauthenticated())
.recover(handle_rejection);
let server = warp::serve(filter);
server
.run(SocketAddr::new(IpAddr::V4(Ipv4Addr::new(0, 0, 0, 0)), 8001))
.await;
}

10
visions/ui/Makefile Normal file
View File

@ -0,0 +1,10 @@
release:
NODE_ENV=production npm run build
dev:
npm run build
server:
npx http-server ./dist

1991
visions/ui/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

24
visions/ui/package.json Normal file
View File

@ -0,0 +1,24 @@
{
"name": "ui",
"version": "1.0.0",
"description": "",
"main": "webpack.config.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1",
"build": "webpack"
},
"author": "",
"license": "GPL-3.0-or-later",
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
},
"devDependencies": {
"@types/react": "^18.2.8",
"@types/react-dom": "^18.2.4",
"copy-webpack-plugin": "^11.0.0",
"ts-loader": "^9.4.3",
"webpack": "^5.85.0",
"webpack-cli": "^5.1.3"
}
}

View File

@ -0,0 +1,6 @@
<!doctype html>
<html>
<body>
<div id="root"></div>
</body>
</html>

11
visions/ui/src/main.tsx Normal file
View File

@ -0,0 +1,11 @@
import React from "react";
import ReactDOM from "react-dom";
const App = () => <div>App</div>;
ReactDOM.render(
<React.StrictMode>
<App />
</React.StrictMode>,
document.getElementById("root")
);

View File

View File

@ -0,0 +1,24 @@
const CopyWebpackPlugin = require('copy-webpack-plugin');
module.exports = {
mode: "development",
entry: {
"main": "./src/main.tsx"
},
module: {
rules: [
{ test: /\.tsx?$/, use: "ts-loader", exclude: /node_modules/ }
]
},
plugins: [
new CopyWebpackPlugin({
patterns: [
{ from: "src/index.html" },
{ from: "src/visions.css" },
]
})
],
resolve: {
extensions: ['.ts', '.tsx'],
}
}