I am using OptsBuilder passing a data source name to create a connection pool:
let mut opts = mysql::OptsBuilder::from_opts(dsn);
opts.stmt_cache_size(0);
let pool = mysql::Pool::new_manual(1, 3, opts).expect("Could not connect to MySQL");
If I pass an invalid DSN, the code panics:
thread 'main' panicked at 'URL ParseError { relative URL without a base }', ', /path/.cargo/registry/src/github.com-1ecc6299db9ec823/mysql-16.0.2/src/conn/opts.rs:827:25
How can I handle the error or verify in advance to prevent panicking?
You can create the Opts with from_url, so that you are sure that it won't fail after that:
let opts = match Opts::from_url(dsn) {
Ok(opts) => opts,
Err(e) => panic!(),// manage error
};
let mut opts = mysql::OptsBuilder::from_opts(opts);
opts.stmt_cache_size(0);
let pool = mysql::Pool::new_manual(1, 3, opts).expect("Could not connect to MySQL");
Related
So when i try to connect mysql database main tread panics it was working fine with sqlite but when i try to use it with mysql it's not working.
cargo check
is also working fine. The error is located at line 20 where i created a database connection.
my main.rs
use dotenv::dotenv;
use roadoxe::data::AppDatabase;
use structopt::StructOpt;
#[derive(StructOpt, Debug)]
#[structopt(name = "roadoxe")]
struct Opt {
#[structopt(default_value = "mysql://root:root#127.0.0.1:33060/automate")]
connection_string: String,
}
fn main() {
dotenv().ok();
let opt = Opt::from_args();
let rt = tokio::runtime::Runtime::new().expect("failed to spawn tokio runtime");
let handle = rt.handle().clone();
let database = rt.block_on(async move { AppDatabase::new(&opt.connection_string).await });
let config = roadoxe::RocketConfig {
database,
// maintenance,
};
rt.block_on(async move {
roadoxe::rocket(config)
.launch()
.await
.expect("failed to launch rocket server");
})
}
and data mod.rs
use sqlx::MySql;
// use std::str::FromStr;
#[derive(Debug, thiserror::Error)]
pub enum DataError {
#[error("Database Error: {0}")]
Database(#[from] sqlx::Error),
}
pub type AppDatabase = Database<MySql>;
pub type DatabasePool = sqlx::mysql::MySqlPool;
pub type Transaction<'a> = sqlx::Transaction<'a, MySql>;
pub type AppDatabaseRow = sqlx::mysql::MySqlRow;
pub type AppQueryResult = sqlx::mysql::MySqlQueryResult;
pub struct Database<D: sqlx::Database>(sqlx::Pool<D>);
impl Database<MySql> {
pub async fn new(path: &str) -> Self {
let pool = sqlx::mysql::MySqlPoolOptions::new().connect(path).await;
match pool {
Ok(pool) => Self(pool),
Err(e) => {
eprintln!("{}\n", e);
eprintln!(
"If the database has not yet been created, run \n $ sqlx database setup\n"
);
panic!("Failed to connect to database");
}
}
}
pub fn get_pool(&self) -> &DatabasePool {
&self.0
}
}
I have no idea what's happening here fairly new to rust. And thanks for your time.
The first issue was the port it is suppose to be
const PORT = 3306
rather than 33060
and the second issue was the ip address it doesn't work with 127.0.0.1 but localhost seems to work fine just needed to switch
#[structopt(default_value = "mysql://root:root#127.0.0.1:33060/automate")]
with
#[structopt(default_value = "mysql://root:root#localhost:3306/automate")]
I am having trouble deserializing json data sent from my client.
server.rs
use std::collections::HashMap;
use std::sync::{Arc,Mutex};
use tokio::net::{TcpListener, TcpStream};
use tokio::io::{AsyncWriteExt, AsyncReadExt};
use serde_json::{ Value};
/*
The type Arc<T> provides shared ownership of a value of type T, allocated in the heap. Invoking clone on Arc produces a new Arc instance, which points to the same allocation on the heap as the source Arc, while increasing a reference count. When the last Arc pointer to a given allocation is destroyed, the value stored in that allocation (often referred to as “inner value”) is also dropped.
*/
// creating a type alias for user to socket map
// Arc points top
type UserToSocket = Arc<Mutex<HashMap<String,TcpStream>>>;
#[tokio::main]
async fn main() {
let listener = TcpListener::bind("127.0.0.1:9090").await;
// creating a threadsafe hashmap mutex
let local_db: UserToSocket = Arc::new(Mutex::new(HashMap::new()));
let listener = match listener{
Result::Ok(value) => {value},
Result::Err(_)=> {panic!("ERROR OCCURED")},
};
println!("[+] Listener has been started");
loop {
// now waiting for connection
println!("[+] Listening for connection");
let (socket,addr) = listener.accept().await.unwrap();
println!("[+] A connection accepted from {:?}, spawwning a new task for it",addr);
// cloning does not actually clone, but rather just increases counter to it
let ld = Arc::clone(&local_db);
// spawning a new task
tokio::spawn(
async move {
handler(socket,ld).await;
}
);
}
}
// a handler for new connection
async fn handler(mut socket: TcpStream, _db: UserToSocket) {
socket.write_all(b"[+] Hello Friend, Welcome to my program\r\n").await.unwrap();
let mut buf = vec![0; 1024];
loop {
// n holds the number of bytes read i think
match socket.read(&mut buf).await {
Ok(0) => {
println!("Client Closed connection");
return;
}
// getting some data
Ok(_n) => {
// ownership is transferred so need to clone it
let bufc = buf.clone();
// unmarshalling json
//let parsed:Value = serde_json::from_slice(&bufc).unwrap();
// obtaining string
match String::from_utf8(bufc) {
Ok(val) => {
println!("[+] So the parsed value is {}",val);
//let temp = val.as_str();
let parsed:Value = serde_json::from_str(&val).unwrap();
println!("{:?}",parsed);
socket.write_all(b"So yeah thanks for sending this\r\n").await.unwrap();
continue;
}
Err(err) => {
println!("ERROR Could not convert to string {:?}",err);
continue;
}
};
//socket.write_all(b"Vnekai bujena\r\n").await.unwrap();
}
Err(_) => {
println!("Unhandeled error occured");
return;
}
}
}
}
client.rs
use tokio::net::{TcpStream};
use tokio::io::{AsyncReadExt, AsyncWriteExt};
use std::{thread,time};
#[tokio::main]
async fn main() {
let sleep_time = time::Duration::from_secs(2);
let socket = TcpStream::connect("127.0.0.1:9090").await;
let mut socket = match socket {
Ok(v) => {
println!("[+] Successfully connected");
v
}
Err(_) => {
println!("ERROR could not connect to the server");
std::process::exit(-1);
}
};
let mut buf = vec![0;1024];
//let mut user_input = String::new();
loop {
thread::sleep(sleep_time);
match socket.read(&mut buf).await {
Ok(0) => {
println!("[+] Connection with server has been closed");
std::process::exit(1);
}
Ok(_n) => {
let bc = buf.clone();
let res = String::from_utf8(bc).unwrap();
println!("[+] Server responded with {}",res);
}
Err(_) => {
panic!("[-] Some fatal error occured");
}
}
println
!("You want to say: ");
/*let _v = match io::stdin().read_line(&mut user_input){
Ok(val) => {val}
Err(_) => panic!("ERROR"),
};*/
let val = "{\"name\": \"John Doe\",\"age\": 43,\"phones\": [\"+44 1234567\",\"+44 2345678\"]}\r\n";
socket.write(val.as_bytes()).await.unwrap();
}
}
When I send json data to server, I receive an error.
thread 'tokio-runtime-worker' panicked at 'called Result::unwrap() on an Err value: Error("trailing characters", line: 2, column: 1)', src\bin\simple_server.rs:79:71
This error does not occur when I try to desterilize the json string directly. It only occurs when I send the data through network.
Since your JSON is newline-terminated, you should use something like read_line() to read it. (And you should never send a formatted JSON, because it will contain newlines - but serde_json is creating non-formatted JSON by default.)
For example, this compiles and should work as intended
use serde_json::Value;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};
use tokio::io::{AsyncBufReadExt, AsyncWriteExt, BufStream};
use tokio::net::{TcpListener, TcpStream};
type UserToSocket = Arc<Mutex<HashMap<String, TcpStream>>>;
// ... main unchanged from your implementation ...
async fn handler(socket: TcpStream, _db: UserToSocket) {
let mut socket = BufStream::new(socket);
socket
.write_all(b"[+] Hello Friend, Welcome to my program\r\n")
.await
.unwrap();
socket.flush().await.unwrap();
let mut line = vec![];
loop {
line.clear();
if let Err(e) = socket.read_until(b'\n', &mut line).await {
println!("Unhandled error occured: {}", e);
return;
}
if line.is_empty() {
println!("Client Closed connection");
return;
}
println!(
"[+] So the received value is {}",
String::from_utf8_lossy(&line)
);
let parsed: Value = serde_json::from_slice(&line).unwrap();
println!("{:?}", parsed);
socket
.write_all(b"So yeah thanks for sending this\r\n")
.await
.unwrap();
socket.flush().await.unwrap();
continue;
}
}
My web application has a REST API via Rocket, connects to a MySQL database, and there's a single endpoint. I cannot figure out how to access the database connection inside the controller:
#![feature(decl_macro)]
#[macro_use]
extern crate rocket;
#[macro_use]
extern crate rocket_contrib;
use rocket_contrib::json::Json;
use serde::Serialize;
#[macro_use]
extern crate mysql;
use mysql as my;
use mysql::consts::ColumnType::MYSQL_TYPE_DATE;
use mysql::prelude::Queryable;
use mysql::Pool;
#[get("/orgs")]
fn get_orgs(conn: MyDb) -> Json<Vec<Org>> {
// I need to have the db connection here to pass it to get_all.
let o = match Org::get_all() {
Ok(o) => o,
Err(e) => panic!(e),
};
Json(o)
}
#[derive(Serialize)]
pub struct Org {
pub id: Option<i32>,
pub name: String,
}
fn main() {
let url = "mysql://root:mysql#(localhost:33061)/somedb";
let pool = Pool::new(url)?;
let mut conn = pool.get_conn();
// I need to pass "conn" around, first to get_orgs, then to Org::get_all.
rocket::ignite().mount("/", routes![get_orgs]).launch();
}
impl Org {
fn get_all(mut conn: mysql::Conn) -> Result<Vec<Org>, Err> {
let all_orgs = conn.query_map("SELECT id, name from organization", |(id, name)| Org {
id,
name,
})?;
return match all_orgs() {
Ok(all_orgs) => all_orgs,
Err(e) => e,
};
}
}
My assumption is that #[get("/orgs")] does a bunch of code generation. I found this: https://rocket.rs/v0.4/guide/state/#databases - which looks correct, but I cannot figure out a working example to connect to my MySQL instance via the connection string.
Here are my dependencies:
[dependencies]
rocket = "0.4.2"
rocket_codegen = "0.4.2"
rocket_contrib = "0.4.2"
serde = {version = "1.0", features = ["derive"]}
serde_json = {version = "1.0"}
mysql = "*"
How do I make the MySQL connection and pass it around?
You need to tell Rocket about your database. This is done via Fairings. The document you linked actually includes them in an example:
fn main() {
rocket::ignite()
.attach(LogsDbConn::fairing())
.launch();
}
The important piece above is attach, where the database connection is passed to Rocket as a fairing. Only then can Rocket pass the connection to your route, so that you can use it...
It doesn't look like the Pony language has made many inroads to stack overflow yet, but you've gotta start somewhere...
Here's the very limited info about Pony constructors, which isn't helping me understand what I'm seeing.
Here's an initial program:
class Wombat
let name: String
var _hunger_level: U64
new anon() =>
name = "Anon"
_hunger_level = 0
new create(name': String) =>
name = name'
_hunger_level = 0
new hungry(name': String, hunger': U64) =>
name = name'
_hunger_level = hunger'
actor Main
new create(env: Env) =>
env.out.print("Started.")
let wombat: Wombat = Wombat("Ernie")
let w: Wombat = createWombat()
env.out.print("Name: "+wombat.name)
env.out.print("Name: "+w.name)
fun createWombat(): Wombat =>
let w: Wombat = Wombat("Bert")
w
Let's rename the "create" constructor to "named":
new named(name': String) =>
name = name'
_hunger_level = 0
... and I see error:
Error:
/src/main/main.pony:22:26: couldn't find 'create' in 'Wombat'
let wombat: Wombat = Wombat("Ernie")
... which suggests that all constructors are not created equal. Huh...?
So, let's undo that change.
Now let's try using the zero-arg constructor:
let wombat: Wombat = Wombat()
let w: Wombat = createWombat()
... and now I see:
Error:
/src/main/main.pony:22:33: not enough arguments
let wombat: Wombat = Wombat()
^
It's ignoring that constructor.
So, let's rename the first two constructors:
new create() =>
name = "Anon"
_hunger_level = 0
new named(name': String) =>
name = name'
_hunger_level = 0
... and now I see:
Error:
/src/main/main.pony:22:26: couldn't find 'apply' in 'Wombat'
let wombat: Wombat = Wombat()
No idea what that means.
Thank you to Chris Double on the Pony mailing list.
The answer is in the Syntactic Sugar docs. We simply need to specify which constructors we're running. So I changed the anon instantiation to:
let wombat: Wombat = Wombat.anon()
I have sent a post request to node express server
app.post('/addUsers', function (req, res) {
var newuser = req.body;
console.log(newuser);
fs.readFile( __dirname + "/" + "users.json", 'utf8', function (err, data) {
data = JSON.parse( data );
data["user4"] = newuser // how can i create a user4 here currently i get an error as newsier is whole req body or something .
console.log( data );
// res.end(data);
res.end( JSON.stringify(data));
});
})
and i have got the value of newuser to console as
{ '{"user4":{"password":"killer","id":4,"profession":"kuchbhi","name":"mukesh"}}': '' }
The question is how can i get the value of user4 so that i can add it to the list of users .
I was using this dictionary in swift
["user4":["name" : "mukesh",
"password" : "killer",
"profession" : "kuchbhi",
"id": 4]]
which i changed to this once knowing its not valid json
["name" : "mukesh",
"password" : "killer",
"profession" : "kuchbhi",
"id": 4]
and know i don't get the error but the data from server response (i have printed it in Xcode console)after adding the fourth user is quite not in the format i think it should be , it looks like this
["user2": {
id = 2;
name = suresh;
password = password2;
profession = librarian;
}, "user4": {
"{\"password\":\"killer\",\"profession\":\"kuchbhi\",\"id\":4,\"name\":\"mukesh\"}" = "";
}, "user1": {
id = 1;
name = mahesh;
password = password1;
profession = teacher;
}, "user3": {
id = 3;
name = ramesh;
password = password3;
profession = clerk;
}]
all other entries are added by me manually in users.son.
This is what is logged into terminal console
user4: { '{"password":"killer","profession":"kuchbhi","id":4,"name":"mukesh"}': '' } }
which i still think is not good json or is it ?
Thank you quite a novice with format conversions and servers get/post thingy .
At the moment, the json that you receive/present is not valid.
Once you actually manage to receive valid JSON from the client, this will look like the following.
var u = {"user4":{"password":"killer","id":4,"profession":"kuchbhi","name":"mukesh"}};
For any json you can get its keys by using the command
var theKeys = Object.keys(u);
In the example above, there is only one key for the entire JSON, so the variable theKeys has contents [ 'user4' ]. Hence, you will be able to access the username that you want by looking at theKeys[0].
Similarly, you can get the properties for the inner json document using the command
Object.keys(u[theKeys[0]]);
which will return [ 'password', 'id', 'profession', 'name' ].
EDIT
Based on the comment below, perhaps the following code can help you send the json object correctly from the client side.
NSDictionary *aDictionary = #{
#"user4": #{#"password": #"killer",
#"id": #4,
#"profession": #"kuchbhi"
}};
NSError * error;
NSData * theData = [NSJSONSerialization dataWithJSONObject:aDictionary options:0 error:&error];
NSString * newStr = [[NSString alloc] initWithData:theData encoding:NSUTF8StringEncoding];
NSLog(#"body: %#", newStr);
[newStr release];
And here is a solution to send json correctly using swift: https://stackoverflow.com/a/31938246/1355058