use std::os::unix::net::{UnixListener, UnixStream};
use std::io::{Read, Write};
use std::process::Command;
use serde_json::Value;
use rand::{thread_rng, Rng};
use rand::distributions::Alphanumeric;
use crate::error::{GuiError, Result};
pub fn generate_random_address() -> String {
thread_rng()
.sample_iter(&Alphanumeric)
.take(50)
.map(char::from)
.collect()
}
pub fn bind_abstract_socket(name: &str) -> Result<UnixListener> {
unsafe {
use std::os::unix::io::FromRawFd;
let fd = libc::socket(libc::AF_UNIX, libc::SOCK_STREAM, 0);
if fd < 0 {
return Err(GuiError::Io(std::io::Error::last_os_error()));
}
let mut addr_bytes = vec![0u8];
addr_bytes.extend_from_slice(name.as_bytes());
let mut addr: libc::sockaddr_un = std::mem::zeroed();
addr.sun_family = libc::AF_UNIX as u16;
for (i, &byte) in addr_bytes.iter().enumerate() {
addr.sun_path[i] = byte as _;
}
let addr_len = (std::mem::size_of::<libc::sa_family_t>() + addr_bytes.len()) as libc::socklen_t;
if libc::bind(fd, &addr as *const _ as *const libc::sockaddr, addr_len) < 0 {
libc::close(fd);
return Err(GuiError::SocketBind(format!("bind failed for {}", name)));
}
if libc::listen(fd, 1) < 0 {
libc::close(fd);
return Err(GuiError::SocketBind(format!("listen failed for {}", name)));
}
Ok(UnixListener::from_raw_fd(fd))
}
}
pub fn send_message(stream: &mut UnixStream, msg: &Value) -> Result<()> {
let json_bytes = msg.to_string().into_bytes();
stream.write_all(&(json_bytes.len() as u32).to_be_bytes())?;
stream.write_all(&json_bytes)?;
stream.flush()?;
Ok(())
}
pub fn read_message(stream: &mut UnixStream) -> Result<Value> {
let mut len_buf = [0u8; 4];
stream.read_exact(&mut len_buf)?;
let len = u32::from_be_bytes(len_buf) as usize;
let mut buf = vec![0u8; len];
stream.read_exact(&mut buf)?;
let value = serde_json::from_slice(&buf)?;
Ok(value)
}
pub fn send_and_read(stream: &mut UnixStream, msg: &Value) -> Result<Value> {
eprintln!("[DEBUG] send_and_read: sending...");
send_message(stream, msg)?;
eprintln!("[DEBUG] send_and_read: reading response...");
let response = read_message(stream)?;
eprintln!("[DEBUG] send_and_read: got response!");
Ok(response)
}
pub struct Connection {
pub main_stream: UnixStream,
pub event_stream: UnixStream,
}
impl Connection {
pub fn new() -> Result<Self> {
eprintln!("[DEBUG] Generating addresses...");
let addr_main = generate_random_address();
let addr_event = generate_random_address();
eprintln!("[DEBUG] Binding sockets...");
let main_listener = bind_abstract_socket(&addr_main)?;
let event_listener = bind_abstract_socket(&addr_event)?;
eprintln!("[DEBUG] Sending broadcast...");
let output = Command::new("termux-am")
.args(&[
"broadcast",
"-n",
"com.termux.gui/.GUIReceiver",
"--es",
"mainSocket",
&addr_main,
"--es",
"eventSocket",
&addr_event,
])
.output();
match output {
Ok(out) if !out.status.success() => {
eprintln!("[DEBUG] termux-am failed, trying am...");
Command::new("am")
.args(&[
"broadcast",
"-n",
"com.termux.gui/.GUIReceiver",
"--es",
"mainSocket",
&addr_main,
"--es",
"eventSocket",
&addr_event,
])
.output()
.map_err(|_| GuiError::ConnectionFailed)?;
}
Err(_) => {
eprintln!("[DEBUG] termux-am not found, trying am...");
Command::new("am")
.args(&[
"broadcast",
"-n",
"com.termux.gui/.GUIReceiver",
"--es",
"mainSocket",
&addr_main,
"--es",
"eventSocket",
&addr_event,
])
.output()
.map_err(|_| GuiError::ConnectionFailed)?;
}
_ => {}
}
eprintln!("[DEBUG] Accepting connections...");
let (mut main_stream, _) = main_listener.accept()?;
let (event_stream, _) = event_listener.accept()?;
eprintln!("[DEBUG] Handshake...");
main_stream.write_all(&[0x01])?;
main_stream.read_exact(&mut [0u8; 1])?;
eprintln!("[DEBUG] Connection established!");
Ok(Connection {
main_stream,
event_stream,
})
}
pub fn send(&mut self, msg: &Value) -> Result<()> {
send_message(&mut self.main_stream, msg)
}
pub fn send_read(&mut self, msg: &Value) -> Result<Value> {
send_and_read(&mut self.main_stream, msg)
}
pub fn event_stream(&mut self) -> &mut UnixStream {
&mut self.event_stream
}
}