Fully moved cart and compile all
This commit is contained in:
parent
f5ecbfb338
commit
7d507602c3
@ -1,9 +1,7 @@
|
|||||||
use std::net::SocketAddr;
|
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use config::UpdateConfig;
|
use config::UpdateConfig;
|
||||||
use tarpc::tokio_serde::formats::Json;
|
use tarpc::context;
|
||||||
use tarpc::{client, context};
|
|
||||||
use tokio::time::sleep;
|
use tokio::time::sleep;
|
||||||
|
|
||||||
#[derive(gumdrop::Options)]
|
#[derive(gumdrop::Options)]
|
||||||
@ -17,24 +15,23 @@ impl UpdateConfig for Flags {}
|
|||||||
|
|
||||||
#[tokio::main]
|
#[tokio::main]
|
||||||
async fn main() -> std::io::Result<()> {
|
async fn main() -> std::io::Result<()> {
|
||||||
|
use channels::accounts::me::Input;
|
||||||
|
|
||||||
let opts: Flags = gumdrop::Options::parse_args_default_or_exit();
|
let opts: Flags = gumdrop::Options::parse_args_default_or_exit();
|
||||||
|
|
||||||
let config = config::default_load(&opts);
|
let config = config::default_load(&opts);
|
||||||
let client = channels::accounts::rpc::create_client(config).await;
|
let client = channels::accounts::rpc::create_client(config).await;
|
||||||
|
|
||||||
let r = client.me(context::current(), 1.into()).await;
|
let r = client
|
||||||
|
.me(
|
||||||
|
context::current(),
|
||||||
|
Input {
|
||||||
|
account_id: 1.into(),
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await;
|
||||||
println!("{:?}", r);
|
println!("{:?}", r);
|
||||||
|
|
||||||
let hello = async move {
|
|
||||||
tokio::join! {
|
|
||||||
client.me(context::current(), 1.into()),
|
|
||||||
client.me(context::current(), 2.into()),
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.await;
|
|
||||||
|
|
||||||
eprintln!("{:?}", hello);
|
|
||||||
|
|
||||||
// Let the background span processor finish.
|
// Let the background span processor finish.
|
||||||
sleep(Duration::from_micros(1)).await;
|
sleep(Duration::from_micros(1)).await;
|
||||||
opentelemetry::global::shutdown_tracer_provider();
|
opentelemetry::global::shutdown_tracer_provider();
|
||||||
|
@ -14,7 +14,7 @@ use email_manager::TestMail;
|
|||||||
use jemallocator::Jemalloc;
|
use jemallocator::Jemalloc;
|
||||||
use model::{Email, Encrypt, Login, PassHash, Password, Role};
|
use model::{Email, Encrypt, Login, PassHash, Password, Role};
|
||||||
use opts::{
|
use opts::{
|
||||||
Command, CreateAccountCmd, CreateAccountOpts, GenerateHashOpts, MigrateOpts, Opts, ServerOpts,
|
Command, CreateAccountCmd, CreateAccountOpts, GenerateHashOpts, Opts, ServerOpts,
|
||||||
TestMailerOpts,
|
TestMailerOpts,
|
||||||
};
|
};
|
||||||
use validator::{validate_email, validate_length};
|
use validator::{validate_email, validate_length};
|
||||||
@ -58,8 +58,8 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
|||||||
let fs_manager = fs_manager::FsManager::build(app_config.clone())
|
let fs_manager = fs_manager::FsManager::build(app_config.clone())
|
||||||
.await
|
.await
|
||||||
.expect("Failed to initialize file system storage");
|
.expect("Failed to initialize file system storage");
|
||||||
let cart_manager = cart_manager::CartManager::new(db.clone()).start();
|
let cart_manager = channels::carts::rpc::create_client(app_config.clone()).await;
|
||||||
let account_manager = channels::account::rpc::create_client(app_config.clone()).await;
|
let account_manager = channels::accounts::rpc::create_client(app_config.clone()).await;
|
||||||
let addr = {
|
let addr = {
|
||||||
let l = app_config.lock();
|
let l = app_config.lock();
|
||||||
let w = l.web();
|
let w = l.web();
|
||||||
@ -105,22 +105,6 @@ async fn server(opts: ServerOpts) -> Result<()> {
|
|||||||
.map_err(Error::Boot)
|
.map_err(Error::Boot)
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn migrate(opts: MigrateOpts) -> Result<()> {
|
|
||||||
use sqlx::migrate::MigrateError;
|
|
||||||
|
|
||||||
let config = config::default_load(&opts);
|
|
||||||
let db = database_manager::Database::build(config).await;
|
|
||||||
let res: std::result::Result<(), MigrateError> =
|
|
||||||
sqlx::migrate!("../migrations").run(db.pool()).await;
|
|
||||||
match res {
|
|
||||||
Ok(()) => Ok(()),
|
|
||||||
Err(e) => {
|
|
||||||
eprintln!("{e}");
|
|
||||||
std::process::exit(1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
async fn generate_hash(_opts: GenerateHashOpts) -> Result<()> {
|
async fn generate_hash(_opts: GenerateHashOpts) -> Result<()> {
|
||||||
model::print_hash();
|
model::print_hash();
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -241,7 +225,6 @@ async fn main() -> Result<()> {
|
|||||||
|
|
||||||
let opts: Opts = gumdrop::Options::parse_args_default_or_exit();
|
let opts: Opts = gumdrop::Options::parse_args_default_or_exit();
|
||||||
match opts.cmd.unwrap_or_default() {
|
match opts.cmd.unwrap_or_default() {
|
||||||
Command::Migrate(opts) => migrate(opts).await,
|
|
||||||
Command::Server(opts) => server(opts).await,
|
Command::Server(opts) => server(opts).await,
|
||||||
Command::GenerateHash(opts) => generate_hash(opts).await,
|
Command::GenerateHash(opts) => generate_hash(opts).await,
|
||||||
Command::CreateAccount(opts) => create_account(opts).await,
|
Command::CreateAccount(opts) => create_account(opts).await,
|
||||||
|
@ -34,8 +34,6 @@ impl UpdateConfig for Opts {
|
|||||||
pub enum Command {
|
pub enum Command {
|
||||||
#[options(help = "Run server")]
|
#[options(help = "Run server")]
|
||||||
Server(ServerOpts),
|
Server(ServerOpts),
|
||||||
#[options(help = "Migrate database")]
|
|
||||||
Migrate(MigrateOpts),
|
|
||||||
#[options(help = "Generate new salt for passwords")]
|
#[options(help = "Generate new salt for passwords")]
|
||||||
GenerateHash(GenerateHashOpts),
|
GenerateHash(GenerateHashOpts),
|
||||||
#[options(help = "Create new account")]
|
#[options(help = "Create new account")]
|
||||||
@ -54,9 +52,6 @@ impl UpdateConfig for Command {
|
|||||||
Command::Server(opts) => {
|
Command::Server(opts) => {
|
||||||
opts.update_config(config);
|
opts.update_config(config);
|
||||||
}
|
}
|
||||||
Command::Migrate(opts) => {
|
|
||||||
opts.update_config(config);
|
|
||||||
}
|
|
||||||
Command::GenerateHash(opts) => {
|
Command::GenerateHash(opts) => {
|
||||||
opts.update_config(config);
|
opts.update_config(config);
|
||||||
}
|
}
|
||||||
|
@ -40,7 +40,6 @@ pub enum Error {
|
|||||||
CriticalFailure,
|
CriticalFailure,
|
||||||
Public(public::Error),
|
Public(public::Error),
|
||||||
Admin(admin::Error),
|
Admin(admin::Error),
|
||||||
Cart(cart_manager::Error),
|
|
||||||
Database(database_manager::Error),
|
Database(database_manager::Error),
|
||||||
Email(email_manager::Error),
|
Email(email_manager::Error),
|
||||||
Fs(fs_manager::Error),
|
Fs(fs_manager::Error),
|
||||||
@ -78,7 +77,6 @@ impl Display for Error {
|
|||||||
})
|
})
|
||||||
.unwrap_or_default(),
|
.unwrap_or_default(),
|
||||||
Error::CriticalFailure => String::from("Something went wrong"),
|
Error::CriticalFailure => String::from("Something went wrong"),
|
||||||
Error::Cart(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
|
||||||
Error::Database(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
Error::Database(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
||||||
Error::Email(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
Error::Email(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
||||||
Error::Fs(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
Error::Fs(_e) => serde_json::to_string(&self).unwrap_or_default(),
|
||||||
@ -100,7 +98,6 @@ impl ResponseError for Error {
|
|||||||
}
|
}
|
||||||
Error::Admin(_) => StatusCode::BAD_REQUEST,
|
Error::Admin(_) => StatusCode::BAD_REQUEST,
|
||||||
Error::Public(_) => StatusCode::BAD_REQUEST,
|
Error::Public(_) => StatusCode::BAD_REQUEST,
|
||||||
Error::Cart(_) => StatusCode::BAD_REQUEST,
|
|
||||||
Error::Database(_) => StatusCode::BAD_REQUEST,
|
Error::Database(_) => StatusCode::BAD_REQUEST,
|
||||||
Error::Email(_) => StatusCode::BAD_REQUEST,
|
Error::Email(_) => StatusCode::BAD_REQUEST,
|
||||||
Error::Fs(_) => StatusCode::BAD_REQUEST,
|
Error::Fs(_) => StatusCode::BAD_REQUEST,
|
||||||
|
@ -2,7 +2,6 @@ use actix::Addr;
|
|||||||
use actix_web::web::{scope, Data, Json, ServiceConfig};
|
use actix_web::web::{scope, Data, Json, ServiceConfig};
|
||||||
use actix_web::{delete, get, post, put, HttpRequest, HttpResponse};
|
use actix_web::{delete, get, post, put, HttpRequest, HttpResponse};
|
||||||
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
use actix_web_httpauth::extractors::bearer::BearerAuth;
|
||||||
use cart_manager::{query_cart, CartManager};
|
|
||||||
use database_manager::{query_db, Database};
|
use database_manager::{query_db, Database};
|
||||||
use model::api;
|
use model::api;
|
||||||
use order_manager::{query_order, OrderManager};
|
use order_manager::{query_order, OrderManager};
|
||||||
@ -96,24 +95,32 @@ async fn shopping_cart(
|
|||||||
|
|
||||||
#[put("/shopping-cart-item")]
|
#[put("/shopping-cart-item")]
|
||||||
async fn update_cart_item(
|
async fn update_cart_item(
|
||||||
cart: Data<Addr<CartManager>>,
|
cart: Data<channels::carts::rpc::CartsClient>,
|
||||||
tm: Data<Addr<TokenManager>>,
|
tm: Data<Addr<TokenManager>>,
|
||||||
credentials: BearerAuth,
|
credentials: BearerAuth,
|
||||||
Json(payload): Json<api::UpdateItemInput>,
|
Json(payload): Json<api::UpdateItemInput>,
|
||||||
) -> Result<Json<api::UpdateItemOutput>> {
|
) -> Result<Json<api::UpdateItemOutput>> {
|
||||||
|
use channels::carts::modify_item::Input;
|
||||||
let token = credentials.require_user(tm.into_inner()).await?;
|
let token = credentials.require_user(tm.into_inner()).await?;
|
||||||
|
|
||||||
let item: Option<model::ShoppingCartItem> = query_cart!(
|
let item = match cart
|
||||||
cart,
|
.modify_item(
|
||||||
cart_manager::ModifyItem {
|
tarpc::context::current(),
|
||||||
buyer_id: token.account_id(),
|
Input {
|
||||||
product_id: payload.product_id,
|
buyer_id: token.account_id(),
|
||||||
quantity: payload.quantity,
|
product_id: payload.product_id,
|
||||||
quantity_unit: payload.quantity_unit,
|
quantity: payload.quantity,
|
||||||
},
|
quantity_unit: payload.quantity_unit,
|
||||||
routes::Error::Public(super::Error::ModifyItem.into()),
|
},
|
||||||
routes::Error::Public(PublicError::DatabaseConnection)
|
)
|
||||||
);
|
.await
|
||||||
|
{
|
||||||
|
Ok(res) => res.item,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("{}", e);
|
||||||
|
return Err(routes::Error::CriticalFailure);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
match item {
|
match item {
|
||||||
Some(item) => Ok(Json(api::UpdateItemOutput {
|
Some(item) => Ok(Json(api::UpdateItemOutput {
|
||||||
@ -125,40 +132,63 @@ async fn update_cart_item(
|
|||||||
|
|
||||||
#[put("/shopping-cart")]
|
#[put("/shopping-cart")]
|
||||||
async fn update_cart(
|
async fn update_cart(
|
||||||
cart: Data<Addr<CartManager>>,
|
cart: Data<channels::carts::rpc::CartsClient>,
|
||||||
tm: Data<Addr<TokenManager>>,
|
tm: Data<Addr<TokenManager>>,
|
||||||
credentials: BearerAuth,
|
credentials: BearerAuth,
|
||||||
Json(payload): Json<api::UpdateCartInput>,
|
Json(payload): Json<api::UpdateCartInput>,
|
||||||
) -> Result<Json<api::UpdateCartOutput>> {
|
) -> Result<Json<api::UpdateCartOutput>> {
|
||||||
let token = credentials.require_user(tm.into_inner()).await?;
|
let token = credentials.require_user(tm.into_inner()).await?;
|
||||||
let items = payload
|
let items = {
|
||||||
.items
|
use channels::carts::modify_item::Input;
|
||||||
.into_iter()
|
payload
|
||||||
.map(
|
.items
|
||||||
|model::api::UpdateItemInput {
|
.into_iter()
|
||||||
product_id,
|
.map(
|
||||||
quantity,
|
|model::api::UpdateItemInput {
|
||||||
quantity_unit,
|
product_id,
|
||||||
}| cart_manager::ModifyItem {
|
quantity,
|
||||||
buyer_id: token.account_id(),
|
quantity_unit,
|
||||||
product_id,
|
}| Input {
|
||||||
quantity,
|
buyer_id: token.account_id(),
|
||||||
quantity_unit,
|
product_id,
|
||||||
},
|
quantity,
|
||||||
)
|
quantity_unit,
|
||||||
.collect();
|
},
|
||||||
|
)
|
||||||
|
.collect()
|
||||||
|
};
|
||||||
|
|
||||||
let res: cart_manager::ModifyCartResult = query_cart!(
|
use channels::carts::modify_cart::{Input, Output};
|
||||||
cart,
|
let res = {
|
||||||
cart_manager::ModifyCart {
|
match cart
|
||||||
buyer_id: token.account_id(),
|
.modify_cart(
|
||||||
items,
|
tarpc::context::current(),
|
||||||
checkout_notes: payload.notes,
|
Input {
|
||||||
payment_method: payload.payment_method,
|
buyer_id: token.account_id(),
|
||||||
},
|
items,
|
||||||
routes::Error::Public(super::Error::ModifyItem.into()),
|
checkout_notes: payload.notes,
|
||||||
routes::Error::Public(PublicError::DatabaseConnection)
|
payment_method: payload.payment_method,
|
||||||
);
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(Output {
|
||||||
|
cart: Some(cart), ..
|
||||||
|
}) => cart,
|
||||||
|
Ok(Output { error: Some(e), .. }) => {
|
||||||
|
tracing::error!("{}", e);
|
||||||
|
return Err(routes::Error::Public(super::Error::ModifyItem.into()));
|
||||||
|
}
|
||||||
|
Ok(out) => {
|
||||||
|
tracing::error!("invalid output {:?}", out);
|
||||||
|
return Err(routes::Error::Public(super::Error::ModifyItem.into()));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("{}", e);
|
||||||
|
return Err(routes::Error::Public(super::Error::ModifyItem.into()));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
Ok(Json(api::UpdateCartOutput {
|
Ok(Json(api::UpdateCartOutput {
|
||||||
cart_id: res.cart_id,
|
cart_id: res.cart_id,
|
||||||
@ -170,46 +200,68 @@ async fn update_cart(
|
|||||||
|
|
||||||
#[delete("/shopping-cart-item")]
|
#[delete("/shopping-cart-item")]
|
||||||
async fn delete_cart_item(
|
async fn delete_cart_item(
|
||||||
db: Data<Addr<Database>>,
|
cart: Data<channels::carts::rpc::CartsClient>,
|
||||||
cart: Data<Addr<CartManager>>,
|
|
||||||
tm: Data<Addr<TokenManager>>,
|
tm: Data<Addr<TokenManager>>,
|
||||||
credentials: BearerAuth,
|
credentials: BearerAuth,
|
||||||
Json(payload): Json<api::DeleteItemInput>,
|
Json(payload): Json<api::DeleteItemInput>,
|
||||||
) -> Result<HttpResponse> {
|
) -> Result<HttpResponse> {
|
||||||
let token = credentials.require_user(tm.into_inner()).await?;
|
let token = credentials.require_user(tm.into_inner()).await?;
|
||||||
|
|
||||||
let sc: model::ShoppingCart = query_db!(
|
let sc = {
|
||||||
db,
|
use channels::carts::active_shopping_cart::{Input, Output};
|
||||||
database_manager::EnsureActiveShoppingCart {
|
match cart
|
||||||
buyer_id: token.account_id(),
|
.active_shopping_cart(
|
||||||
},
|
tarpc::context::current(),
|
||||||
routes::Error::Public(super::Error::RemoveItem.into()),
|
Input {
|
||||||
routes::Error::Public(PublicError::DatabaseConnection)
|
buyer_id: token.account_id(),
|
||||||
);
|
},
|
||||||
|
)
|
||||||
match cart
|
.await
|
||||||
.into_inner()
|
{
|
||||||
.send(cart_manager::RemoveProduct {
|
Ok(Output {
|
||||||
shopping_cart_id: sc.id,
|
cart: Some(cart), ..
|
||||||
shopping_cart_item_id: payload.shopping_cart_item_id,
|
}) => cart,
|
||||||
})
|
Ok(Output { error: Some(e), .. }) => {
|
||||||
.await
|
tracing::error!("{}", e);
|
||||||
{
|
return Err(routes::Error::Public(super::Error::ModifyItem.into()));
|
||||||
Ok(Ok(_)) => Ok(HttpResponse::Ok().json(api::DeleteItemOutput { success: true })),
|
}
|
||||||
Ok(Err(e)) => {
|
Ok(out) => {
|
||||||
tracing::error!("{e}");
|
tracing::error!("invalid output {:?}", out);
|
||||||
Ok(HttpResponse::BadRequest().json(api::DeleteItemOutput { success: false }))
|
return Err(routes::Error::Public(super::Error::ModifyItem.into()));
|
||||||
|
}
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("{e}");
|
||||||
|
return Ok(
|
||||||
|
HttpResponse::BadRequest().json(api::DeleteItemOutput { success: false })
|
||||||
|
);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
Err(e) => {
|
};
|
||||||
tracing::error!("{e:?}");
|
|
||||||
Err(routes::Error::Public(PublicError::DatabaseConnection))
|
{
|
||||||
|
use channels::carts::remove_product::Input;
|
||||||
|
match cart
|
||||||
|
.remove_product(
|
||||||
|
tarpc::context::current(),
|
||||||
|
Input {
|
||||||
|
shopping_cart_id: sc.id,
|
||||||
|
shopping_cart_item_id: payload.shopping_cart_item_id,
|
||||||
|
},
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
|
Ok(_) => Ok(HttpResponse::Ok().json(api::DeleteItemOutput { success: true })),
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("{e:?}");
|
||||||
|
Err(routes::Error::Public(PublicError::DatabaseConnection))
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[get("/me")]
|
#[get("/me")]
|
||||||
pub(crate) async fn me(
|
pub(crate) async fn me(
|
||||||
account: Data<channels::account::rpc::AccountsClient>,
|
account: Data<channels::accounts::rpc::AccountsClient>,
|
||||||
tm: Data<Addr<TokenManager>>,
|
tm: Data<Addr<TokenManager>>,
|
||||||
credentials: BearerAuth,
|
credentials: BearerAuth,
|
||||||
) -> routes::Result<Json<model::api::Account>> {
|
) -> routes::Result<Json<model::api::Account>> {
|
||||||
@ -218,7 +270,13 @@ pub(crate) async fn me(
|
|||||||
.await?
|
.await?
|
||||||
.account_id();
|
.account_id();
|
||||||
|
|
||||||
match account.me(tarpc::context::current(), account_id).await {
|
match account
|
||||||
|
.me(
|
||||||
|
tarpc::context::current(),
|
||||||
|
channels::accounts::me::Input { account_id },
|
||||||
|
)
|
||||||
|
.await
|
||||||
|
{
|
||||||
Ok(me) => Ok(Json((me.account.unwrap(), me.addresses.unwrap()).into())),
|
Ok(me) => Ok(Json((me.account.unwrap(), me.addresses.unwrap()).into())),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("{}", e);
|
tracing::error!("{}", e);
|
||||||
|
@ -248,3 +248,28 @@ pub async fn modify_cart(
|
|||||||
})
|
})
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub async fn active_shopping_cart(
|
||||||
|
input: carts::active_shopping_cart::Input,
|
||||||
|
db: Database,
|
||||||
|
) -> carts::active_shopping_cart::Output {
|
||||||
|
use carts::active_shopping_cart::Output;
|
||||||
|
|
||||||
|
tracing::debug!("{:?}", input);
|
||||||
|
|
||||||
|
let mut t = begin_t!(db);
|
||||||
|
|
||||||
|
let dbm = crate::db::EnsureActiveShoppingCart {
|
||||||
|
buyer_id: input.buyer_id,
|
||||||
|
};
|
||||||
|
let cart = match dbm.run(&mut t).await {
|
||||||
|
Ok(cart) => cart,
|
||||||
|
Err(e) => {
|
||||||
|
tracing::error!("{}", e);
|
||||||
|
t.rollback().await.ok();
|
||||||
|
return Output::error(Error::NoActiveCart);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
end_t!(t, Output::cart(cart))
|
||||||
|
}
|
||||||
|
@ -33,13 +33,21 @@ impl Carts for CartsServer {
|
|||||||
crate::actions::modify_cart(input, self.db).await
|
crate::actions::modify_cart(input, self.db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn remove_cart(
|
async fn remove_product(
|
||||||
self,
|
self,
|
||||||
_: context::Context,
|
_: context::Context,
|
||||||
input: channels::carts::remove_product::Input,
|
input: channels::carts::remove_product::Input,
|
||||||
) -> channels::carts::remove_product::Output {
|
) -> channels::carts::remove_product::Output {
|
||||||
crate::actions::remove_product(input, self.db).await
|
crate::actions::remove_product(input, self.db).await
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn active_shopping_cart(
|
||||||
|
self,
|
||||||
|
_: context::Context,
|
||||||
|
input: channels::carts::active_shopping_cart::Input,
|
||||||
|
) -> channels::carts::active_shopping_cart::Output {
|
||||||
|
crate::actions::active_shopping_cart(input, self.db).await
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub async fn start(config: SharedAppConfig, db: Database, mqtt_client: AsyncClient) {
|
pub async fn start(config: SharedAppConfig, db: Database, mqtt_client: AsyncClient) {
|
||||||
|
@ -78,27 +78,6 @@ pub mod register {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// #[derive(Debug, thiserror::Error, serde::Serialize, serde::Deserialize)]
|
|
||||||
// pub enum AccountFailure {
|
|
||||||
// #[error("Failed to hash password")]
|
|
||||||
// FailedToHashPassword,
|
|
||||||
// #[error("Failed to save account")]
|
|
||||||
// SaveAccount,
|
|
||||||
// #[error("Internal server error")]
|
|
||||||
// InternalServerError,
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// impl TryFrom<bytes::Bytes> for AccountFailure {
|
|
||||||
// type Error = Error;
|
|
||||||
//
|
|
||||||
// fn try_from(value: bytes::Bytes) -> Result<Self, Self::Error> {
|
|
||||||
// bincode::deserialize(value.as_ref()).map_err(|e| {
|
|
||||||
// tracing::error!("{}", e);
|
|
||||||
// Error::InvalidAccountFailure
|
|
||||||
// })
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
|
|
||||||
pub mod me {
|
pub mod me {
|
||||||
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
pub struct Input {
|
pub struct Input {
|
||||||
|
@ -130,8 +130,41 @@ pub mod modify_cart {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub mod active_shopping_cart {
|
||||||
|
use super::Error;
|
||||||
|
|
||||||
|
#[derive(Debug, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Input {
|
||||||
|
pub buyer_id: model::AccountId,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[derive(Debug, Default, serde::Serialize, serde::Deserialize)]
|
||||||
|
pub struct Output {
|
||||||
|
pub error: Option<Error>,
|
||||||
|
pub cart: Option<model::ShoppingCart>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Output {
|
||||||
|
pub fn error(error: Error) -> Self {
|
||||||
|
Self {
|
||||||
|
error: Some(error),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn cart(cart: model::ShoppingCart) -> Self {
|
||||||
|
Self {
|
||||||
|
cart: Some(cart),
|
||||||
|
..Default::default()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
pub mod rpc {
|
pub mod rpc {
|
||||||
use super::{modify_cart, modify_item, remove_product};
|
use config::SharedAppConfig;
|
||||||
|
|
||||||
|
use super::{active_shopping_cart, modify_cart, modify_item, remove_product};
|
||||||
|
|
||||||
#[tarpc::service]
|
#[tarpc::service]
|
||||||
pub trait Carts {
|
pub trait Carts {
|
||||||
@ -141,7 +174,31 @@ pub mod rpc {
|
|||||||
/// Change entire shopping cart content.
|
/// Change entire shopping cart content.
|
||||||
async fn modify_cart(input: modify_cart::Input) -> modify_cart::Output;
|
async fn modify_cart(input: modify_cart::Input) -> modify_cart::Output;
|
||||||
|
|
||||||
/// Remove entire shopping cart.
|
/// Remove product from shopping cart.
|
||||||
async fn remove_cart(input: remove_product::Input) -> remove_product::Output;
|
async fn remove_product(input: remove_product::Input) -> remove_product::Output;
|
||||||
|
|
||||||
|
async fn active_shopping_cart(
|
||||||
|
input: active_shopping_cart::Input,
|
||||||
|
) -> active_shopping_cart::Output;
|
||||||
|
}
|
||||||
|
|
||||||
|
pub async fn create_client(config: SharedAppConfig) -> CartsClient {
|
||||||
|
use tarpc::client;
|
||||||
|
use tarpc::tokio_serde::formats::Bincode;
|
||||||
|
|
||||||
|
let addr = {
|
||||||
|
let l = config.lock();
|
||||||
|
(l.account_manager().bind.clone(), l.account_manager().port)
|
||||||
|
};
|
||||||
|
|
||||||
|
let transport = tarpc::serde_transport::tcp::connect(addr, Bincode::default);
|
||||||
|
|
||||||
|
let client = CartsClient::new(
|
||||||
|
client::Config::default(),
|
||||||
|
transport.await.expect("Failed to connect to server"),
|
||||||
|
)
|
||||||
|
.spawn();
|
||||||
|
|
||||||
|
client
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -5,7 +5,11 @@ use sonic_channel::{Dest, ObjDest, PushRequest, QueryRequest, SonicChannel};
|
|||||||
|
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! search_async_handler {
|
macro_rules! search_async_handler {
|
||||||
($msg: ty, $async: ident, $res: ty) => {
|
($msg: ty, async fn call($($argv: ident : $arg_t: ty,)*) -> Result<Option< $res: ty >> $body: block) => {
|
||||||
|
impl $msg {
|
||||||
|
async fn call ( $($argv : $arg_t,)* ) -> Result<Option< $res >> $body
|
||||||
|
}
|
||||||
|
|
||||||
impl actix::Handler<$msg> for SearchManager {
|
impl actix::Handler<$msg> for SearchManager {
|
||||||
type Result = actix::ResponseActFuture<Self, Result<Option<$res>>>;
|
type Result = actix::ResponseActFuture<Self, Result<Option<$res>>>;
|
||||||
|
|
||||||
@ -14,13 +18,13 @@ macro_rules! search_async_handler {
|
|||||||
match self.channels.clone() {
|
match self.channels.clone() {
|
||||||
Some(channels) => {
|
Some(channels) => {
|
||||||
let config = self.config.clone();
|
let config = self.config.clone();
|
||||||
Box::pin(async { $async(msg, channels, config).await }.into_actor(self))
|
Box::pin(async { <$msg>::call(msg, channels, config).await }.into_actor(self))
|
||||||
}
|
}
|
||||||
None => Box::pin(async { Ok(None) }.into_actor(self)),
|
None => Box::pin(async { Ok(None) }.into_actor(self)),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)]
|
#[derive(Debug, Copy, Clone, serde::Serialize, thiserror::Error)]
|
||||||
@ -91,28 +95,31 @@ pub struct Search {
|
|||||||
pub lang: String,
|
pub lang: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
search_async_handler!(Search, search, Vec<String>);
|
pub type StringList = Vec<String>;
|
||||||
|
|
||||||
pub(crate) async fn search(
|
search_async_handler!(
|
||||||
msg: Search,
|
Search,
|
||||||
channels: Channels,
|
async fn call(
|
||||||
_config: SharedAppConfig,
|
msg: Search,
|
||||||
) -> Result<Option<Vec<String>>> {
|
channels: Channels,
|
||||||
if let Ok(l) = channels.search.lock() {
|
_config: SharedAppConfig,
|
||||||
match l.query(QueryRequest::new(
|
) -> Result<Option<StringList>> {
|
||||||
Dest::col_buc(msg.collection, msg.lang),
|
if let Ok(l) = channels.search.lock() {
|
||||||
&msg.query,
|
match l.query(QueryRequest::new(
|
||||||
)) {
|
Dest::col_buc(msg.collection, msg.lang),
|
||||||
Ok(res) => Ok(Some(res)),
|
&msg.query,
|
||||||
Err(e) => {
|
)) {
|
||||||
tracing::error!("{e:?}");
|
Ok(res) => Ok(Some(res)),
|
||||||
Err(Error::QueryFailed)
|
Err(e) => {
|
||||||
|
tracing::error!("{e:?}");
|
||||||
|
Err(Error::QueryFailed)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(None)
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Ok(None)
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
|
||||||
#[derive(actix::Message)]
|
#[derive(actix::Message)]
|
||||||
#[rtype(result = "Result<Option<()>>")]
|
#[rtype(result = "Result<Option<()>>")]
|
||||||
@ -123,25 +130,26 @@ pub struct CreateIndex {
|
|||||||
pub lang: String,
|
pub lang: String,
|
||||||
}
|
}
|
||||||
|
|
||||||
search_async_handler!(CreateIndex, create_index, ());
|
search_async_handler!(
|
||||||
|
CreateIndex,
|
||||||
pub(crate) async fn create_index(
|
async fn call(
|
||||||
msg: CreateIndex,
|
msg: CreateIndex,
|
||||||
channels: Channels,
|
channels: Channels,
|
||||||
_config: SharedAppConfig,
|
_config: SharedAppConfig,
|
||||||
) -> Result<Option<()>> {
|
) -> Result<Option<()>> {
|
||||||
if let Ok(l) = channels.ingest.lock() {
|
if let Ok(l) = channels.ingest.lock() {
|
||||||
match l.push(PushRequest::new(
|
match l.push(PushRequest::new(
|
||||||
ObjDest::new(Dest::col_buc(msg.collection, msg.lang), &msg.key),
|
ObjDest::new(Dest::col_buc(msg.collection, msg.lang), &msg.key),
|
||||||
&msg.value,
|
&msg.value,
|
||||||
)) {
|
)) {
|
||||||
Ok(_) => Ok(Some(())),
|
Ok(_) => Ok(Some(())),
|
||||||
Err(e) => {
|
Err(e) => {
|
||||||
tracing::error!("{e:?}");
|
tracing::error!("{e:?}");
|
||||||
Err(Error::CantCreate)
|
Err(Error::CantCreate)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
Ok(Some(()))
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
Ok(Some(()))
|
|
||||||
}
|
}
|
||||||
}
|
);
|
||||||
|
Loading…
Reference in New Issue
Block a user