cli/tunnels/
protocol.rs

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 *--------------------------------------------------------------------------------------------*/
5use std::collections::HashMap;
6
7use crate::{
8	constants::{PROTOCOL_VERSION, VSCODE_CLI_VERSION},
9	options::Quality,
10	update_service::Platform,
11};
12use serde::{Deserialize, Serialize};
13
14#[derive(Serialize, Debug)]
15#[serde(tag = "method", content = "params", rename_all = "camelCase")]
16#[allow(non_camel_case_types)]
17pub enum ClientRequestMethod<'a> {
18	servermsg(RefServerMessageParams<'a>),
19	serverclose(ServerClosedParams),
20	serverlog(ServerLog<'a>),
21	makehttpreq(HttpRequestParams<'a>),
22	version(VersionResponse),
23}
24
25#[derive(Deserialize, Debug)]
26pub struct HttpBodyParams {
27	#[serde(with = "serde_bytes")]
28	pub segment: Vec<u8>,
29	pub complete: bool,
30	pub req_id: u32,
31}
32
33#[derive(Serialize, Debug)]
34pub struct HttpRequestParams<'a> {
35	pub url: &'a str,
36	pub method: &'static str,
37	pub req_id: u32,
38}
39
40#[derive(Deserialize, Debug)]
41pub struct HttpHeadersParams {
42	pub status_code: u16,
43	pub headers: Vec<(String, String)>,
44	pub req_id: u32,
45}
46
47#[derive(Deserialize, Debug)]
48pub struct ForwardParams {
49	pub port: u16,
50}
51
52#[derive(Deserialize, Debug)]
53pub struct UnforwardParams {
54	pub port: u16,
55}
56
57#[derive(Serialize)]
58pub struct ForwardResult {
59	pub uri: String,
60}
61
62#[derive(Deserialize, Debug)]
63pub struct ServeParams {
64	pub socket_id: u16,
65	pub commit_id: Option<String>,
66	pub quality: Quality,
67	pub extensions: Vec<String>,
68	/// Optional preferred connection token.
69	#[serde(default)]
70	pub connection_token: Option<String>,
71	#[serde(default)]
72	pub use_local_download: bool,
73	/// If true, the client and server should gzip servermsg's sent in either direction.
74	#[serde(default)]
75	pub compress: bool,
76}
77
78#[derive(Deserialize, Serialize, Debug)]
79pub struct EmptyObject {}
80
81#[derive(Serialize, Deserialize, Debug)]
82pub struct UpdateParams {
83	pub do_update: bool,
84}
85
86#[derive(Deserialize, Debug)]
87pub struct ServerMessageParams {
88	pub i: u16,
89	#[serde(with = "serde_bytes")]
90	pub body: Vec<u8>,
91}
92
93#[derive(Serialize, Debug)]
94pub struct ServerClosedParams {
95	pub i: u16,
96}
97
98#[derive(Serialize, Debug)]
99pub struct RefServerMessageParams<'a> {
100	pub i: u16,
101	#[serde(with = "serde_bytes")]
102	pub body: &'a [u8],
103}
104
105#[derive(Serialize)]
106pub struct UpdateResult {
107	pub up_to_date: bool,
108	pub did_update: bool,
109}
110
111#[derive(Serialize, Debug)]
112pub struct ToClientRequest<'a> {
113	pub id: Option<u32>,
114	#[serde(flatten)]
115	pub params: ClientRequestMethod<'a>,
116}
117
118#[derive(Debug, Default, Serialize)]
119pub struct ServerLog<'a> {
120	pub line: &'a str,
121	pub level: u8,
122}
123
124#[derive(Serialize)]
125pub struct GetHostnameResponse {
126	pub value: String,
127}
128
129#[derive(Serialize)]
130pub struct GetEnvResponse {
131	pub env: HashMap<String, String>,
132	pub os_platform: &'static str,
133	pub os_release: String,
134}
135
136/// Method: `kill`. Sends a generic, platform-specific kill command to the process.
137#[derive(Deserialize)]
138pub struct SysKillRequest {
139	pub pid: u32,
140}
141
142#[derive(Serialize)]
143pub struct SysKillResponse {
144	pub success: bool,
145}
146
147/// Methods: `fs_read`/`fs_write`/`fs_rm`/`fs_mkdirp`/`fs_stat`
148///  - fs_read: reads into a stream returned from the method,
149///  - fs_write: writes from a stream passed to the method.
150///  - fs_rm: recursively removes the file
151///  - fs_mkdirp: recursively creates the directory
152///  - fs_readdir: reads directory contents
153///  - fs_stat: stats the given path
154///  - fs_connect: connect to the given unix or named pipe socket, streaming
155///    data in and out from the method's stream.
156#[derive(Deserialize)]
157pub struct FsSinglePathRequest {
158	pub path: String,
159}
160
161#[derive(Serialize)]
162pub enum FsFileKind {
163	#[serde(rename = "dir")]
164	Directory,
165	#[serde(rename = "file")]
166	File,
167	#[serde(rename = "link")]
168	Link,
169}
170
171impl From<std::fs::FileType> for FsFileKind {
172	fn from(kind: std::fs::FileType) -> Self {
173		if kind.is_dir() {
174			Self::Directory
175		} else if kind.is_file() {
176			Self::File
177		} else if kind.is_symlink() {
178			Self::Link
179		} else {
180			unreachable!()
181		}
182	}
183}
184
185#[derive(Serialize, Default)]
186pub struct FsStatResponse {
187	pub exists: bool,
188	pub size: Option<u64>,
189	#[serde(rename = "type")]
190	pub kind: Option<FsFileKind>,
191}
192
193#[derive(Serialize)]
194pub struct FsReadDirResponse {
195	pub contents: Vec<FsReadDirEntry>,
196}
197
198#[derive(Serialize)]
199pub struct FsReadDirEntry {
200	pub name: String,
201	#[serde(rename = "type")]
202	pub kind: Option<FsFileKind>,
203}
204
205/// Method: `fs_reaname`. Renames a file.
206#[derive(Deserialize)]
207pub struct FsRenameRequest {
208	pub from_path: String,
209	pub to_path: String,
210}
211
212/// Method: `net_connect`. Connects to a port.
213#[derive(Deserialize)]
214pub struct NetConnectRequest {
215	pub port: u16,
216	pub host: String,
217}
218
219#[derive(Deserialize, Debug)]
220pub struct CallServerHttpParams {
221	pub path: String,
222	pub method: String,
223	pub headers: HashMap<String, String>,
224	pub body: Option<Vec<u8>>,
225}
226
227#[derive(Serialize)]
228pub struct CallServerHttpResult {
229	pub status: u16,
230	#[serde(with = "serde_bytes")]
231	pub body: Vec<u8>,
232	pub headers: HashMap<String, String>,
233}
234
235#[derive(Serialize, Debug)]
236pub struct VersionResponse {
237	pub version: &'static str,
238	pub protocol_version: u32,
239}
240
241impl Default for VersionResponse {
242	fn default() -> Self {
243		Self {
244			version: VSCODE_CLI_VERSION.unwrap_or("dev"),
245			protocol_version: PROTOCOL_VERSION,
246		}
247	}
248}
249
250#[derive(Deserialize)]
251pub struct SpawnParams {
252	pub command: String,
253	pub args: Vec<String>,
254	#[serde(default)]
255	pub cwd: Option<String>,
256	#[serde(default)]
257	pub env: HashMap<String, String>,
258}
259
260#[derive(Deserialize)]
261pub struct AcquireCliParams {
262	pub platform: Platform,
263	pub quality: Quality,
264	pub commit_id: Option<String>,
265	#[serde(flatten)]
266	pub spawn: SpawnParams,
267}
268
269#[derive(Serialize)]
270pub struct SpawnResult {
271	pub message: String,
272	pub exit_code: i32,
273}
274
275pub const METHOD_CHALLENGE_ISSUE: &str = "challenge_issue";
276pub const METHOD_CHALLENGE_VERIFY: &str = "challenge_verify";
277
278#[derive(Serialize, Deserialize)]
279pub struct ChallengeIssueParams {
280	pub token: Option<String>,
281}
282
283#[derive(Serialize, Deserialize)]
284pub struct ChallengeIssueResponse {
285	pub challenge: String,
286}
287
288#[derive(Deserialize, Serialize)]
289pub struct ChallengeVerifyParams {
290	pub response: String,
291}
292
293#[derive(Serialize, Deserialize, PartialEq, Eq, Copy, Clone, Debug)]
294#[serde(rename_all = "lowercase")]
295pub enum PortPrivacy {
296	Public,
297	Private,
298}
299
300pub mod forward_singleton {
301	use serde::{Deserialize, Serialize};
302
303	use super::PortPrivacy;
304
305	pub const METHOD_SET_PORTS: &str = "set_ports";
306
307	#[derive(Serialize, Deserialize, PartialEq, Eq, Clone, Debug)]
308	pub struct PortRec {
309		pub number: u16,
310		pub privacy: PortPrivacy,
311	}
312
313	pub type PortList = Vec<PortRec>;
314
315	#[derive(Serialize, Deserialize)]
316	pub struct SetPortsParams {
317		pub ports: PortList,
318	}
319
320	#[derive(Serialize, Deserialize)]
321	pub struct SetPortsResponse {
322		pub port_format: Option<String>,
323	}
324}
325
326pub mod singleton {
327	use crate::log;
328	use chrono::{DateTime, Utc};
329	use serde::{Deserialize, Serialize};
330
331	pub const METHOD_RESTART: &str = "restart";
332	pub const METHOD_SHUTDOWN: &str = "shutdown";
333	pub const METHOD_STATUS: &str = "status";
334	pub const METHOD_LOG: &str = "log";
335	pub const METHOD_LOG_REPLY_DONE: &str = "log_done";
336
337	#[derive(Serialize)]
338	pub struct LogMessage<'a> {
339		pub level: Option<log::Level>,
340		pub prefix: &'a str,
341		pub message: &'a str,
342	}
343
344	#[derive(Deserialize)]
345	pub struct LogMessageOwned {
346		pub level: Option<log::Level>,
347		pub prefix: String,
348		pub message: String,
349	}
350
351	#[derive(Serialize, Deserialize, Clone, Default)]
352	pub struct StatusWithTunnelName {
353		pub name: Option<String>,
354		#[serde(flatten)]
355		pub status: Status,
356	}
357
358	#[derive(Serialize, Deserialize, Clone)]
359	pub struct Status {
360		pub started_at: DateTime<Utc>,
361		pub tunnel: TunnelState,
362		pub last_connected_at: Option<DateTime<Utc>>,
363		pub last_disconnected_at: Option<DateTime<Utc>>,
364		pub last_fail_reason: Option<String>,
365	}
366
367	impl Default for Status {
368		fn default() -> Self {
369			Self {
370				started_at: Utc::now(),
371				tunnel: TunnelState::Disconnected,
372				last_connected_at: None,
373				last_disconnected_at: None,
374				last_fail_reason: None,
375			}
376		}
377	}
378
379	#[derive(Deserialize, Serialize, Debug)]
380	pub struct LogReplayFinished {}
381
382	#[derive(Deserialize, Serialize, Debug, Default, Clone)]
383	pub enum TunnelState {
384		#[default]
385		Disconnected,
386		Connected,
387	}
388}