narrow the surface area of the ControlSettings api to expose only a few remote settings

This commit is contained in:
Oliver Gould
2017-07-23 18:32:22 +00:00
parent 82ba0dde71
commit df5f31a63c
8 changed files with 110 additions and 74 deletions

View File

@@ -11,8 +11,10 @@ use std::io;
/// above---Connection).
pub trait ControlSettings {
fn update_local_settings(&mut self, set: frame::SettingSet) -> Result<(), ConnectionError>;
fn local_settings(&self) -> &SettingSet;
fn remote_settings(&self) -> &SettingSet;
fn remote_push_enabled(&self) -> Option<bool>;
fn remote_max_concurrent_streams(&self) -> Option<u32>;
fn remote_initial_window_size(&self) -> WindowSize;
}
/// Allows settings updates to be pushed "down" the transport (i.e. from Settings down to
@@ -27,17 +29,15 @@ pub struct Settings<T> {
// Upstream transport
inner: T,
// Our settings
local: SettingSet,
// Peer settings
remote: SettingSet,
remote_push_enabled: Option<bool>,
remote_max_concurrent_streams: Option<u32>,
remote_initial_window_size: WindowSize,
// Number of acks remaining to send to the peer
remaining_acks: usize,
// True when the local settings must be flushed to the remote
local_valid_id_dirty: bool,
// Holds a new set of local values to be applied.
pending_local: Option<SettingSet>,
// True when we have received a settings frame from the remote.
received_remote: bool,
@@ -49,46 +49,34 @@ impl<T, U> Settings<T>
pub fn new(inner: T, local: SettingSet) -> Settings<T> {
Settings {
inner: inner,
local: local,
remote: SettingSet::default(),
pending_local: Some(local),
remote_push_enabled: None,
remote_max_concurrent_streams: None,
remote_initial_window_size: 65_535,
remaining_acks: 0,
local_valid_id_dirty: true,
received_remote: false,
}
}
// TODO remove this
pub fn local_settings(&self) -> &SettingSet {
&self.local
}
// TODO replace this with settings a client needs to know about (concurrency, initial
// window size, etc).
pub fn remote_settings(&self) -> &SettingSet {
&self.local
}
/// Swap the inner transport while maintaining the current state.
pub fn swap_inner<T2, F: FnOnce(T) -> T2>(self, f: F) -> Settings<T2> {
let inner = f(self.inner);
Settings {
inner: inner,
local: self.local,
remote: self.remote,
remote_push_enabled: self.remote_push_enabled,
remote_max_concurrent_streams: self.remote_max_concurrent_streams,
remote_initial_window_size: self.remote_initial_window_size,
remaining_acks: self.remaining_acks,
local_valid_id_dirty: self.local_valid_id_dirty,
pending_local: self.pending_local,
received_remote: self.received_remote,
}
}
fn try_send_pending(&mut self) -> Poll<(), ConnectionError> {
trace!("try_send_pending; dirty={} acks={}", self.local_valid_id_dirty, self.remaining_acks);
if self.local_valid_id_dirty {
let frame = frame::Settings::new(self.local.clone());
try_ready!(self.try_send(frame));
self.local_valid_id_dirty = false;
trace!("try_send_pending; dirty={} acks={}", self.pending_local.is_some(), self.remaining_acks);
if let Some(local) = self.pending_local.take() {
try_ready!(self.try_send_local(local));
}
while self.remaining_acks > 0 {
@@ -101,9 +89,19 @@ impl<T, U> Settings<T>
Ok(Async::Ready(()))
}
fn try_send(&mut self, item: frame::Settings) -> Poll<(), ConnectionError> {
fn try_send_local(&mut self, local: SettingSet) -> Poll<(), ConnectionError> {
let frame = frame::Settings::new(local.clone()).into();
if self.try_send(frame)?.is_not_ready() {
self.pending_local = Some(local);
Ok(Async::NotReady)
} else {
Ok(Async::Ready(()))
}
}
fn try_send(&mut self, frame: frame::Settings) -> Poll<(), ConnectionError> {
trace!("try_send");
if self.inner.start_send(item.into())?.is_ready() {
if self.inner.start_send(frame.into())?.is_ready() {
Ok(Async::Ready(()))
} else {
Ok(Async::NotReady)
@@ -111,19 +109,24 @@ impl<T, U> Settings<T>
}
}
impl<T> ControlSettings for Settings<T>{
fn update_local_settings(&mut self, local: frame::SettingSet) -> Result<(), ConnectionError> {
self.local = local;
self.local_valid_id_dirty = true;
impl<T, U> ControlSettings for Settings<T>
where T: Sink<SinkItem = Frame<U>, SinkError = ConnectionError>,
{
fn update_local_settings(&mut self, local: SettingSet) -> Result<(), ConnectionError> {
self.try_send_local(local)?;
Ok(())
}
fn local_settings(&self) -> &SettingSet {
&self.local
fn remote_initial_window_size(&self) -> u32 {
self.remote_initial_window_size
}
fn remote_settings(&self) -> &SettingSet {
&self.remote
fn remote_max_concurrent_streams(&self) -> Option<u32> {
self.remote_max_concurrent_streams
}
fn remote_push_enabled(&self) -> Option<bool> {
self.remote_push_enabled
}
}
@@ -147,7 +150,16 @@ impl<T, U> Stream for Settings<T>
// acknowledgements.
let settings = v.into_set();
self.inner.apply_remote_settings(&settings)?;
self.remote = settings;
if let Some(sz) = settings.initial_window_size() {
self.remote_initial_window_size = sz;
}
if let Some(max) = settings.max_concurrent_streams() {
self.remote_max_concurrent_streams = Some(max);
}
if let Some(ok) = settings.enable_push() {
self.remote_push_enabled = Some(ok);
}
self.remaining_acks += 1;
let _ = try!(self.try_send_pending());