Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/cli/src/tunnels/paths.rs
3314 views
1
/*---------------------------------------------------------------------------------------------
2
* Copyright (c) Microsoft Corporation. All rights reserved.
3
* Licensed under the MIT License. See License.txt in the project root for license information.
4
*--------------------------------------------------------------------------------------------*/
5
6
use std::{
7
fs::{read_dir, read_to_string, remove_dir_all, write},
8
path::PathBuf,
9
};
10
11
use serde::{Deserialize, Serialize};
12
13
use crate::{
14
options::{self, Quality},
15
state::LauncherPaths,
16
util::{
17
errors::{wrap, AnyError, WrappedError},
18
machine,
19
},
20
};
21
22
pub const SERVER_FOLDER_NAME: &str = "server";
23
24
pub struct ServerPaths {
25
// Directory into which the server is downloaded
26
pub server_dir: PathBuf,
27
// Executable path, within the server_id
28
pub executable: PathBuf,
29
// File where logs for the server should be written.
30
pub logfile: PathBuf,
31
// File where the process ID for the server should be written.
32
pub pidfile: PathBuf,
33
}
34
35
impl ServerPaths {
36
// Queries the system to determine the process ID of the running server.
37
// Returns the process ID, if the server is running.
38
pub fn get_running_pid(&self) -> Option<u32> {
39
if let Some(pid) = self.read_pid() {
40
return match machine::process_at_path_exists(pid, &self.executable) {
41
true => Some(pid),
42
false => None,
43
};
44
}
45
46
if let Some(pid) = machine::find_running_process(&self.executable) {
47
// attempt to backfill process ID:
48
self.write_pid(pid).ok();
49
return Some(pid);
50
}
51
52
None
53
}
54
55
/// Delete the server directory
56
pub fn delete(&self) -> Result<(), WrappedError> {
57
remove_dir_all(&self.server_dir).map_err(|e| {
58
wrap(
59
e,
60
format!("error deleting server dir {}", self.server_dir.display()),
61
)
62
})
63
}
64
65
// VS Code Server pid
66
pub fn write_pid(&self, pid: u32) -> Result<(), WrappedError> {
67
write(&self.pidfile, format!("{pid}")).map_err(|e| {
68
wrap(
69
e,
70
format!("error writing process id into {}", self.pidfile.display()),
71
)
72
})
73
}
74
75
fn read_pid(&self) -> Option<u32> {
76
read_to_string(&self.pidfile)
77
.ok()
78
.and_then(|s| s.parse::<u32>().ok())
79
}
80
}
81
82
#[derive(Serialize, Deserialize, Clone, PartialEq, Eq)]
83
pub struct InstalledServer {
84
pub quality: options::Quality,
85
pub commit: String,
86
pub headless: bool,
87
}
88
89
impl InstalledServer {
90
/// Gets path information about where a specific server should be stored.
91
pub fn server_paths(&self, p: &LauncherPaths) -> ServerPaths {
92
let server_dir = self.get_install_folder(p);
93
ServerPaths {
94
// allow using the OSS server in development via an override
95
executable: if let Some(p) = option_env!("VSCODE_CLI_OVERRIDE_SERVER_PATH") {
96
PathBuf::from(p)
97
} else {
98
server_dir
99
.join(SERVER_FOLDER_NAME)
100
.join("bin")
101
.join(self.quality.server_entrypoint())
102
},
103
logfile: server_dir.join("log.txt"),
104
pidfile: server_dir.join("pid.txt"),
105
server_dir,
106
}
107
}
108
109
fn get_install_folder(&self, p: &LauncherPaths) -> PathBuf {
110
p.server_cache.path().join(if !self.headless {
111
format!("{}-web", get_server_folder_name(self.quality, &self.commit))
112
} else {
113
get_server_folder_name(self.quality, &self.commit)
114
})
115
}
116
}
117
118
/// Prunes servers not currently running, and returns the deleted servers.
119
pub fn prune_stopped_servers(launcher_paths: &LauncherPaths) -> Result<Vec<ServerPaths>, AnyError> {
120
get_all_servers(launcher_paths)
121
.into_iter()
122
.map(|s| s.server_paths(launcher_paths))
123
.filter(|s| s.get_running_pid().is_none())
124
.map(|s| s.delete().map(|_| s))
125
.collect::<Result<_, _>>()
126
.map_err(AnyError::from)
127
}
128
129
// Gets a list of all servers which look like they might be running.
130
pub fn get_all_servers(lp: &LauncherPaths) -> Vec<InstalledServer> {
131
let mut servers: Vec<InstalledServer> = vec![];
132
if let Ok(children) = read_dir(lp.server_cache.path()) {
133
for child in children.flatten() {
134
let fname = child.file_name();
135
let fname = fname.to_string_lossy();
136
let (quality, commit) = match fname.split_once('-') {
137
Some(r) => r,
138
None => continue,
139
};
140
141
let quality = match options::Quality::try_from(quality) {
142
Ok(q) => q,
143
Err(_) => continue,
144
};
145
146
servers.push(InstalledServer {
147
quality,
148
commit: commit.to_string(),
149
headless: true,
150
});
151
}
152
}
153
154
servers
155
}
156
157
pub fn get_server_folder_name(quality: Quality, commit: &str) -> String {
158
format!("{quality}-{commit}")
159
}
160
161