how to use tokio_postgres in actix-web - rust

So I want to use tokio_postgres in an actix API, I just started and I am having difficulties with sharing the client in my get request.
Here is my code:
use actix_web::{web, App, HttpServer, HttpResponse};
use tokio_postgres::{NoTls};
use std::cell::RefCell;
mod api;
use api::routes::hello_actix;
fn main() {
actix_rt::System::run(|| {
println!("connecting to postgres");
let pro = tokio::spawn(
async
{
let (client , conn) = match tokio_postgres::connect(
"foo",
NoTls)
.await {
Ok(t) => t,
Err(e) => panic!("{}", e)
};
tokio::spawn(async move {
if let Err(e) = conn.await {
eprintln!("connection error: {}", e);
}
});
println!("connected to postgres");
HttpServer::new(|| {
App::new()
.data(RefCell::new(conn))
.route("/hello", web::get().to(hello_actix))
.default_service(web::route().to(|| HttpResponse::NotFound().body("404 Not Found")))
})
.bind("127.0.0.1:8080")
.unwrap()
.run();
Ok(())
});
});
}
i base this code on this but it does not seem to be working.
I would also like to stay "Pure" so I don't want to have a global client if possible.
Is it even possible to do what I want?

Related

How do I fix type annotations needed for `&Target` error for rust's hyper make_service_fn

My 20th day learning Rust and I try to code a reverse proxy that can authenticate.
Got error in line 30: error[E0282]: type annotations needed for &Target. I tried to follow the help by compiler "consider giving this closure parameter an explicit type where the type for type parameter Target is specified"
But i got even more errors and confuse.
Please help.
use hyper::service::{make_service_fn, service_fn};
use hyper::{Body, Request, Response, Server};
use std::convert::Infallible;
use std::net::{IpAddr, SocketAddr};
async fn authenticate(req: Request<Body>) -> Result<Request<Body>, Infallible> {
// Perform authentication checks here.
// For example, you can check for a valid API key in the request header.
Ok(req)
}
async fn handle(client_ip: IpAddr, req: Request<Body>) -> Result<Response<Body>, Infallible> {
// Forward the request to another server.
let target_url = "http://127.0.0.1:13901";
match hyper_reverse_proxy::call(client_ip, target_url, req).await {
Ok(response) => Ok(response),
Err(error) => {
// println!("Error forwarding request: {}", error);
Ok(Response::builder()
.status(hyper::StatusCode::INTERNAL_SERVER_ERROR)
.body(Body::empty())
.unwrap())
}
}
}
#[tokio::main]
async fn main() {
let make_service = make_service_fn(|conn| async { // <<-- Error!
let client_ip = conn.remote_addr().ip();
Ok::<_, Infallible>(service_fn(move |req| {
let client_ip = client_ip.clone();
async {
match authenticate(req).await {
Ok(req) => handle(client_ip, req).await,
Err(_) => {
eprintln!("Authentication failed");
Ok(Response::builder()
.status(hyper::StatusCode::UNAUTHORIZED)
.body(Body::empty())
.unwrap())
}
}
}
}))
});
let bind_addr = "127.0.0.1:8000";
let addr: SocketAddr = bind_addr.parse().expect("Could not parse ip:port.");
let server = Server::bind(&addr).serve(make_service);
println!("Running reverse proxy on {:?}", addr);
if let Err(error) = server.await {
eprintln!("Error running server: {}", error);
}
}
my cargo.toml
[dependencies]
hyper-reverse-proxy = "0.5"
hyper = { version = "0.14", features = ["full"] }
tokio = { version = "1", features = ["full"] }
the signature of the functions is
pub fn make_service_fn<F, Target, Ret>(f: F) -> MakeServiceFn<F>
where
F: FnMut(&Target) -> Ret,
Ret: Future,
The target is a generic parameter and according to example from documentation
use std::convert::Infallible;
use hyper::{Body, Request, Response, Server};
use hyper::server::conn::AddrStream;
use hyper::service::{make_service_fn, service_fn};
let addr = ([127, 0, 0, 1], 3000).into();
let make_svc = make_service_fn(|socket: &AddrStream| {
let remote_addr = socket.remote_addr();
async move {
Ok::<_, Infallible>(service_fn(move |_: Request<Body>| async move {
Ok::<_, Infallible>(
Response::new(Body::from(format!("Hello, {}!", remote_addr)))
)
}))
}
});
// Then bind and serve...
let server = Server::bind(&addr)
.serve(make_svc);
// Finally, spawn `server` onto an Executor...
if let Err(e) = server.await {
eprintln!("server error: {}", e);
}
we can pass reference to AddrStream which you have to specify since rust cannot infer this...
so the fixed code looks like this
let make_service = make_service_fn(|conn: &AddrStream| {
let client_ip = conn.remote_addr().ip();
async move {
Ok::<_, Infallible>(service_fn(move |req| {
let client_ip = client_ip.clone();
async move {
match authenticate(req).await {
Ok(req) => handle(client_ip, req).await,
Err(_) => {
eprintln!("Authentication failed");
Ok(Response::builder()
.status(hyper::StatusCode::UNAUTHORIZED)
.body(Body::empty())
.unwrap())
}
}
}
}))
}
});

Is there a way where I can parse the response body (token) as a string and temporarily store it and call upon that value when needed?

I want to be able to store a bearer token from the response body temporarily for about 900 seconds and be able to use the token whenever another function calls upon it. I have created the basic structure of creating the client and posting the request and getting a token back. Here is what I have so far:
#[derive(Debug, Deserialize)]
struct SecureToken {
access_token: String,
expiration_date_time: i32,
}
#[tokio::main]
async fn get_new_secure_token() {
let mut map = HashMap::new();
map.insert("client_id", "client_id");
map.insert("client_secret", "client_secret");
map.insert("scope", "scope");
map.insert("grant_type", "client_credentials");
let client = Client::new();
let token_request = client
.post("https://gatway.address")
.form(&map)
.send()
.await
.expect("");
//.json::<TokenResponse>()
//.await;
match token_request.status() {
StatusCode::OK => {
let query_result = token_request.json::<SecureToken>().await;
println!("{:#?}", query_result);
},
StatusCode::FORBIDDEN => {
println!("Unable to connect to auth service");
},
StatusCode::BAD_REQUEST => {
let bad_request = token_request.json::<BadRequest>().await;
println!("Error: {:?}", bad_request);
}
s => println!("STATUS CODE: {:?}", s),
};
}
Instead of printing the response, I want it to store the token temporarily for about 900 seconds along the lines of this:
let token_request = client
.post("https://gatway.address")
.form(&map)
.send()
.await
.expect("");
//.json::<TokenResponse>()
//.await;
match token_request.status() {
StatusCode::OK => {
let query_result = token_request.json::<SecureToken>().await;
let token = quer
},
StatusCode::FORBIDDEN => {
println!("Unable to connect to auth service");
},
StatusCode::BAD_REQUEST => {
let bad_request = token_request.json::<BadRequest>().await;
println!("Error: {:?}", bad_request);
}
s => println!("STATUS CODE: {:?}", s),
};
}
But I don't know how to store the token nor add a expiration time to the token.

Rust server receives empty http request body

I'm learning how to code a server in rust that accepts connections from any client with any request. So far my server can respond with any form of data I've tested it with, but there's something keeping me restless. Clients doing post|put|patch requests with file data as body arrive with empty bodies except 'application/x-www-form-urlencoded' data. How can I solve this? Here is my server code(just for learning purpose):
use std::{
net::TcpListener,
io::prelude::*,
thread::{
self,
Scope
}
};
static RESPONSE: [&'static str; 10] = [
"HTTP/1.1 200 Ok",
"Content-Length: 25",
"Content-Type: text/plain",
"Content-Encoding: identity",
"Access-Control-Allow-Methods: *",
"Access-Control-Allow-Origin: *",
"Access-Control-Allow-Headers: *",
"Accept-Encoding: *",
"Accept: */*\r\n",
"Grateful checking on me.\n"
];
fn main() {
let listener = TcpListener::bind("127.0.0.1:8000").unwrap();
println!("Listening at localhost:8000");
thread::scope(|here| handle_connections(here, &listener));
}
fn handle_connections<'scope, 'env>(scope: &'scope Scope<'scope, 'env>, listener: &'env TcpListener) {
let actor = thread::Builder::new().spawn_scoped(scope, move || loop {
match listener.accept() {
Ok((mut client, addr)) => {
println!("Connection from: {}.", addr);
let mut buff = [0; 1024];
client.read(&mut buff).unwrap();
match client.write_all(RESPONSE.join("\r\n").as_bytes()) {
Ok(_) => println!("Send successful."),
Err(err) => eprintln!("Send failed: {}", err),
}
println!("{}\n", String::from_utf8(buff.to_vec()).unwrap()); // for debugging
}
Err(_) => eprintln!("Connection failed or disrupted!"),
}
});
if let Err(err) = actor {
eprintln!("Recovering from: {}", err);
handle_connections(scope, listener);
}
}

Error with rustls crate CertNotValidForName using rumqttc tls with rustls

I'm using rumqttc tls with rustls
Error = Tls(Io(Custom { kind: InvalidData, error: InvalidCertificateData("invalid peer certificate: CertNotValidForName") }))
this is my function:
#[cfg(feature = "use-rustls")]
#[tokio::main]
pub async fn test_mqtt() -> Result<(), Box<dyn Error>> {
use rumqttc::{self, AsyncClient, Key, MqttOptions, TlsConfiguration, Transport};
let mut mqttoptions = MqttOptions::new("test", "test.test.com", 1000);
mqttoptions.set_credentials("test", "test");
mqttoptions.set_keep_alive(std::time::Duration::from_secs(5));
let ca = include_bytes!("../certs/ca.crt");
let client_cert = include_bytes!("../certs/client.crt");
let client_key = include_bytes!("../certs/client.key");
let transport = Transport::Tls(TlsConfiguration::Simple {
ca: ca.to_vec(),
alpn: None,
client_auth: Some((client_cert.to_vec(), Key::RSA(client_key.to_vec()))),
});
mqttoptions.set_transport(transport);
let (client, mut eventloop) = AsyncClient::new(mqttoptions, 10);
client.subscribe("test/test/test", QoS::AtMostOnce).await.unwrap();
client.subscribe("test/test/test/logs", QoS::AtMostOnce).await.unwrap();
thread::spawn(move || {
client.publish("test/test/test", QoS::AtLeastOnce, false, "test");
client.publish("test/test/test/logs", QoS::AtLeastOnce, false, "test");
thread::sleep(Duration::from_millis(100));
});
loop {
match eventloop.poll().await {
Ok(v) => {
println!("Event = {:?}", v);
}
Err(e) => {
println!("Error = {:?}", e);
break;
}
}
}
Ok(())
}
This results in
2022-11-18 16:11:46 - WARN: Sending fatal alert BadCertificate
Error = Tls(Io(Custom { kind: InvalidData, error: InvalidCertificateData("invalid peer certificate: CertNotValidForName") }))
The rustls certificate verification through webpki is quite strict. You may circumvent it by implementing a custom ServerCertVerifier.
Take a look at: https://users.rust-lang.org/t/rustls-connecting-without-certificate-in-local-network/83822/4

how to push json array on solana blockchain and get it using anchor project

How can I push json on the blockchain and get it using anchor project. I am trying to push simple json like this:
[
{
"text": "What is React?",
"code": "001",
"Options": ["Framework", "Frontend Language", "User Interface", "Backend"]
}
]
I am trying with calculator project example like this (lib.rs):
use std::vec;
use anchor_lang:: prelude::*;
declare_id!("Fg6PaFpoGXkYsidMpWTK6W2BeZ7FEfcYkg476zPFsLnS");
#[program]
pub mod myfirstproject {
use super::*;
pub fn create(ctx: Context < Create >, init_message: String) -> Result<()> {
let calculator = &mut ctx.accounts.calculator;
calculator.greeting = init_message;
Ok(())
}
pub fn add(ctx: Context<Addition>, num1: i64, num2: i64) -> Result<()> {
let calculator = &mut ctx.accounts.calculator;
calculator.result = num1 + num2;
Ok(())
}
pub fn pushjson(ctx:Context<PushingData>, myjson:Vec::new) -> Result<()>{
let calculator = &mut ctx.accounts.calculator;
calculator.data_array = myjson;
Ok(())
}
}
#[derive(Accounts)]
pub struct Create < 'info> {
#[account(init, payer = user, space = 264)]
pub calculator: Account < 'info, Calculator>,
#[account(mut)]
pub user: Signer < 'info>,
pub system_program: Program < 'info, System>
}
#[derive(Accounts)]
pub struct Addition<'info> {
#[account(mut)]
pub calculator: Account<'info, Calculator>
}
#[derive(Accounts)]
pub struct PushingData<'info> {
#[account(mut)]
pub calculator: Account<'info, Calculator>
}
#[account]
pub struct Calculator {
pub greeting: String,
pub result: i64,
pub remainder: i64,
pub data_array: vec![]
}
(test file myfirstproject.ts)
const assert = require('assert')
const anchor1 = require('#project-serum/anchor')
const { SystemProgram } = anchor1.web3
describe('myfirstproject', () => {
const provider = anchor1.AnchorProvider.env();
anchor1.setProvider(provider)
const calculator = anchor1.web3.Keypair.generate()
const program = anchor1.workspace.Myfirstproject
it('Creates a calculator', async () => {
await program.rpc.create("Welcome to Solana calculator", {
accounts: {
calculator: calculator.publicKey,
user: provider.wallet.publicKey,
systemProgram: SystemProgram.programId
},
signers: [calculator]
})
const account = await program.account.calculator.fetch(calculator.publicKey)
assert.ok(account.greeting === "Welcome to Solana calculator")
})
it('Add two numbers', async () => {
await program.rpc.add(new anchor1.BN(2), new anchor1.BN(3), {
accounts: {
calculator: calculator.publicKey
}
})
const account = await program.account.calculator.fetch(calculator.publicKey)
assert.ok(account.result.eq(new anchor1.BN(5)))
})
it('Push Json Data', async () => {
let myArray = [
{
"text": "What is React?",
"code": "001",
"Options": ["Framework", "Frontend Language", "User Interface", "Backend"]
}
]
await program.rpc.pushjson(myArray, {
accounts: {
calculator: calculator.publicKey
}
})
const account = await program.account.calculator.fetch(calculator.publicKey)
assert.ok(account.data_array.eq(myArray))
})
})
I am not able to make it work, how to push the json data on the blockchain or first of all how to test it locally with the anchor project.
If someone can help.
Thanks

Resources