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}