@@ -3,6 +3,7 @@ use reqwest::Client;
33use serde_json:: { Value , json} ;
44use std:: io:: Write ;
55use std:: path:: PathBuf ;
6+ use std:: process:: Stdio ;
67use std:: { env, fs} ;
78use std:: { io, process:: Command } ;
89
@@ -72,6 +73,52 @@ fn run_model_by_sub_process(modelfile: Modelfile) {
7273 }
7374}
7475
76+ #[ allow( clippy:: zombie_processes) ]
77+ pub fn start_server_daemon ( ) -> Result < ( ) > {
78+ // check if the server is running
79+ // start server as a child process
80+ // save the pid in a file under ~/.config/tiles/server_pid
81+ let config_dir = get_config_dir ( ) ?;
82+ let server_dir = get_server_dir ( ) ?;
83+ let pid_file = config_dir. join ( "server.pid" ) ;
84+ if pid_file. exists ( ) {
85+ eprintln ! ( "Server is already running" ) ;
86+ return Ok ( ( ) ) ;
87+ }
88+
89+ let child = Command :: new ( "uv" )
90+ . args ( [
91+ "run" ,
92+ "--project" ,
93+ server_dir. to_str ( ) . unwrap ( ) ,
94+ "python" ,
95+ "-m" ,
96+ "server.main" ,
97+ ] )
98+ . stdout ( Stdio :: null ( ) )
99+ . stderr ( Stdio :: null ( ) )
100+ . spawn ( )
101+ . expect ( "failed to start server" ) ;
102+ fs:: create_dir_all ( & config_dir) . context ( "Failed to create config directory" ) ?;
103+ std:: fs:: write ( pid_file, child. id ( ) . to_string ( ) ) . unwrap ( ) ;
104+ println ! ( "Server started with PID {}" , child. id( ) ) ;
105+ Ok ( ( ) )
106+ }
107+
108+ pub fn stop_server_daemon ( ) -> Result < ( ) > {
109+ let pid_file = get_config_dir ( ) ?. join ( "server.pid" ) ;
110+
111+ if !pid_file. exists ( ) {
112+ eprintln ! ( "Server is not running" ) ;
113+ return Ok ( ( ) ) ;
114+ }
115+
116+ let pid = std:: fs:: read_to_string ( & pid_file) . unwrap ( ) ;
117+ Command :: new ( "kill" ) . arg ( pid. trim ( ) ) . status ( ) . unwrap ( ) ;
118+ std:: fs:: remove_file ( pid_file) . unwrap ( ) ;
119+ println ! ( "Server stopped." ) ;
120+ Ok ( ( ) )
121+ }
75122async fn run_model_with_server ( modelfile : Modelfile ) -> reqwest:: Result < ( ) > {
76123 let stdin = io:: stdin ( ) ;
77124 let mut stdout = io:: stdout ( ) ;
@@ -157,19 +204,8 @@ async fn chat(input: &str, model_name: &str) -> Result<String, String> {
157204}
158205
159206fn get_memory_path ( ) -> Result < String > {
160- let home_dir = env:: home_dir ( ) . context ( "Failed to fetch $HOME" ) ?;
161- let config_dir = match env:: var ( "XDG_CONFIG_HOME" ) {
162- Ok ( val) => PathBuf :: from ( val) ,
163- Err ( _err) => home_dir. join ( ".config" ) ,
164- } ;
165-
166- let data_dir = match env:: var ( "XDG_DATA_HOME" ) {
167- Ok ( val) => PathBuf :: from ( val) ,
168- Err ( _err) => home_dir. join ( ".local/share" ) ,
169- } ;
170-
171- let tiles_config_dir = config_dir. join ( "tiles" ) ;
172- let tiles_data_dir = data_dir. join ( "tiles" ) ;
207+ let tiles_config_dir = get_config_dir ( ) ?;
208+ let tiles_data_dir = get_data_dir ( ) ?;
173209 let mut is_memory_path_found: bool = false ;
174210 let mut memory_path: String = String :: from ( "" ) ;
175211 if tiles_config_dir. is_dir ( )
@@ -193,3 +229,44 @@ fn get_memory_path() -> Result<String> {
193229 Ok ( memory_path. to_string_lossy ( ) . to_string ( ) )
194230 }
195231}
232+
233+ fn get_server_dir ( ) -> Result < PathBuf > {
234+ if cfg ! ( debug_assertions) {
235+ let base_dir = env:: current_dir ( ) . context ( "Failed to fetch CURRENT_DIR" ) ?;
236+ Ok ( base_dir. join ( "server" ) )
237+ } else {
238+ let home_dir = env:: home_dir ( ) . context ( "Failed to fetch $HOME" ) ?;
239+ let data_dir = match env:: var ( "XDG_DATA_HOME" ) {
240+ Ok ( val) => PathBuf :: from ( val) ,
241+ Err ( _err) => home_dir. join ( ".local/share" ) ,
242+ } ;
243+ Ok ( data_dir. join ( "tiles/server" ) )
244+ }
245+ }
246+ fn get_config_dir ( ) -> Result < PathBuf > {
247+ if cfg ! ( debug_assertions) {
248+ let base_dir = env:: current_dir ( ) . context ( "Failed to fetch CURRENT_DIR" ) ?;
249+ Ok ( base_dir. join ( ".tiles_dev/tiles" ) )
250+ } else {
251+ let home_dir = env:: home_dir ( ) . context ( "Failed to fetch $HOME" ) ?;
252+ let config_dir = match env:: var ( "XDG_CONFIG_HOME" ) {
253+ Ok ( val) => PathBuf :: from ( val) ,
254+ Err ( _err) => home_dir. join ( ".config" ) ,
255+ } ;
256+ Ok ( config_dir. join ( "tiles" ) )
257+ }
258+ }
259+
260+ fn get_data_dir ( ) -> Result < PathBuf > {
261+ if cfg ! ( debug_assertions) {
262+ let base_dir = env:: current_dir ( ) . context ( "Failed to fetch CURRENT_DIR" ) ?;
263+ Ok ( base_dir. join ( ".tiles_dev/tiles" ) )
264+ } else {
265+ let home_dir = env:: home_dir ( ) . context ( "Failed to fetch $HOME" ) ?;
266+ let data_dir = match env:: var ( "XDG_DATA_HOME" ) {
267+ Ok ( val) => PathBuf :: from ( val) ,
268+ Err ( _err) => home_dir. join ( ".local/share" ) ,
269+ } ;
270+ Ok ( data_dir. join ( "tiles" ) )
271+ }
272+ }
0 commit comments