tide.rs
raw
// Copyright 2022 Daniel Arbuckle
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
//! Run with `cargo run --example tide --no-default-features --features "asyncstd examples"`
use std::net::TcpListener;
use std::sync::{Arc, Mutex};
use async_std::prelude::FutureExt;
use tide::prelude::*;
use tide::Request;
struct State {
shutdown: Option<async_std::channel::Sender<()>>,
}
async fn index(_req: Request<Arc<Mutex<State>>>) -> tide::Result {
let mut resp: tide::Response = r#"Hello World. <form method="post" action="/shutdown"><input type="submit" value="Shut Down"></form>"#.into();
resp.set_content_type("text/html");
Ok(resp)
}
async fn shutdown(req: Request<Arc<Mutex<State>>>) -> tide::Result {
if let Some(shutdown) = req.state().lock().unwrap().shutdown.take() {
let _ = shutdown.try_send(());
Ok("Shutting down".into())
} else {
Ok("Shutdown already initiated".into())
}
}
fn main() {
// Non-async set up. We can do any server configuration that
// doesn't need an async context here, parse the command line,
// etc.
let (shutdown_tx, shutdown_rx) = async_std::channel::bounded::<()>(1);
let state = Arc::new(Mutex::new(State {
shutdown: Some(shutdown_tx),
}));
let mut app = tide::with_state(state);
app.at("/").get(index);
app.at("/shutdown").post(shutdown);
// Pick a random available port on the loopback interface. Not
// actually required, but usually a good idea.
let ear = TcpListener::bind("127.0.0.1:0").expect("bind port");
let addr = ear.local_addr().expect("retrieve port");
// Here we start up the webview and actually run the server. The
// async block is the asynchronous entry point for the program
// (like tokio::main or async_std::main), so any server set up
// code that needs to run in an async context should be there, as
// well as the code to actually run the server. When the async
// block finishes executing, the program will close.
drteeth::launch(
"Tide Demo",
addr,
async move {
app.listen(ear).await.unwrap();
}
.race(async move {
shutdown_rx.recv().await.unwrap();
}),
)
.unwrap();
}