- Fix get_next_address_index: use try_get::<i32> for PG SERIAL/INTEGER columns - Fix search_tx: use try_get::<i32> for PG status column - Fix execute_insert: parse locktime (String→i64) and in_vout (String→i32) before binding to PG INTEGER columns - Fix execute_insert: bind tbl_out vout as i32, amount as String for PG - Fix save_new_address: cast xpub i64 to i32 for PG INTEGER column - Fix get_pending_txs: cast i64 bind params to i32, use try_get::<i32> for reads - Fix get_stats: use try_get::<i32> for all numeric PG INTEGER columns - Add trace logging in parse_request_transactions for xpub address matching - Add trace logging in get_all_addresses_by_xpub for query debugging
272 lines
7.1 KiB
Plaintext
272 lines
7.1 KiB
Plaintext
Per creare un Webservice in Rust che utilizza Axis (un framework per la definizione di servizi web basato su XML Schema) e Diesel (un ORM per database SQLite), dobbiamo seguire alcuni passaggi. Tuttavia, è
|
|
importante notare che l'uso diretto di Axis con Diesel non è il modo più comune o consigliato per creare servizi web in Rust. Più spesso si usa Axum o Rocket come framework principale.
|
|
|
|
Tuttavia, posso mostrarti un esempio molto simplificato di come potresti iniziare a strutturare il tuo progetto utilizzando Diesel con SQLite3 e una libreria esterna per la definizione dei servizi web. Per
|
|
brevità, utilizzeremo `axum`, che è uno dei framework più popolari per creare servizi web in Rust.
|
|
|
|
### Prerequisiti
|
|
|
|
1. Installa Rust: https://www.rust-lang.org/tools/install
|
|
2. Crea un nuovo progetto con Cargo:
|
|
```sh
|
|
cargo new rust_sqlite_webserver
|
|
cd rust_sqlite_webserver
|
|
```
|
|
|
|
3. Aggiungi le dipendenze al file `Cargo.toml`:
|
|
|
|
```toml
|
|
[dependencies]
|
|
axum = "0.6"
|
|
tokio = { version = "1", features = ["full"] }
|
|
diesel = { version = "2.0", features = ["sqlite"] }
|
|
dotenv = "0.15"
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
|
|
[build-dependencies]
|
|
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
|
|
|
[[bin]]
|
|
name = "main"
|
|
path = "src/main.rs"
|
|
```
|
|
|
|
### Schema di Database
|
|
|
|
Creiamo un semplice schema per un database SQLite3 con Diesel.
|
|
|
|
1. Crea il file `schema.rs` in una nuova directory `src/schema/`.
|
|
|
|
```rust
|
|
// src/schema/users.sql
|
|
CREATE TABLE users (
|
|
id SERIAL PRIMARY KEY,
|
|
name VARCHAR(255) NOT NULL,
|
|
email TEXT NOT NULL UNIQUE
|
|
);
|
|
```
|
|
|
|
2. Genera i modelli Diesel:
|
|
|
|
```sh
|
|
cargo run --bin diesel_cli setup
|
|
cargo run --bin diesel_cli migrate
|
|
```
|
|
|
|
### Creazione del Servizio Web con Axum
|
|
|
|
1. Crea un file `main.rs` nella directory `src/`.
|
|
|
|
```rust
|
|
use axum::{
|
|
routing::get,
|
|
Router,
|
|
};
|
|
use diesel::prelude::*;
|
|
use serde::{Deserialize, Serialize};
|
|
use std::env;
|
|
|
|
mod schema;
|
|
mod models;
|
|
|
|
// Importiamo i modelli generati da Diesel
|
|
use self::schema::users::dsl::*;
|
|
|
|
#[derive(Serialize)]
|
|
struct User {
|
|
id: i32,
|
|
name: String,
|
|
email: String,
|
|
}
|
|
|
|
impl From<models::User> for User {
|
|
fn from(user: models::User) -> Self {
|
|
User {
|
|
id: user.id,
|
|
name: user.name,
|
|
email: user.email,
|
|
}
|
|
}
|
|
}
|
|
|
|
#[derive(Deserialize, Insertable)]
|
|
#[diesel(table_name = users)]
|
|
struct NewUser {
|
|
name: String,
|
|
email: String,
|
|
}
|
|
|
|
async fn get_users() -> impl axum::response::IntoResponse {
|
|
let conn = establish_connection();
|
|
let results = users.load::<models::User>(&conn).expect("Error loading users");
|
|
|
|
(axum::http::StatusCode::OK, axum::Json(results.into_iter().map(User::from).collect()))
|
|
}
|
|
|
|
async fn create_user(user: axum::Json<NewUser>) -> impl axum::response::IntoResponse {
|
|
let conn = establish_connection();
|
|
let new_user = user.0;
|
|
diesel::insert_into(users)
|
|
.values(&new_user)
|
|
.get_result::<models::User>(&conn)
|
|
.expect("Error creating new user");
|
|
|
|
(axum::http::StatusCode::CREATED, axum::Json(User::from(new_user)))
|
|
}
|
|
|
|
fn establish_connection() -> SqliteConnection {
|
|
dotenv().ok();
|
|
|
|
let database_url = env::var("DATABASE_URL").expect("DATABASE_URL must be set");
|
|
SqliteConnection::establish(&database_url).expect(&format!("Error connecting to {}", database_url))
|
|
}
|
|
|
|
#[tokio::main]
|
|
async fn main() {
|
|
// Set the `RUST_LOG` environment variable if you want to see logs
|
|
env_logger::init();
|
|
|
|
let app = Router::new()
|
|
.route("/users", get(get_users).post(create_user));
|
|
|
|
axum::Server::bind(&"0.0.0.0:3000".parse().unwrap())
|
|
.serve(app.into_make_service())
|
|
.await
|
|
.unwrap();
|
|
}
|
|
```
|
|
|
|
### Esecuzione del Progetto
|
|
|
|
1. Crea un file `.env` nella directory root con la seguente riga:
|
|
|
|
```sh
|
|
DATABASE_URL=sqlite://db.sqlite3
|
|
```
|
|
|
|
2. Esegui il progetto:
|
|
|
|
```sh
|
|
cargo run
|
|
```
|
|
|
|
Ora, puoi accedere al tuo servizio web:
|
|
|
|
- Per ottenere tutti gli utenti: `GET http://localhost:3000/users`
|
|
- Per creare un nuovo utente: `POST http://localhost:3000/users` con il corpo JSON:
|
|
```json
|
|
{
|
|
"name": "John Doe",
|
|
"email": "john.doe@example.com"
|
|
}
|
|
```
|
|
|
|
Questo esempio mostra come iniziare a strutturare un servizio web in Rust utilizzando Axum, Diesel con SQLite3. Ricorda che questo è solo un punto di partenza e potrebbe essere esteso o modificato per
|
|
soddisfare le tue specifiche esigenze.
|
|
|
|
>>> il mio progetto prevede vari file binari, oltre al webservice come posso gestire piu' binari?
|
|
Se il tuo progetto in Rust contiene diversi file binari (ad esempio, un client e un server separati), puoi organizzarli in moduli all'interno del tuo progetto. Ogni modulo può essere compilato come un file
|
|
binario separato.
|
|
|
|
Ecco come farlo:
|
|
|
|
1. **Struttura del Progetto**:
|
|
Organizza il tuo progetto in una directory `src` con sottodirectory per i vari binari e moduli. Ad esempio:
|
|
|
|
```
|
|
rust_project/
|
|
├── src/
|
|
│ ├── main.rs
|
|
│ ├── client/
|
|
│ │ └── main.rs
|
|
│ ├── server/
|
|
│ │ └── main.rs
|
|
│ └── common/
|
|
│ └── lib.rs
|
|
├── Cargo.toml
|
|
└── .env
|
|
```
|
|
|
|
2. **Creazione dei Binari**:
|
|
Ogni sottodirectory con un file `main.rs` può essere considerata un binario separato.
|
|
|
|
3. **Cargo.toml**:
|
|
Configura il tuo `Cargo.toml` per gestire i vari binari.
|
|
|
|
```toml
|
|
[package]
|
|
name = "rust_project"
|
|
version = "0.1.0"
|
|
edition = "2018"
|
|
|
|
[dependencies]
|
|
axum = "0.6"
|
|
tokio = { version = "1", features = ["full"] }
|
|
diesel = { version = "2.0", features = ["sqlite"] }
|
|
serde = { version = "1.0", features = ["derive"] }
|
|
serde_json = "1.0"
|
|
|
|
[build-dependencies]
|
|
diesel_cli = { version = "2.0", features = ["sqlite"] }
|
|
|
|
[[bin]]
|
|
name = "server"
|
|
path = "src/server/main.rs"
|
|
|
|
[[bin]]
|
|
name = "client"
|
|
path = "src/client/main.rs"
|
|
```
|
|
|
|
4. **Esecuzione dei Binari**:
|
|
Puoi ora compilare e eseguire i binari separati.
|
|
|
|
```sh
|
|
cargo build --release
|
|
./target/release/server
|
|
./target/release/client
|
|
```
|
|
|
|
5. **Moduli Comuni**:
|
|
Se hai moduli comuni che vengono utilizzati da più binari, puoi organizzarli in una directory `common` e importarli nei vari binari.
|
|
|
|
```rust
|
|
// src/common/lib.rs
|
|
pub mod common_module {
|
|
pub fn common_function() {
|
|
println!("This is a common function");
|
|
}
|
|
}
|
|
```
|
|
|
|
Allora, puoi importare questo modulo in altri binari:
|
|
|
|
```rust
|
|
// src/server/main.rs
|
|
extern crate rust_project;
|
|
|
|
use rust_project::common::lib as common;
|
|
|
|
fn main() {
|
|
common::common_function();
|
|
}
|
|
```
|
|
|
|
6. **File `.env`**:
|
|
Puoi avere un file `.env` nella directory root del progetto per gestire le variabili d'ambiente comuni, e poi specificare variabili d'ambiente separate per ogni binario in sottodirectory.
|
|
|
|
```sh
|
|
# .env
|
|
DATABASE_URL=sqlite://db.sqlite3
|
|
|
|
# src/server/.env
|
|
SERVER_PORT=3000
|
|
|
|
# src/client/.env
|
|
CLIENT_IP=localhost
|
|
```
|
|
|
|
Questo approccio ti permette di mantenere una struttura organizzata per i tuoi progetti multi-binari in Rust, facilitando la gestione e il sviluppo di diverse parti del tuo progetto.
|
|
|