Compare commits

...

2 Commits

Author SHA1 Message Date
Nathan Sobo
24e29488b9 💄 2024-05-14 16:42:19 -06:00
Nathan Sobo
0a6cb92af9 Start on a domain socket event server
Set event_stream: "/path/to/socket" in settings.

Co-Authored-By: Matthew Weitzel <mweitzel@gmail.com>
2024-05-14 16:35:05 -06:00
6 changed files with 183 additions and 0 deletions

15
Cargo.lock generated
View File

@@ -3727,6 +3727,20 @@ dependencies = [
"pin-project-lite",
]
[[package]]
name = "event_server"
version = "0.1.0"
dependencies = [
"anyhow",
"gpui",
"schemars",
"serde",
"serde_json",
"settings",
"smol",
"util",
]
[[package]]
name = "exec"
version = "0.3.1"
@@ -12953,6 +12967,7 @@ dependencies = [
"diagnostics",
"editor",
"env_logger",
"event_server",
"extension",
"extensions_ui",
"feedback",

View File

@@ -23,6 +23,7 @@ members = [
"crates/db",
"crates/diagnostics",
"crates/editor",
"crates/event_server",
"crates/extension",
"crates/extension_api",
"crates/extension_cli",
@@ -168,6 +169,7 @@ copilot = { path = "crates/copilot" }
db = { path = "crates/db" }
diagnostics = { path = "crates/diagnostics" }
editor = { path = "crates/editor" }
event_server = { path = "crates/event_server" }
extension = { path = "crates/extension" }
extensions_ui = { path = "crates/extensions_ui" }
feature_flags = { path = "crates/feature_flags" }

View File

@@ -0,0 +1,23 @@
[package]
name = "event_server"
version = "0.1.0"
edition = "2021"
[lib]
path = "./src/event_server.rs"
[dependencies]
anyhow.workspace = true
gpui.workspace = true
schemars.workspace = true
serde.workspace = true
serde_json.workspace = true
settings.workspace = true
smol.workspace = true
util.workspace = true
[dev-dependencies]
gpui = { workspace = true, features = ["test-support"] }
[lints]
workspace = true

View File

@@ -0,0 +1,141 @@
use anyhow::Result;
use gpui::{AppContext, BorrowAppContext, Global, Task};
use schemars::JsonSchema;
use serde::{Deserialize, Serialize};
use settings::{Settings, SettingsStore};
use smol::{channel::Sender, io::AsyncWriteExt, stream::StreamExt};
use std::{path::PathBuf, time::Duration};
use util::{ResultExt, TryFutureExt};
#[derive(Serialize)]
pub enum OutputEvent {
Hello,
Save { path: PathBuf },
}
struct EventServer {
handler: Option<IoHandler>,
}
struct IoHandler {
tx: Sender<OutputEvent>,
_task: Task<Option<()>>,
}
impl Global for EventServer {}
impl EventServer {
pub fn send(&self, event: OutputEvent) {
if let Some(handler) = &self.handler {
if dbg!(handler.tx.receiver_count()) > 1 {
handler.tx.try_send(event).log_err();
}
}
}
}
#[derive(Deserialize, Serialize, Clone, JsonSchema, Default)]
struct EventServerSettings {
event_server: Option<PathBuf>,
}
impl Settings for EventServerSettings {
const KEY: Option<&'static str> = None;
type FileContent = Self;
fn load(
sources: settings::SettingsSources<Self::FileContent>,
_cx: &mut AppContext,
) -> gpui::Result<Self>
where
Self: Sized,
{
sources.json_merge()
}
}
pub fn init(cx: &mut AppContext) {
EventServerSettings::register(cx);
let mut socket_path = EventServerSettings::get_global(cx).event_server.clone();
let mut server = EventServer::new();
server.set_socket_path(socket_path.clone(), cx).log_err();
cx.set_global(server);
cx.observe_global::<SettingsStore>(move |cx| {
let new_socket_path = &EventServerSettings::get_global(cx).event_server;
if *new_socket_path != socket_path {
socket_path = new_socket_path.clone();
cx.update_global(|server: &mut EventServer, cx| {
server.set_socket_path(socket_path.clone(), cx).log_err();
});
}
})
.detach();
// TODO: Remove this test code
cx.spawn(|cx| async move {
loop {
cx.background_executor()
.timer(Duration::from_millis(2000))
.await;
cx.update(|cx| {
cx.global::<EventServer>().send(OutputEvent::Hello);
})
.ok();
}
})
.detach();
}
impl EventServer {
pub fn new() -> Self {
Self { handler: None }
}
pub fn set_socket_path(&mut self, path: Option<PathBuf>, cx: &AppContext) -> Result<()> {
if let Some(path) = path {
let executor = cx.background_executor().clone();
let (tx, rx) = smol::channel::unbounded();
let _task = cx.background_executor().spawn(
async move {
smol::fs::remove_file(&path).await.ok();
let listener = smol::net::unix::UnixListener::bind(&path)?;
let mut incoming = listener.incoming();
while let Some(stream) = incoming.next().await {
if let Some(mut stream) = stream.log_err() {
let rx = rx.clone();
executor
.spawn(
async move {
while let Some(message) = rx.recv().await.ok() {
stream
.write_all(
serde_json::to_string(&message)?.as_bytes(),
)
.await?;
stream.write_all(b"\n").await?;
}
anyhow::Ok(())
}
.log_err(),
)
.detach();
}
}
anyhow::Ok(())
}
.log_err(),
);
self.handler = Some(IoHandler { tx, _task });
} else {
self.handler = None;
}
Ok(())
}
}

View File

@@ -38,6 +38,7 @@ db.workspace = true
diagnostics.workspace = true
editor.workspace = true
env_logger.workspace = true
event_server.workspace = true
extension.workspace = true
extensions_ui.workspace = true
feedback.workspace = true

View File

@@ -161,6 +161,7 @@ fn init_ui(app_state: Arc<AppState>, cx: &mut AppContext) -> Result<()> {
markdown_preview::init(cx);
welcome::init(cx);
extensions_ui::init(cx);
event_stream::init(cx);
// Initialize each completion provider. Settings are used for toggling between them.
let copilot_language_server_id = app_state.languages.next_language_server_id();