node: Get rid of worker response channel
This commit is contained in:
parent
7e55ed346a
commit
d25c47ad0e
|
|
@ -11,7 +11,7 @@ use thiserror::Error;
|
||||||
|
|
||||||
use crate::address;
|
use crate::address;
|
||||||
use crate::control;
|
use crate::control;
|
||||||
use crate::crypto::Signature;
|
use crate::crypto::{Signature, Signer};
|
||||||
use crate::node::NodeId;
|
use crate::node::NodeId;
|
||||||
use crate::service::{routing, tracking};
|
use crate::service::{routing, tracking};
|
||||||
use crate::wire;
|
use crate::wire;
|
||||||
|
|
@ -55,26 +55,26 @@ pub enum Error {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Holds join handles to the client threads, as well as a client handle.
|
/// Holds join handles to the client threads, as well as a client handle.
|
||||||
pub struct Runtime {
|
pub struct Runtime<G: Signer + EcSign> {
|
||||||
pub id: NodeId,
|
pub id: NodeId,
|
||||||
pub handle: Handle,
|
pub handle: Handle<G>,
|
||||||
pub control: thread::JoinHandle<Result<(), control::Error>>,
|
pub control: thread::JoinHandle<Result<(), control::Error>>,
|
||||||
pub reactor: Reactor<wire::Control>,
|
pub reactor: Reactor<wire::Control<G>>,
|
||||||
pub pool: WorkerPool,
|
pub pool: WorkerPool,
|
||||||
pub local_addrs: Vec<net::SocketAddr>,
|
pub local_addrs: Vec<net::SocketAddr>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Runtime {
|
impl<G: Signer + EcSign> Runtime<G> {
|
||||||
/// Run the client.
|
/// Run the client.
|
||||||
///
|
///
|
||||||
/// This function spawns threads.
|
/// This function spawns threads.
|
||||||
pub fn with<G>(
|
pub fn with(
|
||||||
home: Home,
|
home: Home,
|
||||||
config: service::Config,
|
config: service::Config,
|
||||||
listen: Vec<net::SocketAddr>,
|
listen: Vec<net::SocketAddr>,
|
||||||
proxy: net::SocketAddr,
|
proxy: net::SocketAddr,
|
||||||
signer: G,
|
signer: G,
|
||||||
) -> Result<Runtime, Error>
|
) -> Result<Runtime<G>, Error>
|
||||||
where
|
where
|
||||||
G: crypto::Signer + EcSign<Sig = Signature, Pk = NodeId> + Clone + 'static,
|
G: crypto::Signer + EcSign<Sig = Signature, Pk = NodeId> + Clone + 'static,
|
||||||
{
|
{
|
||||||
|
|
|
||||||
|
|
@ -1,16 +1,19 @@
|
||||||
use std::io::Write;
|
use std::io::{self, Write};
|
||||||
use std::os::unix::net::UnixStream;
|
use std::os::unix::net::UnixStream;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
|
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
|
use cyphernet::EcSign;
|
||||||
use thiserror::Error;
|
use thiserror::Error;
|
||||||
|
|
||||||
|
use crate::crypto::Signer;
|
||||||
use crate::identity::Id;
|
use crate::identity::Id;
|
||||||
use crate::profile::Home;
|
use crate::profile::Home;
|
||||||
use crate::service;
|
use crate::service;
|
||||||
use crate::service::{CommandError, FetchLookup, QueryState};
|
use crate::service::{CommandError, FetchLookup, QueryState};
|
||||||
use crate::service::{NodeId, Sessions};
|
use crate::service::{NodeId, Sessions};
|
||||||
use crate::wire;
|
use crate::wire;
|
||||||
|
use crate::worker::WorkerResp;
|
||||||
|
|
||||||
/// An error resulting from a handle method.
|
/// An error resulting from a handle method.
|
||||||
#[derive(Error, Debug)]
|
#[derive(Error, Debug)]
|
||||||
|
|
@ -50,12 +53,12 @@ impl<T> From<chan::SendError<T>> for Error {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct Handle {
|
pub struct Handle<G: Signer + EcSign> {
|
||||||
pub(crate) home: Home,
|
pub(crate) home: Home,
|
||||||
pub(crate) controller: reactor::Controller<wire::Control>,
|
pub(crate) controller: reactor::Controller<wire::Control<G>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Clone for Handle {
|
impl<G: Signer + EcSign> Clone for Handle<G> {
|
||||||
fn clone(&self) -> Self {
|
fn clone(&self) -> Self {
|
||||||
Self {
|
Self {
|
||||||
home: self.home.clone(),
|
home: self.home.clone(),
|
||||||
|
|
@ -64,25 +67,27 @@ impl Clone for Handle {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Handle {
|
impl<G: Signer + EcSign + 'static> Handle<G> {
|
||||||
pub fn new(home: Home, controller: reactor::Controller<wire::Control>) -> Self {
|
pub fn new(home: Home, controller: reactor::Controller<wire::Control<G>>) -> Self {
|
||||||
Self { home, controller }
|
Self { home, controller }
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn wakeup(&mut self) -> Result<(), Error> {
|
pub fn worker_result(&mut self, resp: WorkerResp<G>) -> Result<(), Error> {
|
||||||
// TODO: Handle channel disconnect error correctly.
|
match self.controller.cmd(wire::Control::Worker(resp)) {
|
||||||
// This just returns `BrokenPipe`.
|
Ok(()) => {}
|
||||||
self.controller.cmd(wire::Control::Wakeup)?;
|
Err(err) if err.kind() == io::ErrorKind::BrokenPipe => return Err(Error::NotConnected),
|
||||||
|
Err(err) => return Err(err.into()),
|
||||||
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
fn command(&self, cmd: service::Command) -> Result<(), Error> {
|
fn command(&self, cmd: service::Command) -> Result<(), Error> {
|
||||||
self.controller.cmd(wire::Control::Command(cmd))?;
|
self.controller.cmd(wire::Control::User(cmd))?;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl radicle::node::Handle for Handle {
|
impl<G: Signer + EcSign + 'static> radicle::node::Handle for Handle<G> {
|
||||||
type Sessions = Sessions;
|
type Sessions = Sessions;
|
||||||
type FetchLookup = FetchLookup;
|
type FetchLookup = FetchLookup;
|
||||||
type Error = Error;
|
type Error = Error;
|
||||||
|
|
|
||||||
|
|
@ -526,7 +526,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn fetch_complete(&mut self, result: FetchResult) {
|
pub fn repo_fetched(&mut self, result: FetchResult) {
|
||||||
// TODO(cloudhead): handle completed job with service business logic
|
// TODO(cloudhead): handle completed job with service business logic
|
||||||
// TODO: Downgrade session to gossip protocol.
|
// TODO: Downgrade session to gossip protocol.
|
||||||
if let Some(session) = self.sessions.get_mut(result.remote()) {
|
if let Some(session) = self.sessions.get_mut(result.remote()) {
|
||||||
|
|
|
||||||
|
|
@ -36,7 +36,7 @@ struct NodeHandle {
|
||||||
storage: Storage,
|
storage: Storage,
|
||||||
addr: net::SocketAddr,
|
addr: net::SocketAddr,
|
||||||
thread: ManuallyDrop<thread::JoinHandle<Result<(), client::Error>>>,
|
thread: ManuallyDrop<thread::JoinHandle<Result<(), client::Error>>>,
|
||||||
handle: ManuallyDrop<Handle>,
|
handle: ManuallyDrop<Handle<MockSigner>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for NodeHandle {
|
impl Drop for NodeHandle {
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@ use std::os::unix::io::AsRawFd;
|
||||||
use std::os::unix::prelude::RawFd;
|
use std::os::unix::prelude::RawFd;
|
||||||
use std::sync::Arc;
|
use std::sync::Arc;
|
||||||
use std::time::{Duration, SystemTime};
|
use std::time::{Duration, SystemTime};
|
||||||
use std::{io, net};
|
use std::{fmt, io, net};
|
||||||
|
|
||||||
use amplify::Wrapper as _;
|
use amplify::Wrapper as _;
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
|
|
@ -31,10 +31,22 @@ use crate::worker::{WorkerReq, WorkerResp};
|
||||||
use crate::Link;
|
use crate::Link;
|
||||||
use crate::{address, service};
|
use crate::{address, service};
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[allow(clippy::large_enum_variant)]
|
||||||
pub enum Control {
|
/// Control message used internally between workers, users, and the service.
|
||||||
Command(service::Command),
|
pub enum Control<G: Signer + EcSign> {
|
||||||
Wakeup,
|
/// Message from the user to the service.
|
||||||
|
User(service::Command),
|
||||||
|
/// Message from a worker to the service.
|
||||||
|
Worker(WorkerResp<G>),
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<G: Signer + EcSign> fmt::Debug for Control<G> {
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
|
match self {
|
||||||
|
Self::User(cmd) => cmd.fmt(f),
|
||||||
|
Self::Worker(resp) => resp.result.fmt(f),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Peer session type.
|
/// Peer session type.
|
||||||
|
|
@ -48,7 +60,7 @@ pub type WireWriter<G> = CypherWriter<G, Sha256>;
|
||||||
type Action<G> = reactor::Action<NetAccept<WireSession<G>>, NetTransport<WireSession<G>>>;
|
type Action<G> = reactor::Action<NetAccept<WireSession<G>>, NetTransport<WireSession<G>>>;
|
||||||
|
|
||||||
/// Peer connection state machine.
|
/// Peer connection state machine.
|
||||||
enum Peer<G: Signer + EcSign> {
|
enum Peer {
|
||||||
/// The initial state before handshake is completed.
|
/// The initial state before handshake is completed.
|
||||||
Connecting { link: Link },
|
Connecting { link: Link },
|
||||||
/// The state after handshake is completed.
|
/// The state after handshake is completed.
|
||||||
|
|
@ -68,14 +80,10 @@ enum Peer<G: Signer + EcSign> {
|
||||||
id: NodeId,
|
id: NodeId,
|
||||||
},
|
},
|
||||||
/// The peer is now upgraded and we are in control of the socket.
|
/// The peer is now upgraded and we are in control of the socket.
|
||||||
Upgraded {
|
Upgraded { link: Link, id: NodeId },
|
||||||
link: Link,
|
|
||||||
id: NodeId,
|
|
||||||
response: chan::Receiver<WorkerResp<G>>,
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Signer + EcSign> std::fmt::Debug for Peer<G> {
|
impl std::fmt::Debug for Peer {
|
||||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
Self::Connecting { link } => write!(f, "Connecting({:?})", link),
|
Self::Connecting { link } => write!(f, "Connecting({:?})", link),
|
||||||
|
|
@ -91,7 +99,7 @@ impl<G: Signer + EcSign> std::fmt::Debug for Peer<G> {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Signer + EcSign> Peer<G> {
|
impl Peer {
|
||||||
/// Return the peer's id, if any.
|
/// Return the peer's id, if any.
|
||||||
fn id(&self) -> Option<&NodeId> {
|
fn id(&self) -> Option<&NodeId> {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -145,7 +153,7 @@ impl<G: Signer + EcSign> Peer<G> {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Switch to upgraded state.
|
/// Switch to upgraded state.
|
||||||
fn upgraded(&mut self, listener: chan::Receiver<WorkerResp<G>>) -> Fetch {
|
fn upgraded(&mut self) -> Fetch {
|
||||||
if let Self::Upgrading { fetch, id, link } = self {
|
if let Self::Upgrading { fetch, id, link } = self {
|
||||||
let fetch = fetch.clone();
|
let fetch = fetch.clone();
|
||||||
log::debug!(target: "wire", "Peer {id} upgraded for fetch {}", fetch.repo);
|
log::debug!(target: "wire", "Peer {id} upgraded for fetch {}", fetch.repo);
|
||||||
|
|
@ -153,7 +161,6 @@ impl<G: Signer + EcSign> Peer<G> {
|
||||||
*self = Self::Upgraded {
|
*self = Self::Upgraded {
|
||||||
id: *id,
|
id: *id,
|
||||||
link: *link,
|
link: *link,
|
||||||
response: listener,
|
|
||||||
};
|
};
|
||||||
fetch
|
fetch
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -187,7 +194,7 @@ pub struct Wire<R, S, W, G: Signer + EcSign> {
|
||||||
/// Internal queue of actions to send to the reactor.
|
/// Internal queue of actions to send to the reactor.
|
||||||
actions: VecDeque<Action<G>>,
|
actions: VecDeque<Action<G>>,
|
||||||
/// Peer sessions.
|
/// Peer sessions.
|
||||||
peers: HashMap<RawFd, Peer<G>>,
|
peers: HashMap<RawFd, Peer>,
|
||||||
/// SOCKS5 proxy address.
|
/// SOCKS5 proxy address.
|
||||||
proxy: net::SocketAddr,
|
proxy: net::SocketAddr,
|
||||||
/// Buffer for incoming peer data.
|
/// Buffer for incoming peer data.
|
||||||
|
|
@ -229,14 +236,14 @@ where
|
||||||
self.actions.push_back(Action::RegisterListener(socket));
|
self.actions.push_back(Action::RegisterListener(socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
fn peer_mut_by_fd(&mut self, fd: RawFd) -> &mut Peer<G> {
|
fn peer_mut_by_fd(&mut self, fd: RawFd) -> &mut Peer {
|
||||||
self.peers.get_mut(&fd).unwrap_or_else(|| {
|
self.peers.get_mut(&fd).unwrap_or_else(|| {
|
||||||
log::error!(target: "wire", "Peer with fd {fd} was not found");
|
log::error!(target: "wire", "Peer with fd {fd} was not found");
|
||||||
panic!("Peer with fd {fd} is not known");
|
panic!("Peer with fd {fd} is not known");
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fd_by_id(&self, node_id: &NodeId) -> (RawFd, &Peer<G>) {
|
fn fd_by_id(&self, node_id: &NodeId) -> (RawFd, &Peer) {
|
||||||
self.peers
|
self.peers
|
||||||
.iter()
|
.iter()
|
||||||
.find(|(_, peer)| peer.id() == Some(node_id))
|
.find(|(_, peer)| peer.id() == Some(node_id))
|
||||||
|
|
@ -292,8 +299,7 @@ where
|
||||||
fn upgraded(&mut self, transport: NetTransport<WireSession<G>>) {
|
fn upgraded(&mut self, transport: NetTransport<WireSession<G>>) {
|
||||||
let fd = transport.as_raw_fd();
|
let fd = transport.as_raw_fd();
|
||||||
let peer = self.peer_mut_by_fd(fd);
|
let peer = self.peer_mut_by_fd(fd);
|
||||||
let (send, recv) = chan::bounded::<WorkerResp<G>>(1);
|
let fetch = peer.upgraded();
|
||||||
let fetch = peer.upgraded(recv);
|
|
||||||
let session = match transport.into_session() {
|
let session = match transport.into_session() {
|
||||||
Ok(session) => session,
|
Ok(session) => session,
|
||||||
Err(_) => panic!("Transport::upgraded: peer write buffer not empty on upgrade"),
|
Err(_) => panic!("Transport::upgraded: peer write buffer not empty on upgrade"),
|
||||||
|
|
@ -305,7 +311,6 @@ where
|
||||||
fetch,
|
fetch,
|
||||||
session,
|
session,
|
||||||
drain: self.read_queue.drain(..).collect(),
|
drain: self.read_queue.drain(..).collect(),
|
||||||
channel: send,
|
|
||||||
})
|
})
|
||||||
.is_err()
|
.is_err()
|
||||||
{
|
{
|
||||||
|
|
@ -313,21 +318,7 @@ where
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn wakeup(&mut self) {
|
fn worker_result(&mut self, resp: WorkerResp<G>) {
|
||||||
let mut completed = Vec::new();
|
|
||||||
for peer in self.peers.values() {
|
|
||||||
if let Peer::Upgraded { response, .. } = peer {
|
|
||||||
if let Ok(resp) = response.try_recv() {
|
|
||||||
completed.push(resp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for resp in completed {
|
|
||||||
self.fetch_complete(resp);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
fn fetch_complete(&mut self, resp: WorkerResp<G>) {
|
|
||||||
log::debug!(target: "wire", "Fetch completed: {:?}", resp.result);
|
log::debug!(target: "wire", "Fetch completed: {:?}", resp.result);
|
||||||
|
|
||||||
let session = resp.session;
|
let session = resp.session;
|
||||||
|
|
@ -351,7 +342,7 @@ where
|
||||||
peer.downgrade();
|
peer.downgrade();
|
||||||
|
|
||||||
self.actions.push_back(Action::RegisterTransport(session));
|
self.actions.push_back(Action::RegisterTransport(session));
|
||||||
self.service.fetch_complete(resp.result);
|
self.service.repo_fetched(resp.result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -364,7 +355,7 @@ where
|
||||||
{
|
{
|
||||||
type Listener = NetAccept<WireSession<G>>;
|
type Listener = NetAccept<WireSession<G>>;
|
||||||
type Transport = NetTransport<WireSession<G>>;
|
type Transport = NetTransport<WireSession<G>>;
|
||||||
type Command = Control;
|
type Command = Control<G>;
|
||||||
|
|
||||||
fn tick(&mut self, _time: Duration) {
|
fn tick(&mut self, _time: Duration) {
|
||||||
// FIXME: Change this once a proper timestamp is passed into the function.
|
// FIXME: Change this once a proper timestamp is passed into the function.
|
||||||
|
|
@ -496,8 +487,8 @@ where
|
||||||
|
|
||||||
fn handle_command(&mut self, cmd: Self::Command) {
|
fn handle_command(&mut self, cmd: Self::Command) {
|
||||||
match cmd {
|
match cmd {
|
||||||
Control::Command(cmd) => self.service.command(cmd),
|
Control::User(cmd) => self.service.command(cmd),
|
||||||
Control::Wakeup => self.wakeup(),
|
Control::Worker(resp) => self.worker_result(resp),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -23,7 +23,6 @@ pub struct WorkerReq<G: Signer + EcSign> {
|
||||||
pub fetch: Fetch,
|
pub fetch: Fetch,
|
||||||
pub session: WireSession<G>,
|
pub session: WireSession<G>,
|
||||||
pub drain: Vec<u8>,
|
pub drain: Vec<u8>,
|
||||||
pub channel: chan::Sender<WorkerResp<G>>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Worker response.
|
/// Worker response.
|
||||||
|
|
@ -37,10 +36,10 @@ struct Worker<G: Signer + EcSign> {
|
||||||
storage: Storage,
|
storage: Storage,
|
||||||
tasks: chan::Receiver<WorkerReq<G>>,
|
tasks: chan::Receiver<WorkerReq<G>>,
|
||||||
timeout: time::Duration,
|
timeout: time::Duration,
|
||||||
handle: Handle,
|
handle: Handle<G>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<G: Signer + EcSign> Worker<G> {
|
impl<G: Signer + EcSign + 'static> Worker<G> {
|
||||||
/// Waits for tasks and runs them. Blocks indefinitely unless there is an error receiving
|
/// Waits for tasks and runs them. Blocks indefinitely unless there is an error receiving
|
||||||
/// the next task.
|
/// the next task.
|
||||||
fn run(mut self) -> Result<(), chan::RecvError> {
|
fn run(mut self) -> Result<(), chan::RecvError> {
|
||||||
|
|
@ -55,7 +54,6 @@ impl<G: Signer + EcSign> Worker<G> {
|
||||||
fetch,
|
fetch,
|
||||||
session,
|
session,
|
||||||
drain,
|
drain,
|
||||||
channel,
|
|
||||||
} = task;
|
} = task;
|
||||||
|
|
||||||
let (session, result) = self._process(&fetch, drain, session);
|
let (session, result) = self._process(&fetch, drain, session);
|
||||||
|
|
@ -71,10 +69,12 @@ impl<G: Signer + EcSign> Worker<G> {
|
||||||
};
|
};
|
||||||
log::debug!(target: "worker", "Sending response back to service..");
|
log::debug!(target: "worker", "Sending response back to service..");
|
||||||
|
|
||||||
if channel.send(WorkerResp { result, session }).is_err() {
|
if self
|
||||||
|
.handle
|
||||||
|
.worker_result(WorkerResp { result, session })
|
||||||
|
.is_err()
|
||||||
|
{
|
||||||
log::error!("Unable to report fetch result: worker channel disconnected");
|
log::error!("Unable to report fetch result: worker channel disconnected");
|
||||||
} else {
|
|
||||||
self.handle.wakeup().unwrap();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -253,7 +253,7 @@ impl WorkerPool {
|
||||||
timeout: time::Duration,
|
timeout: time::Duration,
|
||||||
storage: Storage,
|
storage: Storage,
|
||||||
tasks: chan::Receiver<WorkerReq<G>>,
|
tasks: chan::Receiver<WorkerReq<G>>,
|
||||||
handle: Handle,
|
handle: Handle<G>,
|
||||||
name: String,
|
name: String,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
let mut pool = Vec::with_capacity(capacity);
|
let mut pool = Vec::with_capacity(capacity);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue