aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAram Drevekenin <aram@poor.dev>2026-01-21 10:53:18 +0100
committerGitHub <noreply@github.com>2026-01-21 10:53:18 +0100
commitd8e16ef9fe8c79a542fda969ee53f3e7cb9f837d (patch)
tree2cf78a4d35f7ba28a3d970432cb2780b77bf985a
parentFix tiled new pane borderless (#4618) (diff)
downloadsl0ppij-d8e16ef9fe8c79a542fda969ee53f3e7cb9f837d.tar.gz
sl0ppij-d8e16ef9fe8c79a542fda969ee53f3e7cb9f837d.tar.xz
sl0ppij-d8e16ef9fe8c79a542fda969ee53f3e7cb9f837d.zip
Fix query webserver from IPC rather than HTTPS (#4620)
* move webserver querying from http to ipc * rustfmt * fix no web build * rustfmt * add pr
-rw-r--r--CHANGELOG.md1
-rw-r--r--zellij-client/src/web_client/ipc_listener.rs55
-rw-r--r--zellij-client/src/web_client/mod.rs12
-rw-r--r--zellij-client/src/web_client/unit/web_client_tests.rs32
-rw-r--r--zellij-server/src/background_jobs.rs128
-rw-r--r--zellij-utils/assets/prost_web_server/web_server_contract.rs39
-rw-r--r--zellij-utils/src/shared.rs17
-rw-r--r--zellij-utils/src/web_server_commands.rs60
-rw-r--r--zellij-utils/src/web_server_contract/protobuf_conversion.rs52
-rw-r--r--zellij-utils/src/web_server_contract/web_server_commands.proto19
10 files changed, 316 insertions, 99 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index e4906973..916215ec 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -28,6 +28,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/)
* fix: properly center floating panes started with `--floating` when explicit width/height is provided (https://github.com/zellij-org/zellij/pull/4607)
* fix: allow specifying "0%" coordinates when opening panes wit "zellij run --floating" (https://github.com/zellij-org/zellij/pull/4609)
* feat: allow opening panes as `borderless` or toggling/changing the borderless status of existing panes (https://github.com/zellij-org/zellij/pull/4615 and https://github.com/zellij-org/zellij/pull/4618)
+* fix: query webserver through ipc rather than https (https://github.com/zellij-org/zellij/pull/4620)
## [0.43.1] - 2025-08-08
diff --git a/zellij-client/src/web_client/ipc_listener.rs b/zellij-client/src/web_client/ipc_listener.rs
index ebc8e150..62344ba8 100644
--- a/zellij-client/src/web_client/ipc_listener.rs
+++ b/zellij-client/src/web_client/ipc_listener.rs
@@ -1,10 +1,12 @@
use axum_server::Handle;
-use tokio::io::AsyncReadExt;
+use std::net::IpAddr;
+use tokio::io::{AsyncReadExt, AsyncWriteExt};
use tokio::net::{UnixListener, UnixStream};
use zellij_utils::consts::WEBSERVER_SOCKET_PATH;
use zellij_utils::prost::Message;
-use zellij_utils::web_server_commands::InstructionForWebServer;
+use zellij_utils::web_server_commands::{InstructionForWebServer, VersionInfo, WebServerResponse};
use zellij_utils::web_server_contract::web_server_contract::InstructionForWebServer as ProtoInstructionForWebServer;
+use zellij_utils::web_server_contract::web_server_contract::WebServerResponse as ProtoWebServerResponse;
pub async fn create_webserver_receiver(
id: &str,
@@ -43,23 +45,48 @@ pub async fn receive_webserver_instruction(
.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
}
-pub async fn listen_to_web_server_instructions(server_handle: Handle, id: &str) {
+pub async fn send_webserver_response(
+ sender: &mut UnixStream,
+ response: WebServerResponse,
+) -> std::io::Result<()> {
+ let proto_response: ProtoWebServerResponse = response.into();
+ let encoded = proto_response.encode_to_vec();
+ let len = encoded.len() as u32;
+
+ sender.write_all(&len.to_le_bytes()).await?;
+ sender.write_all(&encoded).await?;
+ sender.flush().await?;
+
+ Ok(())
+}
+
+pub async fn listen_to_web_server_instructions(
+ server_handle: Handle,
+ id: &str,
+ web_server_ip: IpAddr,
+ web_server_port: u16,
+) {
loop {
let receiver = create_webserver_receiver(id).await;
match receiver {
- Ok(mut receiver) => {
- match receive_webserver_instruction(&mut receiver).await {
- Ok(instruction) => match instruction {
- InstructionForWebServer::ShutdownWebServer => {
- server_handle.shutdown();
- break;
- },
+ Ok(mut receiver) => match receive_webserver_instruction(&mut receiver).await {
+ Ok(instruction) => match instruction {
+ InstructionForWebServer::ShutdownWebServer => {
+ server_handle.shutdown();
+ break;
},
- Err(e) => {
- log::error!("Failed to process web server instruction: {}", e);
- // Continue loop to recreate receiver and try again
+ InstructionForWebServer::QueryVersion => {
+ let response = WebServerResponse::Version(VersionInfo {
+ version: zellij_utils::consts::VERSION.to_string(),
+ ip: web_server_ip.to_string(),
+ port: web_server_port,
+ });
+ let _ = send_webserver_response(&mut receiver, response).await;
},
- }
+ },
+ Err(e) => {
+ log::error!("Failed to process web server instruction: {}", e);
+ },
},
Err(e) => {
log::error!("Failed to listen to ipc channel: {}", e);
diff --git a/zellij-client/src/web_client/mod.rs b/zellij-client/src/web_client/mod.rs
index f3e04422..02c9399f 100644
--- a/zellij-client/src/web_client/mod.rs
+++ b/zellij-client/src/web_client/mod.rs
@@ -157,6 +157,8 @@ pub fn start_web_client(
tls_config,
None,
None,
+ web_server_ip,
+ web_server_port,
));
}
@@ -168,6 +170,8 @@ pub async fn serve_web_client(
rustls_config: Option<RustlsConfig>,
session_manager: Option<Arc<dyn SessionManager>>,
client_os_api_factory: Option<Arc<dyn ClientOsApiFactory>>,
+ web_server_ip: IpAddr,
+ web_server_port: u16,
) {
let Some(config_file_path) = config_file_path.or_else(|| Config::default_config_file_path())
else {
@@ -204,7 +208,13 @@ pub async fn serve_web_client(
tokio::spawn({
let server_handle = server_handle.clone();
async move {
- listen_to_web_server_instructions(server_handle, &format!("{}", id)).await;
+ listen_to_web_server_instructions(
+ server_handle,
+ &format!("{}", id),
+ web_server_ip,
+ web_server_port,
+ )
+ .await;
}
});
diff --git a/zellij-client/src/web_client/unit/web_client_tests.rs b/zellij-client/src/web_client/unit/web_client_tests.rs
index 087c2d3b..15a45efa 100644
--- a/zellij-client/src/web_client/unit/web_client_tests.rs
+++ b/zellij-client/src/web_client/unit/web_client_tests.rs
@@ -88,6 +88,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
));
wait_for_server(port, Duration::from_secs(5))
@@ -147,6 +149,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -216,6 +220,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -281,6 +287,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -480,6 +488,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -528,6 +538,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -588,6 +600,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -733,6 +747,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -905,6 +921,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -1049,6 +1067,8 @@ mod web_client_tests {
None,
Some(session_manager),
Some(client_os_api_factory),
+ addr.ip(),
+ port,
)
.await;
});
@@ -1166,6 +1186,7 @@ mod web_client_tests {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let port = addr.port();
+ let ip = addr.ip();
let temp_config_path = std::env::temp_dir().join("test_config.kdl");
let server_handle = tokio::spawn(async move {
@@ -1177,6 +1198,8 @@ mod web_client_tests {
None,
Some(mock_session_manager),
Some(mock_os_api_factory),
+ ip,
+ port,
)
.await;
});
@@ -1263,6 +1286,7 @@ mod web_client_tests {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let port = addr.port();
+ let ip = addr.ip();
let temp_config_path = std::env::temp_dir().join("test_config.kdl");
let server_handle = tokio::spawn(async move {
@@ -1274,6 +1298,8 @@ mod web_client_tests {
None,
Some(mock_session_manager),
Some(mock_os_api_factory),
+ ip,
+ port,
)
.await;
});
@@ -1436,6 +1462,7 @@ mod web_client_tests {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let port = addr.port();
+ let ip = addr.ip();
let temp_config_path = std::env::temp_dir().join("test_config.kdl");
let server_handle = tokio::spawn(async move {
@@ -1447,6 +1474,8 @@ mod web_client_tests {
None,
Some(mock_session_manager),
Some(mock_os_api_factory),
+ ip,
+ port,
)
.await;
});
@@ -1544,6 +1573,7 @@ mod web_client_tests {
let listener = std::net::TcpListener::bind("127.0.0.1:0").unwrap();
let addr = listener.local_addr().unwrap();
let port = addr.port();
+ let ip = addr.ip();
let temp_config_path = std::env::temp_dir().join("test_config.kdl");
let server_handle = tokio::spawn(async move {
@@ -1555,6 +1585,8 @@ mod web_client_tests {
None,
Some(mock_session_manager),
Some(mock_os_api_factory),
+ ip,
+ port,
)
.await;
});
diff --git a/zellij-server/src/background_jobs.rs b/zellij-server/src/background_jobs.rs
index d91a80a4..22828e15 100644
--- a/zellij-server/src/background_jobs.rs
+++ b/zellij-server/src/background_jobs.rs
@@ -6,6 +6,13 @@ use zellij_utils::consts::{
use zellij_utils::data::{Event, HttpVerb, SessionInfo, WebServerStatus};
use zellij_utils::errors::{prelude::*, BackgroundJobContext, ContextType};
use zellij_utils::input::layout::RunPlugin;
+use zellij_utils::shared::parse_base_url;
+
+#[cfg(feature = "web_server_capability")]
+use zellij_utils::web_server_commands::{
+ discover_webserver_sockets, query_webserver_with_response, InstructionForWebServer,
+ WebServerResponse,
+};
use isahc::prelude::*;
use isahc::AsyncReadResponseExt;
@@ -382,85 +389,22 @@ pub(crate) fn background_jobs_main(
});
},
BackgroundJob::QueryZellijWebServerStatus => {
- if !cfg!(feature = "web_server_capability") {
- // no web server capability, no need to query
- continue;
- }
-
+ #[cfg(feature = "web_server_capability")]
task::spawn({
- let http_client = http_client.clone();
let senders = bus.senders.clone();
let web_server_base_url = web_server_base_url.clone();
async move {
- async fn web_request(
- http_client: HttpClient,
- web_server_base_url: &str,
- ) -> Result<
- (u16, Vec<u8>), // status_code, body
- isahc::Error,
- > {
- let request =
- Request::get(format!("{}/info/version", web_server_base_url,));
- let req = request.body(())?;
- let mut res = http_client.send_async(req).await?;
-
- let status_code = res.status();
- let body = res.bytes().await?;
- Ok((status_code.as_u16(), body))
- }
- let Some(http_client) = http_client else {
- log::error!("Cannot perform http request, likely due to a misconfigured http client");
- return;
- };
+ let status = task::spawn_blocking(move || {
+ query_webserver_via_ipc(&web_server_base_url)
+ })
+ .await
+ .unwrap_or(WebServerStatus::Offline);
- let http_client = http_client.clone();
- match web_request(http_client, &web_server_base_url).await {
- Ok((status, body)) => {
- if status == 200 && &body == VERSION.as_bytes() {
- // online
- let _ =
- senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::WebServerStatus(WebServerStatus::Online(
- web_server_base_url.clone(),
- )),
- )]));
- } else if status == 200 {
- let _ =
- senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::WebServerStatus(
- WebServerStatus::DifferentVersion(
- String::from_utf8_lossy(&body).to_string(),
- ),
- ),
- )]));
- } else {
- // offline/error
- let _ =
- senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::WebServerStatus(WebServerStatus::Offline),
- )]));
- }
- },
- Err(e) => {
- if e.kind() == isahc::error::ErrorKind::ConnectionFailed {
- let _ =
- senders.send_to_plugin(PluginInstruction::Update(vec![(
- None,
- None,
- Event::WebServerStatus(WebServerStatus::Offline),
- )]));
- } else {
- // no-op - otherwise we'll get errors if we were mid-request
- // (eg. when the server was shut down by a user action)
- }
- },
- }
+ let _ = senders.send_to_plugin(PluginInstruction::Update(vec![(
+ None,
+ None,
+ Event::WebServerStatus(status),
+ )]));
}
});
},
@@ -678,3 +622,39 @@ fn find_resurrectable_sessions(
},
}
}
+
+#[cfg(feature = "web_server_capability")]
+fn query_webserver_via_ipc(web_server_base_url: &str) -> Result<WebServerStatus> {
+ let expected_addr =
+ parse_base_url(web_server_base_url).context("Failed to parse web server base URL")?;
+
+ let sockets = discover_webserver_sockets().context("Failed to discover web server sockets")?;
+
+ if sockets.is_empty() {
+ return Ok(WebServerStatus::Offline);
+ }
+
+ for socket_path in sockets {
+ let path_str = socket_path.to_str().unwrap_or("");
+
+ match query_webserver_with_response(path_str, InstructionForWebServer::QueryVersion, 500) {
+ Ok(WebServerResponse::Version(info)) => {
+ let matches_expected =
+ info.ip == expected_addr.ip && info.port == expected_addr.port;
+
+ if !matches_expected {
+ continue;
+ }
+
+ if info.version == VERSION {
+ return Ok(WebServerStatus::Online(web_server_base_url.to_string()));
+ } else {
+ return Ok(WebServerStatus::DifferentVersion(info.version));
+ }
+ },
+ Err(_) => continue,
+ }
+ }
+
+ Ok(WebServerStatus::Offline)
+}
diff --git a/zellij-utils/assets/prost_web_server/web_server_contract.rs b/zellij-utils/assets/prost_web_server/web_server_contract.rs
index c2e4dda5..05d9897b 100644
--- a/zellij-utils/assets/prost_web_server/web_server_contract.rs
+++ b/zellij-utils/assets/prost_web_server/web_server_contract.rs
@@ -1,7 +1,7 @@
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct InstructionForWebServer {
- #[prost(oneof="instruction_for_web_server::Instruction", tags="1")]
+ #[prost(oneof="instruction_for_web_server::Instruction", tags="1, 2")]
pub instruction: ::core::option::Option<instruction_for_web_server::Instruction>,
}
/// Nested message and enum types in `InstructionForWebServer`.
@@ -9,11 +9,13 @@ pub mod instruction_for_web_server {
#[allow(clippy::derive_partial_eq_without_eq)]
#[derive(Clone, PartialEq, ::prost::Oneof)]
pub enum Instruction {
- /// Future commands can be added here
- /// RestartWebServerMsg restart_web_server = 2;
- /// ReloadConfigMsg reload_config = 3;
#[prost(message, tag="1")]
ShutdownWebServer(super::ShutdownWebServerMsg),
+ /// Future commands can be added here
+ /// RestartWebServerMsg restart_web_server = 3;
+ /// ReloadConfigMsg reload_config = 4;
+ #[prost(message, tag="2")]
+ QueryVersion(super::QueryVersionMsg),
}
}
/// Empty for now, but allows for future parameters like graceful timeout
@@ -21,3 +23,32 @@ pub mod instruction_for_web_server {
#[derive(Clone, PartialEq, ::prost::Message)]
pub struct ShutdownWebServerMsg {
}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct QueryVersionMsg {
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct WebServerResponse {
+ #[prost(oneof="web_server_response::Response", tags="1")]
+ pub response: ::core::option::Option<web_server_response::Response>,
+}
+/// Nested message and enum types in `WebServerResponse`.
+pub mod web_server_response {
+ #[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Oneof)]
+ pub enum Response {
+ #[prost(message, tag="1")]
+ Version(super::VersionResponseMsg),
+ }
+}
+#[allow(clippy::derive_partial_eq_without_eq)]
+#[derive(Clone, PartialEq, ::prost::Message)]
+pub struct VersionResponseMsg {
+ #[prost(string, tag="1")]
+ pub version: ::prost::alloc::string::String,
+ #[prost(string, tag="2")]
+ pub ip: ::prost::alloc::string::String,
+ #[prost(uint32, tag="3")]
+ pub port: u32,
+}
diff --git a/zellij-utils/src/shared.rs b/zellij-utils/src/shared.rs
index 759bc0f4..5273c205 100644
--- a/zellij-utils/src/shared.rs
+++ b/zellij-utils/src/shared.rs
@@ -5,6 +5,7 @@ use std::{iter, str::from_utf8};
use crate::data::{Palette, PaletteColor, PaletteSource, ThemeHue};
use crate::envs::get_session_name;
+use crate::errors::prelude::*;
use crate::input::options::Options;
use colorsys::{Ansi256, Rgb};
use strip_ansi_escapes::strip;
@@ -207,3 +208,19 @@ pub fn web_server_base_url_from_config(config_options: Options) -> String {
enforce_https_for_localhost,
)
}
+
+pub struct ServerAddress {
+ pub ip: String,
+ pub port: u16,
+}
+
+pub fn parse_base_url(url: &str) -> Result<ServerAddress> {
+ let url = url::Url::parse(url)?;
+ let ip = url
+ .host_str()
+ .ok_or_else(|| anyhow!("No host in URL"))?
+ .to_string();
+ let port = url.port().ok_or_else(|| anyhow!("No port in URL"))?;
+
+ Ok(ServerAddress { ip, port })
+}
diff --git a/zellij-utils/src/web_server_commands.rs b/zellij-utils/src/web_server_commands.rs
index a1bcf885..3b5c4065 100644
--- a/zellij-utils/src/web_server_commands.rs
+++ b/zellij-utils/src/web_server_commands.rs
@@ -1,12 +1,14 @@
use crate::consts::WEBSERVER_SOCKET_PATH;
use crate::errors::prelude::*;
use crate::web_server_contract::web_server_contract::InstructionForWebServer as ProtoInstructionForWebServer;
+use crate::web_server_contract::web_server_contract::WebServerResponse as ProtoWebServerResponse;
use interprocess::local_socket::LocalSocketStream;
use prost::Message;
use serde::{Deserialize, Serialize};
use std::fs;
-use std::io::{BufWriter, Write};
+use std::io::{BufWriter, Read, Write};
use std::os::unix::fs::FileTypeExt;
+use std::path::PathBuf;
pub fn shutdown_all_webserver_instances() -> Result<()> {
let entries = fs::read_dir(&*WEBSERVER_SOCKET_PATH)?;
@@ -42,6 +44,19 @@ pub fn shutdown_all_webserver_instances() -> Result<()> {
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum InstructionForWebServer {
ShutdownWebServer,
+ QueryVersion,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub struct VersionInfo {
+ pub version: String,
+ pub ip: String,
+ pub port: u16,
+}
+
+#[derive(Serialize, Deserialize, Debug, Clone)]
+pub enum WebServerResponse {
+ Version(VersionInfo),
}
pub fn create_webserver_sender(path: &str) -> Result<BufWriter<LocalSocketStream>> {
@@ -65,3 +80,46 @@ pub fn send_webserver_instruction(
sender.flush()?;
Ok(())
}
+
+pub fn discover_webserver_sockets() -> Result<Vec<PathBuf>> {
+ let mut sockets = Vec::new();
+
+ if !WEBSERVER_SOCKET_PATH.exists() {
+ return Ok(sockets);
+ }
+
+ for entry in fs::read_dir(&*WEBSERVER_SOCKET_PATH)? {
+ let entry = entry?;
+ let path = entry.path();
+
+ if entry.metadata()?.file_type().is_socket() {
+ sockets.push(path);
+ }
+ }
+
+ Ok(sockets)
+}
+
+pub fn query_webserver_with_response(
+ path: &str,
+ instruction: InstructionForWebServer,
+ _timeout_ms: u64,
+) -> Result<WebServerResponse> {
+ let mut sender = create_webserver_sender(path)?;
+ send_webserver_instruction(&mut sender, instruction)?;
+
+ let stream = sender.into_inner()?;
+ receive_webserver_response(stream)
+}
+
+fn receive_webserver_response(mut stream: LocalSocketStream) -> Result<WebServerResponse> {
+ let mut len_bytes = [0u8; 4];
+ stream.read_exact(&mut len_bytes)?;
+ let len = u32::from_le_bytes(len_bytes) as usize;
+
+ let mut buffer = vec![0u8; len];
+ stream.read_exact(&mut buffer)?;
+
+ let proto_response = ProtoWebServerResponse::decode(&buffer[..])?;
+ proto_response.try_into()
+}
diff --git a/zellij-utils/src/web_server_contract/protobuf_conversion.rs b/zellij-utils/src/web_server_contract/protobuf_conversion.rs
index 7a89f600..c5f5f496 100644
--- a/zellij-utils/src/web_server_contract/protobuf_conversion.rs
+++ b/zellij-utils/src/web_server_contract/protobuf_conversion.rs
@@ -1,8 +1,11 @@
use crate::errors::prelude::*;
-use crate::web_server_commands::InstructionForWebServer as RustInstructionForWebServer;
+use crate::web_server_commands::{
+ InstructionForWebServer as RustInstructionForWebServer, VersionInfo, WebServerResponse,
+};
use crate::web_server_contract::web_server_contract::{
- instruction_for_web_server, InstructionForWebServer as ProtoInstructionForWebServer,
- ShutdownWebServerMsg,
+ instruction_for_web_server, web_server_response,
+ InstructionForWebServer as ProtoInstructionForWebServer, QueryVersionMsg, ShutdownWebServerMsg,
+ VersionResponseMsg, WebServerResponse as ProtoWebServerResponse,
};
// Convert Rust InstructionForWebServer to protobuf
@@ -12,6 +15,9 @@ impl From<RustInstructionForWebServer> for ProtoInstructionForWebServer {
RustInstructionForWebServer::ShutdownWebServer => {
instruction_for_web_server::Instruction::ShutdownWebServer(ShutdownWebServerMsg {})
},
+ RustInstructionForWebServer::QueryVersion => {
+ instruction_for_web_server::Instruction::QueryVersion(QueryVersionMsg {})
+ },
};
ProtoInstructionForWebServer {
@@ -29,7 +35,47 @@ impl TryFrom<ProtoInstructionForWebServer> for RustInstructionForWebServer {
Some(instruction_for_web_server::Instruction::ShutdownWebServer(_)) => {
Ok(RustInstructionForWebServer::ShutdownWebServer)
},
+ Some(instruction_for_web_server::Instruction::QueryVersion(_)) => {
+ Ok(RustInstructionForWebServer::QueryVersion)
+ },
None => Err(anyhow!("Missing instruction in InstructionForWebServer")),
}
}
}
+
+// Convert Rust WebServerResponse to protobuf
+impl From<WebServerResponse> for ProtoWebServerResponse {
+ fn from(response: WebServerResponse) -> Self {
+ let response = match response {
+ WebServerResponse::Version(version_info) => {
+ web_server_response::Response::Version(VersionResponseMsg {
+ version: version_info.version,
+ ip: version_info.ip,
+ port: version_info.port as u32,
+ })
+ },
+ };
+
+ ProtoWebServerResponse {
+ response: Some(response),
+ }
+ }
+}
+
+// Convert protobuf WebServerResponse to Rust
+impl TryFrom<ProtoWebServerResponse> for WebServerResponse {
+ type Error = anyhow::Error;
+
+ fn try_from(proto_response: ProtoWebServerResponse) -> Result<Self> {
+ match proto_response.response {
+ Some(web_server_response::Response::Version(version_msg)) => {
+ Ok(WebServerResponse::Version(VersionInfo {
+ version: version_msg.version,
+ ip: version_msg.ip,
+ port: version_msg.port as u16,
+ }))
+ },
+ None => Err(anyhow!("Missing response in WebServerResponse")),
+ }
+ }
+}
diff --git a/zellij-utils/src/web_server_contract/web_server_commands.proto b/zellij-utils/src/web_server_contract/web_server_commands.proto
index f8db28f9..dd1d7ae4 100644
--- a/zellij-utils/src/web_server_contract/web_server_commands.proto
+++ b/zellij-utils/src/web_server_contract/web_server_commands.proto
@@ -4,12 +4,27 @@ package web_server_contract;
message InstructionForWebServer {
oneof instruction {
ShutdownWebServerMsg shutdown_web_server = 1;
+ QueryVersionMsg query_version = 2;
// Future commands can be added here
- // RestartWebServerMsg restart_web_server = 2;
- // ReloadConfigMsg reload_config = 3;
+ // RestartWebServerMsg restart_web_server = 3;
+ // ReloadConfigMsg reload_config = 4;
}
}
message ShutdownWebServerMsg {
// Empty for now, but allows for future parameters like graceful timeout
+}
+
+message QueryVersionMsg {}
+
+message WebServerResponse {
+ oneof response {
+ VersionResponseMsg version = 1;
+ }
+}
+
+message VersionResponseMsg {
+ string version = 1;
+ string ip = 2;
+ uint32 port = 3;
} \ No newline at end of file