mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Implement factory in main database, close #80
This commit is contained in:
4
Cargo.lock
generated
4
Cargo.lock
generated
@@ -2546,9 +2546,13 @@ dependencies = [
|
||||
name = "oj_rc_database"
|
||||
version = "1.1.0"
|
||||
dependencies = [
|
||||
"async-trait",
|
||||
"itertools",
|
||||
"libfj",
|
||||
"oj_rc_factory",
|
||||
"sea-orm",
|
||||
"sea-orm-migration",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
|
||||
@@ -14531,7 +14531,7 @@
|
||||
},
|
||||
"factory": {
|
||||
"adapter": {
|
||||
"variant": "Arc",
|
||||
"variant": "BuiltIn",
|
||||
"uri": "sqlite:../data/robocraft/rc_archive.db?mode=ro"
|
||||
}
|
||||
},
|
||||
|
||||
@@ -149,8 +149,8 @@ impl std::convert::From<oj_rc_factory::VehicleQueryInfo> for ItemResult {
|
||||
combat_rating: value.combat_rating,
|
||||
cpu: value.cpu as i32,
|
||||
total_robot_ranking: value.total_robot_ranking as i32,
|
||||
//expiry_date: ticks_from_now(&value.expiry_date),
|
||||
expiry_date: i32::MAX as _,
|
||||
expiry_date: ticks_from_now(&value.expiry_date),
|
||||
//expiry_date: i32::MAX as _,
|
||||
buyable: value.buyable,
|
||||
added_by: value.added_by,
|
||||
added_by_display_name: value.added_by_display_name,
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
pub enum Factory {
|
||||
Arc(oj_rc_factory::arc::ArcAdapter),
|
||||
Primary(oj_rc_database::FactoryDatabase),
|
||||
Custom(Box<dyn oj_rc_factory::VehicleFactoryAdapter + Send + Sync + 'static>),
|
||||
None,
|
||||
}
|
||||
@@ -9,6 +10,7 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn vehicle(&self, id: i32) -> Result<Option<(oj_rc_factory::VehicleInfo, oj_rc_factory::VehicleQueryInfo)>, Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.vehicle(id).await,
|
||||
Self::Primary(x) => x.vehicle(id).await,
|
||||
Self::Custom(x) => x.vehicle(id).await,
|
||||
Self::None => Ok(None),
|
||||
}
|
||||
@@ -17,6 +19,7 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn list(&self, query: libfj::robocraft::ListQuery) -> Result<Vec<oj_rc_factory::VehicleQueryInfo>, Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.list(query).await,
|
||||
Self::Primary(x) => x.list(query).await,
|
||||
Self::Custom(x) => x.list(query).await,
|
||||
Self::None => Ok(Vec::default()),
|
||||
}
|
||||
@@ -25,6 +28,7 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn upload(&self, vehicle: oj_rc_factory::VehicleUploadInfo) -> Result<oj_rc_factory::VehicleThumbnailInfo, Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.upload(vehicle).await,
|
||||
Self::Primary(x) => x.upload(vehicle).await,
|
||||
Self::Custom(x) => x.upload(vehicle).await,
|
||||
Self::None => Ok(oj_rc_factory::VehicleThumbnailInfo {
|
||||
id: i32::MIN,
|
||||
@@ -37,6 +41,7 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn rate_vehicle(&self, id: i32, combat: i32, cosmetic: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.rate_vehicle(id, combat, cosmetic).await,
|
||||
Self::Primary(x) => x.rate_vehicle(id, combat, cosmetic).await,
|
||||
Self::Custom(x) => x.rate_vehicle(id, combat, cosmetic).await,
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
@@ -45,6 +50,7 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn purchase(&self, id: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.purchase(id).await,
|
||||
Self::Primary(x) => x.purchase(id).await,
|
||||
Self::Custom(x) => x.purchase(id).await,
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
@@ -53,14 +59,25 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
async fn update_vehicle(&self, id: i32, cube_data: Option<Vec<u8>>, colour_data: Option<Vec<u8>>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.update_vehicle(id, cube_data, colour_data).await,
|
||||
Self::Primary(x) => x.update_vehicle(id, cube_data, colour_data).await,
|
||||
Self::Custom(x) => x.update_vehicle(id, cube_data, colour_data).await,
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn remove_vehicle(&self, id: i32, user_id: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.remove_vehicle(id, user_id).await,
|
||||
Self::Primary(x) => x.remove_vehicle(id, user_id).await,
|
||||
Self::Custom(x) => x.remove_vehicle(id, user_id).await,
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
}
|
||||
|
||||
async fn set_featured(&self, id: i32, is_featured: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
match self {
|
||||
Self::Arc(x) => x.set_featured(id, is_featured).await,
|
||||
Self::Primary(x) => x.set_featured(id, is_featured).await,
|
||||
Self::Custom(x) => x.set_featured(id, is_featured).await,
|
||||
Self::None => Ok(()),
|
||||
}
|
||||
@@ -68,9 +85,10 @@ impl oj_rc_factory::VehicleFactoryAdapter for Factory {
|
||||
}
|
||||
|
||||
impl Factory {
|
||||
pub async fn from_config(conf: &crate::persist::FactoryConfig, settings: &crate::persist::config::ServerConfig) -> Result<Self, Box<dyn std::error::Error + 'static>> {
|
||||
pub async fn from_config(conf: &crate::persist::FactoryConfig, settings: &crate::persist::config::ServerConfig, builtin_factory_provider: &(dyn (Fn() -> oj_rc_database::FactoryDatabase) + Sync)) -> Result<Self, Box<dyn std::error::Error + 'static>> {
|
||||
Ok(match &conf.adapter {
|
||||
crate::persist::AdapterSettings::Arc(x) => Self::Arc(oj_rc_factory::arc::ArcAdapter::init(&x.uri, x.show_expired, settings.cdn_url.to_owned(), x.override_cdn, x.spoof_username).await?),
|
||||
crate::persist::AdapterSettings::BuiltIn => Self::Primary(builtin_factory_provider()),
|
||||
crate::persist::AdapterSettings::None => Self::None,
|
||||
})
|
||||
}
|
||||
|
||||
@@ -310,8 +310,8 @@ impl <C: Clone + Send> super::ConfigProvider<C> for CubeConfig {
|
||||
}
|
||||
}
|
||||
|
||||
async fn factory(&self) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>> {
|
||||
crate::factory::Factory::from_config(&self.factory, &<Self as super::ConfigProvider<()>>::server_config(self)).await
|
||||
async fn factory(&self, builtin_factory_provider: &(dyn (Fn() -> oj_rc_database::FactoryDatabase) + Sync)) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>> {
|
||||
crate::factory::Factory::from_config(&self.factory, &<Self as super::ConfigProvider<()>>::server_config(self), builtin_factory_provider).await
|
||||
}
|
||||
|
||||
fn cubes(&self) -> &'_ indexmap::IndexMap<String, crate::persist::Cube> {
|
||||
|
||||
@@ -20,7 +20,7 @@ pub trait ConfigProvider<C: Clone> {
|
||||
fn public_channels(&self) -> Typed<C>;
|
||||
fn server_config(&self) -> ServerConfig;
|
||||
fn garage_upgrades(&self) -> GarageUpgrades;
|
||||
async fn factory(&self) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>>;
|
||||
async fn factory(&self, builtin_factory_provider: &(dyn (Fn() -> oj_rc_database::FactoryDatabase) + Sync)) -> Result<crate::factory::Factory, Box<dyn std::error::Error + 'static>>;
|
||||
fn cubes(&self) -> &'_ indexmap::IndexMap<String, crate::persist::Cube>;
|
||||
fn chat_system_config(&self) -> ChatSystemConfig;
|
||||
fn gamemode_events(&self) -> GameEventSequence;
|
||||
|
||||
@@ -41,6 +41,10 @@ impl AccountProvider {
|
||||
})
|
||||
}
|
||||
|
||||
pub fn factory_impl(&self) -> oj_rc_database::FactoryDatabase {
|
||||
self.db.vehicle_factory(self.cdn.clone())
|
||||
}
|
||||
|
||||
pub async fn multiplayer_init(&self) -> Result<(), oj_rc_database::sea_orm::DbErr> {
|
||||
self.db.complete_all_games().await
|
||||
}
|
||||
|
||||
@@ -6,6 +6,10 @@ fn u64_negative_on_err<E>(result: Result<u64, E>) -> i64 {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl super::CommonUser for UserData {
|
||||
fn account_id(&self) -> i32 {
|
||||
self.account.id
|
||||
}
|
||||
|
||||
fn public_id(&self) -> &'_ str {
|
||||
&self.account.public_id
|
||||
}
|
||||
|
||||
@@ -23,6 +23,8 @@ impl super::FactoryUser for UserData {
|
||||
thumbnail: vehicle.thumbnail,
|
||||
added_by: self.account.public_id.clone(),
|
||||
added_by_display_name: self.account.display_name.clone(),
|
||||
added_by_id: self.account.id,
|
||||
garage_id: slot.id,
|
||||
cpu: slot.total_robot_cpu as u32,
|
||||
total_robot_ranking: slot.total_robot_ranking as u32,
|
||||
build_version: vehicle.version,
|
||||
|
||||
@@ -410,6 +410,7 @@ pub struct ResolvedVehicle {
|
||||
|
||||
#[async_trait::async_trait]
|
||||
pub trait CommonUser: Send + Sync {
|
||||
fn account_id(&self) -> i32;
|
||||
async fn resolve_config_vehicle(&self, vehicle: &crate::persist::config::VehicleInfo, factory: &dyn oj_rc_factory::VehicleFactoryAdapter, weapon_order: &crate::cubes::WeaponListParser, cpu_counter: &crate::cubes::CpuListParser) -> Result<ResolvedVehicle, polariton_server::operations::SimpleOpError>;
|
||||
fn public_id(&self) -> &'_ str;
|
||||
fn is_mod(&self) -> bool;
|
||||
|
||||
@@ -23,6 +23,8 @@ fn default_variant() -> AdapterSettings {
|
||||
pub enum AdapterSettings {
|
||||
#[serde(alias = "sqlite")]
|
||||
Arc(ArcFactorySettings),
|
||||
#[serde(alias = "integrated")]
|
||||
BuiltIn,
|
||||
None,
|
||||
}
|
||||
|
||||
|
||||
@@ -12,9 +12,14 @@ all_databases = ["mysql", "postgres", "sqlite"]
|
||||
mysql = [ "sea-orm/sqlx-mysql" ]
|
||||
postgres = [ "sea-orm/sqlx-postgres" ]
|
||||
sqlite = [ "sea-orm/sqlx-sqlite" ]
|
||||
default = [ "all_databases" ]
|
||||
default = [ "all_databases", "factory" ]
|
||||
factory = [ "oj_rc_factory", "libfj", "async-trait", "sea-orm/with-chrono", "serde_json" ]
|
||||
|
||||
[dependencies]
|
||||
sea-orm = { version = "1.1.10", features = [ "runtime-tokio-rustls", "macros" ] }
|
||||
sea-orm-migration = "1.1.10"
|
||||
itertools = "0.14"
|
||||
oj_rc_factory = { version = "*", path = "../rc_factory", optional = true }
|
||||
async-trait = { workspace = true, optional = true }
|
||||
libfj = { workspace = true, optional = true }
|
||||
serde_json = { workspace = true, optional = true }
|
||||
|
||||
368
rc_database/src/factory_wrapper.rs
Normal file
368
rc_database/src/factory_wrapper.rs
Normal file
@@ -0,0 +1,368 @@
|
||||
use oj_rc_factory::{VehicleFactoryAdapter, VehicleInfo, VehicleQueryInfo, VehicleThumbnailInfo, VehicleUploadInfo};
|
||||
use sea_orm::{ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, sqlx::types::chrono, ActiveModelTrait, TransactionTrait};
|
||||
|
||||
pub struct FactoryDatabase {
|
||||
orm: std::sync::Arc<sea_orm::DatabaseConnection>,
|
||||
cdn: std::sync::Arc<String>,
|
||||
upload_duration: std::time::Duration,
|
||||
}
|
||||
|
||||
impl FactoryDatabase {
|
||||
pub async fn init(uri: &str, cdn: std::sync::Arc<String>) -> Result<Self, sea_orm::DbErr>{
|
||||
let db = sea_orm::Database::connect(uri).await?;
|
||||
Ok(Self {
|
||||
orm: std::sync::Arc::new(db),
|
||||
cdn,
|
||||
upload_duration: std::time::Duration::from_secs(365 * 24 * 60 * 60), // 1 year
|
||||
})
|
||||
}
|
||||
|
||||
pub fn init_preconnected(orm: std::sync::Arc<sea_orm::DatabaseConnection>, cdn: std::sync::Arc<String>) -> Self {
|
||||
Self {
|
||||
orm,
|
||||
cdn,
|
||||
upload_duration: std::time::Duration::from_secs(365 * 24 * 60 * 60), // 1 year
|
||||
}
|
||||
}
|
||||
|
||||
async fn full_vehicle_by_id(&self, id: i32) -> Result<Option<(crate::schema::factory::vehicle::Model, crate::schema::user::Model)>, sea_orm::DbErr> {
|
||||
Ok(crate::schema::factory::vehicle::Entity::find_by_id(id)
|
||||
.find_also_related(crate::schema::user::Entity)
|
||||
.one(self.orm.as_ref())
|
||||
.await?
|
||||
.and_then(|(vehicle, user_opt)| user_opt.map(|user| (vehicle, user))))
|
||||
}
|
||||
|
||||
async fn list_query(&self, query: libfj::robocraft::ListQuery) -> Result<Vec<(crate::schema::factory::vehicle_query::VehicleInfo, crate::schema::factory::vehicle_query::VehicleOwnerInfo)>, sea_orm::DbErr> {
|
||||
let mut query_builder = crate::schema::factory::vehicle::Entity::find()
|
||||
.filter(crate::schema::factory::vehicle::Column::RemovedDate.is_null())
|
||||
.filter(crate::schema::factory::vehicle::Column::BanDate.is_null())
|
||||
.filter(crate::schema::factory::vehicle::Column::Buyable.eq(true));
|
||||
|
||||
match query.order {
|
||||
libfj::robocraft::FactoryOrderType::Suggested => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::GetCount); },
|
||||
libfj::robocraft::FactoryOrderType::CombatRating => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::CombatRating); },
|
||||
libfj::robocraft::FactoryOrderType::CosmeticRating => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::CosmeticRating); },
|
||||
libfj::robocraft::FactoryOrderType::Added => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::AddedTime); },
|
||||
libfj::robocraft::FactoryOrderType::CPU => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::Cpu); },
|
||||
libfj::robocraft::FactoryOrderType::MostBought => { query_builder = query_builder.order_by_desc(crate::schema::factory::vehicle::Column::GetCount); },
|
||||
}
|
||||
|
||||
if !query.text_filter.is_empty() {
|
||||
let query_text = format!("%{}%", query.text_filter.replace('%', ""));
|
||||
if query.player_filter {
|
||||
query_builder = query_builder.filter(
|
||||
sea_orm::sea_query::Condition::any()
|
||||
.add(crate::schema::user::Column::PublicId.like(query_text.clone()))
|
||||
.add(crate::schema::user::Column::DisplayName.like(query_text))
|
||||
);
|
||||
} else {
|
||||
match query.text_search_field {
|
||||
libfj::robocraft::FactoryTextSearchField::All => {
|
||||
query_builder = query_builder.filter(
|
||||
sea_orm::sea_query::Condition::any()
|
||||
.add(crate::schema::user::Column::PublicId.like(query_text.clone()))
|
||||
.add(crate::schema::user::Column::DisplayName.like(query_text.clone()))
|
||||
.add(crate::schema::factory::vehicle::Column::Name.like(query_text.clone()))
|
||||
.add(crate::schema::factory::vehicle::Column::Description.like(query_text))
|
||||
);
|
||||
},
|
||||
libfj::robocraft::FactoryTextSearchField::Name => {
|
||||
query_builder = query_builder.filter(
|
||||
sea_orm::sea_query::Condition::any()
|
||||
.add(crate::schema::factory::vehicle::Column::Name.like(query_text.clone()))
|
||||
);
|
||||
},
|
||||
libfj::robocraft::FactoryTextSearchField::Player => {
|
||||
query_builder = query_builder.filter(
|
||||
sea_orm::sea_query::Condition::any()
|
||||
.add(crate::schema::user::Column::PublicId.like(query_text.clone()))
|
||||
.add(crate::schema::user::Column::DisplayName.like(query_text))
|
||||
);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
// TODO support movement and weapon filters
|
||||
if query.minimum_cpu > 0 {
|
||||
query_builder = query_builder.filter(crate::schema::factory::vehicle::Column::Cpu.gte(query.minimum_cpu as u32));
|
||||
}
|
||||
if query.maximum_cpu < usize::MAX {
|
||||
query_builder = query_builder.filter(crate::schema::factory::vehicle::Column::Cpu.lte(query.maximum_cpu as u32));
|
||||
}
|
||||
|
||||
let query_builder = query_builder
|
||||
.find_also_related(crate::schema::user::Entity)
|
||||
.select_only()
|
||||
// WARNING: jank sea_orm query generation (fix)
|
||||
.column_as(crate::schema::factory::vehicle::Column::Id, "A_id")
|
||||
.column_as(crate::schema::factory::vehicle::Column::UserId, "A_user_id")
|
||||
.column_as(crate::schema::factory::vehicle::Column::CreationTime, "A_creation_time")
|
||||
.column_as(crate::schema::factory::vehicle::Column::Name, "A_name")
|
||||
.column_as(crate::schema::factory::vehicle::Column::Description, "A_description")
|
||||
.column_as(crate::schema::factory::vehicle::Column::AddedTime, "A_added_time")
|
||||
.column_as(crate::schema::factory::vehicle::Column::ExpiryTime, "A_expiry_time")
|
||||
.column_as(crate::schema::factory::vehicle::Column::Cpu, "A_cpu")
|
||||
.column_as(crate::schema::factory::vehicle::Column::TotalRobotRanking, "A_total_robot_ranking")
|
||||
.column_as(crate::schema::factory::vehicle::Column::GetCount, "A_get_count")
|
||||
.column_as(crate::schema::factory::vehicle::Column::Buyable, "A_buyable")
|
||||
.column_as(crate::schema::factory::vehicle::Column::RemovedDate, "A_removed_date")
|
||||
.column_as(crate::schema::factory::vehicle::Column::BanDate, "A_ban_date")
|
||||
.column_as(crate::schema::factory::vehicle::Column::Featured, "A_featured")
|
||||
.column_as(crate::schema::factory::vehicle::Column::BannerMessage, "A_banner_message")
|
||||
.column_as(crate::schema::factory::vehicle::Column::CombatRating, "A_combat_rating")
|
||||
.column_as(crate::schema::factory::vehicle::Column::CosmeticRating, "A_cosmetic_rating")
|
||||
.column_as(crate::schema::factory::vehicle::Column::CubeAmounts, "A_cube_amounts")
|
||||
.column_as(crate::schema::user::Column::PublicId, "B_public_id")
|
||||
.column_as(crate::schema::user::Column::DisplayName, "B_display_name")
|
||||
.into_model::<crate::schema::factory::vehicle_query::VehicleInfo, crate::schema::factory::vehicle_query::VehicleOwnerInfo>();
|
||||
//.into_partial_model::<crate::schema::factory::vehicle_query::VehicleInfo, crate::schema::factory::vehicle_query::VehicleOwnerInfo>();
|
||||
let pagination = query_builder.paginate(self.orm.as_ref(), query.page_size as u64);
|
||||
Ok(pagination.fetch_page((query.page - 1) as u64).await?
|
||||
.into_iter()
|
||||
.filter_map(|(vehicle, user_opt)| user_opt.map(|user| (vehicle, user)))
|
||||
.collect())
|
||||
}
|
||||
|
||||
fn thumbnail_url(&self, id: i32) -> String {
|
||||
format!("{}/roboshop/Live/{}", self.cdn, id)
|
||||
}
|
||||
|
||||
fn calculate_cube_amounts(&self, data: &[u8]) -> String {
|
||||
let mut counts: std::collections::HashMap<u32, u32> = std::collections::HashMap::new();
|
||||
let data = &data[4..];
|
||||
for chunk in data.chunks_exact(8) {
|
||||
let id_bytes: [u8; 4] = chunk[0..4].try_into().unwrap();
|
||||
let part_id = u32::from_le_bytes(id_bytes);
|
||||
|
||||
*counts.entry(part_id).or_insert(0) += 1;
|
||||
}
|
||||
let mut str_map: std::collections::HashMap<String, u32> = std::collections::HashMap::new();
|
||||
for (k, v) in counts {
|
||||
str_map.insert(k.to_string(), v);
|
||||
}
|
||||
|
||||
serde_json::to_string(&str_map).unwrap_or_else(|_| "{}".to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl VehicleFactoryAdapter for FactoryDatabase {
|
||||
async fn vehicle(&self, id: i32) -> Result<Option<(VehicleInfo, VehicleQueryInfo)>, Box<dyn std::error::Error>> {
|
||||
let entities = self.full_vehicle_by_id(id).await?;
|
||||
Ok(entities.map(|(vehicle, user)| (
|
||||
VehicleInfo {
|
||||
id,
|
||||
cube_data: vehicle.cube_data,
|
||||
colour_data: vehicle.colour_data,
|
||||
},
|
||||
VehicleQueryInfo {
|
||||
id,
|
||||
name: vehicle.name,
|
||||
description: vehicle.description,
|
||||
thumbnail: self.thumbnail_url(id),
|
||||
added_by: user.public_id,
|
||||
added_by_display_name: user.display_name,
|
||||
added_date: vehicle.added_time.and_utc(),
|
||||
expiry_date: vehicle.expiry_time.and_utc(),
|
||||
cpu: vehicle.cpu as _,
|
||||
total_robot_ranking: vehicle.total_robot_ranking as _,
|
||||
rent_count: vehicle.get_count as _,
|
||||
buy_count: vehicle.get_count as _,
|
||||
removed_date: vehicle.removed_date.map(|t| t.and_utc()),
|
||||
ban_date: vehicle.ban_date.map(|t| t.and_utc()),
|
||||
featured: vehicle.featured,
|
||||
buyable: vehicle.buyable,
|
||||
banner_message: vehicle.banner_message,
|
||||
combat_rating: vehicle.combat_rating,
|
||||
cosmetic_rating: vehicle.cosmetic_rating,
|
||||
cube_amounts: serde_json::from_str(&vehicle.cube_amounts).unwrap_or_default(),
|
||||
},
|
||||
)))
|
||||
}
|
||||
|
||||
async fn list(&self, query: libfj::robocraft::ListQuery) -> Result<Vec<VehicleQueryInfo>, Box<dyn std::error::Error>> {
|
||||
let entities = self.list_query(query).await?;
|
||||
Ok(entities.into_iter().map(|(vehicle, user)| VehicleQueryInfo {
|
||||
id: vehicle.id,
|
||||
name: vehicle.name,
|
||||
description: vehicle.description,
|
||||
thumbnail: self.thumbnail_url(vehicle.id),
|
||||
added_by: user.public_id,
|
||||
added_by_display_name: user.display_name,
|
||||
added_date: vehicle.added_time.and_utc(),
|
||||
expiry_date: vehicle.expiry_time.and_utc(),
|
||||
cpu: vehicle.cpu as _,
|
||||
total_robot_ranking: vehicle.total_robot_ranking as _,
|
||||
rent_count: vehicle.get_count as _,
|
||||
buy_count: vehicle.get_count as _,
|
||||
removed_date: vehicle.removed_date.map(|t| t.and_utc()),
|
||||
ban_date: vehicle.ban_date.map(|t| t.and_utc()),
|
||||
featured: vehicle.featured,
|
||||
buyable: vehicle.buyable,
|
||||
banner_message: vehicle.banner_message,
|
||||
combat_rating: vehicle.combat_rating,
|
||||
cosmetic_rating: vehicle.cosmetic_rating,
|
||||
cube_amounts: serde_json::from_str(&vehicle.cube_amounts).unwrap_or_default(),
|
||||
}).collect())
|
||||
}
|
||||
|
||||
async fn upload(&self, vehicle: VehicleUploadInfo) -> Result<VehicleThumbnailInfo, Box<dyn std::error::Error>> {
|
||||
let now = chrono::Utc::now();
|
||||
let entity = crate::schema::factory::vehicle::ActiveModel {
|
||||
id: sea_orm::ActiveValue::NotSet,
|
||||
user_id: sea_orm::ActiveValue::Set(vehicle.added_by_id),
|
||||
garage_id: sea_orm::ActiveValue::Set(vehicle.garage_id),
|
||||
creation_time: sea_orm::ActiveValue::Set(now.timestamp()),
|
||||
name: sea_orm::ActiveValue::Set(vehicle.name),
|
||||
description: sea_orm::ActiveValue::Set(vehicle.description),
|
||||
added_time: sea_orm::ActiveValue::Set(now.naive_utc()),
|
||||
expiry_time: sea_orm::ActiveValue::Set((now + self.upload_duration).naive_utc()),
|
||||
cpu: sea_orm::ActiveValue::Set(vehicle.cpu as i32),
|
||||
total_robot_ranking: sea_orm::ActiveValue::Set(vehicle.total_robot_ranking as i32),
|
||||
get_count: sea_orm::ActiveValue::Set(0),
|
||||
buyable: sea_orm::ActiveValue::Set(true),
|
||||
removed_date: sea_orm::ActiveValue::Set(None),
|
||||
ban_date: sea_orm::ActiveValue::Set(None),
|
||||
featured: sea_orm::ActiveValue::Set(false),
|
||||
banner_message: sea_orm::ActiveValue::Set(None),
|
||||
combat_rating: sea_orm::ActiveValue::Set(2.5),
|
||||
cosmetic_rating: sea_orm::ActiveValue::Set(2.5),
|
||||
cube_amounts: sea_orm::ActiveValue::Set(self.calculate_cube_amounts(&vehicle.cube_data)),
|
||||
cube_data: sea_orm::ActiveValue::Set(vehicle.cube_data),
|
||||
colour_data: sea_orm::ActiveValue::Set(vehicle.colour_data),
|
||||
};
|
||||
let saved_entity = entity.insert(self.orm.as_ref()).await?;
|
||||
Ok(VehicleThumbnailInfo {
|
||||
id: saved_entity.id,
|
||||
thumbnail: vehicle.thumbnail,
|
||||
needs_upload: true,
|
||||
})
|
||||
}
|
||||
|
||||
async fn rate_vehicle(&self, id: i32, combat: i32, cosmetic: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let result = self.orm.as_ref().transaction::<'_, '_, _, (), sea_orm::DbErr>(|txn| {
|
||||
Box::pin(async move {
|
||||
let select_q = crate::schema::factory::vehicle::Entity::find_by_id(id)
|
||||
.select_only()
|
||||
.columns([
|
||||
crate::schema::factory::vehicle::Column::CombatRating,
|
||||
crate::schema::factory::vehicle::Column::CosmeticRating,
|
||||
crate::schema::factory::vehicle::Column::GetCount,
|
||||
])
|
||||
.into_tuple::<(f64, f64, i32)>();
|
||||
if let Some((curr_combat_rating, curr_cosmetic_rating, get_count)) = select_q.one(txn).await? {
|
||||
let get_count = get_count.clamp(1, 100) as f64;
|
||||
let next_combat_rating = curr_combat_rating + (((combat as f64) - curr_combat_rating) / get_count);
|
||||
let next_cosmetic_rating = curr_cosmetic_rating + (((cosmetic as f64) - curr_cosmetic_rating) / get_count);
|
||||
crate::schema::factory::vehicle::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id),
|
||||
cosmetic_rating: sea_orm::ActiveValue::Set(next_cosmetic_rating),
|
||||
combat_rating: sea_orm::ActiveValue::Set(next_combat_rating),
|
||||
..Default::default()
|
||||
}.update(txn).await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}).await;
|
||||
if let Err(e) = result {
|
||||
return match e {
|
||||
sea_orm::TransactionError::Connection(x) => Err(x.into()),
|
||||
sea_orm::TransactionError::Transaction(x) => Err(x.into()),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
/// Just update any purchase trackers
|
||||
async fn purchase(&self, id: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
crate::schema::factory::vehicle::Entity::update_many()
|
||||
.col_expr(crate::schema::factory::vehicle::Column::GetCount, crate::schema::factory::vehicle::Column::GetCount.into_expr().add(1))
|
||||
.filter(crate::schema::factory::vehicle::Column::Id.eq(id))
|
||||
.exec(self.orm.as_ref()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn update_vehicle(&self, id: i32, cube_data: Option<Vec<u8>>, colour_data: Option<Vec<u8>>) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let cube_amounts = if let Some(cube_data) = &cube_data {
|
||||
sea_orm::ActiveValue::Set(self.calculate_cube_amounts(cube_data))
|
||||
} else {
|
||||
sea_orm::ActiveValue::NotSet
|
||||
};
|
||||
let result = self.orm.as_ref().transaction::<'_, '_, _, (), sea_orm::DbErr>(|txn| {
|
||||
Box::pin(async move {
|
||||
let select_q = crate::schema::factory::vehicle::Entity::find_by_id(id)
|
||||
.select_only()
|
||||
.columns([
|
||||
crate::schema::factory::vehicle::Column::Id,
|
||||
]);
|
||||
if select_q.count(txn).await? == 1 {
|
||||
let mut to_update = crate::schema::factory::vehicle::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id),
|
||||
cube_amounts,
|
||||
..Default::default()
|
||||
};
|
||||
if let Some(cube_data) = cube_data {
|
||||
to_update.cube_data = sea_orm::ActiveValue::Set(cube_data);
|
||||
}
|
||||
if let Some(colour_data) = colour_data {
|
||||
to_update.colour_data = sea_orm::ActiveValue::Set(colour_data);
|
||||
}
|
||||
to_update.update(txn).await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}).await;
|
||||
if let Err(e) = result {
|
||||
return match e {
|
||||
sea_orm::TransactionError::Connection(x) => Err(x.into()),
|
||||
sea_orm::TransactionError::Transaction(x) => Err(x.into()),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_vehicle(&self, id: i32, user_id: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
let now = chrono::Utc::now();
|
||||
let result = self.orm.as_ref().transaction::<'_, '_, _, (), sea_orm::DbErr>(|txn| {
|
||||
Box::pin(async move {
|
||||
let select_q = crate::schema::factory::vehicle::Entity::find_by_id(id)
|
||||
.select_only()
|
||||
.columns([
|
||||
crate::schema::factory::vehicle::Column::Id,
|
||||
crate::schema::factory::vehicle::Column::UserId,
|
||||
])
|
||||
.into_tuple::<(i32, i32)>();
|
||||
if let Some((_selected_id, selected_user_id)) = select_q.one(txn).await? {
|
||||
if selected_user_id != user_id {
|
||||
//log::warn!("User {} tried to remove factory vehicle owned by {}", user_id, selected_user_id);
|
||||
return Ok(());
|
||||
}
|
||||
crate::schema::factory::vehicle::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id),
|
||||
buyable: sea_orm::ActiveValue::Set(false),
|
||||
removed_date: sea_orm::ActiveValue::Set(Some(now.naive_utc())),
|
||||
..Default::default()
|
||||
}.update(txn).await?;
|
||||
}
|
||||
Ok(())
|
||||
})
|
||||
}).await;
|
||||
if let Err(e) = result {
|
||||
return match e {
|
||||
sea_orm::TransactionError::Connection(x) => Err(x.into()),
|
||||
sea_orm::TransactionError::Transaction(x) => Err(x.into()),
|
||||
};
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_featured(&self, id: i32, is_featured: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
crate::schema::factory::vehicle::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id),
|
||||
featured: sea_orm::ActiveValue::Set(is_featured),
|
||||
..Default::default()
|
||||
}.update(self.orm.as_ref()).await?;
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@@ -9,4 +9,9 @@ pub use wrapper::Database;
|
||||
mod metrics;
|
||||
pub use metrics::DatabaseMetrics;
|
||||
|
||||
#[cfg(feature = "factory")]
|
||||
mod factory_wrapper;
|
||||
#[cfg(feature = "factory")]
|
||||
pub use factory_wrapper::FactoryDatabase;
|
||||
|
||||
pub use sea_orm;
|
||||
|
||||
@@ -0,0 +1,69 @@
|
||||
use sea_orm_migration::prelude::*;
|
||||
|
||||
pub struct Migration;
|
||||
|
||||
impl MigrationName for Migration {
|
||||
fn name(&self) -> &str {
|
||||
"m20260126_000001_create_factory_vehicle_table"
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl MigrationTrait for Migration {
|
||||
// Define how to apply this migration: Create the Factory Vehicles table.
|
||||
async fn up(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.create_table(
|
||||
Table::create()
|
||||
.table(crate::schema::factory::vehicle::Entity)
|
||||
.col(
|
||||
ColumnDef::new(crate::schema::factory::vehicle::Column::Id)
|
||||
.integer()
|
||||
.not_null()
|
||||
.auto_increment()
|
||||
.primary_key(),
|
||||
)
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::UserId).integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk-factory_vehicles-user_id")
|
||||
.from(crate::schema::factory::vehicle::Entity, crate::schema::factory::vehicle::Column::UserId)
|
||||
.to(crate::schema::user::Entity, crate::schema::user::Column::Id),
|
||||
)
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::GarageId).integer().not_null())
|
||||
.foreign_key(
|
||||
ForeignKey::create()
|
||||
.name("fk-factory_vehicles-garage_id")
|
||||
.from(crate::schema::factory::vehicle::Entity, crate::schema::factory::vehicle::Column::GarageId)
|
||||
.to(crate::schema::garage::Entity, crate::schema::garage::Column::Id),
|
||||
)
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::CreationTime).big_integer().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::Name).string().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::Description).string().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::AddedTime).date_time().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::ExpiryTime).date_time().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::Cpu).integer().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::TotalRobotRanking).integer().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::GetCount).integer().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::Buyable).boolean().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::RemovedDate).date_time().null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::BanDate).date_time().null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::Featured).boolean().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::BannerMessage).string().null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::CombatRating).double().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::CosmeticRating).double().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::CubeAmounts).string().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::CubeData).binary().not_null())
|
||||
.col(ColumnDef::new(crate::schema::factory::vehicle::Column::ColourData).binary().not_null())
|
||||
.to_owned(),
|
||||
)
|
||||
.await
|
||||
}
|
||||
|
||||
// Define how to rollback this migration: Drop the Factory Vehicles table.
|
||||
async fn down(&self, manager: &SchemaManager) -> Result<(), DbErr> {
|
||||
manager
|
||||
.drop_table(Table::drop().table(crate::schema::factory::vehicle::Entity).to_owned())
|
||||
.await
|
||||
}
|
||||
}
|
||||
@@ -13,6 +13,8 @@ mod m20250722_000001_create_game_event_table;
|
||||
mod m20250816_000001_add_fake_players;
|
||||
mod m20250918_000001_add_player_variant;
|
||||
mod m20251228_000001_create_score_table;
|
||||
#[cfg(feature = "factory")]
|
||||
mod m20260126_000001_create_factory_vehicle_table;
|
||||
|
||||
pub struct Migrator;
|
||||
|
||||
@@ -33,6 +35,8 @@ impl MigratorTrait for Migrator {
|
||||
Box::new(m20250816_000001_add_fake_players::Migration),
|
||||
Box::new(m20250918_000001_add_player_variant::Migration),
|
||||
Box::new(m20251228_000001_create_score_table::Migration),
|
||||
#[cfg(feature = "factory")]
|
||||
Box::new(m20260126_000001_create_factory_vehicle_table::Migration),
|
||||
]
|
||||
}
|
||||
}
|
||||
|
||||
2
rc_database/src/schema/factory/mod.rs
Normal file
2
rc_database/src/schema/factory/mod.rs
Normal file
@@ -0,0 +1,2 @@
|
||||
pub mod vehicle;
|
||||
pub mod vehicle_query;
|
||||
58
rc_database/src/schema/factory/vehicle.rs
Normal file
58
rc_database/src/schema/factory/vehicle.rs
Normal file
@@ -0,0 +1,58 @@
|
||||
use sea_orm::entity::prelude::*;
|
||||
|
||||
#[derive(Clone, Debug, DeriveEntityModel)]
|
||||
#[sea_orm(table_name = "factory_vehicles")]
|
||||
pub struct Model {
|
||||
#[sea_orm(primary_key)]
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub garage_id: i32,
|
||||
pub creation_time: i64, // seconds since unix epoch
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub added_time: DateTime,
|
||||
pub expiry_time: DateTime,
|
||||
pub cpu: i32,
|
||||
pub total_robot_ranking: i32,
|
||||
pub get_count: i32,
|
||||
pub buyable: bool,
|
||||
pub removed_date: Option<DateTime>,
|
||||
pub ban_date: Option<DateTime>,
|
||||
pub featured: bool,
|
||||
pub banner_message: Option<String>,
|
||||
pub combat_rating: f64,
|
||||
pub cosmetic_rating: f64,
|
||||
pub cube_amounts: String,
|
||||
pub cube_data: Vec<u8>,
|
||||
pub colour_data: Vec<u8>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, EnumIter, DeriveRelation)]
|
||||
pub enum Relation {
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::user::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::user::Column::Id"
|
||||
)]
|
||||
User,
|
||||
#[sea_orm(
|
||||
belongs_to = "super::super::garage::Entity",
|
||||
from = "Column::UserId",
|
||||
to = "super::super::garage::Column::Id"
|
||||
)]
|
||||
Garage,
|
||||
}
|
||||
|
||||
impl Related<super::super::user::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::super::garage::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::User.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
32
rc_database/src/schema/factory/vehicle_query.rs
Normal file
32
rc_database/src/schema/factory/vehicle_query.rs
Normal file
@@ -0,0 +1,32 @@
|
||||
use sea_orm::{DerivePartialModel, FromQueryResult};
|
||||
use sea_orm::entity::prelude::DateTime;
|
||||
|
||||
#[derive(FromQueryResult, DerivePartialModel)]
|
||||
#[sea_orm(entity = "crate::schema::factory::vehicle::Entity")]
|
||||
pub struct VehicleInfo {
|
||||
pub id: i32,
|
||||
pub user_id: i32,
|
||||
pub creation_time: i64, // seconds since unix epoch
|
||||
pub name: String,
|
||||
pub description: String,
|
||||
pub added_time: DateTime,
|
||||
pub expiry_time: DateTime,
|
||||
pub cpu: i32,
|
||||
pub total_robot_ranking: i32,
|
||||
pub get_count: i32,
|
||||
pub buyable: bool,
|
||||
pub removed_date: Option<DateTime>,
|
||||
pub ban_date: Option<DateTime>,
|
||||
pub featured: bool,
|
||||
pub banner_message: Option<String>,
|
||||
pub combat_rating: f64,
|
||||
pub cosmetic_rating: f64,
|
||||
pub cube_amounts: String,
|
||||
}
|
||||
|
||||
#[derive(FromQueryResult, DerivePartialModel)]
|
||||
#[sea_orm(entity = "crate::schema::user::Entity")]
|
||||
pub struct VehicleOwnerInfo {
|
||||
pub public_id: String,
|
||||
pub display_name: String,
|
||||
}
|
||||
@@ -54,6 +54,8 @@ pub enum Relation {
|
||||
to = "super::user::Column::Id"
|
||||
)]
|
||||
User,
|
||||
#[sea_orm(has_many = "super::factory::vehicle::Entity")]
|
||||
FactoryUploads,
|
||||
}
|
||||
|
||||
impl Related<super::user::Entity> for Entity {
|
||||
@@ -62,6 +64,12 @@ impl Related<super::user::Entity> for Entity {
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::factory::vehicle::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::FactoryUploads.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
#[repr(i32)]
|
||||
|
||||
@@ -10,6 +10,8 @@ pub mod multiplayer_game;
|
||||
pub mod multiplayer_game_player;
|
||||
pub mod game_event;
|
||||
pub mod multiplayer_game_score;
|
||||
#[cfg(feature = "factory")]
|
||||
pub mod factory;
|
||||
|
||||
pub fn parse_int_csv(s: &str) -> Vec<u32> {
|
||||
s.split(',').filter_map(|i_as_s| {
|
||||
|
||||
@@ -25,6 +25,8 @@ pub enum Relation {
|
||||
Campaigns,
|
||||
#[sea_orm(has_many = "super::multiplayer_game_player::Entity")]
|
||||
Player,
|
||||
#[sea_orm(has_many = "super::factory::vehicle::Entity")]
|
||||
FactoryUploads,
|
||||
}
|
||||
|
||||
impl Related<super::permissions::Entity> for Entity {
|
||||
@@ -57,4 +59,10 @@ impl Related<super::multiplayer_game_player::Entity> for Entity {
|
||||
}
|
||||
}
|
||||
|
||||
impl Related<super::factory::vehicle::Entity> for Entity {
|
||||
fn to() -> RelationDef {
|
||||
Relation::FactoryUploads.def()
|
||||
}
|
||||
}
|
||||
|
||||
impl ActiveModelBehavior for ActiveModel {}
|
||||
|
||||
@@ -2,7 +2,7 @@ use sea_orm_migration::MigratorTrait;
|
||||
use sea_orm::{ActiveModelTrait, ColumnTrait, EntityTrait, PaginatorTrait, QueryFilter, QueryOrder, QuerySelect, TransactionTrait};
|
||||
|
||||
pub struct Database {
|
||||
orm: sea_orm::DatabaseConnection,
|
||||
orm: std::sync::Arc<sea_orm::DatabaseConnection>,
|
||||
metrics: std::sync::Arc<std::sync::Mutex<super::metrics::MetricsState>>,
|
||||
}
|
||||
|
||||
@@ -14,14 +14,18 @@ impl Database {
|
||||
//let schema_manager = SchemaManager::new(&db);
|
||||
super::Migrator::up(&db, None).await?;
|
||||
Ok(Self {
|
||||
orm: db,
|
||||
orm: std::sync::Arc::new(db),
|
||||
metrics: metrics_data,
|
||||
})
|
||||
}
|
||||
|
||||
pub fn vehicle_factory(&self, cdn: std::sync::Arc<String>) -> super::FactoryDatabase {
|
||||
super::FactoryDatabase::init_preconnected(self.orm.clone(), cdn)
|
||||
}
|
||||
|
||||
pub async fn user_count(&self) -> Result<u64, sea_orm::DbErr> {
|
||||
crate::schema::user::Entity::find()
|
||||
.count(&self.orm)
|
||||
.count(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -31,14 +35,14 @@ impl Database {
|
||||
sea_orm::sea_query::Func::lower(crate::schema::user::Column::DisplayName.into_expr())
|
||||
).eq(public_id.to_lowercase())
|
||||
)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn user_by_steam_id(&self, steam_id: u64) -> Result<Option<crate::schema::user::Model>, sea_orm::DbErr> {
|
||||
crate::schema::user::Entity::find()
|
||||
.filter(crate::schema::user::Column::SteamId.eq(Some(steam_id.to_string())))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -48,7 +52,7 @@ impl Database {
|
||||
sea_orm::sea_query::Func::lower(crate::schema::user::Column::Email.into_expr())
|
||||
).eq(email.to_lowercase())
|
||||
)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -67,13 +71,13 @@ impl Database {
|
||||
}
|
||||
|
||||
pub async fn insert_user(&self, entity: crate::schema::user::ActiveModel) -> Result<crate::schema::user::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn user_aux_by_user_id(&self, user_id: i32) -> Result<Vec<crate::schema::user_aux::Model>, sea_orm::DbErr> {
|
||||
crate::schema::user_aux::Entity::find()
|
||||
.filter(crate::schema::user_aux::Column::UserId.eq(user_id))
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -81,12 +85,12 @@ impl Database {
|
||||
crate::schema::user_aux::Entity::find()
|
||||
.filter(crate::schema::user_aux::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::user_aux::Column::Descriptor.eq(descriptor))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_user_aux(&self, entities: Vec<crate::schema::user_aux::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::user_aux::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
||||
crate::schema::user_aux::Entity::insert_many(entities.into_iter()).exec(self.orm.as_ref()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -97,13 +101,13 @@ impl Database {
|
||||
.filter(crate::schema::user_aux::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::user_aux::Column::Descriptor.eq(descriptor.clone()))
|
||||
.into_model::<crate::schema::common_query::Id>()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?;
|
||||
if let Some(id) = id_opt {
|
||||
// update
|
||||
entity.id = sea_orm::ActiveValue::Set(id.id);
|
||||
Ok(Some(crate::schema::user_aux::Entity::update(entity)
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -142,12 +146,12 @@ impl Database {
|
||||
pub async fn perms_by_user_id(&self, user_id: i32) -> Result<Option<crate::schema::permissions::Model>, sea_orm::DbErr> {
|
||||
crate::schema::permissions::Entity::find()
|
||||
.filter(crate::schema::permissions::Column::UserId.eq(user_id))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_perms(&self, entity: crate::schema::permissions::ActiveModel) -> Result<crate::schema::permissions::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn update_perms_by_user_id(&self, mut entity: crate::schema::permissions::ActiveModel, user_id: i32) -> Result<Option<crate::schema::permissions::Model>, sea_orm::DbErr> {
|
||||
@@ -156,12 +160,12 @@ impl Database {
|
||||
.column(crate::schema::permissions::Column::Id)
|
||||
.filter(crate::schema::permissions::Column::UserId.eq(user_id))
|
||||
.into_model::<crate::schema::common_query::Id>()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?;
|
||||
if let Some(id) = id_opt {
|
||||
entity.id = sea_orm::ActiveValue::Set(id.id);
|
||||
Ok(Some(crate::schema::permissions::Entity::update(entity)
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -170,7 +174,7 @@ impl Database {
|
||||
|
||||
pub async fn garage_count(&self) -> Result<u64, sea_orm::DbErr> {
|
||||
crate::schema::garage::Entity::find()
|
||||
.count(&self.orm)
|
||||
.count(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -180,7 +184,7 @@ impl Database {
|
||||
.column_as(crate::schema::garage::Column::Slot.max(), "column")
|
||||
.filter(crate::schema::garage::Column::UserId.eq(user_id))
|
||||
.into_model::<crate::schema::common_query::SingleColumn<i32>>()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?;
|
||||
Ok(result.map(|x| *x).unwrap_or(0))
|
||||
}
|
||||
@@ -189,7 +193,7 @@ impl Database {
|
||||
crate::schema::garage::Entity::find()
|
||||
.filter(crate::schema::garage::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::garage::Column::Selected.eq(true))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -197,7 +201,7 @@ impl Database {
|
||||
crate::schema::garage::Entity::find()
|
||||
.filter(crate::schema::garage::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::garage::Column::Slot.eq(garage_slot))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -205,35 +209,35 @@ impl Database {
|
||||
crate::schema::garage::Entity::find()
|
||||
.filter(crate::schema::garage::Column::UserId.eq(user_id))
|
||||
.order_by_asc(crate::schema::garage::Column::Slot)
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn garage_by_uuid(&self, uuid: i64) -> Result<Option<crate::schema::garage::Model>, sea_orm::DbErr> {
|
||||
crate::schema::garage::Entity::find()
|
||||
.filter(crate::schema::garage::Column::Uuid.eq(uuid))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn garage_by_id(&self, id: i32) -> Result<Option<crate::schema::garage::Model>, sea_orm::DbErr> {
|
||||
crate::schema::garage::Entity::find_by_id(id)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_garages(&self, entities: Vec<crate::schema::garage::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::garage::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
||||
crate::schema::garage::Entity::insert_many(entities.into_iter()).exec(self.orm.as_ref()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_garage(&self, entity: crate::schema::garage::ActiveModel) -> Result<crate::schema::garage::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn update_garage(&self, entity: crate::schema::garage::ActiveModel) -> Result<crate::schema::garage::Model, sea_orm::DbErr> {
|
||||
crate::schema::garage::Entity::update(entity)
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -244,12 +248,12 @@ impl Database {
|
||||
.filter(crate::schema::garage::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::garage::Column::Slot.eq(slot))
|
||||
.into_model::<crate::schema::common_query::Id>()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?;
|
||||
if let Some(id) = id_opt {
|
||||
entity.id = sea_orm::ActiveValue::Set(id.id);
|
||||
Ok(Some(crate::schema::garage::Entity::update(entity)
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -262,12 +266,12 @@ impl Database {
|
||||
.column(crate::schema::garage::Column::Id)
|
||||
.filter(crate::schema::garage::Column::Uuid.eq(uuid))
|
||||
.into_model::<crate::schema::common_query::Id>()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?;
|
||||
if let Some(id) = id_opt {
|
||||
entity.id = sea_orm::ActiveValue::Set(id.id);
|
||||
Ok(Some(crate::schema::garage::Entity::update(entity)
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?))
|
||||
} else {
|
||||
Ok(None)
|
||||
@@ -307,7 +311,7 @@ impl Database {
|
||||
.filter(crate::schema::sanction::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::sanction::Column::Descriptor.eq(desc))
|
||||
.filter(crate::schema::sanction::Column::Acknowledged.is_null())
|
||||
.count(&self.orm)
|
||||
.count(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -316,17 +320,17 @@ impl Database {
|
||||
.filter(crate::schema::sanction::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::sanction::Column::Acknowledged.is_null())
|
||||
.order_by_asc(crate::schema::sanction::Column::CreationTime)
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_sanction(&self, entity: crate::schema::sanction::ActiveModel) -> Result<crate::schema::sanction::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn game_count(&self) -> Result<u64, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game::Entity::find()
|
||||
.count(&self.orm)
|
||||
.count(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -334,7 +338,7 @@ impl Database {
|
||||
crate::schema::multiplayer_game::Entity::find()
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.order_by_desc(crate::schema::multiplayer_game::Column::CreationTime)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -346,7 +350,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.order_by_desc(crate::schema::multiplayer_game::Column::CreationTime)
|
||||
//.into_model()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?
|
||||
.map(|(x, _)| x))
|
||||
}
|
||||
@@ -359,7 +363,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.order_by_asc(crate::schema::multiplayer_game::Column::CreationTime)
|
||||
//.into_model()
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?
|
||||
.and_then(|(game, player)| player.map(|player| (game, player))))
|
||||
}
|
||||
@@ -368,7 +372,7 @@ impl Database {
|
||||
crate::schema::multiplayer_game::Entity::update_many()
|
||||
.col_expr(crate::schema::multiplayer_game::Column::IsComplete, sea_orm::sea_query::Expr::value(true))
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -377,13 +381,13 @@ impl Database {
|
||||
crate::schema::multiplayer_game::Entity::update_many()
|
||||
.col_expr(crate::schema::multiplayer_game::Column::IsComplete, sea_orm::sea_query::Expr::value(true))
|
||||
.filter(crate::schema::multiplayer_game::Column::IsComplete.eq(false))
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
pub async fn insert_game(&self, entity: crate::schema::multiplayer_game::ActiveModel) -> Result<crate::schema::multiplayer_game::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn players_by_game_guid_and_completion(&self, game_guid: i64, is_complete: bool) -> Result<Vec<crate::schema::multiplayer_game_player::Model>, sea_orm::DbErr> {
|
||||
@@ -392,7 +396,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game::Column::IsComplete.eq(is_complete))
|
||||
//.into_model::<crate::schema::multiplayer_game_player::Model>()
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(player, _)| player)
|
||||
@@ -407,7 +411,7 @@ impl Database {
|
||||
//.join(sea_orm::JoinType::InnerJoin, crate::schema::user::Relation::Player.def())
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game::Column::IsComplete.eq(is_complete))
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|(player, user, _)| user.map(|user| (player, user)))
|
||||
@@ -423,7 +427,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game::Column::IsComplete.eq(is_complete))
|
||||
.filter(crate::schema::multiplayer_game_player::Column::Team.eq(team))
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await?
|
||||
.into_iter()
|
||||
.filter_map(|(player, user, _)| user.map(|user| (player, user)))
|
||||
@@ -438,7 +442,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game::Column::IsComplete.eq(is_complete))
|
||||
.filter(crate::schema::multiplayer_game_player::Column::Team.eq(team))
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(player, _)| player)
|
||||
@@ -449,7 +453,7 @@ impl Database {
|
||||
Ok(crate::schema::multiplayer_game_player::Entity::find()
|
||||
.find_also_related(crate::schema::multiplayer_game::Entity)
|
||||
.filter(crate::schema::multiplayer_game::Column::Id.eq(game_id))
|
||||
.all(&self.orm)
|
||||
.all(self.orm.as_ref())
|
||||
.await?
|
||||
.into_iter()
|
||||
.map(|(player, _)| player)
|
||||
@@ -462,17 +466,17 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game::Column::Guid.eq(game_guid))
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
//.order_by_asc(crate::schema::multiplayer_game::Column::CreationTime)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await?
|
||||
.and_then(|(_, player)| player))
|
||||
}
|
||||
|
||||
pub async fn insert_player(&self, entity: crate::schema::multiplayer_game_player::ActiveModel) -> Result<crate::schema::multiplayer_game_player::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn insert_players(&self, entities: Vec<crate::schema::multiplayer_game_player::ActiveModel>) -> Result<(), sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_player::Entity::insert_many(entities.into_iter()).exec(&self.orm).await?;
|
||||
crate::schema::multiplayer_game_player::Entity::insert_many(entities.into_iter()).exec(self.orm.as_ref()).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -482,7 +486,7 @@ impl Database {
|
||||
is_claimed: sea_orm::Set(is_claimed),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -493,18 +497,18 @@ impl Database {
|
||||
.filter(crate::schema::game_event::Column::End.gte(time))
|
||||
.filter(crate::schema::game_event::Column::Variant.eq(variant))
|
||||
.order_by_desc(crate::schema::game_event::Column::Start)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
pub async fn insert_game_event(&self, entity: crate::schema::game_event::ActiveModel) -> Result<crate::schema::game_event::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn score_by_player_id(&self, player_id: i32) -> Result<Option<crate::schema::multiplayer_game_score::Model>, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_score::Entity::find()
|
||||
.filter(crate::schema::multiplayer_game_score::Column::PlayerId.eq(player_id))
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
@@ -514,17 +518,17 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::multiplayer_game_score::Column::IsClaimed.eq(is_claimed))
|
||||
.order_by_asc(crate::schema::multiplayer_game_player::Column::CreationTime)
|
||||
.one(&self.orm)
|
||||
.one(self.orm.as_ref())
|
||||
.await
|
||||
.map(|opt| opt.and_then(|(_player, score)| score))
|
||||
}
|
||||
|
||||
pub async fn insert_score(&self, entity: crate::schema::multiplayer_game_score::ActiveModel) -> Result<crate::schema::multiplayer_game_score::Model, sea_orm::DbErr> {
|
||||
entity.insert(&self.orm).await
|
||||
entity.insert(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn update_score(&self, entity: crate::schema::multiplayer_game_score::ActiveModel) -> Result<crate::schema::multiplayer_game_score::Model, sea_orm::DbErr> {
|
||||
crate::schema::multiplayer_game_score::Entity::update(entity).exec(&self.orm).await
|
||||
crate::schema::multiplayer_game_score::Entity::update(entity).exec(self.orm.as_ref()).await
|
||||
}
|
||||
|
||||
pub async fn score_claim(&self, score_id: i32) -> Result<(), sea_orm::DbErr> {
|
||||
@@ -533,7 +537,7 @@ impl Database {
|
||||
is_claimed: sea_orm::Set(true),
|
||||
..Default::default()
|
||||
})
|
||||
.exec(&self.orm)
|
||||
.exec(self.orm.as_ref())
|
||||
.await?;
|
||||
Ok(())
|
||||
}
|
||||
@@ -544,7 +548,7 @@ impl Database {
|
||||
.filter(crate::schema::multiplayer_game_player::Column::UserId.eq(user_id))
|
||||
.filter(crate::schema::multiplayer_game_score::Column::IsClaimed.eq(is_claimed))
|
||||
.order_by_asc(crate::schema::multiplayer_game_player::Column::CreationTime)
|
||||
.count(&self.orm)
|
||||
.count(self.orm.as_ref())
|
||||
.await
|
||||
}
|
||||
|
||||
|
||||
@@ -294,14 +294,10 @@ impl crate::VehicleFactoryAdapter for ArcAdapter {
|
||||
if self.is_readonly {
|
||||
return Ok(());
|
||||
}
|
||||
// TODO this should probably be a transaction
|
||||
if let Some(meta) = super::entities::robot_metadata::Entity::find_by_id(id as u32).one(&self.orm).await? {
|
||||
super::entities::robot_metadata::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id as u32),
|
||||
buy_count: sea_orm::ActiveValue::Set(meta.buy_count + 1),
|
||||
..Default::default()
|
||||
}.update(&self.orm).await?;
|
||||
}
|
||||
super::entities::robot_metadata::Entity::update_many()
|
||||
.col_expr(super::entities::robot_metadata::Column::BuyCount, super::entities::robot_metadata::Column::BuyCount.into_expr().add(1))
|
||||
.filter(super::entities::robot_metadata::Column::Id.eq(id))
|
||||
.exec(&self.orm).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
@@ -325,6 +321,18 @@ impl crate::VehicleFactoryAdapter for ArcAdapter {
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn remove_vehicle(&self, id: i32, _user_id: i32) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.is_readonly {
|
||||
return Ok(());
|
||||
}
|
||||
super::entities::robot_metadata::ActiveModel {
|
||||
id: sea_orm::ActiveValue::Set(id as u32),
|
||||
buyable: sea_orm::ActiveValue::Set(0),
|
||||
..Default::default()
|
||||
}.update(&self.orm).await?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
async fn set_featured(&self, id: i32, is_featured: bool) -> Result<(), Box<dyn std::error::Error>> {
|
||||
if self.is_readonly {
|
||||
return Ok(());
|
||||
|
||||
@@ -7,6 +7,7 @@ pub trait VehicleFactoryAdapter: Send + Sync + 'static {
|
||||
/// Just update any purchase trackers
|
||||
async fn purchase(&self, id: i32) -> Result<(), Box<dyn std::error::Error>>;
|
||||
async fn update_vehicle(&self, id: i32, cube_data: Option<Vec<u8>>, colour_data: Option<Vec<u8>>) -> Result<(), Box<dyn std::error::Error>>;
|
||||
async fn remove_vehicle(&self, id: i32, user_id: i32) -> Result<(), Box<dyn std::error::Error>>;
|
||||
async fn set_featured(&self, id: i32, is_featured: bool) -> Result<(), Box<dyn std::error::Error>>;
|
||||
}
|
||||
|
||||
@@ -64,6 +65,8 @@ pub struct VehicleUploadInfo {
|
||||
pub thumbnail: Vec<u8>,
|
||||
pub added_by: String,
|
||||
pub added_by_display_name: String,
|
||||
pub added_by_id: i32,
|
||||
pub garage_id: i32,
|
||||
pub cpu: u32,
|
||||
pub total_robot_ranking: u32,
|
||||
pub cube_data: Vec<u8>,
|
||||
|
||||
@@ -14,6 +14,10 @@ pub struct CliArgs {
|
||||
/// Assets root
|
||||
#[arg(long, default_value_t = {"../assets/robocraft".to_string()})]
|
||||
pub assets: String,
|
||||
|
||||
/// User data root
|
||||
#[arg(long, default_value_t = {"../data/robocraft".to_string()})]
|
||||
pub data: String,
|
||||
}
|
||||
|
||||
impl CliArgs {
|
||||
|
||||
@@ -25,7 +25,8 @@ async fn main() -> std::io::Result<()> {
|
||||
let cli_args = cli::CliArgs::get();
|
||||
|
||||
let conf = ConfigImpl::load(&cli_args.assets).map_err(io_error)?;
|
||||
let factory_enum = <ConfigImpl as ConfigProvider<()>>::factory(&conf).await.map_err(io_error)?;
|
||||
let users = oj_rc_core::persist::user::UserImpl::load(&cli_args.data, &conf).await.map_err(io_error)?;
|
||||
let factory_enum = <ConfigImpl as ConfigProvider<()>>::factory(&conf, &|| users.factory_impl()).await.map_err(io_error)?;
|
||||
let factory_data = actix_web::web::Data::new(factory_enum);
|
||||
|
||||
let mut handlebars_conf = handlebars::Handlebars::new();
|
||||
|
||||
@@ -33,7 +33,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
let config = oj_rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &config).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory::<'_, '_>(&config).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&config, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = oj_rc_core::cubes::CubeParsers::new(&config);
|
||||
let queue = std::sync::Arc::new(QueueHandler::new(&config, &args.redirect, factory.clone(), parsers.cpu_counter(), parsers.weapon_order()));
|
||||
|
||||
|
||||
@@ -28,7 +28,7 @@ async fn main() -> std::io::Result<()> {
|
||||
let config = oj_rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &config).await.expect("Bad user data"));
|
||||
users.multiplayer_init().await.expect("Multiplayer init task failed");
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory::<'_, '_>(&config).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&config, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = std::sync::Arc::new(oj_rc_core::cubes::CubeParsers::new(&config));
|
||||
let matches = matches::GameMatches::new(&config, parsers.clone(), factory.clone());
|
||||
let matches_chann = matches.spawn();
|
||||
|
||||
@@ -33,7 +33,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
let cubes = oj_rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &cubes).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory::<'_, '_>(&cubes).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&cubes, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = oj_rc_core::cubes::CubeParsers::new(&cubes);
|
||||
let init_ctx = std::sync::Arc::new(InitConfig {
|
||||
cubes,
|
||||
|
||||
44
rc_services_room/src/operations/crf_remove.rs
Normal file
44
rc_services_room/src/operations/crf_remove.rs
Normal file
@@ -0,0 +1,44 @@
|
||||
use polariton_server::operations::{SimpleOpError, SimpleOperation, SimpleOpImpl};
|
||||
use polariton::operation::{ParameterTable, Typed};
|
||||
use oj_rc_factory::VehicleFactoryAdapter;
|
||||
|
||||
const CODE: u8 = 91;
|
||||
|
||||
const ID_PARAM_KEY: u8 = 94; // int; in
|
||||
const EARNINGS_PARAM_KEY: u8 = 96;
|
||||
|
||||
pub(super) struct FactoryRemoveVehicle {
|
||||
factory: std::sync::Arc<oj_rc_core::factory::Factory>,
|
||||
}
|
||||
|
||||
#[async_trait::async_trait]
|
||||
impl <C: Send + 'static> SimpleOperation<C> for FactoryRemoveVehicle {
|
||||
type User = crate::UserTy;
|
||||
const CODE: u8 = CODE;
|
||||
|
||||
async fn handle(&self, mut params: ParameterTable<C>, user: &Self::User) -> Result<ParameterTable<C>, SimpleOpError> {
|
||||
if let Some(Typed::Int(factory_id)) = params.remove(&ID_PARAM_KEY) {
|
||||
let user_info = user.user()?;
|
||||
let user_id = user_info.account_id();
|
||||
self.factory.remove_vehicle(factory_id, user_id).await.map_err(|e| {
|
||||
log::error!("Failed to remove vehicle {} by user {} from factory: {}", factory_id, user_id, e);
|
||||
SimpleOpError::with_message(
|
||||
oj_rc_core::data::error_codes::WebServicesError::DatabaseError as i16,
|
||||
format!("Failed to remove vehicle (for offset) from factory: {}", e)
|
||||
)
|
||||
})?;
|
||||
}
|
||||
// TODO Factory earnings
|
||||
params.insert(EARNINGS_PARAM_KEY, Typed::HashMap(vec![
|
||||
(Typed::Str("buyCount".into()), Typed::Int(0)),
|
||||
(Typed::Str("earnings".into()), Typed::Int(0)),
|
||||
].into()));
|
||||
Ok(params)
|
||||
}
|
||||
}
|
||||
|
||||
pub(super) fn factory_remove_provider<C: Send + 'static>(factory: &std::sync::Arc<oj_rc_core::factory::Factory>) -> SimpleOpImpl<C, crate::UserTy, FactoryRemoveVehicle> {
|
||||
SimpleOpImpl::new(FactoryRemoveVehicle {
|
||||
factory: factory.to_owned()
|
||||
})
|
||||
}
|
||||
@@ -106,6 +106,7 @@ mod crf_shift_vehicle;
|
||||
mod crf_make_featured;
|
||||
mod crf_unmake_featured;
|
||||
mod tech_tree_unlock_cube;
|
||||
mod crf_remove;
|
||||
|
||||
use polariton_server::operations::OperationsHandler;
|
||||
|
||||
@@ -236,4 +237,6 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
||||
.add(crf_unmake_featured::factory_featured_provider(&init_ctx.factory))
|
||||
.add(polariton_server::operations::Ack::<101, _>::default()) // RestoreCRFFeaturedRobot unused and also redundant???
|
||||
.add(tech_tree_unlock_cube::tech_tree_cube_unlock_provider(&init_ctx.cubes))
|
||||
.add(crf_remove::factory_remove_provider(&init_ctx.factory))
|
||||
.add(polariton_server::operations::Ack::<94, _>::default()) // ReportCommunityShopItemRequest FIXME: log reports
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@ async fn main() -> std::io::Result<()> {
|
||||
|
||||
let config = oj_rc_core::persist::config::ConfigImpl::load(&args.assets).expect("Bad config data");
|
||||
let users = std::sync::Arc::new(oj_rc_core::persist::user::UserImpl::load(&args.data, &config).await.expect("Bad user data"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory::<'_, '_>(&config).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let factory = std::sync::Arc::new(<oj_rc_core::persist::config::ConfigImpl as oj_rc_core::ConfigProvider<()>>::factory(&config, &|| users.factory_impl()).await.expect("Bad vehicle factory (CRF) config"));
|
||||
let parsers = oj_rc_core::cubes::CubeParsers::new(&config);
|
||||
|
||||
let init_ctx = InitConfig {
|
||||
|
||||
Reference in New Issue
Block a user