mirror of
https://github.com/atuinsh/atuin.git
synced 2025-06-25 04:11:53 +02:00
feat(daemon): add support for daemon on windows (#2014)
* fix: gracefully exit on windows * feat(daemon): tcp support for windows * feat(daemon): add tcp port configuration * fix: logging and fix compiler error * docs: add build dependency to the readme fix(docs): move a line up * fix: missing field error * docs: adds the daemon section to the default config * fix: clippy and fmt * feat: Update README.md Co-authored-by: Ellie Huxtable <ellie@elliehuxtable.com> * refactor: changes tcp port and other stuff as per request * fix(config): update default tcp port in example config * fix: complier error on unix * refactor: make the cfg stuff look better --------- Co-authored-by: Ellie Huxtable <ellie@elliehuxtable.com>
This commit is contained in:
parent
0da534d524
commit
ce67e52772
@ -174,6 +174,9 @@ cargo install atuin
|
|||||||
|
|
||||||
And then follow [the shell setup](#shell-plugin)
|
And then follow [the shell setup](#shell-plugin)
|
||||||
|
|
||||||
|
#### Daemon Build Dependencies
|
||||||
|
[Protoc](https://grpc.io/docs/protoc-installation/) is required to build the daemon, which is enabled by default. This is because we use protobufs for the message serialization
|
||||||
|
|
||||||
### Homebrew
|
### Homebrew
|
||||||
|
|
||||||
```
|
```
|
||||||
|
@ -210,3 +210,18 @@ records = true
|
|||||||
## auto: length of the selected command.
|
## auto: length of the selected command.
|
||||||
## static: length of the longest command stored in the history.
|
## static: length of the longest command stored in the history.
|
||||||
# strategy = "auto"
|
# strategy = "auto"
|
||||||
|
|
||||||
|
[daemon]
|
||||||
|
## Enables using the daemon to sync. Requires the daemon to be running in the background. Start it with `atuin daemon`
|
||||||
|
# enabled = false
|
||||||
|
|
||||||
|
## How often the daemon should sync in seconds
|
||||||
|
# sync_frequency = 300
|
||||||
|
|
||||||
|
## The path to the unix socket used by the daemon (on unix systems)
|
||||||
|
## linux/mac: ~/.local/share/atuin/atuin.sock
|
||||||
|
## windows: Not Supported
|
||||||
|
# socket_path = "~/atuin.sock"
|
||||||
|
|
||||||
|
## The port that should be used for TCP on non unix systems
|
||||||
|
# tcp_port = 8889
|
||||||
|
@ -353,6 +353,9 @@ pub struct Daemon {
|
|||||||
|
|
||||||
/// The path to the unix socket used by the daemon
|
/// The path to the unix socket used by the daemon
|
||||||
pub socket_path: String,
|
pub socket_path: String,
|
||||||
|
|
||||||
|
/// The port that should be used for TCP on non unix systems
|
||||||
|
pub tcp_port: u64,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Default for Preview {
|
impl Default for Preview {
|
||||||
@ -369,6 +372,7 @@ impl Default for Daemon {
|
|||||||
enabled: false,
|
enabled: false,
|
||||||
sync_frequency: 300,
|
sync_frequency: 300,
|
||||||
socket_path: "".to_string(),
|
socket_path: "".to_string(),
|
||||||
|
tcp_port: 8889,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -706,6 +710,7 @@ impl Settings {
|
|||||||
.set_default("daemon.sync_frequency", 300)?
|
.set_default("daemon.sync_frequency", 300)?
|
||||||
.set_default("daemon.enabled", false)?
|
.set_default("daemon.enabled", false)?
|
||||||
.set_default("daemon.socket_path", socket_path.to_str())?
|
.set_default("daemon.socket_path", socket_path.to_str())?
|
||||||
|
.set_default("daemon.tcp_port", 8889)?
|
||||||
.set_default(
|
.set_default(
|
||||||
"prefers_reduced_motion",
|
"prefers_reduced_motion",
|
||||||
std::env::var("NO_MOTION")
|
std::env::var("NO_MOTION")
|
||||||
|
@ -1,8 +1,12 @@
|
|||||||
use eyre::{eyre, Result};
|
use eyre::{eyre, Result};
|
||||||
use tokio::net::UnixStream;
|
#[cfg(windows)]
|
||||||
|
use tokio::net::TcpStream;
|
||||||
use tonic::transport::{Channel, Endpoint, Uri};
|
use tonic::transport::{Channel, Endpoint, Uri};
|
||||||
use tower::service_fn;
|
use tower::service_fn;
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
use tokio::net::UnixStream;
|
||||||
|
|
||||||
use atuin_client::history::History;
|
use atuin_client::history::History;
|
||||||
|
|
||||||
use crate::history::{
|
use crate::history::{
|
||||||
@ -15,6 +19,7 @@ pub struct HistoryClient {
|
|||||||
|
|
||||||
// Wrap the grpc client
|
// Wrap the grpc client
|
||||||
impl HistoryClient {
|
impl HistoryClient {
|
||||||
|
#[cfg(unix)]
|
||||||
pub async fn new(path: String) -> Result<Self> {
|
pub async fn new(path: String) -> Result<Self> {
|
||||||
let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
|
let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
|
||||||
.connect_with_connector(service_fn(move |_: Uri| {
|
.connect_with_connector(service_fn(move |_: Uri| {
|
||||||
@ -30,6 +35,21 @@ impl HistoryClient {
|
|||||||
Ok(HistoryClient { client })
|
Ok(HistoryClient { client })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
pub async fn new(port: u64) -> Result<Self> {
|
||||||
|
let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
|
||||||
|
.connect_with_connector(service_fn(move |_: Uri| {
|
||||||
|
let url = format!("127.0.0.1:{}", port);
|
||||||
|
TcpStream::connect(url)
|
||||||
|
}))
|
||||||
|
.await
|
||||||
|
.map_err(|_| eyre!("failed to connect to local atuin daemon. Is it running?"))?;
|
||||||
|
|
||||||
|
let client = HistoryServiceClient::new(channel);
|
||||||
|
|
||||||
|
Ok(HistoryClient { client })
|
||||||
|
}
|
||||||
|
|
||||||
pub async fn start_history(&mut self, h: History) -> Result<String> {
|
pub async fn start_history(&mut self, h: History) -> Result<String> {
|
||||||
let req = StartHistoryRequest {
|
let req = StartHistoryRequest {
|
||||||
command: h.command,
|
command: h.command,
|
||||||
|
@ -13,8 +13,6 @@ use atuin_client::database::{Database, Sqlite as HistoryDatabase};
|
|||||||
use atuin_client::history::{History, HistoryId};
|
use atuin_client::history::{History, HistoryId};
|
||||||
use dashmap::DashMap;
|
use dashmap::DashMap;
|
||||||
use eyre::Result;
|
use eyre::Result;
|
||||||
use tokio::net::UnixListener;
|
|
||||||
use tokio_stream::wrappers::UnixListenerStream;
|
|
||||||
use tonic::{transport::Server, Request, Response, Status};
|
use tonic::{transport::Server, Request, Response, Status};
|
||||||
|
|
||||||
use crate::history::history_server::{History as HistorySvc, HistoryServer};
|
use crate::history::history_server::{History as HistorySvc, HistoryServer};
|
||||||
@ -134,6 +132,7 @@ impl HistorySvc for HistoryService {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
async fn shutdown_signal(socket: PathBuf) {
|
async fn shutdown_signal(socket: PathBuf) {
|
||||||
let mut term = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
|
let mut term = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
|
||||||
.expect("failed to register sigterm handler");
|
.expect("failed to register sigterm handler");
|
||||||
@ -150,6 +149,52 @@ async fn shutdown_signal(socket: PathBuf) {
|
|||||||
eprintln!("Shutting down...");
|
eprintln!("Shutting down...");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(windows)]
|
||||||
|
async fn shutdown_signal() {
|
||||||
|
tokio::signal::windows::ctrl_c()
|
||||||
|
.expect("failed to register signal handler")
|
||||||
|
.recv()
|
||||||
|
.await;
|
||||||
|
eprintln!("Shutting down...");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(unix)]
|
||||||
|
async fn start_server(settings: Settings, history: HistoryService) -> Result<()> {
|
||||||
|
use tokio::net::UnixListener;
|
||||||
|
use tokio_stream::wrappers::UnixListenerStream;
|
||||||
|
|
||||||
|
let socket = settings.daemon.socket_path.clone();
|
||||||
|
|
||||||
|
let uds = UnixListener::bind(socket.clone())?;
|
||||||
|
let uds_stream = UnixListenerStream::new(uds);
|
||||||
|
|
||||||
|
tracing::info!("listening on unix socket {:?}", socket);
|
||||||
|
Server::builder()
|
||||||
|
.add_service(HistoryServer::new(history))
|
||||||
|
.serve_with_incoming_shutdown(uds_stream, shutdown_signal(socket.into()))
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
async fn start_server(settings: Settings, history: HistoryService) -> Result<()> {
|
||||||
|
use tokio::net::TcpListener;
|
||||||
|
use tokio_stream::wrappers::TcpListenerStream;
|
||||||
|
|
||||||
|
let port = settings.daemon.tcp_port;
|
||||||
|
let url = format!("127.0.0.1:{}", port);
|
||||||
|
let tcp = TcpListener::bind(url).await?;
|
||||||
|
let tcp_stream = TcpListenerStream::new(tcp);
|
||||||
|
|
||||||
|
tracing::info!("listening on tcp port {:?}", port);
|
||||||
|
|
||||||
|
Server::builder()
|
||||||
|
.add_service(HistoryServer::new(history))
|
||||||
|
.serve_with_incoming_shutdown(tcp_stream, shutdown_signal())
|
||||||
|
.await?;
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
// break the above down when we end up with multiple services
|
// break the above down when we end up with multiple services
|
||||||
|
|
||||||
/// Listen on a unix socket
|
/// Listen on a unix socket
|
||||||
@ -168,12 +213,6 @@ pub async fn listen(
|
|||||||
|
|
||||||
let history = HistoryService::new(history_store.clone(), history_db.clone());
|
let history = HistoryService::new(history_store.clone(), history_db.clone());
|
||||||
|
|
||||||
let socket = settings.daemon.socket_path.clone();
|
|
||||||
let uds = UnixListener::bind(socket.clone())?;
|
|
||||||
let uds_stream = UnixListenerStream::new(uds);
|
|
||||||
|
|
||||||
tracing::info!("listening on unix socket {:?}", socket);
|
|
||||||
|
|
||||||
// start services
|
// start services
|
||||||
tokio::spawn(sync::worker(
|
tokio::spawn(sync::worker(
|
||||||
settings.clone(),
|
settings.clone(),
|
||||||
@ -182,10 +221,5 @@ pub async fn listen(
|
|||||||
history_db,
|
history_db,
|
||||||
));
|
));
|
||||||
|
|
||||||
Server::builder()
|
start_server(settings, history).await
|
||||||
.add_service(HistoryServer::new(history))
|
|
||||||
.serve_with_incoming_shutdown(uds_stream, shutdown_signal(socket.into()))
|
|
||||||
.await?;
|
|
||||||
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
@ -315,8 +315,12 @@ impl Cmd {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if settings.daemon.enabled {
|
if settings.daemon.enabled {
|
||||||
let resp =
|
let resp = atuin_daemon::client::HistoryClient::new(
|
||||||
atuin_daemon::client::HistoryClient::new(settings.daemon.socket_path.clone())
|
#[cfg(not(unix))]
|
||||||
|
settings.daemon.tcp_port,
|
||||||
|
#[cfg(unix)]
|
||||||
|
settings.daemon.socket_path.clone(),
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
.start_history(h)
|
.start_history(h)
|
||||||
.await?;
|
.await?;
|
||||||
@ -350,7 +354,12 @@ impl Cmd {
|
|||||||
// We will need to keep the old code around for a while.
|
// We will need to keep the old code around for a while.
|
||||||
// At the very least, while this is opt-in
|
// At the very least, while this is opt-in
|
||||||
if settings.daemon.enabled {
|
if settings.daemon.enabled {
|
||||||
atuin_daemon::client::HistoryClient::new(settings.daemon.socket_path.clone())
|
let resp = atuin_daemon::client::HistoryClient::new(
|
||||||
|
#[cfg(not(unix))]
|
||||||
|
settings.daemon.tcp_port,
|
||||||
|
#[cfg(unix)]
|
||||||
|
settings.daemon.socket_path.clone(),
|
||||||
|
)
|
||||||
.await?
|
.await?
|
||||||
.end_history(id.to_string(), duration.unwrap_or(0), exit)
|
.end_history(id.to_string(), duration.unwrap_or(0), exit)
|
||||||
.await?;
|
.await?;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user