new to rust here. I am trying to build a simple server that provides and decodes JWT tokens and I am missing a big part. Here is the code:
pub struct Server {
pub host: String,
pub port: String,
pub public_key: String,
pub private_key: String
}
impl Server {
pub async fn start(&self) {
let routes = Router::new()
.route("/", get(check))
.route("/auth", post(auth));
let mut hostport = String::from(&self.host);
hostport.push_str(":");
hostport.push_str(&self.port);
println!("{}", hostport);
let addr : SocketAddr = hostport.parse().expect("invalid host:port pair");
axum::Server::bind(
&addr
).serve(routes.into_make_service()).await.unwrap();
}
}
async fn auth(Json(payload): Json<LoginInput>) -> impl IntoResponse {
let claims = Claims::create(Duration::from_hours(1));
RS384PublicKey::from_pem("id_like_to_put_Server::public_key_here").sign(claims)?;
let lo = LoginOutput{
token: payload.username
};
(StatusCode::OK, Json(lo))
}
As you can see Server holds routing logic and applies configuration. Among configuration there is a public key I'd like to use in order to sign the JWT token (I am using jwt_simple to achieve that). Since public key is a Server's attribute, I want to pass that value to the auth handler but I can't figure out how to do that. How can I pass a parameter to an Axum handler and sign the token is generated inside?
Although here are the examples using both Extension and State, State is preferred as from the docs of Axum:
You should prefer using State if possible since it’s more type safe. The downside is that its less dynamic than request extensions.
In Cargo.toml:
[dependencies]
axum = "0.6.0-rc.2"
serde = { version = "1.0.147", features = ["derive"] }
tokio = { version = "1.21.2", features = ["macros", "rt-multi-thread"] }
Using State:
use std::net::SocketAddr;
use axum::{
extract::State,
response::IntoResponse,
routing::{get, post},
Json, Router,
};
use serde::Deserialize;
#[derive(Clone)]
pub struct ServerConfig {
pub host: String,
pub port: String,
pub public_key: String,
pub private_key: String,
}
#[derive(Deserialize)]
pub struct LoginInput {
username: String,
password: String,
}
#[tokio::main]
async fn main() {
let server_config = ServerConfig {
host: "0.0.0.0".into(),
port: "8080".into(),
public_key: "public_key".into(),
private_key: "private_key".into(),
};
let addr: SocketAddr = format!("{}:{}", server_config.host, server_config.port)
.parse()
.unwrap();
let routes = Router::with_state(server_config) // state will be available to all the routes
.route("/", get(check))
.route("/auth", post(auth));
axum::Server::bind(&addr)
.serve(routes.into_make_service())
.await
.unwrap();
}
async fn check() -> &'static str {
"check"
}
async fn auth(
State(server_config): State<ServerConfig>, // extract state in this handler
// `Json` supports any type that implements `serde::Deserialize`
Json(payload): Json<LoginInput>,
) -> impl IntoResponse {
// use server_config and payload to run the `auth` logic
println!("host: {}", server_config.host);
"jwt"
}
Using Extension
use std::net::SocketAddr;
use axum::{
response::IntoResponse,
routing::{get, post},
Extension, Json, Router,
};
use serde::Deserialize;
#[derive(Clone)]
pub struct ServerConfig {
pub host: String,
pub port: String,
pub public_key: String,
pub private_key: String,
}
#[derive(Deserialize)]
pub struct LoginInput {
username: String,
password: String,
}
#[tokio::main]
async fn main() {
let server_config = ServerConfig {
host: "0.0.0.0".into(),
port: "8080".into(),
public_key: "public_key".into(),
private_key: "private_key".into(),
};
let addr: SocketAddr = format!("{}:{}", server_config.host, server_config.port)
.parse()
.unwrap();
let routes = Router::new()
.route("/", get(check))
.route("/auth", post(auth))
.layer(Extension(server_config));
axum::Server::bind(&addr)
.serve(routes.into_make_service())
.await
.unwrap();
}
async fn check() -> &'static str {
"check"
}
async fn auth(
Extension(server_config): Extension<ServerConfig>,
// `Json` supports any type that implements `serde::Deserialize`
Json(payload): Json<LoginInput>,
) -> impl IntoResponse {
// use server_config and payload to run the `auth` logic
println!("host: {}", server_config.host);
"jwt"
}
Related
I am using actix-web to run a webserver and want to be able to mutate state through websocket messages.
My current way of using websockets is through implementing the handle method from actix::StreamHandler. However this limits my ability of passing data to it. How can I access the data (actix_web::web::Data) in my handle method?
The only way I can think of solving this issue is to somehow overwrite the function signature of handle, however that doesn't seem possible
Hers is some important code snippets, we have app_name and nonces in app_data:
// main.rs
let nonces = Arc::new(Mutex::new(nonces::Nonces::new()));
HttpServer::new(move || {
App::new()
.app_data(web::Data::new(app_data::AppData {
app_name: String::from("Actix Web"),
nonces: Arc::clone(&nonces),
}))
...
// app_data.rs
pub struct AppData {
pub app_name: String,
pub nonces: Arc<Mutex<nonces::Nonces>>,
}
// ws.rs
struct Ws {
app_data: web::Data<app_data::AppData>,
}
impl StreamHandler<Result<ws::Message, ws::ProtocolError>> for Ws {
fn handle(&mut self, msg: Result<ws::Message, ws::ProtocolError>, ctx: &mut Self::Context) {
let app_name = &self.app_data.app_name;
let mut nonces = self.app_data.nonces.lock().unwrap();
println!(">>> {app_name}");
println!(">>> {:?}", nonces.nonces); // I have a nonces data in nonces
...
}
}
async fn index(
req: HttpRequest,
stream: web::Payload,
app_data: web::Data<app_data::AppData>,
) -> Result<HttpResponse, Error> {
ws::start(Ws { app_data: app_data.clone() }, &req, stream)
}
I'm trying to understand how to accomplish this flow:
a main function that create a new Config struct
passes it to a function that live until the program is closed (is 'static)
This is the code and the error I'm getting:
#[tokio::main]
async fn main() {
let config = new_config();
start(config).await.unwrap(); // here the error is: "`config` does not live long enough, borrowed value does not live long enough"
}
pub struct Config {
pub app_name: String,
pub host: String,
pub logging: LoggingConfig,
}
pub struct LoggingConfig {
pub level: String,
}
fn new_config() -> Config {
Config {
app_name: std::env::var("APP_NAME").unwrap(),
host: std::env::var("HOST").unwrap(),
logging: LoggingConfig {
level: std::env::var("LOGGING_LEVEL").unwrap(),
},
}
}
pub struct AppState {
pub config: &'static Config,
}
async fn start(config: &'static Config) -> std::io::Result<()> {
HttpServer::new(|| {
App::new()
.app_data(web::Data::new(AppState {
config: &config, // this is what I need
}))
.route("/", web::get().to(hello))
.bind(("127.0.0.1", 8080))?
.run()
.await
}
As you can see I want to pass a reference to the Config to each server worker without clone().
How to do that?
web::Data is similar to Arc; you can clone it, it won't clone the actual data it contains (here AppState).
Here is a simple fix of your code.
Once config is set up in main(), we pass it by value (i.e. move) to start().
Then start() handles the necessary web::Data, cloning...
If the Config is not supposed to change, we can keep it as is in AppState; only shared references (&) will be taken.
In case you need to mutate some part of the AppState, I added an example with a Mutex protecting a String.
Each time the page is loaded, the String is extended.
use actix_web::{web, App, HttpRequest, HttpResponse, HttpServer};
use std::sync::Mutex;
#[tokio::main]
async fn main() {
let config = new_config();
start(config).await.unwrap(); // pass by value
}
pub struct Config {
pub app_name: String,
pub host: String,
pub logging: LoggingConfig,
}
pub struct LoggingConfig {
pub level: String,
}
fn new_config() -> Config {
Config {
app_name: std::env::var("APP_NAME").unwrap(),
host: std::env::var("HOST").unwrap(),
logging: LoggingConfig {
level: std::env::var("LOGGING_LEVEL").unwrap(),
},
}
}
pub struct AppState {
pub config: Config,
pub value: Mutex<String>,
}
async fn hello(
_req: HttpRequest,
data: web::Data<AppState>,
) -> HttpResponse {
let config = &data.config;
let mut value = data.value.lock().unwrap();
value.push('*');
let body = format!(
"<!DOCTYPE html><html><body>\
<p>app_name: {:?}</p>\
<p>host: {:?}</p>\
<p>logging level: {:?}</p>\
<p>value: {:?}</p>\
</body></html>",
config.app_name, config.host, config.logging.level, value
);
HttpResponse::Ok().content_type("text/html").body(body)
}
async fn start(config: Config) -> std::io::Result<()> {
let app_state = web::Data::new(AppState {
config,
value: Mutex::new("".to_owned()),
});
HttpServer::new(move || {
App::new()
.app_data(app_state.clone())
.route("/", web::get().to(hello))
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
The simple answer is: You can't.
First, you probably don't want &'static Config but rather regular old &Config. This would work for normal functions.
When using async functions instead, it sadly no longer works, because the compiler cannot guarantee that the async function actually terminates in time and releases the reference. There are multiple reasons for that, but I'm not going to go into detail.
If you really do want to avoid duplicating it, I'd use an Arc instead.
can anyone help get my head around the FromRequest trait.
As I understand, we can use it to share data with the resolvers.
I'm trying to inject the http headers so I can authenticate users before some actions in the resolvers.
See my code below.
Looks like the from_request isn't even called.
I'm using rocket 0.5.rc1
Thank you for your help
use juniper::{graphql_object, EmptySubscription, RootNode};
use mongodb::Client;
use mongodb::Database;
use rocket::{catch, catchers};
use rocket::{response::content, Rocket, State};
type Schema = RootNode<'static, Query, Mutations, EmptySubscription<AppContext>>;
use rocket::{
http::Status,
request::{FromRequest, Outcome},
Request,
};
struct Mutations;
struct Query;
#[derive(Debug)]
pub struct AppContext {
pub mongodb_pool: Database,
pub user: String,
}
impl juniper::Context for AppContext {}
#[rocket::async_trait]
impl<'r> FromRequest<'r> for AppContext {
type Error = ();
async fn from_request(request: &'r Request<'_>) -> Outcome<AppContext, Self::Error> {
let client = Client::with_uri_str("mongodb://admin:admin#localhost:28017").await;
let db = client.unwrap().database("override");
Outcome::Success(AppContext { mongodb_pool: db, user: "from request".to_string() }, )
}
}
#[graphql_object(context = AppContext)]
impl Query {
fn api_version(db: &AppContext) -> &str {
println!("{:?}", db.user);
"1.0"
}
}
#[graphql_object(context = AppContext)]
impl Mutations {
fn api_version(db: &AppContext) -> String {
"1.0".to_string()
}
}
#[rocket::get("/")]
fn graphiql() -> content::Html<String> {
juniper_rocket::graphiql_source("/graphql", None)
}
#[rocket::get("/graphql?<request>")]
async fn get_graphql_handler(
context: &State<AppContext>,
request: juniper_rocket::GraphQLRequest,
schema: &State<Schema>,
) -> juniper_rocket::GraphQLResponse {
request.execute(&*schema, &*context).await
}
#[rocket::post("/graphql", data = "<request>")]
async fn post_graphql_handler(
context: &State<AppContext>,
request: juniper_rocket::GraphQLRequest,
schema: &State<Schema>,
) -> juniper_rocket::GraphQLResponse {
request.execute(&*schema, &*context).await
}
#[tokio::main]
async fn main() {
let client = Client::with_uri_str("mongodb://admin:admin#localhost:28017").await;
let db = client.unwrap().database("app_db");
Rocket::build()
.manage(AppContext{ mongodb_pool: db, user: "from build".to_string() })
.manage(Schema::new(
Query,
Mutations,
EmptySubscription::<AppContext>::new(),
))
.mount(
"/",
rocket::routes![graphiql, get_graphql_handler, post_graphql_handler],
)
.launch()
.await
.expect("server failed to launch");
}
I am trying to make this code snippet run concurrently instead of sequentially since the number of peers can be a large value. I am using async_std 1.4 and rust 1.41
pub struct Peer {
pub peer_id: String,
pub tcp_stream: Arc<TcpStream>,
pub public_key: [u8; 32],
}
async fn send_to_all_peers(message: Protocol, peers: &HashMap<String,Peer>) -> Result<()> {
for peer in peers.values() {
let mut stream = &*peer.tcp_stream;
stream.write_all(&bincode::serialize(&message)?).await?;
}
Ok(())
}
I've tried to use the futures::future::join_all method without any luck since wrapping future I created and used within async_std::task::spawn requires a static lifetime. Here is what I tried:
async fn send_to_all_peers(message: Protocol, peers: &HashMap<String,Peer>) {
let handles = peers.values().into_iter().map(|peer| {
task::spawn(
async {
let mut stream = &*peer.tcp_stream;
if let Err(err) = stream
.write_all(&bincode::serialize(&message).unwrap())
.await
{
error!("Error when writing to tcp_stream: {}", err);
}
}
)
});
futures::future::join_all(handles).await;
}
I'm sure there is some method I am missing, thanks for any help!
Since you are trying to send message concurrently, each task has to have its own copy of the message:
use async_std::{task, net::TcpStream};
use futures::{future, io::AsyncWriteExt};
use serde::Serialize;
use std::{
collections::HashMap,
error::Error,
sync::Arc,
};
pub struct Peer {
pub peer_id: String,
pub tcp_stream: Arc<TcpStream>,
pub public_key: [u8; 32],
}
#[derive(Serialize)]
struct Protocol;
async fn send_to_all_peers(
message: Protocol,
peers: &HashMap<String, Peer>)
-> Result<(), Box<dyn Error>>
{
let msg = bincode::serialize(&message)?;
let handles = peers.values()
.map(|peer| {
let msg = msg.clone();
let socket = peer.tcp_stream.clone();
task::spawn(async move {
let mut socket = &*socket;
socket.write_all(&msg).await
})
});
future::try_join_all(handles).await?;
Ok(())
}
Have you tried something like
let handles = peers.values().into_iter().map(|peer| {
let mut stream = &*peer.tcp_stream;
stream.write_all(&bincode::serialize(&message).unwrap())
}
let results = futures::future::join_all(handles).await
?
Notice how the .map closure doesn’t await, but straight up returns a future, which is then passed to join_all, and then awaited.
I am trying to create a network of nodes in Rust, where I want every node in the network to be aware of every other connected node. I thought that this could be done with weak Rc's, like this:
use std::cell::Cell;
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}
impl Node {
fn connect_to_network(&mut self) {
self.known_nodes
.borrow_mut()
.push(Rc::downgrade(&Rc::new(*self)));
}
}
fn main() {
let known_nodes = Rc::new(RefCell::new(Vec::new()));
let node_one = Node {
name: "node1",
known_nodes: known_nodes.copy(),
};
node_one.connect_to_network();
let node_two = Node {
name: "node2",
known_nodes: known_nodes.copy(),
};
node_two.connect_to_network();
}
This however yields
cannot move out of borrowed content
at:
self.known_senders.borrow_mut().push(Rc::downgrade(&Rc::new(*self)));
Because *self is moved out of borrowed content in the &Rc::new(*self).
Any ideas, on how each node can keep track of all the other nodes in the network?
You should separate your node and your network, because your network must take the ownership of your node to create an Rc (or at least, it must take an already created Rc). Here is a better design that achieves what you want:
use std::rc::Rc;
use std::rc::Weak;
use std::cell::RefCell;
#[derive(Debug)]
struct Node {
name: String,
}
#[derive(Default, Debug)]
struct Network {
nodes: Rc<RefCell<Vec<Weak<Node>>>>,
}
impl Network {
fn add_node(&mut self, node: Node) -> Rc<Node> {
let node = Rc::new(node);
self.nodes.borrow_mut().push(Rc::downgrade(&node));
node
}
}
fn main() {
let mut network = Network::default();
let node_1 = Node { name: "node_1".into() };
let node_2 = Node { name: "node_2".into() };
let _node_1 = network.add_node(node_1);
let _node_2 = network.add_node(node_2);
}
If you want to store a reference to self, you can do this:
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
type MutableNode = Rc<RefCell<Node>>;
type Network = Rc<RefCell<Vec<Weak<RefCell<Node>>>>>;
struct Node {
name: String,
others: Network,
}
impl Node {
fn new(name: String) -> MutableNode {
let node = Rc::new(RefCell::new(Node {
name,
others: Rc::new(RefCell::new(Vec::new())),
}));
{
let tmp = node.borrow();
tmp.others.borrow_mut().push(Rc::downgrade(&node));
}
node
}
fn add_node(&mut self, name: String) -> MutableNode {
let others = self.others.clone();
let node = Rc::new(RefCell::new(Node { name, others }));
self.others
.borrow_mut()
.push(Rc::downgrade(&node));
node
}
fn len(&self) -> usize {
self.others.borrow().len()
}
}
fn main() {
let node_0 = Node::new("node_0".into());
let node_1 = node_0.borrow_mut().add_node("node_1".into());
let node_2 = node_0.borrow_mut().add_node("node_2".into());
assert_eq!(node_0.borrow().len(), 3);
assert_eq!(node_1.borrow().len(), 3);
assert_eq!(node_2.borrow().len(), 3);
}
Rc::new(value:T) consume the value.Your function only borrow it, so you can't call Rc::new(*self)
I would recommend you to create a Network struct like the above answer. Or you can wrap your node in Rc<RefCell<Node>> like this:
use std::cell::RefCell;
use std::rc::Rc;
use std::rc::Weak;
#[derive(Debug)]
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}
impl Node {
fn connect_to_network(&mut self,ref_to_self: Weak<RefCell<Node>>) {
self.known_nodes
.borrow_mut()
.push(ref_to_self);
}
}
fn main() {
let known_nodes = Rc::new(RefCell::new(Vec::new()));
let node_one = Rc::new(RefCell::new(Node {
name: "node1".into(),
known_nodes: known_nodes.clone(),
}));
node_one.borrow_mut().connect_to_network(Rc::downgrade(&node_one));
let node_two = Rc::new(RefCell::new(Node {
name: "node2".into(),
known_nodes: known_nodes.clone(),
}));
node_two.borrow_mut().connect_to_network(Rc::downgrade(&node_two));
println!("{:?}",known_nodes.borrow()[0].upgrade());
println!("{:?}",known_nodes.borrow()[1].upgrade());
drop(node_one);
drop(node_two);
println!("{:?}",known_nodes.borrow()[0].upgrade());
println!("{:?}",known_nodes.borrow()[1].upgrade());
}
Which in this case you don't really need connect_to_network function, you can just add each Weak<RefCell<Node>> to known_nodes directly
If you want the code to look cleaner, you can introduce a new type alias to Rc<RefCell<Node>> like this
struct Node {
name: String,
known_nodes: Rc<RefCell<Vec<Weak<RefCell<Node>>>>>,
}
type RcNode = Rc<RefCell<Node>>;
trait Connectable {
fn connect_to_network(&self);
}
impl Connectable for RcNode {
fn connect_to_network(&self){
let node = self.borrow_mut();
node.known_nodes.borrow_mut().push(Rc::downgrade(self));
}
}
so then you can call
let node_one:RcNode = Rc::new(RefCell::new(Node {
name: "node1".into(),
known_nodes: known_nodes.clone(),
}));
node_one.connect_to_network();