11use super :: dto:: { GraphEdgeDto , GraphInfoDto , GraphNodeDto } ;
22use miette:: IntoDiagnostic ;
33use moon_action_graph:: ActionGraph ;
4+ use moon_common:: color;
5+ use moon_process:: ProcessRegistry ;
46use moon_project_graph:: { GraphConversions , ProjectGraph } ;
57use moon_task_graph:: TaskGraph ;
68use petgraph:: { graph:: NodeIndex , Graph } ;
79use rustc_hash:: FxHashMap ;
810use serde:: Serialize ;
9- use starbase:: AppResult ;
1011use starbase_utils:: json;
1112use std:: env;
1213use std:: fmt:: Display ;
14+ use std:: sync:: Arc ;
1315use tera:: { Context , Tera } ;
1416use tiny_http:: { Header , Request , Response , Server } ;
17+ use tokio:: task:: { spawn, JoinHandle } ;
1518
1619const INDEX_HTML : & str = include_str ! ( "graph.html.tera" ) ;
1720
@@ -22,10 +25,10 @@ pub struct RenderContext {
2225 pub js_url : String ,
2326}
2427
25- pub async fn setup_server ( ) -> miette:: Result < ( Server , Tera ) > {
28+ pub async fn setup_server ( ) -> miette:: Result < ( Arc < Server > , Tera ) > {
2629 let port = match env:: var ( "MOON_PORT" ) {
2730 Ok ( p) => p. parse :: < u16 > ( ) . unwrap ( ) ,
28- Err ( ..) => 8000 ,
31+ Err ( ..) => 0 , // Uses an available port
2932 } ;
3033 let host = match env:: var ( "MOON_HOST" ) {
3134 Ok ( h) => h,
@@ -35,7 +38,7 @@ pub async fn setup_server() -> miette::Result<(Server, Tera)> {
3538 let server = Server :: http ( address) . unwrap ( ) ;
3639 let tera = Tera :: default ( ) ;
3740
38- Ok ( ( server, tera) )
41+ Ok ( ( Arc :: new ( server) , tera) )
3942}
4043
4144pub fn extract_nodes_and_edges_from_graph < T : Display > (
@@ -100,7 +103,7 @@ pub fn respond_to_request(
100103 tera : & mut Tera ,
101104 graph : & GraphInfoDto ,
102105 page_title : String ,
103- ) -> AppResult {
106+ ) -> miette :: Result < ( ) > {
104107 let response = match req. url ( ) {
105108 "/graph-data" => {
106109 let mut response = Response :: from_data ( json:: format ( graph, false ) ?) ;
@@ -132,7 +135,7 @@ pub fn respond_to_request(
132135
133136 req. respond ( response) . unwrap_or_default ( ) ;
134137
135- Ok ( None )
138+ Ok ( ( ) )
136139}
137140
138141// Use the local version of the JS file when in development mode otherwise the CDN URL.
@@ -145,3 +148,43 @@ pub fn get_js_url() -> String {
145148 } ,
146149 }
147150}
151+
152+ pub async fn run_server ( title : & str , graph_info : GraphInfoDto ) -> miette:: Result < ( ) > {
153+ let ( server, mut tera) = setup_server ( ) . await ?;
154+ let url = format ! ( "http://{}" , server. server_addr( ) ) ;
155+ let _ = open:: that ( & url) ;
156+
157+ println ! ( "Started server on {}" , color:: url( url) ) ;
158+
159+ let server_clone = server. clone ( ) ;
160+ let handle1: JoinHandle < miette:: Result < ( ) > > = spawn ( async move {
161+ let mut listener = ProcessRegistry :: instance ( ) . receive_signal ( ) ;
162+
163+ if listener. recv ( ) . await . is_ok ( ) {
164+ server_clone. unblock ( ) ;
165+ }
166+
167+ Ok ( ( ) )
168+ } ) ;
169+
170+ let title = title. to_owned ( ) ;
171+ let handle2: JoinHandle < miette:: Result < ( ) > > = spawn ( async move {
172+ for req in server. incoming_requests ( ) {
173+ respond_to_request ( req, & mut tera, & graph_info, title. clone ( ) ) ?;
174+ }
175+
176+ Ok ( ( ) )
177+ } ) ;
178+
179+ tokio:: try_join!( flatten( handle1) , flatten( handle2) ) ?;
180+
181+ Ok ( ( ) )
182+ }
183+
184+ async fn flatten ( handle : JoinHandle < miette:: Result < ( ) > > ) -> miette:: Result < ( ) > {
185+ match handle. await {
186+ Ok ( Ok ( result) ) => Ok ( result) ,
187+ Ok ( Err ( err) ) => Err ( err) ,
188+ Err ( err) => Err ( miette:: miette!( "{err}" ) ) ,
189+ }
190+ }
0 commit comments