use serde_json::json;
pub(crate) fn rust_template_cargo_toml(name: &str) -> String {
format!(
"[package]\nname = \"{name}\"\nversion = \"0.1.0\"\nedition = \"2024\"\npublish = false\n\n[dependencies]\nsocket2 = \"0.6.4\"\n\n[lints.rust]\nunsafe_code = \"forbid\"\nwarnings = \"deny\"\n\n[lints.clippy]\nall = {{ level = \"deny\", priority = -1 }}\npedantic = {{ level = \"deny\", priority = -1 }}\ndbg_macro = \"deny\"\ntodo = \"deny\"\nunimplemented = \"deny\"\npanic = \"deny\"\nunwrap_used = \"deny\"\nexpect_used = \"deny\"\nlarge_futures = \"deny\"\nlarge_include_file = \"deny\"\nlarge_stack_frames = \"deny\"\nmem_forget = \"deny\"\nrc_buffer = \"deny\"\nrc_mutex = \"deny\"\nredundant_clone = \"deny\"\nclone_on_ref_ptr = \"deny\"\n"
)
}
pub(crate) fn rust_template_cargo_lock(name: &str) -> String {
format!(
"# This file is automatically @generated by Cargo.\n# It is not intended for manual editing.\nversion = 4\n\n[[package]]\nname = \"{name}\"\nversion = \"0.1.0\"\ndependencies = [\n \"socket2\",\n]\n\n[[package]]\nname = \"libc\"\nversion = \"0.2.186\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"68ab91017fe16c622486840e4c83c9a37afeff978bd239b5293d61ece587de66\"\n\n[[package]]\nname = \"socket2\"\nversion = \"0.6.4\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"52d1cfed4120b4d927bf7c0f86d2087a4a7d6027c906d9f9d525a80573b9be51\"\ndependencies = [\n \"libc\",\n \"windows-sys\",\n]\n\n[[package]]\nname = \"windows-link\"\nversion = \"0.2.1\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"f0805222e57f7521d6a62e36fa9163bc891acd422f971defe97d64e70d0a4fe5\"\n\n[[package]]\nname = \"windows-sys\"\nversion = \"0.61.2\"\nsource = \"registry+https://github.com/rust-lang/crates.io-index\"\nchecksum = \"ae137229bcbd6cdf0f7b80a31df61766145077ddf49416a728b02cb3921ff3fc\"\ndependencies = [\n \"windows-link\",\n]\n"
)
}
pub(crate) fn frontend_package_json(name: &str) -> String {
serde_json::to_string_pretty(&json!({
"name": name,
"private": true,
"type": "module",
"scripts": {
"typecheck": "oxlint src vite.config.ts --deny-warnings --type-aware --type-check --tsconfig tsconfig.json",
"lint": "oxlint src vite.config.ts --deny-warnings && fallow dead-code --production --include-dupes --include-entry-exports --fail-on-issues && fallow dupes --production --mode semantic --threshold 1 --ignore-imports --fail-on-issues && fallow health --production --max-cyclomatic 10 --max-cognitive 15 --max-crap 20 --complexity",
"build": "vite build",
"preview": "vite preview --host 0.0.0.0"
},
"dependencies": {
"@tanstack/react-router": "^1.170.8",
"react": "^19.2.6",
"react-dom": "^19.2.6"
},
"devDependencies": {
"@types/node": "^25.9.1",
"@types/react": "^19.2.15",
"@types/react-dom": "^19.2.3",
"@vitejs/plugin-react": "^6.0.2",
"fallow": "^2.84.0",
"oxlint": "^1.67.0",
"oxlint-tsgolint": "^0.23.0",
"vite": "^8.0.14"
}
}))
.map_or_else(|_error| "{}\n".to_owned(), |source| format!("{source}\n"))
}
pub(crate) fn frontend_ts_config() -> String {
serde_json::to_string_pretty(&json!({
"compilerOptions": {
"allowUnreachableCode": false,
"allowUnusedLabels": false,
"alwaysStrict": true,
"erasableSyntaxOnly": true,
"exactOptionalPropertyTypes": true,
"forceConsistentCasingInFileNames": true,
"isolatedModules": true,
"jsx": "react-jsx",
"lib": ["ESNext", "DOM"],
"module": "ESNext",
"moduleDetection": "force",
"moduleResolution": "Bundler",
"noEmit": true,
"noFallthroughCasesInSwitch": true,
"noImplicitAny": true,
"noImplicitOverride": true,
"noImplicitReturns": true,
"noImplicitThis": true,
"noPropertyAccessFromIndexSignature": true,
"noUncheckedIndexedAccess": true,
"noUncheckedSideEffectImports": true,
"noUnusedLocals": true,
"noUnusedParameters": true,
"skipLibCheck": false,
"strict": true,
"strictBindCallApply": true,
"strictFunctionTypes": true,
"strictNullChecks": true,
"strictPropertyInitialization": true,
"target": "ES2022",
"types": ["vite/client", "node"],
"useUnknownInCatchVariables": true,
"verbatimModuleSyntax": true
},
"include": ["src", "vite.config.ts"]
}))
.map_or_else(|_error| "{}\n".to_owned(), |source| format!("{source}\n"))
}
pub(crate) fn rust_api_source() -> &'static str {
RUST_API_SOURCE
}
const RUST_API_SOURCE: &str = r##"use std::{
io::{Read, Write},
net::{SocketAddr, TcpListener, TcpStream},
thread,
time::Duration,
};
use socket2::{Domain, Protocol, SockAddr, Socket, Type};
const LISTEN_BACKLOG: i32 = 1024;
const MIN_WORKER_THREADS: usize = 8;
const MAX_WORKER_THREADS: usize = 128;
fn main() -> std::io::Result<()> {
let port = std::env::var("PORT")
.ok()
.and_then(|value| value.parse::<u16>().ok())
.unwrap_or(3000);
let listener = bind_listener(port)?;
let worker_count = thread::available_parallelism().map_or(MIN_WORKER_THREADS, |count| {
count.get().clamp(MIN_WORKER_THREADS, MAX_WORKER_THREADS)
});
let mut workers = Vec::with_capacity(worker_count);
for _index in 0..worker_count {
let worker_listener = listener.try_clone()?;
workers.push(thread::spawn(move || accept_loop(&worker_listener)));
}
for worker in workers {
match worker.join() {
Ok(Ok(())) => {}
Ok(Err(error)) => return Err(error),
Err(_panic) => return Err(std::io::Error::other("request worker thread failed")),
}
}
Ok(())
}
fn bind_listener(port: u16) -> std::io::Result<TcpListener> {
let address = SocketAddr::from(([0, 0, 0, 0], port));
let socket = Socket::new(Domain::IPV4, Type::STREAM, Some(Protocol::TCP))?;
socket.set_reuse_address(true)?;
socket.bind(&SockAddr::from(address))?;
socket.listen(LISTEN_BACKLOG)?;
Ok(socket.into())
}
fn accept_loop(listener: &TcpListener) -> std::io::Result<()> {
for stream in listener.incoming() {
match stream {
Ok(stream) => {
if let Err(error) = handle(stream) {
eprintln!("request failed: {error}");
}
}
Err(error) if error.kind() == std::io::ErrorKind::Interrupted => {}
Err(error) => return Err(error),
}
}
Ok(())
}
fn handle(mut stream: TcpStream) -> std::io::Result<()> {
stream.set_read_timeout(Some(Duration::from_secs(5)))?;
stream.set_write_timeout(Some(Duration::from_secs(5)))?;
let mut buffer = [0_u8; 2048];
let size = stream.read(&mut buffer)?;
let request = String::from_utf8_lossy(&buffer[..size]);
let mut parts = request
.lines()
.next()
.unwrap_or_default()
.split_whitespace();
let method = parts.next().unwrap_or_default();
let path = parts.next().unwrap_or("/");
let origin = request
.lines()
.find_map(|line| line.strip_prefix("Origin: "))
.unwrap_or("*");
let cors_origin = allowed_origin(origin);
if method == "OPTIONS" {
return write_response(&mut stream, "204 No Content", "", &cors_origin);
}
let body = if path == "/healthz" || path == "/api/healthz" {
r#"{"ok":true}"#
} else if method == "POST" && path.starts_with("/.tovuk/queues/") {
r#"{"ok":true,"event":"queue"}"#
} else if method == "POST" && path.starts_with("/.tovuk/cron/") {
r#"{"ok":true,"event":"cron"}"#
} else {
r#"{"message":"hello from tovuk","worker":"rust"}"#
};
write_response(&mut stream, "200 OK", body, &cors_origin)
}
fn allowed_origin(request_origin: &str) -> String {
let configured =
std::env::var("FRONTEND_ORIGIN").unwrap_or_else(|_error| request_origin.to_owned());
if configured == "*" || configured == request_origin {
configured
} else {
"null".to_owned()
}
}
fn write_response(
stream: &mut TcpStream,
status: &str,
body: &str,
origin: &str,
) -> std::io::Result<()> {
write!(
stream,
"HTTP/1.1 {status}\r\ncontent-type: application/json\r\ncontent-length: {}\r\naccess-control-allow-origin: {origin}\r\naccess-control-allow-methods: GET, POST, OPTIONS\r\naccess-control-allow-headers: content-type, authorization\r\nconnection: close\r\n\r\n{body}",
body.len()
)
}
"##;
pub(crate) fn frontend_source(api_base_url: &str) -> String {
format!(
"import {{ createRootRoute, createRouter, RouterProvider }} from '@tanstack/react-router'\nimport {{ createRoot }} from 'react-dom/client'\nimport './styles.css'\n\nconst apiBaseUrl = import.meta.env.VITE_API_URL ?? '{api_base_url}'\n\nfunction App() {{\n return (\n <main>\n <section>\n <h1>Tovuk TanStack Frontend</h1>\n <p>Static runtime, dynamic Rust worker calls.</p>\n <code>{{apiBaseUrl}}</code>\n </section>\n </main>\n )\n}}\n\nconst rootRoute = createRootRoute({{ component: App }})\nconst router = createRouter({{ routeTree: rootRoute }})\n\ndeclare module '@tanstack/react-router' {{\n interface Register {{\n router: typeof router\n }}\n}}\n\nconst rootElement = document.getElementById('root')\nif (rootElement === null) {{\n throw new Error('missing root element')\n}}\n\ncreateRoot(rootElement).render(<RouterProvider router={{router}} />)\n"
)
}
pub(crate) fn frontend_vite_env_source() -> &'static str {
"/// <reference types=\"vite/client\" />\n\ninterface ViteTypeOptions {\n strictImportMetaEnv: unknown\n}\n\ninterface ImportMetaEnv {\n readonly VITE_API_URL?: string\n}\n"
}