node: Share channel type between modules
Shares the `Channels` type between the `wire::protocol` and `worker` modules.
This commit is contained in:
parent
d0e24bd0ce
commit
51b372ecad
|
|
@ -32,6 +32,7 @@ use crate::service::{session, DisconnectReason, Service};
|
||||||
use crate::wire::frame;
|
use crate::wire::frame;
|
||||||
use crate::wire::frame::{Frame, FrameData, StreamId};
|
use crate::wire::frame::{Frame, FrameData, StreamId};
|
||||||
use crate::wire::Encode;
|
use crate::wire::Encode;
|
||||||
|
use crate::worker;
|
||||||
use crate::worker::{ChannelEvent, Fetch, Task, TaskResult};
|
use crate::worker::{ChannelEvent, Fetch, Task, TaskResult};
|
||||||
use crate::Link;
|
use crate::Link;
|
||||||
use crate::{address, service};
|
use crate::{address, service};
|
||||||
|
|
@ -64,20 +65,12 @@ pub type WireWriter<G> = NetWriter<NoiseState<G, Sha256>, Socks5Session<net::Tcp
|
||||||
/// Reactor action.
|
/// Reactor action.
|
||||||
type Action<G> = reactor::Action<NetAccept<WireSession<G>>, NetTransport<WireSession<G>>>;
|
type Action<G> = reactor::Action<NetAccept<WireSession<G>>, NetTransport<WireSession<G>>>;
|
||||||
|
|
||||||
/// Worker channels used to send Git frames back and forth.
|
|
||||||
struct WorkerChannels {
|
|
||||||
/// Send data to the git worker.
|
|
||||||
sender: chan::Sender<ChannelEvent>,
|
|
||||||
/// Receive data from the git worker.
|
|
||||||
receiver: chan::Receiver<ChannelEvent>,
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Streams associated with a connected peer.
|
/// Streams associated with a connected peer.
|
||||||
struct Streams {
|
struct Streams {
|
||||||
/// Active streams and their associated worker channels.
|
/// Active streams and their associated worker channels.
|
||||||
/// Note that the gossip and control streams are not included here as they are always
|
/// Note that the gossip and control streams are not included here as they are always
|
||||||
/// implied to exist.
|
/// implied to exist.
|
||||||
streams: HashMap<StreamId, WorkerChannels>,
|
streams: HashMap<StreamId, worker::Channels>,
|
||||||
/// Connection direction.
|
/// Connection direction.
|
||||||
link: Link,
|
link: Link,
|
||||||
/// Sequence number used to compute the next stream id.
|
/// Sequence number used to compute the next stream id.
|
||||||
|
|
@ -95,12 +88,12 @@ impl Streams {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get a known stream.
|
/// Get a known stream.
|
||||||
fn get(&self, stream: &StreamId) -> Option<&WorkerChannels> {
|
fn get(&self, stream: &StreamId) -> Option<&worker::Channels> {
|
||||||
self.streams.get(stream)
|
self.streams.get(stream)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Open a new stream.
|
/// Open a new stream.
|
||||||
fn open(&mut self) -> (StreamId, WorkerChannels) {
|
fn open(&mut self) -> (StreamId, worker::Channels) {
|
||||||
self.seq += 1;
|
self.seq += 1;
|
||||||
|
|
||||||
let id = StreamId::git(self.link)
|
let id = StreamId::git(self.link)
|
||||||
|
|
@ -114,27 +107,21 @@ impl Streams {
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Register an open stream.
|
/// Register an open stream.
|
||||||
fn register(&mut self, stream: StreamId) -> Option<WorkerChannels> {
|
fn register(&mut self, stream: StreamId) -> Option<worker::Channels> {
|
||||||
let (wire_send, wire_recv) = chan::unbounded::<ChannelEvent>();
|
let (wire, worker) =
|
||||||
let (work_send, work_recv) = chan::unbounded::<ChannelEvent>();
|
worker::Channels::pair().expect("Streams::register: fatal: unable to create channels");
|
||||||
|
|
||||||
match self.streams.entry(stream) {
|
match self.streams.entry(stream) {
|
||||||
Entry::Vacant(e) => {
|
Entry::Vacant(e) => {
|
||||||
e.insert(WorkerChannels {
|
e.insert(worker);
|
||||||
sender: wire_send,
|
Some(wire)
|
||||||
receiver: work_recv,
|
|
||||||
});
|
|
||||||
Some(WorkerChannels {
|
|
||||||
sender: work_send,
|
|
||||||
receiver: wire_recv,
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
Entry::Occupied(_) => None,
|
Entry::Occupied(_) => None,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Unregister an open stream.
|
/// Unregister an open stream.
|
||||||
fn unregister(&mut self, stream: &StreamId) -> Option<WorkerChannels> {
|
fn unregister(&mut self, stream: &StreamId) -> Option<worker::Channels> {
|
||||||
self.streams.remove(stream)
|
self.streams.remove(stream)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -412,7 +399,7 @@ where
|
||||||
return;
|
return;
|
||||||
};
|
};
|
||||||
|
|
||||||
for data in c.receiver.try_iter() {
|
for data in c.try_iter() {
|
||||||
let frame = match data {
|
let frame = match data {
|
||||||
ChannelEvent::Data(data) => Frame::git(stream, data),
|
ChannelEvent::Data(data) => Frame::git(stream, data),
|
||||||
ChannelEvent::Close => Frame::control(*link, frame::Control::Close { stream }),
|
ChannelEvent::Close => Frame::control(*link, frame::Control::Close { stream }),
|
||||||
|
|
@ -534,10 +521,7 @@ where
|
||||||
})) => {
|
})) => {
|
||||||
log::debug!(target: "wire", "Received stream open for id={stream} from {nid}");
|
log::debug!(target: "wire", "Received stream open for id={stream} from {nid}");
|
||||||
|
|
||||||
let Some(WorkerChannels {
|
let Some(channels) = streams.register(stream) else {
|
||||||
sender: work_send,
|
|
||||||
receiver: wire_recv,
|
|
||||||
}) = streams.register(stream) else {
|
|
||||||
log::warn!(target: "wire", "Peer attempted to open already-open stream id={stream}");
|
log::warn!(target: "wire", "Peer attempted to open already-open stream id={stream}");
|
||||||
continue;
|
continue;
|
||||||
};
|
};
|
||||||
|
|
@ -545,8 +529,7 @@ where
|
||||||
let task = Task {
|
let task = Task {
|
||||||
fetch: Fetch::Responder { remote: *nid },
|
fetch: Fetch::Responder { remote: *nid },
|
||||||
stream,
|
stream,
|
||||||
send: work_send,
|
channels,
|
||||||
recv: wire_recv,
|
|
||||||
};
|
};
|
||||||
if self.worker.send(task).is_err() {
|
if self.worker.send(task).is_err() {
|
||||||
log::error!(target: "wire", "Worker pool is disconnected; cannot send task");
|
log::error!(target: "wire", "Worker pool is disconnected; cannot send task");
|
||||||
|
|
@ -557,7 +540,7 @@ where
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
if let Some(channels) = streams.get(&stream) {
|
if let Some(channels) = streams.get(&stream) {
|
||||||
if channels.sender.send(ChannelEvent::Eof).is_err() {
|
if channels.send(ChannelEvent::Eof).is_err() {
|
||||||
log::error!(target: "wire", "Worker is disconnected; cannot send `EOF`");
|
log::error!(target: "wire", "Worker is disconnected; cannot send `EOF`");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -571,7 +554,7 @@ where
|
||||||
log::debug!(target: "wire", "Received stream close command for id={stream} from {nid}");
|
log::debug!(target: "wire", "Received stream close command for id={stream} from {nid}");
|
||||||
|
|
||||||
if let Some(chans) = streams.unregister(&stream) {
|
if let Some(chans) = streams.unregister(&stream) {
|
||||||
chans.sender.send(ChannelEvent::Close).ok();
|
chans.send(ChannelEvent::Close).ok();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Ok(Some(Frame {
|
Ok(Some(Frame {
|
||||||
|
|
@ -586,7 +569,7 @@ where
|
||||||
..
|
..
|
||||||
})) => {
|
})) => {
|
||||||
if let Some(channels) = streams.get(&stream) {
|
if let Some(channels) = streams.get(&stream) {
|
||||||
if channels.sender.send(ChannelEvent::Data(data)).is_err() {
|
if channels.send(ChannelEvent::Data(data)).is_err() {
|
||||||
log::error!(target: "wire", "Worker is disconnected; cannot send data");
|
log::error!(target: "wire", "Worker is disconnected; cannot send data");
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
|
|
@ -835,8 +818,7 @@ where
|
||||||
remote,
|
remote,
|
||||||
},
|
},
|
||||||
stream,
|
stream,
|
||||||
send: channels.sender,
|
channels,
|
||||||
recv: channels.receiver,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
if self.worker.send(task).is_err() {
|
if self.worker.send(task).is_err() {
|
||||||
|
|
|
||||||
|
|
@ -17,10 +17,10 @@ use radicle::{git, Storage};
|
||||||
use crate::runtime::Handle;
|
use crate::runtime::Handle;
|
||||||
use crate::storage;
|
use crate::storage;
|
||||||
use crate::wire::StreamId;
|
use crate::wire::StreamId;
|
||||||
use channels::{ChannelReader, ChannelWriter, Channels};
|
use channels::{ChannelReader, ChannelWriter};
|
||||||
use tunnel::Tunnel;
|
use tunnel::Tunnel;
|
||||||
|
|
||||||
pub use channels::ChannelEvent;
|
pub use channels::{ChannelEvent, Channels};
|
||||||
|
|
||||||
/// Worker pool configuration.
|
/// Worker pool configuration.
|
||||||
pub struct Config {
|
pub struct Config {
|
||||||
|
|
@ -133,8 +133,7 @@ impl Fetch {
|
||||||
pub struct Task {
|
pub struct Task {
|
||||||
pub fetch: Fetch,
|
pub fetch: Fetch,
|
||||||
pub stream: StreamId,
|
pub stream: StreamId,
|
||||||
pub send: chan::Sender<ChannelEvent>,
|
pub channels: Channels,
|
||||||
pub recv: chan::Receiver<ChannelEvent>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Worker response.
|
/// Worker response.
|
||||||
|
|
@ -170,11 +169,9 @@ impl Worker {
|
||||||
fn process(&mut self, task: Task) {
|
fn process(&mut self, task: Task) {
|
||||||
let Task {
|
let Task {
|
||||||
fetch,
|
fetch,
|
||||||
recv,
|
channels,
|
||||||
send,
|
|
||||||
stream,
|
stream,
|
||||||
} = task;
|
} = task;
|
||||||
let channels = Channels::new(send, recv);
|
|
||||||
let result = self._process(&fetch, stream, channels);
|
let result = self._process(&fetch, stream, channels);
|
||||||
|
|
||||||
log::trace!(target: "worker", "Sending response back to service..");
|
log::trace!(target: "worker", "Sending response back to service..");
|
||||||
|
|
@ -339,18 +336,18 @@ impl Worker {
|
||||||
log::debug!(target: "worker", "Entering Git protocol loop for {rid}..");
|
log::debug!(target: "worker", "Entering Git protocol loop for {rid}..");
|
||||||
|
|
||||||
thread::scope(|s| {
|
thread::scope(|s| {
|
||||||
let daemon_to_stream = s.spawn(|| -> Result<(), UploadError> {
|
let daemon_to_stream = thread::Builder::new().name(self.name.clone()).spawn_scoped(s, || {
|
||||||
let mut buffer = [0; u16::MAX as usize + 1];
|
let mut buffer = [0; u16::MAX as usize + 1];
|
||||||
|
|
||||||
loop {
|
loop {
|
||||||
match daemon_r.read(&mut buffer) {
|
match daemon_r.read(&mut buffer) {
|
||||||
Ok(0) => break,
|
Ok(0) => break,
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
stream_w.write_all(&buffer[..n])?;
|
stream_w.send(buffer[..n].to_vec())?;
|
||||||
|
|
||||||
if let Err(e) = self.handle.flush(remote, stream) {
|
if let Err(e) = self.handle.flush(remote, stream) {
|
||||||
log::error!(target: "worker", "Worker channel disconnected; aborting");
|
log::error!(target: "worker", "Worker channel disconnected; aborting");
|
||||||
return Err(e.into());
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
|
|
@ -358,12 +355,12 @@ impl Worker {
|
||||||
log::debug!(target: "worker", "Daemon closed the git connection for {rid}");
|
log::debug!(target: "worker", "Daemon closed the git connection for {rid}");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
return Err(e.into());
|
return Err(e);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
Self::eof(remote, stream, stream_w, &mut self.handle).map_err(UploadError::from)
|
Self::eof(remote, stream, stream_w, &mut self.handle)
|
||||||
});
|
})?;
|
||||||
|
|
||||||
let stream_to_daemon = s.spawn(move || {
|
let stream_to_daemon = s.spawn(move || {
|
||||||
stream_r
|
stream_r
|
||||||
|
|
@ -531,11 +528,6 @@ pub mod pktline {
|
||||||
Self { stream }
|
Self { stream }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the underlying stream.
|
|
||||||
pub fn stream(&mut self) -> &mut R {
|
|
||||||
self.stream
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Parse a Git request packet-line.
|
/// Parse a Git request packet-line.
|
||||||
///
|
///
|
||||||
/// Example: `0032git-upload-pack /project.git\0host=myserver.com\0`
|
/// Example: `0032git-upload-pack /project.git\0host=myserver.com\0`
|
||||||
|
|
|
||||||
|
|
@ -1,4 +1,5 @@
|
||||||
use std::io::{Read, Write};
|
use std::io::Read;
|
||||||
|
use std::ops::Deref;
|
||||||
use std::{fmt, io};
|
use std::{fmt, io};
|
||||||
|
|
||||||
use crossbeam_channel as chan;
|
use crossbeam_channel as chan;
|
||||||
|
|
@ -14,6 +15,12 @@ pub enum ChannelEvent<T = Vec<u8>> {
|
||||||
Eof,
|
Eof,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<T> From<T> for ChannelEvent<T> {
|
||||||
|
fn from(value: T) -> Self {
|
||||||
|
Self::Data(value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<T> fmt::Debug for ChannelEvent<T> {
|
impl<T> fmt::Debug for ChannelEvent<T> {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
match self {
|
match self {
|
||||||
|
|
@ -26,43 +33,42 @@ impl<T> fmt::Debug for ChannelEvent<T> {
|
||||||
|
|
||||||
/// Worker channels for communicating through the git stream with the remote.
|
/// Worker channels for communicating through the git stream with the remote.
|
||||||
pub struct Channels<T = Vec<u8>> {
|
pub struct Channels<T = Vec<u8>> {
|
||||||
pub sender: ChannelWriter<T>,
|
sender: ChannelWriter<T>,
|
||||||
pub receiver: ChannelReader<T>,
|
receiver: ChannelReader<T>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Write for Channels {
|
impl<T: AsRef<[u8]>> Channels<T> {
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
self.sender.write(buf)
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
self.sender.flush()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Read for Channels {
|
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
|
||||||
self.receiver.read(buf)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> Channels<T> {
|
|
||||||
pub fn new(
|
pub fn new(
|
||||||
sender: chan::Sender<ChannelEvent<T>>,
|
sender: chan::Sender<ChannelEvent<T>>,
|
||||||
receiver: chan::Receiver<ChannelEvent<T>>,
|
receiver: chan::Receiver<ChannelEvent<T>>,
|
||||||
) -> Self {
|
) -> Self {
|
||||||
Channels {
|
let sender = ChannelWriter { sender };
|
||||||
sender: ChannelWriter(sender),
|
let receiver = ChannelReader::new(receiver);
|
||||||
receiver: ChannelReader {
|
|
||||||
receiver,
|
Self { sender, receiver }
|
||||||
buffer: io::Cursor::new(Vec::new()),
|
|
||||||
},
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn pair() -> io::Result<(Channels<T>, Channels<T>)> {
|
||||||
|
let (l_send, r_recv) = chan::unbounded::<ChannelEvent<T>>();
|
||||||
|
let (r_send, l_recv) = chan::unbounded::<ChannelEvent<T>>();
|
||||||
|
|
||||||
|
let l = Channels::new(l_send, l_recv);
|
||||||
|
let r = Channels::new(r_send, r_recv);
|
||||||
|
|
||||||
|
Ok((l, r))
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn try_iter(&self) -> impl Iterator<Item = ChannelEvent<T>> + '_ {
|
||||||
|
self.receiver.try_iter()
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn split(&mut self) -> (&mut ChannelWriter<T>, &mut ChannelReader<T>) {
|
pub fn split(&mut self) -> (&mut ChannelWriter<T>, &mut ChannelReader<T>) {
|
||||||
(&mut self.sender, &mut self.receiver)
|
(&mut self.sender, &mut self.receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn send(&self, event: ChannelEvent<T>) -> io::Result<()> {
|
||||||
|
self.sender.send(event)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a [`chan::Receiver`] and provides it with [`io::Read`].
|
/// Wraps a [`chan::Receiver`] and provides it with [`io::Read`].
|
||||||
|
|
@ -72,11 +78,26 @@ pub struct ChannelReader<T = Vec<u8>> {
|
||||||
receiver: chan::Receiver<ChannelEvent<T>>,
|
receiver: chan::Receiver<ChannelEvent<T>>,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl ChannelReader<Vec<u8>> {
|
impl<T> Deref for ChannelReader<T> {
|
||||||
|
type Target = chan::Receiver<ChannelEvent<T>>;
|
||||||
|
|
||||||
|
fn deref(&self) -> &Self::Target {
|
||||||
|
&self.receiver
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<[u8]>> ChannelReader<T> {
|
||||||
|
pub fn new(receiver: chan::Receiver<ChannelEvent<T>>) -> Self {
|
||||||
|
Self {
|
||||||
|
buffer: io::Cursor::new(Vec::new()),
|
||||||
|
receiver,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub fn pipe<W: io::Write>(&mut self, mut writer: W) -> io::Result<()> {
|
pub fn pipe<W: io::Write>(&mut self, mut writer: W) -> io::Result<()> {
|
||||||
loop {
|
loop {
|
||||||
match self.receiver.recv() {
|
match self.receiver.recv() {
|
||||||
Ok(ChannelEvent::Data(data)) => writer.write_all(&data)?,
|
Ok(ChannelEvent::Data(data)) => writer.write_all(data.as_ref())?,
|
||||||
Ok(ChannelEvent::Eof) => return Ok(()),
|
Ok(ChannelEvent::Eof) => return Ok(()),
|
||||||
Ok(ChannelEvent::Close) => return Err(io::ErrorKind::ConnectionReset.into()),
|
Ok(ChannelEvent::Close) => return Err(io::ErrorKind::ConnectionReset.into()),
|
||||||
Err(_) => {
|
Err(_) => {
|
||||||
|
|
@ -93,33 +114,39 @@ impl ChannelReader<Vec<u8>> {
|
||||||
impl Read for ChannelReader<Vec<u8>> {
|
impl Read for ChannelReader<Vec<u8>> {
|
||||||
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
let read = self.buffer.read(buf)?;
|
let read = self.buffer.read(buf)?;
|
||||||
if read == 0 {
|
if read > 0 {
|
||||||
let event = self.receiver.recv().map_err(|_| {
|
return Ok(read);
|
||||||
io::Error::new(
|
}
|
||||||
io::ErrorKind::BrokenPipe,
|
|
||||||
"error reading from stream: channel is disconnected",
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
match event {
|
match self.receiver.recv() {
|
||||||
ChannelEvent::Data(data) => {
|
Ok(ChannelEvent::Data(data)) => {
|
||||||
self.buffer = io::Cursor::new(data);
|
self.buffer = io::Cursor::new(data);
|
||||||
self.buffer.read(buf)
|
self.buffer.read(buf)
|
||||||
}
|
}
|
||||||
ChannelEvent::Eof => Err(io::ErrorKind::UnexpectedEof.into()),
|
Ok(ChannelEvent::Eof) => Err(io::ErrorKind::UnexpectedEof.into()),
|
||||||
ChannelEvent::Close => Err(io::ErrorKind::ConnectionReset.into()),
|
Ok(ChannelEvent::Close) => Err(io::ErrorKind::ConnectionReset.into()),
|
||||||
}
|
|
||||||
} else {
|
Err(_) => Err(io::Error::new(
|
||||||
Ok(read)
|
io::ErrorKind::BrokenPipe,
|
||||||
|
"error reading from stream: channel is disconnected",
|
||||||
|
)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Wraps a [`chan::Sender`] and provides it with [`io::Write`].
|
/// Wraps a [`chan::Sender`] and provides it with [`io::Write`].
|
||||||
#[derive(Clone)]
|
#[derive(Clone)]
|
||||||
pub struct ChannelWriter<T = Vec<u8>>(chan::Sender<ChannelEvent<T>>);
|
pub struct ChannelWriter<T = Vec<u8>> {
|
||||||
|
sender: chan::Sender<ChannelEvent<T>>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: AsRef<[u8]>> ChannelWriter<T> {
|
||||||
|
pub fn send(&self, event: impl Into<ChannelEvent<T>>) -> io::Result<()> {
|
||||||
|
self.sender
|
||||||
|
.send(event.into())
|
||||||
|
.map_err(|_| io::Error::from(io::ErrorKind::BrokenPipe))
|
||||||
|
}
|
||||||
|
|
||||||
impl ChannelWriter {
|
|
||||||
/// Since the git protocol is tunneled over an existing connection, we can't signal the end of
|
/// Since the git protocol is tunneled over an existing connection, we can't signal the end of
|
||||||
/// the protocol via the usual means, which is to close the connection. Git also doesn't have
|
/// the protocol via the usual means, which is to close the connection. Git also doesn't have
|
||||||
/// any special message we can send to signal the end of the protocol.
|
/// any special message we can send to signal the end of the protocol.
|
||||||
|
|
@ -127,28 +154,7 @@ impl ChannelWriter {
|
||||||
/// Hence, we there's no other way for the server to know that we're done sending requests
|
/// Hence, we there's no other way for the server to know that we're done sending requests
|
||||||
/// than to send a special message outside the git protocol. This message can then be processed
|
/// than to send a special message outside the git protocol. This message can then be processed
|
||||||
/// by the remote worker to end the protocol. We use the special "eof" control message for this.
|
/// by the remote worker to end the protocol. We use the special "eof" control message for this.
|
||||||
pub fn eof(&self) -> Result<(), chan::SendError<ChannelEvent>> {
|
pub fn eof(&self) -> Result<(), chan::SendError<ChannelEvent<T>>> {
|
||||||
self.0.send(ChannelEvent::Eof)
|
self.sender.send(ChannelEvent::Eof)
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Write for ChannelWriter {
|
|
||||||
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
|
||||||
let data = buf.to_vec();
|
|
||||||
self.0.send(ChannelEvent::Data(data)).map_err(|m| {
|
|
||||||
io::Error::new(
|
|
||||||
io::ErrorKind::BrokenPipe,
|
|
||||||
format!(
|
|
||||||
"error writing to stream: channel is disconnected: dropped {:?}",
|
|
||||||
m.into_inner()
|
|
||||||
),
|
|
||||||
)
|
|
||||||
})?;
|
|
||||||
|
|
||||||
Ok(buf.len())
|
|
||||||
}
|
|
||||||
|
|
||||||
fn flush(&mut self) -> io::Result<()> {
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -1,5 +1,5 @@
|
||||||
use std::{
|
use std::{
|
||||||
io::{self, Read, Write},
|
io::{self, Read},
|
||||||
net, thread, time,
|
net, thread, time,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
@ -69,7 +69,7 @@ impl<'a> Tunnel<'a> {
|
||||||
match local_r.read(&mut buffer) {
|
match local_r.read(&mut buffer) {
|
||||||
Ok(0) => break,
|
Ok(0) => break,
|
||||||
Ok(n) => {
|
Ok(n) => {
|
||||||
remote_w.write_all(&buffer[..n])?;
|
remote_w.send(buffer[..n].to_vec())?;
|
||||||
|
|
||||||
if let Err(e) = self.handle.flush(nid, stream_id) {
|
if let Err(e) = self.handle.flush(nid, stream_id) {
|
||||||
log::error!(
|
log::error!(
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue