@@ -2,21 +2,22 @@ use std::collections::HashMap;
22use std:: env;
33use std:: error:: Error ;
44use std:: fmt:: { Display , Formatter } ;
5- use std:: fs:: File ;
5+ use std:: fs:: { self , File } ;
66use std:: io:: { BufRead , BufReader , Read , Write } ;
77use std:: net:: TcpStream ;
88use std:: path:: { Path , PathBuf } ;
99
1010use anyhow:: { anyhow, Context , Result } ;
1111use rustix:: fs:: { flock, FlockOperation } ;
12- use rustix :: path :: Arg ;
12+ use uuid :: Uuid ;
1313
1414use crate :: env:: prepare_env_vars;
1515use crate :: utils:: launch:: Launch ;
1616
1717pub enum LaunchResult {
1818 LaunchRequested ,
1919 LockAcquired {
20+ cookie : Uuid ,
2021 lock_file : File ,
2122 command : PathBuf ,
2223 command_args : Vec < String > ,
@@ -59,53 +60,63 @@ pub fn launch_or_lock(
5960 if let Some ( port) = running_server_port {
6061 let port: u32 = port. parse ( ) ?;
6162 let env = prepare_env_vars ( env) ?;
62- if let Err ( err) = request_launch ( port, command, command_args, env) {
63+ let cookie = read_cookie ( ) ?;
64+ if let Err ( err) = request_launch ( port, cookie, command, command_args, env) {
6365 return Err ( anyhow ! ( "could not request launch to server: {err}" ) ) ;
6466 }
6567 return Ok ( LaunchResult :: LaunchRequested ) ;
6668 }
6769
68- let ( lock_file, running_server_port ) = lock_file ( server_port ) ?;
70+ let ( lock_file, cookie ) = lock_file ( ) ?;
6971 match lock_file {
7072 Some ( lock_file) => Ok ( LaunchResult :: LockAcquired {
73+ cookie,
7174 lock_file,
7275 command,
7376 command_args,
7477 env,
7578 } ) ,
7679 None => {
77- if let Some ( port) = running_server_port {
78- let env = prepare_env_vars ( env) ?;
79- let mut tries = 0 ;
80- loop {
81- match request_launch ( port, command. clone ( ) , command_args. clone ( ) , env. clone ( ) ) {
82- Err ( err) => match err. downcast_ref :: < LaunchError > ( ) {
83- Some ( & LaunchError :: Connection ( _) ) => {
84- if tries == 3 {
85- return Err ( anyhow ! (
86- "could not request launch to server: {err}"
87- ) ) ;
88- } else {
89- tries += 1 ;
90- }
91- } ,
92- _ => {
80+ let env = prepare_env_vars ( env) ?;
81+ let mut tries = 0 ;
82+ loop {
83+ match request_launch (
84+ server_port,
85+ cookie,
86+ command. clone ( ) ,
87+ command_args. clone ( ) ,
88+ env. clone ( ) ,
89+ ) {
90+ Err ( err) => match err. downcast_ref :: < LaunchError > ( ) {
91+ Some ( & LaunchError :: Connection ( _) ) => {
92+ if tries == 3 {
9393 return Err ( anyhow ! ( "could not request launch to server: {err}" ) ) ;
94- } ,
94+ } else {
95+ tries += 1 ;
96+ }
9597 } ,
96- Ok ( _) => return Ok ( LaunchResult :: LaunchRequested ) ,
97- }
98+ _ => {
99+ return Err ( anyhow ! ( "could not request launch to server: {err}" ) ) ;
100+ } ,
101+ } ,
102+ Ok ( _) => return Ok ( LaunchResult :: LaunchRequested ) ,
98103 }
99- } else {
100- Err ( anyhow ! (
101- "muvm is already running but couldn't find its server port, bailing out"
102- ) )
103104 }
104105 } ,
105106 }
106107}
107108
108- fn lock_file ( server_port : u32 ) -> Result < ( Option < File > , Option < u32 > ) > {
109+ fn read_cookie ( ) -> Result < Uuid > {
110+ let run_path = env:: var ( "XDG_RUNTIME_DIR" )
111+ . context ( "Failed to read XDG_RUNTIME_DIR environment variable" ) ?;
112+ let lock_path = Path :: new ( & run_path) . join ( "muvm.lock" ) ;
113+ let data: Vec < u8 > = fs:: read ( lock_path) . context ( "Failed to read lock file" ) ?;
114+ assert ! ( data. len( ) == 16 ) ;
115+
116+ Uuid :: from_slice ( & data) . context ( "Failed to read cookie from lock file" )
117+ }
118+
119+ fn lock_file ( ) -> Result < ( Option < File > , Uuid ) > {
109120 let run_path = env:: var ( "XDG_RUNTIME_DIR" )
110121 . context ( "Failed to read XDG_RUNTIME_DIR environment variable" ) ?;
111122 let lock_path = Path :: new ( & run_path) . join ( "muvm.lock" ) ;
@@ -123,30 +134,23 @@ fn lock_file(server_port: u32) -> Result<(Option<File>, Option<u32>)> {
123134 . context ( "Failed to create lock file" ) ?;
124135 let ret = flock ( & lock_file, FlockOperation :: NonBlockingLockExclusive ) ;
125136 if ret. is_err ( ) {
126- let mut data: Vec < u8 > = Vec :: with_capacity ( 5 ) ;
137+ let mut data: Vec < u8 > = Vec :: with_capacity ( 16 ) ;
127138 lock_file. read_to_end ( & mut data) ?;
128- let port = match data. to_string_lossy ( ) . parse :: < u32 > ( ) {
129- Ok ( port) => {
130- if port > 1024 {
131- Some ( port)
132- } else {
133- None
134- }
135- } ,
136- Err ( _) => None ,
137- } ;
138- return Ok ( ( None , port) ) ;
139+ let cookie = Uuid :: from_slice ( & data) . context ( "Failed to read cookie from lock file" ) ?;
140+ return Ok ( ( None , cookie) ) ;
139141 }
140142 lock_file
141143 } ;
142144
145+ let cookie = Uuid :: now_v7 ( ) ;
143146 lock_file. set_len ( 0 ) ?;
144- lock_file. write_all ( format ! ( "{server_port}" ) . as_bytes ( ) ) ?;
145- Ok ( ( Some ( lock_file) , None ) )
147+ lock_file. write_all ( cookie . as_bytes ( ) ) ?;
148+ Ok ( ( Some ( lock_file) , cookie ) )
146149}
147150
148151fn request_launch (
149152 server_port : u32 ,
153+ cookie : Uuid ,
150154 command : PathBuf ,
151155 command_args : Vec < String > ,
152156 env : HashMap < String , String > ,
@@ -155,6 +159,7 @@ fn request_launch(
155159 TcpStream :: connect ( format ! ( "127.0.0.1:{server_port}" ) ) . map_err ( LaunchError :: Connection ) ?;
156160
157161 let launch = Launch {
162+ cookie,
158163 command,
159164 command_args,
160165 env,
0 commit comments