fluentci_server/
lib.rs

1use actix_cors::Cors;
2use actix_web::{
3    guard,
4    http::header::HOST,
5    web::{self, Data},
6    App, HttpRequest, HttpResponse, HttpServer, Result,
7};
8use anyhow::Error;
9use async_graphql::{http::GraphiQLSource, EmptyMutation, EmptySubscription, Schema};
10use async_graphql_actix_web::{GraphQLRequest, GraphQLResponse, GraphQLSubscription};
11use fluentci_core::deps::Graph;
12use fluentci_ext::runner::Runner;
13use fluentci_graphql::{schema::Query, FluentCISchema};
14use owo_colors::OwoColorize;
15use std::{
16    env,
17    sync::{mpsc, Arc, Mutex},
18};
19
20#[actix_web::post("/graphql")]
21async fn index_graphql(schema: web::Data<FluentCISchema>, req: GraphQLRequest) -> GraphQLResponse {
22    schema.execute(req.into_inner()).await.into()
23}
24
25#[actix_web::get("/graphiql")]
26async fn index_graphiql(req: HttpRequest) -> Result<HttpResponse> {
27    let host = req
28        .headers()
29        .get(HOST)
30        .unwrap()
31        .to_str()
32        .unwrap()
33        .split(":")
34        .next()
35        .unwrap();
36
37    let port = env::var("FLUENTCI_PORT").unwrap_or("6880".to_string());
38    let graphql_endpoint = format!("http://{}:{}/graphql", host, port);
39    let ws_endpoint = format!("ws://{}:{}/graphql", host, port);
40    Ok(HttpResponse::Ok()
41        .content_type("text/html; charset=utf-8")
42        .body(
43            GraphiQLSource::build()
44                .endpoint(&graphql_endpoint)
45                .subscription_endpoint(&ws_endpoint)
46                .finish(),
47        ))
48}
49
50async fn index_ws(
51    schema: web::Data<FluentCISchema>,
52    req: HttpRequest,
53    payload: web::Payload,
54) -> Result<HttpResponse> {
55    GraphQLSubscription::new(Schema::clone(&*schema)).start(&req, payload)
56}
57
58pub async fn start(listen: &str) -> Result<(), Error> {
59    fluentci_core::init_tracer().map_err(|e| Error::msg(e.to_string()))?;
60    match fluentci_core::set_git_repo_metadata() {
61        Ok(_) => {}
62        Err(e) => {
63            println!("{}", e.to_string().bright_red());
64        }
65    }
66    let banner = r#"
67
68    ________                 __  __________   ______            _          
69   / ____/ /_  _____  ____  / /_/ ____/  _/  / ____/___  ____ _(_)___  ___ 
70  / /_  / / / / / _ \/ __ \/ __/ /    / /   / __/ / __ \/ __ `/ / __ \/ _ \
71 / __/ / / /_/ /  __/ / / / /_/ /____/ /   / /___/ / / / /_/ / / / / /  __/
72/_/   /_/\__,_/\___/_/ /_/\__/\____/___/  /_____/_/ /_/\__, /_/_/ /_/\___/ 
73                                                      /____/               
74
75  "#;
76
77    println!("{}", banner.bright_green());
78    let port =
79        env::var("FLUENTCI_ENGINE_PORT").unwrap_or(listen.split(":").last().unwrap().to_string());
80    let host =
81        env::var("FLUENTCI_ENGINE_HOST").unwrap_or(listen.split(":").next().unwrap().to_string());
82    let addr = format!("{}:{}", host, port);
83    println!(
84        "Server is running on {}",
85        format!("{}", addr).bright_green()
86    );
87
88    let (tx, rx) = mpsc::channel();
89
90    let graph = Arc::new(Mutex::new(Graph::new(
91        tx,
92        Arc::new(Box::new(Runner::default())),
93    )));
94
95    let schema = Schema::build(
96        Query::default(),
97        EmptyMutation::default(),
98        EmptySubscription::default(),
99    )
100    .data(graph)
101    .data(Arc::new(Mutex::new(rx)))
102    .finish();
103
104    HttpServer::new(move || {
105        let cors = Cors::permissive();
106        App::new()
107            .app_data(Data::new(schema.clone()))
108            .wrap(cors)
109            .service(index_graphql)
110            .service(index_graphiql)
111            .service(
112                web::resource("/graphql")
113                    .guard(guard::Get())
114                    .guard(guard::Header("upgrade", "websocket"))
115                    .to(index_ws),
116            )
117    })
118    .bind(addr)?
119    .run()
120    .await
121    .map_err(|e| Error::msg(e.to_string()))
122}