Skip to content

Rewind page 2 #344

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 10 commits into from
Nov 3, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,8 @@ serde_json = "1.0.41"
typemap = "0.3.3"
serde_urlencoded = "0.6.1"
log = "0.4.8"
accept-encoding = "0.2.0-alpha.2"
async-compression = "0.1.0-alpha.7"

[dependencies.http-service-hyper]
optional = true
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -54,7 +54,7 @@ and **not ready for production use yet**.
fn main() -> Result<(), std::io::Error> {
let mut app = tide::App::new();
app.at("/").get(|_| async move { "Hello, world!" });
Ok(app.serve("127.0.0.1:8000")?)
Ok(app.run("127.0.0.1:8000")?)
}
```

Expand Down
2 changes: 1 addition & 1 deletion examples/body_types.rs
Original file line number Diff line number Diff line change
Expand Up @@ -43,5 +43,5 @@ fn main() {
app.at("/echo/json").post(echo_json);
app.at("/echo/form").post(echo_form);

app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/catch_all.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,5 +8,5 @@ async fn echo_path(cx: Context<()>) -> String {
fn main() {
let mut app = tide::App::new();
app.at("/echo_path/*path").get(echo_path);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/cookies.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,5 +22,5 @@ fn main() {
app.at("/").get(retrieve_cookie);
app.at("/set").get(set_cookie);
app.at("/remove").get(remove_cookie);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/default_headers.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,5 +11,5 @@ fn main() {

app.at("/").get(|_| async move { "Hello, world!" });

app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
16 changes: 8 additions & 8 deletions examples/graphql.rs
Original file line number Diff line number Diff line change
Expand Up @@ -8,19 +8,19 @@ use juniper::graphql_object;
use std::sync::{atomic, Arc};
use tide::{error::ResultExt, response, App, Context, EndpointResult};

// First, we define `Data` that holds accumulator state. This is accessible as App data in
// First, we define `State` that holds accumulator state. This is accessible as App data in
// Tide, and as executor context in Juniper.
#[derive(Clone, Default)]
struct Data(Arc<atomic::AtomicIsize>);
struct State(Arc<atomic::AtomicIsize>);

impl juniper::Context for Data {}
impl juniper::Context for State {}

// We define `Query` unit struct here. GraphQL queries will refer to this struct. The struct itself
// doesn't have any associated data (and there's no need to do so), but instead it exposes the
// accumulator state from the context.
struct Query;

graphql_object!(Query: Data |&self| {
graphql_object!(Query: State |&self| {
// GraphQL integers are signed and 32 bits long.
field accumulator(&executor) -> i32 as "Current value of the accumulator" {
executor.context().0.load(atomic::Ordering::Relaxed) as i32
Expand All @@ -31,7 +31,7 @@ graphql_object!(Query: Data |&self| {
// `Query`, but it provides the way to "mutate" the accumulator state.
struct Mutation;

graphql_object!(Mutation: Data |&self| {
graphql_object!(Mutation: State |&self| {
field add(&executor, by: i32) -> i32 as "Add given value to the accumulator." {
executor.context().0.fetch_add(by as isize, atomic::Ordering::Relaxed) as i32 + by
}
Expand All @@ -43,7 +43,7 @@ type Schema = juniper::RootNode<'static, Query, Mutation>;

// Finally, we'll bridge between Tide and Juniper. `GraphQLRequest` from Juniper implements
// `Deserialize`, so we use `Json` extractor to deserialize the request body.
async fn handle_graphql(mut cx: Context<Data>) -> EndpointResult {
async fn handle_graphql(mut cx: Context<State>) -> EndpointResult {
let query: juniper::http::GraphQLRequest = cx.body_json().await.client_err()?;
let schema = Schema::new(Query, Mutation);
let response = query.execute(&schema, cx.state());
Expand All @@ -58,7 +58,7 @@ async fn handle_graphql(mut cx: Context<Data>) -> EndpointResult {
}

fn main() {
let mut app = App::with_state(Data::default());
let mut app = App::with_state(State::default());
app.at("/graphql").post(handle_graphql);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/hello.rs
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
fn main() {
let mut app = tide::App::new();
app.at("/").get(|_| async move { "Hello, world!" });
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/messages.rs
Original file line number Diff line number Diff line change
Expand Up @@ -66,5 +66,5 @@ fn main() {
let mut app = App::with_state(Database::default());
app.at("/message").post(new_message);
app.at("/message/:id").get(get_message).post(set_message);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
2 changes: 1 addition & 1 deletion examples/multipart-form/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ async fn upload_file(mut cx: Context<()>) -> EndpointResult {
fn main() {
let mut app = App::new();
app.at("/upload_file").post(upload_file);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}

// Test with:
Expand Down
2 changes: 1 addition & 1 deletion examples/staticfile.rs
Original file line number Diff line number Diff line change
Expand Up @@ -122,5 +122,5 @@ async fn handle_path(ctx: Context<StaticFile>) -> EndpointResult {
fn main() {
let mut app = App::with_state(StaticFile::new("./"));
app.at("/*").get(handle_path);
app.serve("127.0.0.1:8000").unwrap();
app.run("127.0.0.1:8000").unwrap();
}
62 changes: 39 additions & 23 deletions src/app.rs
Original file line number Diff line number Diff line change
Expand Up @@ -33,13 +33,13 @@ use crate::{
///
/// let mut app = tide::App::new();
/// app.at("/hello").get(|_| async move {"Hello, world!"});
/// app.serve("127.0.0.1:8000").unwrap();
/// app.run("127.0.0.1:8000").unwrap();
/// ```
///
/// # Routing and parameters
///
/// Tide's routing system is simple and similar to many other frameworks. It
/// uses `:foo` for "wildcard" URL segments, and `:foo*` to match the rest of a
/// uses `:foo` for "wildcard" URL segments, and `*foo` to match the rest of a
/// URL (which may include multiple segments). Here's an example using wildcard
/// segments as parameters to endpoints:
///
Expand All @@ -64,7 +64,7 @@ use crate::{
/// "Use /hello/{your name} or /goodbye/{your name}"
/// });
///
/// app.serve("127.0.0.1:8000").unwrap();
/// app.run("127.0.0.1:8000").unwrap();
/// ```
///
/// You can learn more about routing in the [`App::at`] documentation.
Expand Down Expand Up @@ -119,15 +119,15 @@ use crate::{
/// let mut app = App::with_state(Database::default());
/// app.at("/message").post(new_message);
/// app.at("/message/:id").get(get_message);
/// app.serve("127.0.0.1:8000").unwrap();
/// app.run("127.0.0.1:8000").unwrap();
/// }
/// ```

#[allow(missing_debug_implementations)]
pub struct App<State> {
router: Router<State>,
middleware: Vec<Arc<dyn Middleware<State>>>,
data: State,
state: State,
}

impl App<()> {
Expand All @@ -149,7 +149,7 @@ impl<State: Send + Sync + 'static> App<State> {
App {
router: Router::new(),
middleware: Vec::new(),
data: state,
state,
}
}

Expand All @@ -176,12 +176,13 @@ impl<State: Send + Sync + 'static> App<State> {
/// parameter called `name`. It is not possible to define wildcard segments
/// with different names for otherwise identical paths.
///
/// Wildcard definitions can be followed by an optional *wildcard
/// modifier*. Currently, there is only one modifier: `*`, which means that
/// the wildcard will match to the end of given path, no matter how many
/// segments are left, even nothing. It is an error to define two wildcard
/// segments with different wildcard modifiers, or to write other path
/// segment after a segment with wildcard modifier.
/// Alternatively a wildcard definitions can start with a `*`, for example
/// `*path`, which means that the wildcard will match to the end of given
/// path, no matter how many segments are left, even nothing.
///
/// The name of the parameter can be omitted to define a path that matches
/// the required structure, but where the parameters are not required.
/// `:` will match a segment, and `*` will match an entire path.
///
/// Here are some examples omitting the HTTP verb based endpoint selection:
///
Expand All @@ -190,7 +191,9 @@ impl<State: Send + Sync + 'static> App<State> {
/// app.at("/");
/// app.at("/hello");
/// app.at("add_two/:num");
/// app.at("static/:path*");
/// app.at("files/:user/*");
/// app.at("static/*path");
/// app.at("static/:context/:");
/// ```
///
/// There is no fallback route matching, i.e. either a resource is a full
Expand Down Expand Up @@ -222,16 +225,16 @@ impl<State: Send + Sync + 'static> App<State> {
pub fn into_http_service(self) -> Server<State> {
Server {
router: Arc::new(self.router),
data: Arc::new(self.data),
state: Arc::new(self.state),
middleware: Arc::new(self.middleware),
}
}

/// Start serving the app at the given address.
/// Start Running the app at the given address.
///
/// Blocks the calling thread indefinitely.
#[cfg(feature = "hyper")]
pub fn serve(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> {
pub fn run(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> {
let addr = addr
.to_socket_addrs()?
.next()
Expand All @@ -241,6 +244,19 @@ impl<State: Send + Sync + 'static> App<State> {
http_service_hyper::run(self.into_http_service(), addr);
Ok(())
}

/// Asynchronously serve the app at the given address.
#[cfg(feature = "hyper")]
pub async fn serve(self, addr: impl std::net::ToSocketAddrs) -> std::io::Result<()> {
// TODO: try handling all addresses
let addr = addr
.to_socket_addrs()?
.next()
.ok_or(std::io::ErrorKind::InvalidInput)?;

let res = http_service_hyper::serve(self.into_http_service(), addr).await;
res.map_err(|e| std::io::Error::new(std::io::ErrorKind::Other, e))
}
}

/// An instantiated Tide server.
Expand All @@ -251,7 +267,7 @@ impl<State: Send + Sync + 'static> App<State> {
#[allow(missing_debug_implementations)]
pub struct Server<State> {
router: Arc<Router<State>>,
data: Arc<State>,
state: Arc<State>,
middleware: Arc<Vec<Arc<dyn Middleware<State>>>>,
}

Expand All @@ -269,12 +285,12 @@ impl<State: Sync + Send + 'static> HttpService for Server<State> {
let method = req.method().to_owned();
let router = self.router.clone();
let middleware = self.middleware.clone();
let data = self.data.clone();
let state = self.state.clone();

Box::pin(async move {
let fut = {
let Selection { endpoint, params } = router.route(&path, method);
let cx = Context::new(data, req, params);
let cx = Context::new(state, req, params);

let next = Next {
endpoint,
Expand All @@ -297,19 +313,19 @@ mod tests {
use super::*;
use crate::{middleware::Next, router::Selection, Context, Response};

fn simulate_request<'a, Data: Default + Clone + Send + Sync + 'static>(
app: &'a App<Data>,
fn simulate_request<'a, State: Default + Clone + Send + Sync + 'static>(
app: &'a App<State>,
path: &'a str,
method: http::Method,
) -> BoxFuture<'a, Response> {
let Selection { endpoint, params } = app.router.route(path, method.clone());

let data = Arc::new(Data::default());
let state = Arc::new(State::default());
let req = http::Request::builder()
.method(method)
.body(http_service::Body::empty())
.unwrap();
let cx = Context::new(data, req, params);
let cx = Context::new(state, req, params);
let next = Next {
endpoint,
next_middleware: &app.middleware,
Expand Down
9 changes: 7 additions & 2 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ use http_service::Body;
use route_recognizer::Params;
use std::{str::FromStr, sync::Arc};

/// Data associated with a request-response lifecycle.
/// State associated with a request-response lifecycle.
///
/// The `Context` gives endpoints access to basic information about the incoming
/// request, route parameters, and various ways of accessing the request's body.
Expand Down Expand Up @@ -55,7 +55,12 @@ impl<State> Context<State> {
&self.request
}

/// Access app-global data.
/// Access a mutable handle to the entire request.
pub fn request_mut(&mut self) -> &mut http_service::Request {
&mut self.request
}

/// Access app-global state.
pub fn state(&self) -> &State {
&self.state
}
Expand Down
4 changes: 2 additions & 2 deletions src/endpoint.rs
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ use crate::{response::IntoResponse, Context, Response};
/// fn main() {
/// let mut app = tide::App::new();
/// app.at("/hello").get(hello);
/// app.serve("127.0.0.1:8000").unwrap()
/// app.run("127.0.0.1:8000").unwrap()
/// }
/// ```
///
Expand All @@ -41,7 +41,7 @@ use crate::{response::IntoResponse, Context, Response};
/// fn main() {
/// let mut app = tide::App::new();
/// app.at("/hello").get(hello);
/// app.serve("127.0.0.1:8000").unwrap()
/// app.run("127.0.0.1:8000").unwrap()
/// }
/// ```
///
Expand Down
2 changes: 0 additions & 2 deletions src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,8 +7,6 @@
//! Welcome to Tide.
//!
//! The [`App`](struct.App.html) docs are a good place to get started.
//!
//!

#[macro_use]
pub mod error;
Expand Down
Loading