1
0
mirror of https://github.com/fafhrd91/actix-net synced 2025-08-13 13:08:23 +02:00

Compare commits

..

14 Commits

Author SHA1 Message Date
Nikolay Kim
2955e49d78 add unix domain sockets support 2019-07-18 16:43:42 +06:00
Nikolay Kim
9d1b428b34 undeprecate framed transport 2019-07-17 13:31:00 +06:00
Nikolay Kim
42d526bced mark some fn as unsafe 2019-07-17 11:16:38 +06:00
Nikolay Kim
23a230a83b deprecate ClonableService and FramedTransport 2019-07-17 10:57:52 +06:00
Nikolay Kim
411e31786f update actix-connect changes 2019-07-17 10:33:47 +06:00
Nikolay Kim
b491d373b1 update actix-rt changes 2019-07-17 10:30:59 +06:00
Jeff Muizelaar
9271b95c87 Avoid a copy of the Future when initializing the Box. (#29)
Future's can be pretty big (> 1500 bytes) so this probably worth doing.

I confirmed with memcpy-find that this did infact eliminate two ~1500
byte copies from the actix-web basic example.
2019-07-17 10:29:22 +06:00
Jan Michael Auer
1b3cd0d88c Expose Connect addrs (#30) 2019-07-17 06:17:51 +06:00
Nikolay Kim
da302d4b7a fix disconnect callback 2019-07-03 13:02:03 +06:00
Nikolay Kim
922a919572 simple callback 2019-07-02 12:35:27 +06:00
Nikolay Kim
5a62175b6e add disconnect callback 2019-07-02 12:10:05 +06:00
Nikolay Kim
5445e341c3 give access to io object during connect stage 2019-07-01 22:37:59 +06:00
Nikolay Kim
1b17d274a0 refactor connect stage 2019-07-01 11:20:24 +06:00
Nikolay Kim
9d8b3e6275 impl Stream and Sink for Connect 2019-06-30 22:58:23 +06:00
25 changed files with 454 additions and 137 deletions

View File

@@ -10,9 +10,9 @@ matrix:
include:
- rust: stable
- rust: beta
- rust: nightly-2019-03-02
- rust: nightly-2019-06-15
allow_failures:
- rust: nightly-2019-03-02
- rust: nightly-2019-06-15
env:
global:
@@ -25,8 +25,8 @@ before_install:
- sudo apt-get install -y openssl libssl-dev libelf-dev libdw-dev cmake gcc binutils-dev libiberty-dev
before_cache: |
if [[ "$TRAVIS_RUST_VERSION" == "nightly-2019-03-02" ]]; then
RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install cargo-tarpaulin
if [[ "$TRAVIS_RUST_VERSION" == "nightly-2019-06-15" ]]; then
RUSTFLAGS="--cfg procmacro2_semver_exempt" cargo install --version 0.6.11 cargo-tarpaulin
fi
# Add clippy
@@ -35,14 +35,14 @@ before_script:
script:
- |
if [[ "$TRAVIS_RUST_VERSION" != "nightly-2019-03-02" ]]; then
if [[ "$TRAVIS_RUST_VERSION" != "nightly-2019-06-15" ]]; then
cargo clean
cargo test --all --all-features -- --nocapture
fi
after_success:
- |
if [[ "$TRAVIS_RUST_VERSION" == "nightly-2019-03-02" ]]; then
if [[ "$TRAVIS_RUST_VERSION" == "nightly-2019-06-15" ]]; then
taskset -c 0 cargo tarpaulin --all --all-features --out Xml
echo "Uploaded code coverage"
bash <(curl -s https://codecov.io/bash)

View File

@@ -1,9 +1,16 @@
# Changes
## [0.2.1] - 2019-07-17
### Added
* Expose Connect addrs #30
### Changed
* Update `derive_more` to 0.15
## [0.2.0] - 2019-05-12
### Changed

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-connect"
version = "0.2.0"
version = "0.2.1"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix Connector - tcp connector service"
keywords = ["network", "framework", "async", "futures"]

View File

@@ -1,5 +1,6 @@
use std::collections::VecDeque;
use std::collections::{vec_deque, VecDeque};
use std::fmt;
use std::iter::{FromIterator, FusedIterator};
use std::net::SocketAddr;
use either::Either;
@@ -77,6 +78,20 @@ impl<T: Address> Connect<T> {
self
}
/// Use addresses.
pub fn set_addrs<I>(mut self, addrs: I) -> Self
where
I: IntoIterator<Item = SocketAddr>,
{
let mut addrs = VecDeque::from_iter(addrs);
self.addr = if addrs.len() < 2 {
addrs.pop_front().map(Either::Left)
} else {
Some(Either::Right(addrs))
};
self
}
/// Host name
pub fn host(&self) -> &str {
self.req.host()
@@ -86,6 +101,28 @@ impl<T: Address> Connect<T> {
pub fn port(&self) -> u16 {
self.req.port().unwrap_or(self.port)
}
/// Preresolved addresses of the request.
pub fn addrs(&self) -> ConnectAddrsIter<'_> {
let inner = match self.addr {
None => Either::Left(None),
Some(Either::Left(addr)) => Either::Left(Some(addr)),
Some(Either::Right(ref addrs)) => Either::Right(addrs.iter()),
};
ConnectAddrsIter { inner }
}
/// Takes preresolved addresses of the request.
pub fn take_addrs(&mut self) -> ConnectTakeAddrsIter {
let inner = match self.addr.take() {
None => Either::Left(None),
Some(Either::Left(addr)) => Either::Left(Some(addr)),
Some(Either::Right(addrs)) => Either::Right(addrs.into_iter()),
};
ConnectTakeAddrsIter { inner }
}
}
impl<T: Address> From<T> for Connect<T> {
@@ -100,6 +137,70 @@ impl<T: Address> fmt::Display for Connect<T> {
}
}
/// Iterator over addresses in a [`Connect`](struct.Connect.html) request.
#[derive(Clone)]
pub struct ConnectAddrsIter<'a> {
inner: Either<Option<SocketAddr>, vec_deque::Iter<'a, SocketAddr>>,
}
impl Iterator for ConnectAddrsIter<'_> {
type Item = SocketAddr;
fn next(&mut self) -> Option<Self::Item> {
match self.inner {
Either::Left(ref mut opt) => opt.take(),
Either::Right(ref mut iter) => iter.next().copied(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.inner {
Either::Left(Some(_)) => (1, Some(1)),
Either::Left(None) => (0, Some(0)),
Either::Right(ref iter) => iter.size_hint(),
}
}
}
impl fmt::Debug for ConnectAddrsIter<'_> {
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
f.debug_list().entries(self.clone()).finish()
}
}
impl ExactSizeIterator for ConnectAddrsIter<'_> {}
impl FusedIterator for ConnectAddrsIter<'_> {}
/// Owned iterator over addresses in a [`Connect`](struct.Connect.html) request.
#[derive(Debug)]
pub struct ConnectTakeAddrsIter {
inner: Either<Option<SocketAddr>, vec_deque::IntoIter<SocketAddr>>,
}
impl Iterator for ConnectTakeAddrsIter {
type Item = SocketAddr;
fn next(&mut self) -> Option<Self::Item> {
match self.inner {
Either::Left(ref mut opt) => opt.take(),
Either::Right(ref mut iter) => iter.next(),
}
}
fn size_hint(&self) -> (usize, Option<usize>) {
match self.inner {
Either::Left(Some(_)) => (1, Some(1)),
Either::Left(None) => (0, Some(0)),
Either::Right(ref iter) => iter.size_hint(),
}
}
}
impl ExactSizeIterator for ConnectTakeAddrsIter {}
impl FusedIterator for ConnectTakeAddrsIter {}
fn parse(host: &str) -> (&str, Option<u16>) {
let mut parts_iter = host.splitn(2, ':');
if let Some(host) = parts_iter.next() {

View File

@@ -1,4 +1,3 @@
use std::collections::VecDeque;
use std::marker::PhantomData;
use std::net::SocketAddr;
@@ -162,23 +161,20 @@ impl<T: Address> Future for ResolverFuture<T> {
})? {
Async::NotReady => Ok(Async::NotReady),
Async::Ready(ips) => {
let mut req = self.req.take().unwrap();
let mut addrs: VecDeque<_> = ips
.iter()
.map(|ip| SocketAddr::new(ip, req.port()))
.collect();
let req = self.req.take().unwrap();
let port = req.port();
let req = req.set_addrs(ips.iter().map(|ip| SocketAddr::new(ip, port)));
trace!(
"DNS resolver: host {:?} resolved to {:?}",
req.host(),
addrs
req.addrs()
);
if addrs.is_empty() {
if req.addr.is_none() {
Err(ConnectError::NoRecords)
} else if addrs.len() == 1 {
req.addr = Some(either::Either::Left(addrs.pop_front().unwrap()));
Ok(Async::Ready(req))
} else {
req.addr = Some(either::Either::Right(addrs));
Ok(Async::Ready(req))
}
}

View File

@@ -1,5 +1,5 @@
# Changes
## [0.1.0] - 2019-xx-xx
## [0.1.0] - 2019-07-17
* Initial release

View File

@@ -18,8 +18,8 @@ name = "actix_ioframe"
path = "src/lib.rs"
[dependencies]
actix-service = "0.4.0"
actix-codec = "0.1.1"
actix-service = "0.4.1"
actix-codec = "0.1.2"
bytes = "0.4"
either = "1.5.2"
futures = "0.1.25"
@@ -28,3 +28,8 @@ log = "0.4"
[dev-dependencies]
actix-rt = "0.2.2"
actix-connect = "0.2.0"
actix-test-server = "0.2.2"
actix-server-config = "0.1.1"
tokio-tcp = "0.1"
tokio-timer = "0.2"

View File

@@ -29,11 +29,7 @@ impl<T> Cell<T> {
}
}
pub fn get_ref(&self) -> &T {
unsafe { &*self.inner.as_ref().get() }
}
pub fn get_mut(&mut self) -> &mut T {
unsafe { &mut *self.inner.as_ref().get() }
pub(crate) unsafe fn get_mut(&mut self) -> &mut T {
&mut *self.inner.as_ref().get()
}
}

View File

@@ -1,69 +1,37 @@
use std::marker::PhantomData;
use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed};
use futures::unsync::mpsc;
use crate::cell::Cell;
use crate::dispatcher::FramedMessage;
use crate::sink::Sink;
pub struct Connect<Io, St = (), Codec = ()> {
io: Io,
codec: Codec,
state: St,
// rx: mpsc::UnboundedReceiver<FramedMessage<<Codec as Encoder>::Item>>,
// sink: Sink<<Codec as Encoder>::Item>,
_t: PhantomData<(St, Codec)>,
}
impl<Io> Connect<Io> {
impl<Io> Connect<Io>
where
Io: AsyncRead + AsyncWrite,
{
pub(crate) fn new(io: Io) -> Self {
Self {
io,
codec: (),
state: (),
}
}
}
impl<Io, S, C> Connect<Io, S, C> {
pub fn codec<Codec>(self, codec: Codec) -> Connect<Io, S, Codec> {
Connect {
codec,
io: self.io,
state: self.state,
_t: PhantomData,
}
}
pub fn state<St>(self, state: St) -> Connect<Io, St, C> {
Connect {
state,
io: self.io,
codec: self.codec,
}
}
pub fn state_fn<St, F>(self, f: F) -> Connect<Io, St, C>
pub fn codec<Codec>(self, codec: Codec) -> ConnectResult<Io, (), Codec>
where
F: FnOnce(&Connect<Io, S, C>) -> St,
Codec: Encoder + Decoder,
{
Connect {
state: f(&self),
io: self.io,
codec: self.codec,
}
}
}
impl<Io, S, C> Connect<Io, S, C>
where
C: Encoder + Decoder,
Io: AsyncRead + AsyncWrite,
{
pub fn into_result(self) -> ConnectResult<Io, S, C> {
let (tx, rx) = mpsc::unbounded();
let sink = Sink::new(tx);
ConnectResult {
state: Cell::new(self.state),
framed: Framed::new(self.io, self.codec),
state: (),
framed: Framed::new(self.io, codec),
rx,
sink,
}
@@ -71,7 +39,7 @@ where
}
pub struct ConnectResult<Io, St, Codec: Encoder + Decoder> {
pub(crate) state: Cell<St>,
pub(crate) state: St,
pub(crate) framed: Framed<Io, Codec>,
pub(crate) rx: mpsc::UnboundedReceiver<FramedMessage<<Codec as Encoder>::Item>>,
pub(crate) sink: Sink<<Codec as Encoder>::Item>,
@@ -82,6 +50,26 @@ impl<Io, St, Codec: Encoder + Decoder> ConnectResult<Io, St, Codec> {
pub fn sink(&self) -> &Sink<<Codec as Encoder>::Item> {
&self.sink
}
#[inline]
pub fn get_ref(&self) -> &Io {
self.framed.get_ref()
}
#[inline]
pub fn get_mut(&mut self) -> &mut Io {
self.framed.get_mut()
}
#[inline]
pub fn state<S>(self, state: S) -> ConnectResult<Io, S, Codec> {
ConnectResult {
state,
framed: self.framed,
rx: self.rx,
sink: self.sink,
}
}
}
impl<Io, St, Codec> futures::Stream for ConnectResult<Io, St, Codec>

View File

@@ -1,6 +1,7 @@
//! Framed dispatcher service and related utilities
use std::collections::VecDeque;
use std::mem;
use std::rc::Rc;
use actix_codec::{AsyncRead, AsyncWrite, Decoder, Encoder, Framed};
use actix_service::{IntoService, Service};
@@ -13,6 +14,7 @@ use crate::cell::Cell;
use crate::error::ServiceError;
use crate::item::Item;
use crate::sink::Sink;
use crate::state::State;
type Request<S, U> = Item<S, U>;
type Response<U> = <U as Encoder>::Item;
@@ -37,11 +39,12 @@ where
{
service: S,
sink: Sink<<U as Encoder>::Item>,
state: Cell<St>,
dispatch_state: State<S, U>,
state: State<St>,
dispatch_state: FramedState<S, U>,
framed: Framed<T, U>,
rx: Option<mpsc::UnboundedReceiver<FramedMessage<<U as Encoder>::Item>>>,
inner: Cell<FramedDispatcherInner<<U as Encoder>::Item, S::Error>>,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
}
impl<St, S, T, U> FramedDispatcher<St, S, T, U>
@@ -56,18 +59,20 @@ where
{
pub(crate) fn new<F: IntoService<S>>(
framed: Framed<T, U>,
state: Cell<St>,
state: State<St>,
service: F,
rx: mpsc::UnboundedReceiver<FramedMessage<<U as Encoder>::Item>>,
sink: Sink<<U as Encoder>::Item>,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
) -> Self {
FramedDispatcher {
framed,
state,
sink,
disconnect,
rx: Some(rx),
service: service.into_service(),
dispatch_state: State::Processing,
dispatch_state: FramedState::Processing,
inner: Cell::new(FramedDispatcherInner {
buf: VecDeque::new(),
task: AtomicTask::new(),
@@ -76,7 +81,7 @@ where
}
}
enum State<S: Service, U: Encoder + Decoder> {
enum FramedState<S: Service, U: Encoder + Decoder> {
Processing,
Error(ServiceError<S::Error, U>),
FramedError(ServiceError<S::Error, U>),
@@ -84,22 +89,22 @@ enum State<S: Service, U: Encoder + Decoder> {
Stopping,
}
impl<S: Service, U: Encoder + Decoder> State<S, U> {
impl<S: Service, U: Encoder + Decoder> FramedState<S, U> {
fn stop(&mut self, tx: Option<oneshot::Sender<()>>) {
match self {
State::FlushAndStop(ref mut vec) => {
FramedState::FlushAndStop(ref mut vec) => {
if let Some(tx) = tx {
vec.push(tx)
}
}
State::Processing => {
*self = State::FlushAndStop(if let Some(tx) = tx {
FramedState::Processing => {
*self = FramedState::FlushAndStop(if let Some(tx) = tx {
vec![tx]
} else {
Vec::new()
})
}
State::Error(_) | State::FramedError(_) | State::Stopping => {
FramedState::Error(_) | FramedState::FramedError(_) | FramedState::Stopping => {
if let Some(tx) = tx {
let _ = tx.send(());
}
@@ -123,6 +128,12 @@ where
<U as Encoder>::Item: 'static,
<U as Encoder>::Error: std::fmt::Debug,
{
fn disconnect(&mut self, error: bool) {
if let Some(ref disconnect) = self.disconnect {
(&*disconnect)(&mut *self.state.get_mut(), error);
}
}
fn poll_read(&mut self) -> bool {
loop {
match self.service.poll_ready() {
@@ -131,18 +142,18 @@ where
Ok(Async::Ready(Some(el))) => el,
Err(err) => {
self.dispatch_state =
State::FramedError(ServiceError::Decoder(err));
FramedState::FramedError(ServiceError::Decoder(err));
return true;
}
Ok(Async::NotReady) => return false,
Ok(Async::Ready(None)) => {
self.dispatch_state = State::Stopping;
self.dispatch_state = FramedState::Stopping;
return true;
}
};
let mut cell = self.inner.clone();
cell.get_mut().task.register();
unsafe { cell.get_mut().task.register() };
tokio_current_thread::spawn(
self.service
.call(Item::new(self.state.clone(), self.sink.clone(), item))
@@ -152,16 +163,18 @@ where
Ok(None) => return Ok(()),
Err(err) => Err(err),
};
let inner = cell.get_mut();
inner.buf.push_back(item);
inner.task.notify();
unsafe {
let inner = cell.get_mut();
inner.buf.push_back(item);
inner.task.notify();
}
Ok(())
}),
);
}
Ok(Async::NotReady) => return false,
Err(err) => {
self.dispatch_state = State::Error(ServiceError::Service(err));
self.dispatch_state = FramedState::Error(ServiceError::Service(err));
return true;
}
}
@@ -170,7 +183,7 @@ where
/// write to framed object
fn poll_write(&mut self) -> bool {
let inner = self.inner.get_mut();
let inner = unsafe { self.inner.get_mut() };
let mut rx_done = self.rx.is_none();
let mut buf_empty = inner.buf.is_empty();
loop {
@@ -180,13 +193,14 @@ where
Ok(msg) => {
if let Err(err) = self.framed.force_send(msg) {
self.dispatch_state =
State::FramedError(ServiceError::Encoder(err));
FramedState::FramedError(ServiceError::Encoder(err));
return true;
}
buf_empty = inner.buf.is_empty();
}
Err(err) => {
self.dispatch_state = State::Error(ServiceError::Service(err));
self.dispatch_state =
FramedState::Error(ServiceError::Service(err));
return true;
}
}
@@ -197,7 +211,7 @@ where
Ok(Async::Ready(Some(FramedMessage::Message(msg)))) => {
if let Err(err) = self.framed.force_send(msg) {
self.dispatch_state =
State::FramedError(ServiceError::Encoder(err));
FramedState::FramedError(ServiceError::Encoder(err));
return true;
}
}
@@ -231,7 +245,8 @@ where
Ok(Async::NotReady) => break,
Err(err) => {
debug!("Error sending data: {:?}", err);
self.dispatch_state = State::FramedError(ServiceError::Encoder(err));
self.dispatch_state =
FramedState::FramedError(ServiceError::Encoder(err));
return true;
}
Ok(Async::Ready(_)) => (),
@@ -259,32 +274,33 @@ where
type Error = ServiceError<S::Error, U>;
fn poll(&mut self) -> Poll<Self::Item, Self::Error> {
match mem::replace(&mut self.dispatch_state, State::Processing) {
State::Processing => {
match mem::replace(&mut self.dispatch_state, FramedState::Processing) {
FramedState::Processing => {
if self.poll_read() || self.poll_write() {
self.poll()
} else {
Ok(Async::NotReady)
}
}
State::Error(err) => {
FramedState::Error(err) => {
if self.framed.is_write_buf_empty()
|| (self.poll_write() || self.framed.is_write_buf_empty())
{
self.disconnect(true);
Err(err)
} else {
self.dispatch_state = State::Error(err);
self.dispatch_state = FramedState::Error(err);
Ok(Async::NotReady)
}
}
State::FlushAndStop(mut vec) => {
FramedState::FlushAndStop(mut vec) => {
if !self.framed.is_write_buf_empty() {
match self.framed.poll_complete() {
Err(err) => {
debug!("Error sending data: {:?}", err);
}
Ok(Async::NotReady) => {
self.dispatch_state = State::FlushAndStop(vec);
self.dispatch_state = FramedState::FlushAndStop(vec);
return Ok(Async::NotReady);
}
Ok(Async::Ready(_)) => (),
@@ -293,10 +309,17 @@ where
for tx in vec.drain(..) {
let _ = tx.send(());
}
self.disconnect(false);
Ok(Async::Ready(()))
}
FramedState::FramedError(err) => {
self.disconnect(true);
Err(err)
}
FramedState::Stopping => {
self.disconnect(false);
Ok(Async::Ready(()))
}
State::FramedError(err) => Err(err),
State::Stopping => Ok(Async::Ready(())),
}
}
}

View File

@@ -1,13 +1,14 @@
use std::cell::{Ref, RefMut};
use std::fmt;
use std::ops::{Deref, DerefMut};
use actix_codec::{Decoder, Encoder};
use crate::cell::Cell;
use crate::sink::Sink;
use crate::state::State;
pub struct Item<S, Codec: Encoder + Decoder> {
state: Cell<S>,
pub struct Item<St, Codec: Encoder + Decoder> {
state: State<St>,
sink: Sink<<Codec as Encoder>::Item>,
item: <Codec as Decoder>::Item,
}
@@ -17,7 +18,7 @@ where
Codec: Encoder + Decoder,
{
pub(crate) fn new(
state: Cell<St>,
state: State<St>,
sink: Sink<<Codec as Encoder>::Item>,
item: <Codec as Decoder>::Item,
) -> Self {
@@ -25,12 +26,12 @@ where
}
#[inline]
pub fn state(&self) -> &St {
pub fn state(&self) -> Ref<St> {
self.state.get_ref()
}
#[inline]
pub fn state_mut(&mut self) -> &mut St {
pub fn state_mut(&mut self) -> RefMut<St> {
self.state.get_mut()
}
@@ -43,6 +44,17 @@ where
pub fn into_inner(self) -> <Codec as Decoder>::Item {
self.item
}
#[inline]
pub fn into_parts(
self,
) -> (
State<St>,
Sink<<Codec as Encoder>::Item>,
<Codec as Decoder>::Item,
) {
(self.state, self.sink, self.item)
}
}
impl<St, Codec> Deref for Item<St, Codec>

View File

@@ -5,9 +5,11 @@ mod error;
mod item;
mod service;
mod sink;
mod state;
pub use self::connect::{Connect, ConnectResult};
pub use self::error::ServiceError;
pub use self::item::Item;
pub use self::service::{Builder, NewServiceBuilder, ServiceBuilder};
pub use self::sink::Sink;
pub use self::state::State;

View File

@@ -9,6 +9,7 @@ use crate::connect::{Connect, ConnectResult};
use crate::dispatcher::FramedDispatcher;
use crate::error::ServiceError;
use crate::item::Item;
use crate::state::State;
type RequestItem<S, U> = Item<S, U>;
type ResponseItem<U> = Option<<U as Encoder>::Item>;
@@ -32,6 +33,7 @@ impl<St, Codec> Builder<St, Codec> {
{
ServiceBuilder {
connect: connect.into_service(),
disconnect: None,
_t: PhantomData,
}
}
@@ -52,6 +54,7 @@ impl<St, Codec> Builder<St, Codec> {
{
NewServiceBuilder {
connect: connect.into_new_service(),
disconnect: None,
_t: PhantomData,
}
}
@@ -59,6 +62,7 @@ impl<St, Codec> Builder<St, Codec> {
pub struct ServiceBuilder<St, C, Io, Codec> {
connect: C,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
_t: PhantomData<(St, Io, Codec)>,
}
@@ -72,6 +76,18 @@ where
<Codec as Encoder>::Item: 'static,
<Codec as Encoder>::Error: std::fmt::Debug,
{
/// Callback to execute on disconnect
///
/// Second parameter indicates error occured during disconnect.
pub fn disconnect<F, Out>(mut self, disconnect: F) -> Self
where
F: Fn(&mut St, bool) + 'static,
{
self.disconnect = Some(Rc::new(disconnect));
self
}
/// Provide stream items handler service and construct service factory.
pub fn finish<F, T>(
self,
service: F,
@@ -89,6 +105,7 @@ where
FramedServiceImpl {
connect: self.connect,
handler: Rc::new(service.into_new_service()),
disconnect: self.disconnect.clone(),
_t: PhantomData,
}
}
@@ -96,6 +113,7 @@ where
pub struct NewServiceBuilder<St, C, Io, Codec> {
connect: C,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
_t: PhantomData<(St, Io, Codec)>,
}
@@ -110,11 +128,22 @@ where
<Codec as Encoder>::Item: 'static,
<Codec as Encoder>::Error: std::fmt::Debug,
{
pub fn finish<F, T>(
/// Callback to execute on disconnect
///
/// Second parameter indicates error occured during disconnect.
pub fn disconnect<F>(mut self, disconnect: F) -> Self
where
F: Fn(&mut St, bool) + 'static,
{
self.disconnect = Some(Rc::new(disconnect));
self
}
pub fn finish<F, T, Cfg>(
self,
service: F,
) -> impl NewService<
Config = (),
Config = Cfg,
Request = Io,
Response = (),
Error = ServiceError<C::Error, Codec>,
@@ -132,18 +161,20 @@ where
FramedService {
connect: self.connect,
handler: Rc::new(service.into_new_service()),
disconnect: self.disconnect,
_t: PhantomData,
}
}
}
pub(crate) struct FramedService<St, C, T, Io, Codec> {
pub(crate) struct FramedService<St, C, T, Io, Codec, Cfg> {
connect: C,
handler: Rc<T>,
_t: PhantomData<(St, Io, Codec)>,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
_t: PhantomData<(St, Io, Codec, Cfg)>,
}
impl<St, C, T, Io, Codec> NewService for FramedService<St, C, T, Io, Codec>
impl<St, C, T, Io, Codec, Cfg> NewService for FramedService<St, C, T, Io, Codec, Cfg>
where
St: 'static,
Io: AsyncRead + AsyncWrite,
@@ -161,7 +192,7 @@ where
<Codec as Encoder>::Item: 'static,
<Codec as Encoder>::Error: std::fmt::Debug,
{
type Config = ();
type Config = Cfg;
type Request = Io;
type Response = ();
type Error = ServiceError<C::Error, Codec>;
@@ -169,8 +200,9 @@ where
type Service = FramedServiceImpl<St, C::Service, T, Io, Codec>;
type Future = Box<Future<Item = Self::Service, Error = Self::InitError>>;
fn new_service(&self, _: &()) -> Self::Future {
fn new_service(&self, _: &Cfg) -> Self::Future {
let handler = self.handler.clone();
let disconnect = self.disconnect.clone();
// create connect service and then create service impl
Box::new(
@@ -179,6 +211,7 @@ where
.map(move |connect| FramedServiceImpl {
connect,
handler,
disconnect,
_t: PhantomData,
}),
)
@@ -188,12 +221,12 @@ where
pub struct FramedServiceImpl<St, C, T, Io, Codec> {
connect: C,
handler: Rc<T>,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
_t: PhantomData<(St, Io, Codec)>,
}
impl<St, C, T, Io, Codec> Service for FramedServiceImpl<St, C, T, Io, Codec>
where
// St: 'static,
Io: AsyncRead + AsyncWrite,
C: Service<Request = Connect<Io>, Response = ConnectResult<Io, St, Codec>>,
C::Error: 'static,
@@ -224,6 +257,7 @@ where
self.connect.call(Connect::new(req)),
self.handler.clone(),
),
disconnect: self.disconnect.clone(),
}
}
}
@@ -246,6 +280,7 @@ where
<Codec as Encoder>::Error: std::fmt::Debug,
{
inner: FramedServiceImplResponseInner<St, Io, Codec, C, T>,
disconnect: Option<Rc<Fn(&mut St, bool)>>,
}
enum FramedServiceImplResponseInner<St, Io, Codec, C, T>
@@ -296,7 +331,7 @@ where
match fut.poll()? {
Async::Ready(res) => {
self.inner = FramedServiceImplResponseInner::Handler(
handler.new_service(res.state.get_ref()),
handler.new_service(&res.state),
Some(res),
);
self.poll()
@@ -310,7 +345,12 @@ where
let res = res.take().unwrap();
self.inner =
FramedServiceImplResponseInner::Dispatcher(FramedDispatcher::new(
res.framed, res.state, handler, res.rx, res.sink,
res.framed,
State::new(res.state),
handler,
res.rx,
res.sink,
self.disconnect.clone(),
));
self.poll()
}

View File

@@ -0,0 +1,30 @@
use std::cell::{Ref, RefCell, RefMut};
use std::rc::Rc;
/// Connection state
///
/// Connection state is an arbitrary data attached to the each incoming message.
#[derive(Debug)]
pub struct State<T>(Rc<RefCell<T>>);
impl<T> State<T> {
pub(crate) fn new(st: T) -> Self {
State(Rc::new(RefCell::new(st)))
}
#[inline]
pub fn get_ref(&self) -> Ref<T> {
self.0.borrow()
}
#[inline]
pub fn get_mut(&mut self) -> RefMut<T> {
self.0.borrow_mut()
}
}
impl<T> Clone for State<T> {
fn clone(&self) -> Self {
State(self.0.clone())
}
}

View File

@@ -0,0 +1,60 @@
use std::sync::atomic::{AtomicBool, Ordering};
use std::sync::Arc;
use std::time::Duration;
use actix_codec::BytesCodec;
use actix_server_config::Io;
use actix_service::{new_apply_fn, Service};
use actix_test_server::TestServer;
use futures::Future;
use tokio_tcp::TcpStream;
use tokio_timer::sleep;
use actix_ioframe::{Builder, Connect};
struct State;
#[test]
fn test_disconnect() -> std::io::Result<()> {
let disconnect = Arc::new(AtomicBool::new(false));
let disconnect1 = disconnect.clone();
let mut srv = TestServer::with(move || {
let disconnect1 = disconnect1.clone();
new_apply_fn(
Builder::new()
.factory(|conn: Connect<_>| Ok(conn.codec(BytesCodec).state(State)))
.disconnect(move |_, _| {
disconnect1.store(true, Ordering::Relaxed);
})
.finish(|_t| Ok(None)),
|io: Io<TcpStream>, srv| srv.call(io.into_parts().0),
)
});
let mut client = Builder::new()
.service(|conn: Connect<_>| {
let conn = conn.codec(BytesCodec).state(State);
conn.sink().close();
Ok(conn)
})
.finish(|_t| Ok(None));
let conn = srv
.block_on(
actix_connect::default_connector()
.call(actix_connect::Connect::with(String::new(), srv.addr())),
)
.unwrap();
srv.block_on(client.call(conn.into_parts().0)).unwrap();
let _ = srv.block_on(
sleep(Duration::from_millis(100))
.map(|_| ())
.map_err(|_| ()),
);
assert!(disconnect.load(Ordering::Relaxed));
Ok(())
}

View File

@@ -1,5 +1,12 @@
# Changes
## [0.2.4] - 2019-07-17
### Changed
* Avoid a copy of the Future when initializing the Box. #29
## [0.2.3] - 2019-06-22
### Added

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-rt"
version = "0.2.3"
version = "0.2.4"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix runtime"
keywords = ["network", "framework", "async", "futures"]
@@ -24,3 +24,4 @@ tokio-current-thread = "0.1"
tokio-executor = "0.1.5"
tokio-reactor = "0.1.7"
tokio-timer = "0.2.8"
copyless = "0.1.4"

View File

@@ -11,6 +11,8 @@ use tokio_current_thread::spawn;
use crate::builder::Builder;
use crate::system::System;
use copyless::BoxHelper;
thread_local!(
static ADDR: RefCell<Option<Arbiter>> = RefCell::new(None);
static RUNNING: Cell<bool> = Cell::new(false);
@@ -141,9 +143,9 @@ impl Arbiter {
{
RUNNING.with(move |cell| {
if cell.get() {
spawn(Box::new(future));
spawn(Box::alloc().init(future));
} else {
Q.with(move |cell| cell.borrow_mut().push(Box::new(future)));
Q.with(move |cell| cell.borrow_mut().push(Box::alloc().init(future)));
}
});
}

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-server-config"
version = "0.1.1"
version = "0.1.2"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix server config utils"
homepage = "https://actix.rs"
@@ -14,7 +14,7 @@ name = "actix_server_config"
path = "src/lib.rs"
[package.metadata.docs.rs]
features = ["ssl", "rust-tls"]
features = ["ssl", "rust-tls", "uds"]
[features]
default = []
@@ -25,6 +25,9 @@ ssl = ["tokio-openssl"]
# rustls
rust-tls = ["rustls", "tokio-rustls"]
# unix domain sockets
uds = ["tokio-uds"]
[dependencies]
futures = "0.1.25"
tokio-io = "0.1.12"
@@ -32,3 +35,4 @@ tokio-tcp = "0.1"
tokio-openssl = { version="0.3.0", optional = true }
rustls = { version = "0.15.2", optional = true }
tokio-rustls = { version = "0.9.1", optional = true }
tokio-uds = { version="0.2.5", optional = true }

View File

@@ -1,5 +1,12 @@
# Changes
## [0.1.2] - 2019-07-18
### Added
* Add unix domnain sockets support
## [0.1.1] - 2019-04-16
### Added

View File

@@ -95,9 +95,9 @@ impl<T, P> Io<T, P> {
/// Return new Io object with new parameter.
pub fn set<U>(self, params: U) -> Io<T, U> {
Io {
params,
io: self.io,
proto: self.proto,
params: params,
}
}
@@ -216,3 +216,26 @@ impl<T: IoStream> IoStream for tokio_rustls::TlsStream<T, rustls::ServerSession>
self.get_mut().0.set_keepalive(dur)
}
}
#[cfg(all(unix, feature = "uds"))]
impl IoStream for tokio_uds::UnixStream {
#[inline]
fn peer_addr(&self) -> Option<net::SocketAddr> {
None
}
#[inline]
fn set_nodelay(&mut self, _: bool) -> io::Result<()> {
Ok(())
}
#[inline]
fn set_linger(&mut self, _: Option<time::Duration>) -> io::Result<()> {
Ok(())
}
#[inline]
fn set_keepalive(&mut self, _: Option<time::Duration>) -> io::Result<()> {
Ok(())
}
}

View File

@@ -6,17 +6,11 @@ use futures::{Async, Future, IntoFuture, Poll};
use crate::transform_err::{TransformFromErr, TransformMapInitErr};
use crate::{IntoNewService, NewService, Service};
/// The `Transform` trait defines the interface of a Service factory. `Transform`
/// is often implemented for middleware, defining how to manufacture a
/// middleware Service. A Service that is manufactured by the factory takes
/// The `Transform` trait defines the interface of a Service factory. `Transform`
/// is often implemented for middleware, defining how to construct a
/// middleware Service. A Service that is constructed by the factory takes
/// the Service that follows it during execution as a parameter, assuming
/// ownership of the next Service. A Service can be a variety of types, such
/// as (but not limited to) another middleware Service, an extractor Service,
/// other helper Services, or the request handler endpoint Service.
///
/// A Service is created by the factory during server initialization.
///
/// `Config` is a service factory configuration type.
/// ownership of the next Service.
pub trait Transform<S> {
/// Requests handled by the service.
type Request;

View File

@@ -1,5 +1,21 @@
# Changes
## [0.4.4] - 2019-07-17
### Changed
* Undeprecate `FramedTransport` as it is actually useful
## [0.4.3] - 2019-07-17
### Deprecated
* Deprecate `CloneableService` as it is not safe and in general not very useful
* Deprecate `FramedTransport` in favor of `actix-ioframe`
## [0.4.2] - 2019-06-26
### Fixed

View File

@@ -1,6 +1,6 @@
[package]
name = "actix-utils"
version = "0.4.2"
version = "0.4.4"
authors = ["Nikolay Kim <fafhrd91@gmail.com>"]
description = "Actix utils - various actix net related services"
keywords = ["network", "framework", "async", "futures"]

View File

@@ -1,3 +1,4 @@
#![allow(deprecated)]
use std::marker::PhantomData;
use std::rc::Rc;
@@ -6,6 +7,8 @@ use futures::Poll;
use super::cell::Cell;
#[doc(hidden)]
#[deprecated(since = "0.4.3", note = "support will be removed in actix-utils 0.4.5")]
/// Service that allows to turn non-clone service to a service with `Clone` impl
pub struct CloneableService<T> {
service: Cell<T>,