parent
a4fd1ddfbb
commit
51a5d0aeba
@ -1,99 +0,0 @@
|
|||||||
//! For API calls if enabled
|
|
||||||
use super::*;
|
|
||||||
use std::{
|
|
||||||
fmt,
|
|
||||||
error,
|
|
||||||
iter,
|
|
||||||
convert::Infallible,
|
|
||||||
};
|
|
||||||
use futures::{
|
|
||||||
stream::{
|
|
||||||
self,
|
|
||||||
BoxStream,
|
|
||||||
StreamExt,
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
#[inline] fn aggregate(mut body: impl Buf) -> Result<String, std::str::Utf8Error>
|
|
||||||
{
|
|
||||||
/*let mut output = Vec::new();
|
|
||||||
while body.has_remaining() {
|
|
||||||
let bytes = body.bytes();
|
|
||||||
output.extend_from_slice(&bytes[..]);
|
|
||||||
let cnt = bytes.len();
|
|
||||||
body.advance(cnt);
|
|
||||||
}*/
|
|
||||||
|
|
||||||
std::str::from_utf8(&body.to_bytes()).map(ToOwned::to_owned)
|
|
||||||
}
|
|
||||||
|
|
||||||
pub async fn single(host: IpAddr, num: Option<usize>, body: impl Buf) -> Result<impl warp::Reply, warp::reject::Rejection>
|
|
||||||
{
|
|
||||||
single_stream(host, num, body).await
|
|
||||||
.map(|rx| Response::new(Body::wrap_stream(rx.map(move |x| {
|
|
||||||
info!("{} <- {:?}", host, x);
|
|
||||||
x
|
|
||||||
}))))
|
|
||||||
.map_err(warp::reject::custom)
|
|
||||||
}
|
|
||||||
|
|
||||||
//TODO: Change to stream impl like normal `feed` has, instead of taking aggregate?
|
|
||||||
async fn single_stream(host: IpAddr, num: Option<usize>, body: impl Buf) -> Result<BoxStream<'static, Result<String, Infallible>>, ApiError>
|
|
||||||
{
|
|
||||||
let body = aggregate(body)?;
|
|
||||||
info!("{} <- {:?}", host, &body[..]);
|
|
||||||
|
|
||||||
let mut chain = Chain::new();
|
|
||||||
|
|
||||||
if_debug! {
|
|
||||||
let timer = std::time::Instant::now();
|
|
||||||
}
|
|
||||||
cfg_if! {
|
|
||||||
if #[cfg(feature="split-newlines")] {
|
|
||||||
for body in body.split('\n').filter(|line| !line.trim().is_empty()) {
|
|
||||||
feed::feed(&mut chain, body, 1..);
|
|
||||||
}
|
|
||||||
}else {
|
|
||||||
feed::feed(&mut chain, body, 1..);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if_debug!{
|
|
||||||
trace!("Write took {}ms", timer.elapsed().as_millis());
|
|
||||||
}
|
|
||||||
match num {
|
|
||||||
None => Ok(stream::iter(iter::once(Ok(chain.generate_str()))).boxed()),
|
|
||||||
Some(num) => {
|
|
||||||
let (mut tx, rx) = mpsc::channel(num);
|
|
||||||
tokio::spawn(async move {
|
|
||||||
for string in chain.str_iter_for(num) {
|
|
||||||
tx.send(string).await.expect("Failed to send string to body");
|
|
||||||
}
|
|
||||||
});
|
|
||||||
Ok(StreamExt::map(rx, |x| Ok::<_, Infallible>(x)).boxed())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Debug)]
|
|
||||||
pub enum ApiError {
|
|
||||||
Body,
|
|
||||||
}
|
|
||||||
impl warp::reject::Reject for ApiError{}
|
|
||||||
impl error::Error for ApiError{}
|
|
||||||
impl std::fmt::Display for ApiError
|
|
||||||
{
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
|
||||||
{
|
|
||||||
match self {
|
|
||||||
Self::Body => write!(f, "invalid data in request body"),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl From<std::str::Utf8Error> for ApiError
|
|
||||||
{
|
|
||||||
fn from(_: std::str::Utf8Error) -> Self
|
|
||||||
{
|
|
||||||
Self::Body
|
|
||||||
}
|
|
||||||
}
|
|
@ -0,0 +1,55 @@
|
|||||||
|
//! API errors
|
||||||
|
//use super::*;
|
||||||
|
use std::{
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
use warp::{
|
||||||
|
Rejection,
|
||||||
|
Reply,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum ApiError {
|
||||||
|
Body,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl ApiError
|
||||||
|
{
|
||||||
|
#[inline] fn error_code(&self) -> warp::http::StatusCode
|
||||||
|
{
|
||||||
|
status!(match self {
|
||||||
|
Self::Body => 422,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl warp::reject::Reject for ApiError{}
|
||||||
|
impl error::Error for ApiError{}
|
||||||
|
impl std::fmt::Display for ApiError
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
match self {
|
||||||
|
Self::Body => write!(f, "invalid data in request body"),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl From<std::str::Utf8Error> for ApiError
|
||||||
|
{
|
||||||
|
fn from(_: std::str::Utf8Error) -> Self
|
||||||
|
{
|
||||||
|
Self::Body
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles API rejections
|
||||||
|
pub async fn rejection(err: Rejection) -> Result<impl Reply, Rejection>
|
||||||
|
{
|
||||||
|
if let Some(api) = err.find::<ApiError>() {
|
||||||
|
Ok(warp::reply::with_status(format!("ApiError: {}\n", api), api.error_code()))
|
||||||
|
} else {
|
||||||
|
Err(err)
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,32 @@
|
|||||||
|
//! For API calls if enabled
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
iter,
|
||||||
|
convert::Infallible,
|
||||||
|
};
|
||||||
|
use futures::{
|
||||||
|
stream::{
|
||||||
|
self,
|
||||||
|
BoxStream,
|
||||||
|
StreamExt,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
pub mod error;
|
||||||
|
use error::ApiError;
|
||||||
|
|
||||||
|
mod single;
|
||||||
|
|
||||||
|
#[inline] fn aggregate(mut body: impl Buf) -> Result<String, std::str::Utf8Error>
|
||||||
|
{
|
||||||
|
std::str::from_utf8(&body.to_bytes()).map(ToOwned::to_owned)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn single(host: IpAddr, num: Option<usize>, body: impl Buf) -> Result<impl warp::Reply, warp::reject::Rejection>
|
||||||
|
{
|
||||||
|
single::single_stream(host, num, body).await
|
||||||
|
.map(|rx| Response::new(Body::wrap_stream(rx.map(move |x| {
|
||||||
|
info!("{} <- {:?}", host, x);
|
||||||
|
x
|
||||||
|
}))))
|
||||||
|
.map_err(warp::reject::custom)
|
||||||
|
}
|
@ -0,0 +1,2 @@
|
|||||||
|
//! /sentance/
|
||||||
|
use super::*;
|
@ -0,0 +1,47 @@
|
|||||||
|
//! Handler for /single/
|
||||||
|
use super::*;
|
||||||
|
|
||||||
|
//TODO: Change to stream impl like normal `feed` has, instead of taking aggregate?
|
||||||
|
pub async fn single_stream(host: IpAddr, num: Option<usize>, body: impl Buf) -> Result<BoxStream<'static, Result<String, Infallible>>, ApiError>
|
||||||
|
{
|
||||||
|
let body = aggregate(body)?;
|
||||||
|
info!("{} <- {:?}", host, &body[..]);
|
||||||
|
|
||||||
|
let mut chain = Chain::new();
|
||||||
|
|
||||||
|
if_debug! {
|
||||||
|
let timer = std::time::Instant::now();
|
||||||
|
}
|
||||||
|
cfg_if! {
|
||||||
|
if #[cfg(feature="split-newlines")] {
|
||||||
|
for body in body.split('\n').filter(|line| !line.trim().is_empty()) {
|
||||||
|
feed::feed(&mut chain, body, 1..);
|
||||||
|
}
|
||||||
|
}else {
|
||||||
|
feed::feed(&mut chain, body, 1..);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if_debug!{
|
||||||
|
trace!("Write took {}ms", timer.elapsed().as_millis());
|
||||||
|
}
|
||||||
|
if chain.is_empty() {
|
||||||
|
Ok(stream::empty().boxed())
|
||||||
|
} else {
|
||||||
|
match num {
|
||||||
|
|
||||||
|
None => Ok(stream::iter(iter::once(Ok(chain.generate_str()))).boxed()),
|
||||||
|
Some(num) => {
|
||||||
|
let (mut tx, rx) = mpsc::channel(num);
|
||||||
|
tokio::spawn(async move {
|
||||||
|
for string in chain.str_iter_for(num) {
|
||||||
|
if let Err(e) = tx.send(string).await {
|
||||||
|
error!("Failed to send string to body, aborting: {:?}", e.0);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
Ok(StreamExt::map(rx, |x| Ok::<_, Infallible>(x)).boxed())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,37 @@
|
|||||||
|
//! Sanitisers
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
marker::Unpin,
|
||||||
|
error,
|
||||||
|
fmt,
|
||||||
|
};
|
||||||
|
use tokio::{
|
||||||
|
prelude::*,
|
||||||
|
io::{
|
||||||
|
AsyncRead,
|
||||||
|
AsyncBufRead
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
mod word;
|
||||||
|
pub use word::*;
|
||||||
|
|
||||||
|
pub fn take_sentance<T: AsyncBufRead+ ?Sized + Unpin, U: AsyncWrite + ?Sized + Unpin>(from: &mut T, to: &mut U) -> Result<usize, Error>
|
||||||
|
{
|
||||||
|
todo!()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub enum Error {
|
||||||
|
|
||||||
|
}
|
||||||
|
impl error::Error for Error{}
|
||||||
|
impl fmt::Display for Error
|
||||||
|
{
|
||||||
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -0,0 +1,45 @@
|
|||||||
|
//! Word splitting
|
||||||
|
use super::*;
|
||||||
|
use std::{
|
||||||
|
borrow::Borrow,
|
||||||
|
};
|
||||||
|
|
||||||
|
#[derive(Debug, PartialEq, Eq)]
|
||||||
|
#[repr(transparent)]
|
||||||
|
pub struct Word(str);
|
||||||
|
|
||||||
|
impl Word
|
||||||
|
{
|
||||||
|
pub fn new<'a>(from: &'a str) -> &'a Self
|
||||||
|
{
|
||||||
|
unsafe {
|
||||||
|
std::mem::transmute(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'a> From<&'a str> for &'a Word
|
||||||
|
{
|
||||||
|
fn from(from: &'a str) -> Self
|
||||||
|
{
|
||||||
|
Word::new(from)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<str> for Word
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &str
|
||||||
|
{
|
||||||
|
&self.0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl AsRef<Word> for str
|
||||||
|
{
|
||||||
|
fn as_ref(&self) -> &Word
|
||||||
|
{
|
||||||
|
Word::new(self)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
//impl Borrow<>
|
Loading…
Reference in new issue