~kmaasrud/toe

3340218c9fa4d22d69dc0bca3e63ae124d946d45 — kmaasrud 11 months ago 7e66b6b
feat: setup simple server/client communication
5 files changed, 100 insertions(+), 7 deletions(-)

M Cargo.toml
A README.md
A src/bin/toed.rs
A src/bin/toenail.rs
D src/main.rs
M Cargo.toml => Cargo.toml +0 -4
@@ 6,7 6,3 @@ edition = "2021"
authors = ["Knut Magnus Aasrud <km@aasrud.com>"]
homepage = "https://git.sr.ht/~kmaasrud/toe"
license = "MIT"

# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html

[dependencies]

A README.md => README.md +18 -0
@@ 0,0 1,18 @@
# toe

To run the daemon:

```
$ cargo run --bin toed
```

This will start the daemon process, which listens on a TCP socket at
`127.0.0.1:1702`. You can then query information with the client:

```
$ cargo run --bin toenail [request]
```

Replace `[request]` with the request you want to send to the server. The default
(and currently only) request is "user", which returns the name of the user
running the daemon process.

A src/bin/toed.rs => src/bin/toed.rs +61 -0
@@ 0,0 1,61 @@
use std::env;
use std::error::Error;
use std::io::{BufRead, BufReader, Write};
use std::net::{TcpListener, TcpStream};
use std::process;
use std::thread;

fn main() -> Result<(), Box<dyn Error>> {
    let listener = TcpListener::bind("127.0.0.1:1702")?;

    for stream in listener.incoming() {
        match stream {
            Ok(stream) => {
                println!("New connection: {}", stream.peer_addr().unwrap());
                thread::spawn(move || {
                    handle_client(stream).unwrap();
                });
            }
            Err(e) => {
                println!("Error: {}", e);
            }
        }
    }

    Ok(())
}

fn handle_client(mut stream: TcpStream) -> Result<(), Box<dyn Error>> {
    let buf_reader = BufReader::new(&mut stream);
    let request: Vec<String> = buf_reader
        .lines()
        .map(|result| result.unwrap())
        .take_while(|line| !line.is_empty())
        .collect();

    if let Some(request) = request.get(0) {
        match request.as_str() {
            "user" => {
                writeln!(stream, "Daemon host user: {}", get_user().unwrap())?;
                stream.flush()?;
            }
            _ => writeln!(stream, "Unknown request: {request}").unwrap(),
        }
    }

    Ok(())
}

fn get_user() -> Option<String> {
    if let Some(user) = env::var_os("USER") {
        return Some(user.into_string().unwrap());
    }

    if let Ok(output) = process::Command::new("id").arg("-un").output() {
        if output.status.success() {
            return Some(String::from_utf8(output.stdout).ok()?);
        }
    }

    None
}

A src/bin/toenail.rs => src/bin/toenail.rs +21 -0
@@ 0,0 1,21 @@
use std::io::{prelude::*, BufRead, BufReader};
use std::net::TcpStream;

fn main() {
    let request = std::env::args().nth(1).unwrap_or("user".to_string());

    match TcpStream::connect("127.0.0.1:1702") {
        Ok(mut stream) => {
            write!(stream, "{request}\n\n").unwrap();
            stream.flush().unwrap();

            let buf_reader = BufReader::new(&mut stream);
            for line in buf_reader.lines() {
                if let Ok(line) = line {
                    println!("{}", line);
                }
            }
        }
        Err(e) => eprintln!("{e}"),
    }
}

D src/main.rs => src/main.rs +0 -3
@@ 1,3 0,0 @@
fn main() {
    println!("Hello from toe!");
}