Skip to content

Instantly share code, notes, and snippets.

@ethereumdegen
Last active June 3, 2023 23:40
Show Gist options
  • Save ethereumdegen/e5d1d6886e75de0bfc9fe0168f8ffc35 to your computer and use it in GitHub Desktop.
Save ethereumdegen/e5d1d6886e75de0bfc9fe0168f8ffc35 to your computer and use it in GitHub Desktop.
Actix webserver wrapper (controllers)
use actix_web::{web, HttpRequest, HttpResponse, Responder};
use std::future::{Future};
use std::pin::Pin;
use futures::future::BoxFuture;
use std::sync::Arc;
use crate::lib::web_server::{WebServerResources};
pub trait JsonInput: serde::de::DeserializeOwned {}
impl<T: serde::de::DeserializeOwned> JsonInput for T {}
#[derive(Clone)]
pub enum RequestType {
Get,
Post // { JsonData :T }
}
#[derive(Clone)]
pub struct Route<T> {
pub path: &'static str,
pub handler: RouteHandler<T>,
pub request_type: RequestType,
}
// handler: Box<dyn Fn(HttpRequest, web::Json<T>) -> impl Responder>,
/*
pub async fn client_register(
input: web::Json<ClientRegisterInputData>,
res: web::Data<GridServerResources>,
) -> impl Responder {
*/
// Assuming this is the signature of your handlers.
//pub type RouteHandler = fn(HttpRequest) -> Pin<Box<dyn Future<Output = Result<HttpResponse, actix_web::Error>>>>;
//pub type RouteHandler = fn(web::Data<HttpRequest>) -> Pin<Box<dyn Future<Output = Result<HttpResponse, actix_web::Error>>>>;
//pub type RouteHandler = fn(web::Data<HttpRequest>) -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>>;
/*
pub type RouteHandler<T> = Arc<Box< dyn Fn(
Arc<web::Data<WebServerResources>>,
HttpRequest,
web::json<T>
)> > -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>> + Send + Sync>;
*/
pub type RouteHandler<T> = Arc<Box<dyn Fn(
Arc<web::Data<WebServerResources>>,
HttpRequest,
web::Json<T>,
) -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>> + Send + Sync>>;
//pub type RouteHandler = Arc<dyn Fn(Arc<web::Data<WebServerResources>>, web::Json<MyData>, HttpRequest) -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>> + Send + Sync>;
//pub type RouteHandler = fn(HttpRequest) -> impl futures::Future<Output = HttpResponse> ;
pub trait ApiController {
fn get_routes(&self) -> Vec<Route<Box<dyn JsonInput>>>;
}
/*
pub struct Route {
path: &'static str,
handler: Box<dyn Fn(_, _, _) -> _>,
}
impl Route {
pub fn new<T, F>(path: &'static str, handler: F) -> Self
where
T: serde::de::DeserializeOwned + 'static,
F: Fn(_, _, web::Json<T>) -> _ + 'static,
{
Self {
path,
handler: Box::new(handler),
}
}
}
*/
#[macro_use]
extern crate log;
use actix_web::{get, middleware::Logger, post, web, App, HttpResponse, HttpServer, Responder};
//use actix_web_lab::{extract::Path, respond::Html};
use tokio::signal::unix::{signal, SignalKind};
use std::sync::{ atomic::{AtomicBool, Ordering}};
mod lib;
mod db;
mod controllers;
use std::thread;
use std::{io, sync::{Arc, Mutex,RwLock}};
use crate::lib::web_server::WebServerResources;
use crate::controllers::session_controller::SessionController;
use lib::web_server::WebServer;
use crate::controllers::api_controller::{ApiController, RouteHandler};
#[actix_web::main]
async fn main() {
env_logger::builder().filter_level(log::LevelFilter::Debug).init();
let shutdown_flag = Arc::new(AtomicBool::new(false));
let mut web_server = WebServer::new(
WebServerResources {
//db: db,
}
);
//need to put dyn in a box since its size is unknown
let api_controllers: Vec<Box<dyn ApiController>> = vec![
Box::new(SessionController::new()),
];
for controller in api_controllers {
web_server.register_controller_routes(controller);
}
//do this in a new tokio thread ?
let web_server_future = web_server.start(
"127.0.0.1".to_string(),
"7000".to_string()
).unwrap();
// web_server_future.await
let web_server_thread = thread::spawn(move || { //use a non-tokio thread here
let runtime = tokio::runtime::Runtime::new().unwrap();
runtime.block_on(async {
println!("Starting server");
if let Err(e) = web_server_future.await {
eprintln!("Server error: {}", e);
}
});
});
let web_server_thread_tokio = tokio::task::spawn_blocking(move || web_server_thread.join());
// Register a signal handler for SIGINT
let mut sigint = signal(SignalKind::interrupt()).expect("Failed to register SIGINT handler");
// Wait for either the process threads or the SIGINT signal to complete. If any complete, the whole app ends
tokio::select! {
_ = web_server_thread_tokio => {
// Web server future completed
println!("Web server has shut down");
}
_ = sigint.recv() => {
// SIGINT signal received
println!("Received SIGINT signal, shutting down...");
// Perform any necessary cleanup or shutdown logic here
shutdown_flag.store(true, Ordering::SeqCst);
}
}
}
use actix_web::{web, HttpResponse, HttpRequest};
use futures::future::BoxFuture;
use super::api_controller::{ApiController, RouteHandler,Route, RequestType, JsonInput};
use std::sync::Arc;
use crate::lib::web_server::WebServerResources;
use serde::{Serialize, Deserialize};
pub struct SessionController {}
impl SessionController {
pub fn new() -> Self {
Self {}
}
}
pub struct CreateSessionInputData {
session_id: String
}
impl JsonInput for CreateSessionInputData {}
// why does the httprequest data need to be in an arc?
fn get_session(
res: Arc<web::Data<WebServerResources>>,
input: web::Json<()>,
) -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>> {
Box::pin(async {
Ok(HttpResponse::Ok().body("get_session"))
})
}
fn create_session(
res: Arc<web::Data<WebServerResources>>,
input: web::Json<CreateSessionInputData>,
) -> BoxFuture<'static, Result<HttpResponse, actix_web::Error>> {
Box::pin(async {
Ok(HttpResponse::Ok().body("get_session"))
})
}
impl ApiController for SessionController {
fn get_routes(&self) -> Vec<Route<Box<dyn JsonInput>>> {
vec![
Route {path: "/api/session", handler: Arc::new(get_session), request_type: RequestType::Get},
Route {path: "/api/create", handler: Arc::new(create_session), request_type: RequestType::Post},
/* ("/api/session/{id}", Arc::new(get_session_by_id)),
("/api/session", Arc::new(create_session)),
("/api/session/{id}", Arc::new(update_session)),
("/api/session/{id}", Arc::new(delete_session)),*/
]
}
}
/*
pub async fn get_session_by_id(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().body("get_session_by_id")
}
pub async fn create_session(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().body("create_session")
}
pub async fn update_session(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().body("update_session")
}
pub async fn delete_session(req: HttpRequest) -> HttpResponse {
HttpResponse::Ok().body("delete_session")
}*/
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment