node: Test control socket
Signed-off-by: Alexis Sellier <self@cloudhead.io>
This commit is contained in:
parent
12dd6d4a5d
commit
400ba8d935
|
|
@ -53,14 +53,14 @@ pub struct Handle<R: Reactor> {
|
||||||
pub(crate) listening: chan::Receiver<net::SocketAddr>,
|
pub(crate) listening: chan::Receiver<net::SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<R: Reactor> Handle<R> {
|
impl<R: Reactor> traits::Handle for Handle<R> {
|
||||||
/// Notify the client that a project has been updated.
|
/// Notify the client that a project has been updated.
|
||||||
pub fn updated(&self, id: ProjId) -> Result<(), Error> {
|
fn updated(&self, id: ProjId) -> Result<(), Error> {
|
||||||
self.command(protocol::Command::AnnounceInventory(id))
|
self.command(protocol::Command::AnnounceInventory(id))
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Send a command to the command channel, and wake up the event loop.
|
/// Send a command to the command channel, and wake up the event loop.
|
||||||
pub fn command(&self, cmd: protocol::Command) -> Result<(), Error> {
|
fn command(&self, cmd: protocol::Command) -> Result<(), Error> {
|
||||||
self.commands.send(cmd)?;
|
self.commands.send(cmd)?;
|
||||||
R::wake(&self.waker)?;
|
R::wake(&self.waker)?;
|
||||||
|
|
||||||
|
|
@ -68,10 +68,23 @@ impl<R: Reactor> Handle<R> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Ask the client to shutdown.
|
/// Ask the client to shutdown.
|
||||||
pub fn shutdown(self) -> Result<(), Error> {
|
fn shutdown(self) -> Result<(), Error> {
|
||||||
self.shutdown.send(())?;
|
self.shutdown.send(())?;
|
||||||
R::wake(&self.waker)?;
|
R::wake(&self.waker)?;
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod traits {
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
pub trait Handle {
|
||||||
|
/// Notify the client that a project has been updated.
|
||||||
|
fn updated(&self, id: ProjId) -> Result<(), Error>;
|
||||||
|
/// Send a command to the command channel, and wake up the event loop.
|
||||||
|
fn command(&self, cmd: protocol::Command) -> Result<(), Error>;
|
||||||
|
/// Ask the client to shutdown.
|
||||||
|
fn shutdown(self) -> Result<(), Error>;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -7,10 +7,8 @@ use std::path::Path;
|
||||||
use std::str::FromStr;
|
use std::str::FromStr;
|
||||||
use std::{fs, io, net};
|
use std::{fs, io, net};
|
||||||
|
|
||||||
use nakamoto_net::Reactor;
|
|
||||||
|
|
||||||
use crate::client;
|
use crate::client;
|
||||||
use crate::client::handle::Handle;
|
use crate::client::handle::traits::Handle;
|
||||||
use crate::identity::ProjId;
|
use crate::identity::ProjId;
|
||||||
|
|
||||||
/// Default name for control socket file.
|
/// Default name for control socket file.
|
||||||
|
|
@ -23,7 +21,7 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Listen for commands on the control socket, and process them.
|
/// Listen for commands on the control socket, and process them.
|
||||||
pub fn listen<P: AsRef<Path>, R: Reactor>(path: P, handle: Handle<R>) -> Result<(), Error> {
|
pub fn listen<P: AsRef<Path>, H: Handle>(path: P, handle: H) -> Result<(), Error> {
|
||||||
// Remove the socket file on startup before rebinding.
|
// Remove the socket file on startup before rebinding.
|
||||||
fs::remove_file(&path).ok();
|
fs::remove_file(&path).ok();
|
||||||
|
|
||||||
|
|
@ -34,10 +32,12 @@ pub fn listen<P: AsRef<Path>, R: Reactor>(path: P, handle: Handle<R>) -> Result<
|
||||||
if let Err(e) = drain(&stream, &handle) {
|
if let Err(e) = drain(&stream, &handle) {
|
||||||
log::error!("Received {} on control socket", e);
|
log::error!("Received {} on control socket", e);
|
||||||
|
|
||||||
write!(stream, "error: {}", e).ok();
|
writeln!(stream, "error: {}", e).ok();
|
||||||
|
|
||||||
stream.flush().ok();
|
stream.flush().ok();
|
||||||
stream.shutdown(net::Shutdown::Both).ok();
|
stream.shutdown(net::Shutdown::Both).ok();
|
||||||
|
} else {
|
||||||
|
writeln!(stream, "ok").ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => log::error!("Failed to open control socket stream: {}", e),
|
Err(e) => log::error!("Failed to open control socket stream: {}", e),
|
||||||
|
|
@ -59,7 +59,7 @@ enum DrainError {
|
||||||
Client(#[from] client::handle::Error),
|
Client(#[from] client::handle::Error),
|
||||||
}
|
}
|
||||||
|
|
||||||
fn drain<R: Reactor>(stream: &UnixStream, handle: &Handle<R>) -> Result<(), DrainError> {
|
fn drain<H: Handle>(stream: &UnixStream, handle: &H) -> Result<(), DrainError> {
|
||||||
let mut reader = BufReader::new(stream);
|
let mut reader = BufReader::new(stream);
|
||||||
|
|
||||||
for line in reader.by_ref().lines().flatten() {
|
for line in reader.by_ref().lines().flatten() {
|
||||||
|
|
@ -79,3 +79,43 @@ fn drain<R: Reactor>(stream: &UnixStream, handle: &Handle<R>) -> Result<(), Drai
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[cfg(test)]
|
||||||
|
mod tests {
|
||||||
|
use std::io::prelude::*;
|
||||||
|
use std::os::unix::net::UnixStream;
|
||||||
|
use std::{net, thread};
|
||||||
|
|
||||||
|
use super::*;
|
||||||
|
use crate::identity::ProjId;
|
||||||
|
use crate::test;
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_control_socket() {
|
||||||
|
let tmp = tempfile::tempdir().unwrap();
|
||||||
|
let handle = test::handle::Handle::default();
|
||||||
|
let socket = tmp.path().join("alice.sock");
|
||||||
|
let proj = test::arbitrary::gen::<ProjId>(1);
|
||||||
|
|
||||||
|
thread::spawn({
|
||||||
|
let socket = socket.clone();
|
||||||
|
let handle = handle.clone();
|
||||||
|
|
||||||
|
move || listen(socket, handle)
|
||||||
|
});
|
||||||
|
|
||||||
|
let mut stream = loop {
|
||||||
|
if let Ok(stream) = UnixStream::connect(&socket) {
|
||||||
|
break stream;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
writeln!(&stream, "update {}", proj).unwrap();
|
||||||
|
|
||||||
|
let mut buf = [0; 2];
|
||||||
|
stream.shutdown(net::Shutdown::Write).unwrap();
|
||||||
|
stream.read_exact(&mut buf).unwrap();
|
||||||
|
|
||||||
|
assert_eq!(&buf, &[b'o', b'k']);
|
||||||
|
assert!(handle.updates.lock().unwrap().contains(&proj));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -2,6 +2,7 @@ pub(crate) mod arbitrary;
|
||||||
pub(crate) mod assert;
|
pub(crate) mod assert;
|
||||||
pub(crate) mod crypto;
|
pub(crate) mod crypto;
|
||||||
pub(crate) mod fixtures;
|
pub(crate) mod fixtures;
|
||||||
|
pub(crate) mod handle;
|
||||||
pub(crate) mod logger;
|
pub(crate) mod logger;
|
||||||
pub(crate) mod peer;
|
pub(crate) mod peer;
|
||||||
pub(crate) mod storage;
|
pub(crate) mod storage;
|
||||||
|
|
|
||||||
|
|
@ -0,0 +1,26 @@
|
||||||
|
use std::sync::{Arc, Mutex};
|
||||||
|
|
||||||
|
use crate::client::handle;
|
||||||
|
use crate::client::handle::traits;
|
||||||
|
use crate::{client, identity, protocol};
|
||||||
|
|
||||||
|
#[derive(Default, Clone)]
|
||||||
|
pub struct Handle {
|
||||||
|
pub updates: Arc<Mutex<Vec<identity::ProjId>>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl traits::Handle for Handle {
|
||||||
|
fn updated(&self, id: identity::ProjId) -> Result<(), handle::Error> {
|
||||||
|
self.updates.lock().unwrap().push(id);
|
||||||
|
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn command(&self, _cmd: protocol::Command) -> Result<(), handle::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
fn shutdown(self) -> Result<(), client::handle::Error> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
Loading…
Reference in New Issue