Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(daemon): add support for daemon on windows #2014

Merged
merged 14 commits into from
May 13, 2024
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
45 changes: 24 additions & 21 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
Atuin replaces your existing shell history with a SQLite database, and records
additional context for your commands. Additionally, it provides optional and
_fully encrypted_ synchronisation of your history between machines, via an Atuin
server.
server.



Expand Down Expand Up @@ -90,7 +90,7 @@ I wanted to. And I **really** don't want to.
- fish
- nushell
- xonsh

## Community

### Forum
Expand All @@ -102,11 +102,11 @@ Atuin has a community forum, please ask here for help and support: https://forum
Atuin also has a community Discord, available [here](https://discord.gg/jR3tfchVvW)

# Quickstart

## With the default sync server

This will sign you up for the default sync server, hosted by me. Everything is end-to-end encrypted, so your secrets are safe!

Read more below for offline-only usage, or for hosting your own server.

```
Expand All @@ -130,10 +130,10 @@ Then restart your shell!
> section below.

## Offline only (no sync)

```
bash <(curl https://raw.githubusercontent.com/atuinsh/atuin/main/install.sh)

atuin import auto
```

Expand Down Expand Up @@ -171,25 +171,28 @@ toolchain, then you can run:
```
cargo install atuin
```

And then follow [the shell setup](#shell-plugin)

#### Daemon Build Dependencies
[Protocol](https://grpc.io/docs/protoc-installation/) is required to build the daemon, which is enabled by default.
YummyOreo marked this conversation as resolved.
Show resolved Hide resolved

### Homebrew

```
brew install atuin
```

And then follow [the shell setup](#shell-plugin)

### MacPorts

Atuin is also available in [MacPorts](https://ports.macports.org/port/atuin/)
Atuin is also available in [MacPorts](https://ports.macports.org/port/atuin/)

```
sudo port install atuin
```

And then follow [the shell setup](#shell-plugin)

### Cave
Expand Down Expand Up @@ -223,7 +226,7 @@ Atuin is available in the Arch Linux [[extra] repository](https://archlinux.org/
```
pacman -S atuin
```

And then follow [the shell setup](#shell-plugin)

### Xbps
Expand All @@ -243,7 +246,7 @@ Atuin is available in the Termux package repository:
```
pkg install atuin
```

And then follow [the shell setup](#shell-plugin)

### From source
Expand All @@ -253,7 +256,7 @@ git clone https://github.com/atuinsh/atuin.git
cd atuin/crates/atuin
cargo install --path .
```

And then follow [the shell setup](#shell-plugin)

## Shell plugin
Expand All @@ -273,9 +276,9 @@ echo 'eval "$(atuin init zsh)"' >> ~/.zshrc
zinit load atuinsh/atuin
```

#### Antigen
```sh
#### Antigen

```sh
antigen bundle atuinsh/atuin@main
```

Expand Down Expand Up @@ -345,7 +348,7 @@ atuin init fish | source
```

to your `is-interactive` block in your `~/.config/fish/config.fish` file

### Nushell

Run in *Nushell*:
Expand All @@ -371,7 +374,7 @@ to the end of your `~/.xonshrc`

# Security

If you find any security issues, we'd appreciate it if you could alert ellie@atuin.sh
If you find any security issues, we'd appreciate it if you could alert ellie@atuin.sh

# Contributors

Expand Down
15 changes: 15 additions & 0 deletions crates/atuin-client/config.toml
Original file line number Diff line number Diff line change
Expand Up @@ -210,3 +210,18 @@ records = true
## auto: length of the selected command.
## static: length of the longest command stored in the history.
# 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 = 2468
5 changes: 5 additions & 0 deletions crates/atuin-client/src/settings.rs
Original file line number Diff line number Diff line change
Expand Up @@ -353,6 +353,9 @@ pub struct Daemon {

/// The path to the unix socket used by the daemon
pub socket_path: String,

/// The port that should be used for TCP on non unix systems
pub tcp_port: u64,
}

impl Default for Preview {
Expand All @@ -369,6 +372,7 @@ impl Default for Daemon {
enabled: false,
sync_frequency: 300,
socket_path: "".to_string(),
tcp_port: 2468,
YummyOreo marked this conversation as resolved.
Show resolved Hide resolved
}
}
}
Expand Down Expand Up @@ -706,6 +710,7 @@ impl Settings {
.set_default("daemon.sync_frequency", 300)?
.set_default("daemon.enabled", false)?
.set_default("daemon.socket_path", socket_path.to_str())?
.set_default("daemon.tcp_port", 2468)?
YummyOreo marked this conversation as resolved.
Show resolved Hide resolved
.set_default(
"prefers_reduced_motion",
std::env::var("NO_MOTION")
Expand Down
20 changes: 17 additions & 3 deletions crates/atuin-daemon/src/client.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,12 @@
use eyre::{eyre, Result};
use tokio::net::UnixStream;
#[cfg(windows)]
use tokio::net::TcpStream;
use tonic::transport::{Channel, Endpoint, Uri};
use tower::service_fn;

#[cfg(unix)]
use tokio::net::UnixStream;

use atuin_client::history::History;

use crate::history::{
Expand All @@ -15,12 +19,22 @@ pub struct HistoryClient {

// Wrap the grpc client
impl HistoryClient {
pub async fn new(path: String) -> Result<Self> {
// Allow unused because the port won't be used on unix and the path won't be on non-unix.
YummyOreo marked this conversation as resolved.
Show resolved Hide resolved
#[allow(unused_variables)]
pub async fn new(path: String, port: u64) -> Result<Self> {
let channel = Endpoint::try_from("http://atuin_local_daemon:0")?
.connect_with_connector(service_fn(move |_: Uri| {
let path = path.to_string();

UnixStream::connect(path)
#[cfg(unix)]
{
UnixStream::connect(path)
}
#[cfg(windows)]
{
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?"))?;
Expand Down
56 changes: 44 additions & 12 deletions crates/atuin-daemon/src/server.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,8 +13,6 @@ use atuin_client::database::{Database, Sqlite as HistoryDatabase};
use atuin_client::history::{History, HistoryId};
use dashmap::DashMap;
use eyre::Result;
use tokio::net::UnixListener;
use tokio_stream::wrappers::UnixListenerStream;
use tonic::{transport::Server, Request, Response, Status};

use crate::history::history_server::{History as HistorySvc, HistoryServer};
Expand Down Expand Up @@ -134,6 +132,7 @@ impl HistorySvc for HistoryService {
}
}

#[cfg(unix)]
async fn shutdown_signal(socket: PathBuf) {
let mut term = tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate())
.expect("failed to register sigterm handler");
Expand All @@ -150,6 +149,15 @@ async fn shutdown_signal(socket: PathBuf) {
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...");
}

// break the above down when we end up with multiple services

/// Listen on a unix socket
Expand All @@ -168,12 +176,6 @@ pub async fn listen(

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
tokio::spawn(sync::worker(
settings.clone(),
Expand All @@ -182,10 +184,40 @@ pub async fn listen(
history_db,
));

Server::builder()
.add_service(HistoryServer::new(history))
.serve_with_incoming_shutdown(uds_stream, shutdown_signal(socket.into()))
.await?;
#[cfg(unix)]
YummyOreo marked this conversation as resolved.
Show resolved Hide resolved
{
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?;
}

#[cfg(not(unix))]
{
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(())
}
23 changes: 14 additions & 9 deletions crates/atuin/src/command/client/history.rs
Original file line number Diff line number Diff line change
Expand Up @@ -315,11 +315,13 @@ impl Cmd {
}

if settings.daemon.enabled {
let resp =
atuin_daemon::client::HistoryClient::new(settings.daemon.socket_path.clone())
.await?
.start_history(h)
.await?;
let resp = atuin_daemon::client::HistoryClient::new(
settings.daemon.socket_path.clone(),
settings.daemon.tcp_port,
)
.await?
.start_history(h)
.await?;

// print the ID
// we use this as the key for calling end
Expand Down Expand Up @@ -350,10 +352,13 @@ impl Cmd {
// We will need to keep the old code around for a while.
// At the very least, while this is opt-in
if settings.daemon.enabled {
atuin_daemon::client::HistoryClient::new(settings.daemon.socket_path.clone())
.await?
.end_history(id.to_string(), duration.unwrap_or(0), exit)
.await?;
atuin_daemon::client::HistoryClient::new(
settings.daemon.socket_path.clone(),
settings.daemon.tcp_port,
)
.await?
.end_history(id.to_string(), duration.unwrap_or(0), exit)
.await?;

return Ok(());
}
Expand Down
Loading