not working, basic structure with grpc
This commit is contained in:
@@ -1,21 +1,7 @@
|
||||
use multieko2::accounting_client::AccountingClient;
|
||||
use multieko2::{CreateAccountRequest, GetAccountRequest};
|
||||
|
||||
pub async fn run_client(server_url: String) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut client = AccountingClient::connect(server_url).await?;
|
||||
|
||||
// Create an account
|
||||
let create_response = client
|
||||
.create_account(CreateAccountRequest { name: "John Doe".into() })
|
||||
.await?;
|
||||
println!("Created account with ID: {}", create_response.into_inner().id);
|
||||
|
||||
// Get an account
|
||||
let get_response = client
|
||||
.get_account(GetAccountRequest { id: "1".into() })
|
||||
.await?;
|
||||
let account = get_response.into_inner();
|
||||
println!("Account ID: {}, Name: {}", account.id, account.name);
|
||||
use crate::proto::api::accounting_client::AccountingClient;
|
||||
|
||||
pub async fn run_client() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let mut client = AccountingClient::connect("http://[::1]:50051").await?;
|
||||
// Client implementation
|
||||
Ok(())
|
||||
}
|
||||
|
||||
52
src/db.rs
Normal file
52
src/db.rs
Normal file
@@ -0,0 +1,52 @@
|
||||
// src/db.rs
|
||||
use sqlx::postgres::{PgPool, PgPoolOptions};
|
||||
use std::time::Duration;
|
||||
use tracing::info;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct DatabaseConfig {
|
||||
pub username: String,
|
||||
pub password: String,
|
||||
pub host: String,
|
||||
pub port: u16,
|
||||
pub database_name: String,
|
||||
pub max_connections: u32,
|
||||
}
|
||||
|
||||
impl DatabaseConfig {
|
||||
pub fn from_env() -> Self {
|
||||
Self {
|
||||
username: std::env::var("RUST_DB_USER").expect("RUST_DB_USER must be set"),
|
||||
password: std::env::var("RUST_DB_PASSWORD").expect("RUST_DB_PASSWORD must be set"),
|
||||
host: std::env::var("RUST_DB_HOST").expect("RUST_DB_HOST must be set"),
|
||||
port: std::env::var("RUST_DB_PORT")
|
||||
.expect("RUST_DB_PORT must be set")
|
||||
.parse()
|
||||
.expect("RUST_DB_PORT must be a valid port number"),
|
||||
database_name: std::env::var("RUST_DB_NAME").expect("RUST_DB_NAME must be set"),
|
||||
max_connections: 5,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn connection_string(&self) -> String {
|
||||
format!(
|
||||
"postgres://{}:{}@{}:{}/{}",
|
||||
self.username, self.password, self.host, self.port, self.database_name
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn create_pool(config: &DatabaseConfig) -> Result<PgPool, sqlx::Error> {
|
||||
let conn_str = config.connection_string();
|
||||
info!("Connecting to database: {}", conn_str);
|
||||
PgPoolOptions::new()
|
||||
.max_connections(config.max_connections)
|
||||
.acquire_timeout(Duration::from_secs(3))
|
||||
.connect(&conn_str)
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn check_connection(pool: &PgPool) -> Result<(), sqlx::Error> {
|
||||
sqlx::query("SELECT 1").execute(pool).await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
// src/lib.rs
|
||||
pub mod db;
|
||||
pub mod server;
|
||||
|
||||
52
src/main.rs
52
src/main.rs
@@ -1,35 +1,33 @@
|
||||
use clap::{Parser, Subcommand};
|
||||
// src/main.rs
|
||||
use tonic::transport::Server;
|
||||
use sqlx::PgPool;
|
||||
|
||||
#[derive(Parser)]
|
||||
struct Cli {
|
||||
#[clap(subcommand)]
|
||||
command: Commands,
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
enum Commands {
|
||||
Standalone,
|
||||
Server,
|
||||
Client { server_url: String },
|
||||
}
|
||||
use crate::db;
|
||||
use crate::server;
|
||||
|
||||
#[tokio::main]
|
||||
async fn main() -> Result<(), Box<dyn std::error::Error>> {
|
||||
let args = Cli::parse();
|
||||
// Load .env file
|
||||
dotenvy::dotenv().ok();
|
||||
|
||||
match args.command {
|
||||
Commands::Standalone => {
|
||||
standalone::run().await?;
|
||||
}
|
||||
Commands::Server => {
|
||||
let db_pool = PgPool::connect("postgres://user:password@localhost/multieko2").await?;
|
||||
server::run_server(db_pool).await?;
|
||||
}
|
||||
Commands::Client { server_url } => {
|
||||
client::run_client(server_url).await?;
|
||||
}
|
||||
// Initialize database
|
||||
let db_config = db::DatabaseConfig::from_env();
|
||||
let db_pool = db::create_pool(&db_config)
|
||||
.await
|
||||
.expect("Failed to create database pool");
|
||||
|
||||
|
||||
// Check database connection
|
||||
db::check_connection(&db_pool)
|
||||
.await
|
||||
.expect("Failed to connect to database");
|
||||
|
||||
// Choose mode based on command line arguments
|
||||
let args: Vec<String> = env::args().collect();
|
||||
match args.get(1).map(|s| s.as_str()) {
|
||||
Some("server") => server::run_server(db_pool).await?,
|
||||
Some("client") => client::run_client().await?,
|
||||
Some("standalone") => standalone::run().await?,
|
||||
_ => println!("Usage: [server|client|standalone]"),
|
||||
}
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -1,52 +1,27 @@
|
||||
use tonic::{Request, Response, Status};
|
||||
use sqlx::PgPool;
|
||||
use multieko2::accounting_server::{Accounting, AccountingServer};
|
||||
use multieko2::{CreateAccountRequest, CreateAccountResponse, GetAccountRequest, GetAccountResponse};
|
||||
use crate::{db, proto::api::*};
|
||||
|
||||
pub struct MyAccountingService {
|
||||
db_pool: PgPool,
|
||||
pub struct AccountingService {
|
||||
db_pool: sqlx::PgPool,
|
||||
}
|
||||
|
||||
#[tonic::async_trait]
|
||||
impl Accounting for MyAccountingService {
|
||||
impl accounting_server::Accounting for AccountingService {
|
||||
async fn create_account(
|
||||
&self,
|
||||
request: Request<CreateAccountRequest>,
|
||||
) -> Result<Response<CreateAccountResponse>, Status> {
|
||||
let name = request.into_inner().name;
|
||||
let account = sqlx::query!("INSERT INTO accounts (name) VALUES ($1) RETURNING id", name)
|
||||
.fetch_one(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
|
||||
Ok(Response::new(CreateAccountResponse { id: account.id.to_string() }))
|
||||
}
|
||||
|
||||
async fn get_account(
|
||||
&self,
|
||||
request: Request<GetAccountRequest>,
|
||||
) -> Result<Response<GetAccountResponse>, Status> {
|
||||
let id = request.into_inner().id;
|
||||
let account = sqlx::query!("SELECT id, name FROM accounts WHERE id = $1", id)
|
||||
.fetch_one(&self.db_pool)
|
||||
.await
|
||||
.map_err(|e| Status::internal(e.to_string()))?;
|
||||
|
||||
Ok(Response::new(GetAccountResponse {
|
||||
id: account.id.to_string(),
|
||||
name: account.name,
|
||||
}))
|
||||
// Database implementation
|
||||
}
|
||||
}
|
||||
|
||||
pub async fn run_server(db_pool: PgPool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
pub async fn run_server(pool: sqlx::PgPool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let addr = "[::1]:50051".parse()?;
|
||||
let service = MyAccountingService { db_pool };
|
||||
|
||||
tonic::transport::Server::builder()
|
||||
.add_service(AccountingServer::new(service))
|
||||
.add_service(accounting_server::AccountingServer::new(
|
||||
AccountingService { db_pool: pool }
|
||||
))
|
||||
.serve(addr)
|
||||
.await?;
|
||||
|
||||
Ok(())
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user