Added Config -> State -> Adaptor pipeline. TODO: `impl Read for ThrottleAdaptor<S: Read, ...>` TODO: Arg parsing into `Config` Fortune for throttle's current commit: Small blessing − 小吉master
parent
07764d4deb
commit
0a065ed2b6
@ -0,0 +1,82 @@
|
|||||||
|
//! Configuration
|
||||||
|
use super::*;
|
||||||
|
use prov::prelude::*;
|
||||||
|
|
||||||
|
|
||||||
|
/// Application state
|
||||||
|
pub struct State
|
||||||
|
{
|
||||||
|
pub throttle_generator: Option<Box<dyn DynThrottleProvider<'static> + 'static>>,
|
||||||
|
pub buffer_size: Box<dyn BufferProvider + 'static>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl State
|
||||||
|
{
|
||||||
|
/// Convert into an instance that can be used to create a `StateThrottleAdaptor`
|
||||||
|
#[inline(always)]
|
||||||
|
pub fn with_stream<S>(self, stream: S) -> (Self, S)
|
||||||
|
{
|
||||||
|
(self, stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Configuration for application
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct Config
|
||||||
|
{
|
||||||
|
pub throttle: Option<(Duration, Option<Duration>)>,
|
||||||
|
pub buffer_size: Option<(usize, Option<usize>)>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<Config> for State
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn from(from: Config) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
throttle_generator: if let Some(throttle) = from.throttle {
|
||||||
|
Some(match throttle {
|
||||||
|
(Duration::ZERO, Some(Duration::ZERO) | None) => Box::new(NoThrottleProvider),
|
||||||
|
(low, Some(high)) if low == high => Box::new(SingleThrottleProvider::from(low)),
|
||||||
|
(low, Some(high)) => Box::new(UniformThrottleProvider::from(low..high)),
|
||||||
|
(low, _) => Box::new(SingleThrottleProvider::from(low)),
|
||||||
|
})
|
||||||
|
} else {
|
||||||
|
None
|
||||||
|
},
|
||||||
|
buffer_size: if let Some(size) = from.buffer_size {
|
||||||
|
match size {
|
||||||
|
(0, Some(0) | None) => Box::new(NoBufferProvider),
|
||||||
|
(low, Some(high)) if low == high => Box::new(low),
|
||||||
|
(low, Some(high)) => Box::new(UniformBufferProvider::from(low..high)),
|
||||||
|
(low, _) => Box::new(low)
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
Box::new(DefaultBufferSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for Config
|
||||||
|
{
|
||||||
|
#[inline]
|
||||||
|
fn default() -> Self
|
||||||
|
{
|
||||||
|
Self::new()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Config
|
||||||
|
{
|
||||||
|
/// Create an empty new config
|
||||||
|
#[inline(always)]
|
||||||
|
pub const fn new() -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
throttle: None,
|
||||||
|
buffer_size: None,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -1,9 +1,114 @@
|
|||||||
//! Stream adaptors
|
//! Stream adaptors
|
||||||
use super::*;
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
io::{
|
||||||
|
self,
|
||||||
|
Read,
|
||||||
|
Write,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
use prov::prelude::*;
|
||||||
|
|
||||||
|
/// Adaptor over a reader/writer that can chunk and throttle either way.
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct ThrottleAdaptor<S: ?Sized, T: ThrottleProvider, B: BufferProvider>
|
||||||
|
{
|
||||||
|
timeout_provider: T,
|
||||||
|
buffer_size_provier: B,
|
||||||
|
|
||||||
|
stream: S
|
||||||
|
}
|
||||||
|
|
||||||
|
/// `ThrottleAdaptor` with configuration created from a `conf::State`
|
||||||
|
pub type StateThrottleAdaptor<S> = ThrottleAdaptor<S, Box<dyn DynThrottleProvider<'static> + 'static>, Box<dyn BufferProvider + 'static>>;
|
||||||
|
|
||||||
|
impl<S> StateThrottleAdaptor<S>
|
||||||
|
{
|
||||||
|
/// Create a new instance from `conf::State`
|
||||||
|
#[inline]
|
||||||
|
pub fn new_from_state(state: conf::State, stream: S) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
timeout_provider: state.throttle_generator.unwrap_or_else(|| Box::new(NoThrottleProvider)),
|
||||||
|
buffer_size_provier: state.buffer_size,
|
||||||
|
stream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<S: Read + Write> From<(conf::State, S)> for StateThrottleAdaptor<S>
|
||||||
|
{
|
||||||
|
#[inline(always)]
|
||||||
|
fn from((state, stream): (conf::State, S)) -> Self
|
||||||
|
{
|
||||||
|
Self::new_from_state(state, stream)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
impl<S, T: ThrottleProvider, B: BufferProvider> ThrottleAdaptor<S, T, B>
|
||||||
|
{
|
||||||
|
/// Create a new adaptor instance from these providers over this stream
|
||||||
|
#[inline]
|
||||||
|
pub fn new(throttle: T, buffer: B, stream: S) -> Self
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
timeout_provider: throttle,
|
||||||
|
buffer_size_provier: buffer,
|
||||||
|
stream,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
#[inline]
|
||||||
|
fn write_buf_with_timeout(writer: &mut (impl Write + ?Sized), timeout: &mut (impl DurationProvider + ?Sized), mut buf: &[u8]) -> io::Result<usize>
|
||||||
|
{
|
||||||
|
let mut sz = 0;
|
||||||
|
while !buf.is_empty() {
|
||||||
|
// Wait
|
||||||
|
if let Some(dur) = timeout.get_next_duration() {
|
||||||
|
std::thread::sleep(dur);
|
||||||
|
}
|
||||||
|
// Write
|
||||||
|
let w = writer.write(buf)?;
|
||||||
|
sz += w;
|
||||||
|
if w != buf.len() {
|
||||||
|
// Update buffer
|
||||||
|
buf = &buf[w..];
|
||||||
|
} else {
|
||||||
|
// Whole buffer written, we're done
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(sz)
|
||||||
|
}
|
||||||
|
|
||||||
pub struct ThrottleAdaptor<R, T>
|
impl<W: ?Sized + Write, T: ThrottleProvider, B: BufferProvider> Write for ThrottleAdaptor<W, T, B>
|
||||||
{
|
{
|
||||||
reader: R,
|
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
|
||||||
timeout_provider: T
|
let buffsz = self.buffer_size_provier.get_next_buffer_size().map(|x| x.get());
|
||||||
|
let mut timeout = self.timeout_provider.get_timeout();
|
||||||
|
|
||||||
|
Ok(match buffsz {
|
||||||
|
// Chunk buffer
|
||||||
|
Some(buffsz) => {
|
||||||
|
buf.chunks(buffsz).map(|buf| {
|
||||||
|
write_buf_with_timeout(&mut self.stream, &mut timeout, buf)
|
||||||
|
}).try_fold(0usize, |a, b| b.map(|b| b + a))?
|
||||||
|
},
|
||||||
|
_ => write_buf_with_timeout(&mut self.stream, &mut timeout, buf)?
|
||||||
|
})
|
||||||
|
//self.reader.read(buf)
|
||||||
|
|
||||||
|
}
|
||||||
|
fn flush(&mut self) -> io::Result<()> {
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<R: ?Sized + Read, T: ThrottleProvider, B: BufferProvider> Read for ThrottleAdaptor<R, T, B>
|
||||||
|
{
|
||||||
|
fn read(&mut self, buf: &mut [u8]) -> io::Result<usize> {
|
||||||
|
todo!("read_buf_with_timeout()")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in new issue