use std::sync::Arc;
use actix_files::Files;
use actix_web::{App, HttpServer, web};
use env_logger::Env;
use log::info;
use corium::{
code::{Code, CodeVersion, Lang},
compiler::Compiler,
config,
runner::Runner,
store::DB,
};
mod routes;
#[actix_web::main]
async fn main() -> std::io::Result<()> {
let server_config = config::from_env();
env_logger::Builder::from_env(Env::default().default_filter_or(server_config.log_level())).init();
let db_path = server_config.db_path().to_string();
let db = Arc::new(DB::new(&db_path).expect("Failed to open database"));
initialize_default_endpoint(&db).await;
info!("{}", server_config);
let db_data = web::Data::new(db);
let compiler_data = web::Data::new(Arc::new(Compiler::new()));
let runner_data = web::Data::new(Arc::new(Runner::new()));
let config_data = web::Data::new(Arc::new(server_config.clone()));
let bind_address = server_config.address();
HttpServer::new(move || {
App::new()
.app_data(db_data.clone())
.app_data(compiler_data.clone())
.app_data(runner_data.clone())
.app_data(config_data.clone())
.service(Files::new("/assets", "/home/silen/code/silen/corium/assets"))
.service(routes::health)
.service(routes::up)
.configure(routes::configure_routes)
})
.bind(bind_address)?
.run()
.await
}
async fn initialize_default_endpoint(db: &Arc<DB>) {
if db.load_code("/api/hello").await.is_none() {
let compiler = Compiler::new();
let default_code = r#"fun main() {
val name = getQueryParam("name") ?: "World"
val response = """{"message": "Hello, $name!", "timestamp": "${getTimestamp()}"}"""
respond(200, response)
}
fun getQueryParam(name: String): String? {
return null
}
fun getTimestamp(): String {
return "2024-01-01T00:00:00Z"
}
fun respond(status: Int, body: String) {
println(body)
}"#;
match compiler.compile(default_code, Lang::Kotlin).await {
Ok(wasm_bytes) => {
let code = Code::new("/api/hello", default_code, Lang::Kotlin, wasm_bytes.clone());
match db.save_code(&code).await {
Ok(_) => {
let code_version = CodeVersion::new(code.id(), 1, default_code, Lang::Kotlin, wasm_bytes);
let _ = db.save_code_version(&code_version).await;
info!("Created default endpoint at /api/hello");
}
Err(e) => info!("Could not save default endpoint: {}", e),
}
}
Err(e) => {
info!("Could not compile default endpoint: {}", e);
let code = Code::new("/api/hello", default_code, Lang::Kotlin, vec![]);
match db.save_code(&code).await {
Ok(_) => {
let code_version = CodeVersion::new(code.id(), 1, default_code, Lang::Kotlin, vec![]);
let _ = db.save_code_version(&code_version).await;
}
Err(e) => info!("Could not save default endpoint: {}", e),
}
}
}
}
}