I have a project you can try:
but it might be the easiest thing to expect of someone, (plus you'll have to run src/gameserver/ which is also a cargo project, simultaneously, as thats required)
I'll show you my relevant snippets of code:
let cors = CorsLayer::new()
.allow_origin(Any)
.allow_methods([Method::GET, Method::POST])
.allow_headers(Any);
let fallback_router = routes_static(state.clone().into());
let inner = Router::new()
.route("/api/message", get(get_message))
.route("/api/nodes", get(get_nodes))
.route("/api/ws", get(ws_handler))
.route("/api/users", get(users))
.route("/api/send", post(receive_message))
.route("/api/general", post(process_general))
.route("/api/signin", post(sign_in))
.route("/api/createuser", post(create_user))
.route("/api/deleteuser", post(delete_user))
.merge(fallback_router)
.with_state(state.clone());
let app = if base_path.is_empty() || base_path == "/" {
inner.layer(cors)
} else {
Router::new().nest(&base_path, inner).layer(cors)
};
let addr: SocketAddr = LocalUrl.parse().unwrap();
println!("Listening on http://{}{}", addr, base_path);
// let addr: SocketAddr = "0.0.0.0:8081".parse().unwrap();
// println!("Listening on http://{}{}", addr, base_path);
// axum::serve(TcpListener::bind(addr).await?, app).await?;
// Updated server start:
let listener = TcpListener::bind(addr).await?;
axum::serve(listener, app.into_make_service())
.await?;
let base_path = std::env::var("SITE_URL")
.map(|s| {
let mut s = s.trim().to_string();
if !s.is_empty() {
if !s.starts_with('/') { s.insert(0, '/'); }
if s.ends_with('/') && s != "/" { s.pop(); }
}
s
})
.unwrap_or_default();
^ this is just the main function, the rest is:
async fn serve_html_with_replacement(
file: &str,
state: &AppState,
) -> Result<Response<Body>, StatusCode> {
let path = Path::new("src/svelte/dist").join(file);
if path.extension().and_then(|e| e.to_str()) == Some("html") {
let html = tokio_fs::read_to_string(&path)
.await
.map_err(|_| StatusCode::INTERNAL_SERVER_ERROR)?;
let replaced = html.replace("[[SITE_URL]]", &state.base_path);
return Ok(Html(replaced).into_response());
}
let bytes = tokio_fs::read(&path)
.await
.map_err(|_| StatusCode::NOT_FOUND)?;
let content_type = from_path(&path).first_or_octet_stream().to_string();
Ok(Response::builder()
.header("Content-Type", content_type)
.body(Body::from(bytes))
.unwrap())
}
async fn handle_static_request(
Extension(state): Extension<Arc<AppState>>,
req: Request<Body>,
) -> Result<Response<Body>, StatusCode> {
let mut path = req.uri().path().to_string();
let base_path = &state.base_path;
// if let Some(stripped) = path.strip_prefix(base_path) {
// path = stripped.to_string();
// }
let file = if path == "/" || path.is_empty() {
"index.html".to_string()
} else {
path.trim_start_matches('/').to_string()
};
match serve_html_with_replacement(&file, &state).await {
Ok(res) => Ok(res),
Err(status) => Ok(Response::builder()
.status(status)
.header("content-type", "text/plain")
.body(format!("Error serving `{}`", file).into())
.unwrap()),
}
}
Not that short, but I hope easy to read, now the main issue I am having is, again, I dont know how to dynamically tell svelte where the base path is, i explained how i substituted it with html, but svelte bundles their own stuff, which you could control over some statically set stuff, but thats not what I want, I was hoping I could fix this in the backend, in my main function you can see how i nest everything under the base path
, so everything will be there, so when svelte asks for a asset at http://localhost:8080/_app there is a immediate issue, in the backend, I am wondering how I could give svelte access to its assets by re-routing the requests, (preferably not making the entire site accessible without the gameserver prefix but at this point ill take anything). Or some substitution method, I was suggested two things:
alternatively create a [...rest]
endpoint in sveltekit and proxy the other routes to your backend
Issue with 1, ill need to run another process simultaneously, issue with 2, I dont think itll work for internal assets like under _app? I tried to keep this purely rust based, and while the solution could be in rust, i might need help will how I approach this whole thinf