aboutsummaryrefslogtreecommitdiffstats
path: root/ui/backend/src/run/pty.rs
blob: 382b45ddde6456bc416f878f24493e877ca2dc21 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
use eyre::{Result, WrapErr};
use std::io::BufRead;
use std::path::PathBuf;

use crate::state::AtuinState;
use tauri::{Manager, State};

use atuin_client::{database::Sqlite, record::sqlite_store::SqliteStore, settings::Settings};

#[tauri::command]
pub async fn pty_open<'a>(
    app: tauri::AppHandle,
    state: State<'a, AtuinState>,
) -> Result<uuid::Uuid, String> {
    let id = uuid::Uuid::new_v4();
    let pty = crate::pty::Pty::open(24, 80).await.unwrap();

    let reader = pty.reader.clone();

    tauri::async_runtime::spawn_blocking(move || loop {
        let mut buf = [0u8; 512];

        match reader.lock().unwrap().read(&mut buf) {
            // EOF
            Ok(0) => {
                println!("reader loop hit eof");
                break;
            }

            Ok(n) => {
                println!("read {n} bytes");

                // TODO: sort inevitable encoding issues
                let out = String::from_utf8_lossy(&buf).to_string();
                let out = out.trim_matches(char::from(0));
                let channel = format!("pty-{id}");

                app.emit(channel.as_str(), out).unwrap();
            }

            Err(e) => {
                println!("failed to read: {e}");
                break;
            }
        }
    });

    state.pty_sessions.write().await.insert(id, pty);

    Ok(id)
}

#[tauri::command]
pub(crate) async fn pty_write(
    pid: uuid::Uuid,
    data: String,
    state: tauri::State<'_, AtuinState>,
) -> Result<(), String> {
    let sessions = state.pty_sessions.read().await;
    let pty = sessions.get(&pid).ok_or("Pty not found")?;

    let bytes = data.as_bytes().to_vec();
    pty.send_bytes(bytes.into())
        .await
        .map_err(|e| e.to_string())?;
    Ok(())
}

#[tauri::command]
pub(crate) async fn pty_resize(
    pid: uuid::Uuid,
    rows: u16,
    cols: u16,
    state: tauri::State<'_, AtuinState>,
) -> Result<(), String> {
    let sessions = state.pty_sessions.read().await;
    let pty = sessions.get(&pid).ok_or("Pty not found")?;

    pty.resize(rows, cols).await.map_err(|e| e.to_string())?;

    Ok(())
}

#[tauri::command]
pub(crate) async fn pty_kill(
    pid: uuid::Uuid,
    state: tauri::State<'_, AtuinState>,
) -> Result<(), String> {
    let pty = state.pty_sessions.write().await.remove(&pid).unwrap();
    println!("RIP {pid:?}");

    Ok(())
}