I am trying to create a REST-API in Rust, using mysqlx
and actix_web
. I have one database called db
in which I have two tables: users
and fhekeys
. At the moment when a HttpRequest
with POST body is received by the API, it retrieves a key from fhekeys
in the pk
column. But the key is so long, so Rust panicks at the moment of retrieving that variable.
I have already increased max_allow_packet size of mysql in my ubuntu20.04 machine, the thing is that it works fine when I try to "SELECT pk FROM fhekeys" manually in mysql command prompt, but throws the following error when trying to retrieve that value from my Rust program:
thread 'actix-rt|system:0|arbiter:0' panicked at 'cannot advance past `remaining`: 87148184 <= 16777204', /root/.cargo/registry/src/index.crates.io-6f17d22bba15001f/bytes-1.4.0/src/bytes.rs:549:9
stack backtrace:
0: 0x55a55414a821 - std::backtrace_rs::backtrace::libunwind::trace::h6aeaf83abc038fe6
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/../../backtrace/src/backtrace/libunwind.rs:93:5
1: 0x55a55414a821 - std::backtrace_rs::backtrace::trace_unsynchronized::h4f9875212db0ad97
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/../../backtrace/src/backtrace/mod.rs:66:5
2: 0x55a55414a821 - std::sys_common::backtrace::_print_fmt::h3f820027e9c39d3b
at /rustc/8ede3aae28fe6e4d52b38157d7bfe0d3bceef225/library/std/src/sys_c
...
I also tried to retrieve some other values from "users", such as "heights" column in the first value, and the function works fine, it retrieves that value correctly as you can see here:
// Function to retrieve the server key from the 'fhekeys' table
async fn get_server_key(pool: &MySqlPool) -> Result<String, sqlx::Error> {
// Define the SQL query to retrieve the 'pk' key from the 'fhekeys' table
let query = "SELECT height FROM users";
// Execute the query and fetch all rows
let rows: Result<Vec<(String,)>, sqlx::Error> = sqlx::query_as(query).fetch_all(pool).await;
// Handle the possible outcomes using a match statement
match rows {
Ok(rows) => {
// Extract the 'pk' column values from the rows and concatenate them
let server_key = rows
.into_iter()
.map(|row| row.0)
.collect::<Vec<String>>()
.join("");
// Return the server key
let server_key_str: String = server_key.chars().take(100).collect();
println!("Heights : {:?}", server_key_str);
Ok(server_key)
}
Err(err) => Err(err), // Return the error if fetching rows fails
}
}
// RESULT
✅ Connection to the database is successful!
Heights : "AAAAAAoDAAAAAAAAiiXCvDbtX+qDm8fvf+cmPoXktEyYwh/J6SJjCu0SP7HEEC3deZc8k10PqthJZkE7GHHsp16AY2w2sEHnG4MT"
[2023-08-01T12:31:35Z INFO actix_web::middleware::logger] 127.0.0.1 "POST /api/healthchecker HTTP/1.1" 200 111 "-" "PostmanRuntime/7.32.3" 0.069827
So the problem comes with fhekeys
table, as the only table with a value inside that is so long.
This is the main function for starting the API:
mod routes;
mod fhe;
// mod models;
use actix_cors::Cors;
use actix_web::{HttpServer, web::PayloadConfig, HttpResponse, middleware::Logger, App, http::header};
use sqlx::mysql::{MySqlPool, MySqlPoolOptions};
use dotenv::dotenv;
use routes::{health_route::health_checker_handler, config::config};
pub struct AppState {
db: MySqlPool,
}
#[actix_web::main]
async fn main() -> std::io::Result<()> {
if std::env::var_os("RUST_LOG").is_none() {
std::env::set_var("RUST_LOG", "actix_web=info");
}
dotenv().ok();
env_logger::init();
let database_url: String = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
let pool = match MySqlPoolOptions::new()
.max_connections(10)
.connect(&database_url)
.await
{
Ok(pool) => {
println!("✅ Connection to the database is successful!");
pool
}
Err(err) => {
println!(" Failed to connect to the database: {:?}", err);
std::process::exit(1);
}
};
println!("Server started successfully !");
HttpServer::new(move || {
let cors = Cors::default()
.allowed_methods(vec!["GET", "POST", "PUT", "DELETE"])
.allowed_origin("http://localhost:3000")
.allowed_headers(vec![
header::CONTENT_TYPE,
header::AUTHORIZATION,
header::CONTENT_ENCODING,
header::ACCEPT,
])
.supports_credentials();
App::new()
.app_data(actix_web::web::Data::new(AppState {db: pool.clone()}))
.service(health_checker_handler)
.configure(config)
.wrap(cors)
.wrap(Logger::default())
})
.bind(("127.0.0.1", 8080))?
.run()
.await
}
And this is the function that retrieves the value from the database:
use actix_web::{post, web, HttpResponse, Responder};
use sqlx::mysql::MySqlPoolOptions;
use std::collections::HashMap;
use serde::{Deserialize, Serialize};
use serde_json::json;
use sqlx::mysql::MySqlPool;
use sqlx::query;
use sqlx::mysql::MySqlRow;
use sqlx::{MySql, MySqlConnection};
use crate::AppState; // Make sure to import the AppState struct from main.rs
#[derive(Deserialize, Serialize)]
struct HealthCheckerParams {
...
}
#[post("/api/healthchecker")]
pub async fn health_checker_handler(
query_params: web::Json<HealthCheckerParams>,
data: web::Data<AppState>
) -> impl Responder {
//Dagtabase url for database queries
let database_url: String = std::env::var("DATABASE_URL").expect("DATABASE_URL must be set");
...
// Retrieve the key from the fhekeys table in the database
let pool = match MySqlPoolOptions::new()
.max_connections(10)
.connect(&database_url)
.await
{
Ok(pool) => {
println!("✅ Connection to the database is successful!");
pool
}
Err(err) => {
println!(" Failed to connect to the database: {:?}", err);
std::process::exit(1);
}
};
let server_key: String = match get_server_key(&pool)
.await{
Ok(key) => key,
Err(err) => {
println!("Error retrieving server key: {:?}", err);
std::process::exit(1);
}
};
// Use the key and other parameters as needed...
const MESSAGE: &str = "Build Simple Crud";
HttpResponse::Ok().json(json!({
---
}))
}
// Function to retrieve the server key from the 'fhekeys' table
async fn get_server_key(pool: &MySqlPool) -> Result<String, sqlx::Error> {
// Define the SQL query to retrieve the 'pk' key from the 'fhekeys' table
let query = "SELECT pk FROM fhekeys";
// Execute the query and fetch all rows
let rows: Result<Vec<(String,)>, sqlx::Error> = sqlx::query_as(query).fetch_all(pool).await;
// Handle the possible outcomes using a match statement
match rows {
Ok(rows) => {
// Extract the 'pk' column values from the rows and concatenate them
let server_key = rows
.into_iter()
.map(|row| row.0)
.collect::<Vec<String>>()
.join("");
// Return the server key
let server_key_str: String = server_key.chars().take(100).collect();
println!("server key : {:?}", server_key_str);
Ok(server_key)
}
Err(err) => Err(err), // Return the error if fetching rows fails
}
}
Any idea of what that error means? How can I increment the size limit of the HttpResponses
in actix web? How can I know if the problem is in the framework actix_web
or in a mysqlx
query?