mirror of
https://git.ngram.ca/OpenJam/rc-servers
synced 2026-08-23 23:08:52 +00:00
Add factory upload support to trait, make client handle rejections gracefully #6
This commit is contained in:
@@ -28,15 +28,15 @@ impl ShopItemListFilters {
|
|||||||
page_size: read_u32(r)?,
|
page_size: read_u32(r)?,
|
||||||
weapon_filter: read_i32(r)?,
|
weapon_filter: read_i32(r)?,
|
||||||
movement_filter: read_i32(r)?,
|
movement_filter: read_i32(r)?,
|
||||||
weapon_groups: rc_core::data::read_str_for_binwriter(r)?,
|
weapon_groups: super::read_str_for_binwriter(r)?,
|
||||||
movement_groups: rc_core::data::read_str_for_binwriter(r)?,
|
movement_groups: super::read_str_for_binwriter(r)?,
|
||||||
player: read_bool(r)?,
|
player: read_bool(r)?,
|
||||||
sort_mode: read_i32(r)?,
|
sort_mode: read_i32(r)?,
|
||||||
min_cpu: read_i32(r)?,
|
min_cpu: read_i32(r)?,
|
||||||
max_cpu: read_i32(r)?,
|
max_cpu: read_i32(r)?,
|
||||||
min_robot_ranking: read_i32(r)?,
|
min_robot_ranking: read_i32(r)?,
|
||||||
max_robot_ranking: read_i32(r)?,
|
max_robot_ranking: read_i32(r)?,
|
||||||
text: rc_core::data::read_str_for_binwriter(r)?,
|
text: super::read_str_for_binwriter(r)?,
|
||||||
text_search_field: read_i32(r)?,
|
text_search_field: read_i32(r)?,
|
||||||
show_featured: read_bool(r)?,
|
show_featured: read_bool(r)?,
|
||||||
show_hidden: read_bool(r)?,
|
show_hidden: read_bool(r)?,
|
||||||
@@ -94,22 +94,22 @@ pub struct ItemResult {
|
|||||||
impl ItemResult {
|
impl ItemResult {
|
||||||
pub fn dump(&self, w: &mut dyn std::io::Write) -> std::io::Result<usize> {
|
pub fn dump(&self, w: &mut dyn std::io::Write) -> std::io::Result<usize> {
|
||||||
let mut total_len = write_i32(w, self.id)?;
|
let mut total_len = write_i32(w, self.id)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.name, w)?;
|
total_len += super::write_str_for_binreader(&self.name, w)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.description, w)?;
|
total_len += super::write_str_for_binreader(&self.description, w)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.thumbnail, w)?;
|
total_len += super::write_str_for_binreader(&self.thumbnail, w)?;
|
||||||
total_len += write_f64(w, self.style_rating)?;
|
total_len += write_f64(w, self.style_rating)?;
|
||||||
total_len += write_f64(w, self.combat_rating)?;
|
total_len += write_f64(w, self.combat_rating)?;
|
||||||
total_len += write_i32(w, self.cpu)?;
|
total_len += write_i32(w, self.cpu)?;
|
||||||
total_len += write_i32(w, self.total_robot_ranking)?;
|
total_len += write_i32(w, self.total_robot_ranking)?;
|
||||||
total_len += write_i64(w, self.expiry_date)?;
|
total_len += write_i64(w, self.expiry_date)?;
|
||||||
total_len += write_bool(w, self.buyable)?;
|
total_len += write_bool(w, self.buyable)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.added_by, w)?;
|
total_len += super::write_str_for_binreader(&self.added_by, w)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.added_by_display_name, w)?;
|
total_len += super::write_str_for_binreader(&self.added_by_display_name, w)?;
|
||||||
total_len += write_i64(w, self.added_date)?;
|
total_len += write_i64(w, self.added_date)?;
|
||||||
total_len += write_i32(w, self.rent_count)?;
|
total_len += write_i32(w, self.rent_count)?;
|
||||||
total_len += write_i32(w, self.buy_count)?;
|
total_len += write_i32(w, self.buy_count)?;
|
||||||
total_len += write_bool(w, self.featured)?;
|
total_len += write_bool(w, self.featured)?;
|
||||||
total_len += rc_core::data::write_str_for_binreader(&self.banner_message, w)?;
|
total_len += super::write_str_for_binreader(&self.banner_message, w)?;
|
||||||
total_len += write_i32(w, self.cube_counts.len() as i32)?;
|
total_len += write_i32(w, self.cube_counts.len() as i32)?;
|
||||||
for (key, val) in self.cube_counts.iter() {
|
for (key, val) in self.cube_counts.iter() {
|
||||||
total_len += write_u32(w, *key)?;
|
total_len += write_u32(w, *key)?;
|
||||||
@@ -192,6 +192,69 @@ impl std::convert::From<rc_factory::VehicleInfo> for ItemData {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct UploadData {
|
||||||
|
pub version: String,
|
||||||
|
pub slot: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub thumbnail: Vec<u8>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl UploadData {
|
||||||
|
pub fn from_transmissibles<C>(build_version: String, mut data: polariton::operation::Dict<C>) -> Result<Self, i16> {
|
||||||
|
if let Some(slot_i) = data.items.iter().position(|(key, _)| typed_is_str(key, "SlotId")) {
|
||||||
|
if let (_, polariton::operation::Typed::Int(slot)) = data.items.swap_remove(slot_i) {
|
||||||
|
if let Some(name_i) = data.items.iter().position(|(key, _)| typed_is_str(key, "Name")) {
|
||||||
|
if let (_, polariton::operation::Typed::Str(name)) = data.items.swap_remove(name_i) {
|
||||||
|
if let Some(description_i) = data.items.iter().position(|(key, _)| typed_is_str(key, "Description")) {
|
||||||
|
if let (_, polariton::operation::Typed::Str(description)) = data.items.swap_remove(description_i) {
|
||||||
|
if let Some(thumb_i) = data.items.iter().position(|(key, _)| typed_is_str(key, "Thumbnail")) {
|
||||||
|
if let (_, polariton::operation::Typed::Bytes(thumb)) = data.items.swap_remove(thumb_i) {
|
||||||
|
return Ok(Self {
|
||||||
|
version: build_version,
|
||||||
|
slot,
|
||||||
|
name: name.string,
|
||||||
|
description: description.string,
|
||||||
|
thumbnail: thumb.vec,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data Thumbnail is not Bytes");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data is missing Thumbnail");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data Description is not Str");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data is missing Description");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data Name is not Str");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data is missing Name");
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data SlotId is not Int")
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
log::warn!("Factory upload data is missing SlotId")
|
||||||
|
}
|
||||||
|
Err(crate::data::error_codes::WebServicesError::UnexpectedError as i16)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn into_core(self) -> crate::persist::user::VehicleUploadData {
|
||||||
|
crate::persist::user::VehicleUploadData {
|
||||||
|
version: self.version,
|
||||||
|
slot: self.slot,
|
||||||
|
name: self.name,
|
||||||
|
description: self.description,
|
||||||
|
thumbnail: self.thumbnail,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
fn read_i32(r: &mut dyn std::io::Read) -> std::io::Result<i32> {
|
fn read_i32(r: &mut dyn std::io::Read) -> std::io::Result<i32> {
|
||||||
let mut buf = [0u8; 4];
|
let mut buf = [0u8; 4];
|
||||||
@@ -247,3 +310,11 @@ fn write_bool(w: &mut dyn std::io::Write, b: bool) -> std::io::Result<usize> {
|
|||||||
fn split_u32(s: &str) -> Vec<u32> {
|
fn split_u32(s: &str) -> Vec<u32> {
|
||||||
s.split(',').filter_map(|x| x.parse().ok()).collect()
|
s.split(',').filter_map(|x| x.parse().ok()).collect()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn typed_is_str<C>(ty: &polariton::operation::Typed<C>, s: &str) -> bool {
|
||||||
|
if let polariton::operation::Typed::Str(ty_s) = ty {
|
||||||
|
ty_s.string == s
|
||||||
|
} else {
|
||||||
|
false
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -10,6 +10,7 @@ pub mod tech_tree;
|
|||||||
pub mod voting;
|
pub mod voting;
|
||||||
pub mod weapon_list;
|
pub mod weapon_list;
|
||||||
pub mod weapon_upgrade;
|
pub mod weapon_upgrade;
|
||||||
|
pub mod crf;
|
||||||
|
|
||||||
pub mod error_codes;
|
pub mod error_codes;
|
||||||
|
|
||||||
|
|||||||
@@ -21,6 +21,14 @@ impl rc_factory::VehicleFactoryAdapter for Factory {
|
|||||||
Self::None => Ok(Vec::default()),
|
Self::None => Ok(Vec::default()),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn upload(&self, vehicle: rc_factory::VehicleUploadInfo) -> Result<bool, Box<dyn std::error::Error>> {
|
||||||
|
match self {
|
||||||
|
Self::Arc(x) => x.upload(vehicle).await,
|
||||||
|
Self::Custom(x) => x.upload(vehicle).await,
|
||||||
|
Self::None => Ok(false),
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Factory {
|
impl Factory {
|
||||||
|
|||||||
@@ -470,4 +470,26 @@ impl <C: Clone> super::User<C> for UserData {
|
|||||||
],
|
],
|
||||||
}.as_transmissible())
|
}.as_transmissible())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn prepare_factory_upload(&self, vehicle: super::VehicleUploadData) -> Result<rc_factory::VehicleUploadInfo, i16> {
|
||||||
|
let slot = self.load_garage_by_slot(vehicle.slot as u32).await.map_err(|e| {
|
||||||
|
log::error!("Failed to retrieve vehicle slot {} for user_id {} (prepare_factory_upload): {}", vehicle.slot, self.account.id, e);
|
||||||
|
DATABASE_ERR
|
||||||
|
})?.ok_or_else(|| {
|
||||||
|
log::error!("Failed to find vehicle slot {} for user_id {} (prepare_factory_upload)", vehicle.slot, self.account.id);
|
||||||
|
INVALID_ROBOT_ERR
|
||||||
|
})?;
|
||||||
|
Ok(rc_factory::VehicleUploadInfo {
|
||||||
|
name: vehicle.name,
|
||||||
|
description: vehicle.description,
|
||||||
|
thumbnail: vehicle.thumbnail,
|
||||||
|
added_by: self.account.public_id.clone(),
|
||||||
|
added_by_display_name: self.account.display_name.clone(),
|
||||||
|
cpu: slot.total_robot_cpu,
|
||||||
|
total_robot_ranking: slot.total_robot_ranking,
|
||||||
|
build_version: vehicle.version,
|
||||||
|
cube_data: slot.robot_data,
|
||||||
|
colour_data: slot.colour_data,
|
||||||
|
})
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ mod inventory;
|
|||||||
pub use inventory::UnlockedParts;
|
pub use inventory::UnlockedParts;
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo};
|
pub use traits::{UserProvider, User, UserToken, UserSlots, UserSlotData, VehicleData, UserInfo, UserLoginInfo, ExtraUserInfo, UserAuthenticator, NewSlotData, UserId, RegistrationInfo, VehicleUploadData};
|
||||||
|
|
||||||
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
pub const TOKEN_SECRET_FILENAME: &str = "token_secret.key";
|
||||||
|
|
||||||
|
|||||||
@@ -71,6 +71,7 @@ pub trait User<C> {
|
|||||||
async fn upgrade_slot(&self, increments: i32) -> Result<polariton::operation::Typed<C>, i16>;
|
async fn upgrade_slot(&self, increments: i32) -> Result<polariton::operation::Typed<C>, i16>;
|
||||||
fn signup_date(&self) -> i64;
|
fn signup_date(&self) -> i64;
|
||||||
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16>;
|
async fn singleplayer_robots(&self) -> Result<polariton::operation::Typed<C>, i16>;
|
||||||
|
async fn prepare_factory_upload(&self, vehicle: VehicleUploadData) -> Result<rc_factory::VehicleUploadInfo, i16>;
|
||||||
}
|
}
|
||||||
|
|
||||||
pub struct UserSlots<C> {
|
pub struct UserSlots<C> {
|
||||||
@@ -111,3 +112,11 @@ pub struct VehicleData {
|
|||||||
pub weapon_order: Vec<i32>,
|
pub weapon_order: Vec<i32>,
|
||||||
pub crf_id: Option<i32>,
|
pub crf_id: Option<i32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct VehicleUploadData {
|
||||||
|
pub version: String,
|
||||||
|
pub slot: i32,
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub thumbnail: Vec<u8>,
|
||||||
|
}
|
||||||
|
|||||||
@@ -146,4 +146,9 @@ impl crate::VehicleFactoryAdapter for ArcAdapter {
|
|||||||
log::debug!("Search vehicles returned {} results", infos.len());
|
log::debug!("Search vehicles returned {} results", infos.len());
|
||||||
Ok(infos)
|
Ok(infos)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async fn upload(&self, _vehicle: crate::VehicleUploadInfo) -> Result<bool, Box<dyn std::error::Error>> {
|
||||||
|
log::info!("Arc adapter does not support uploading factory vehicles");
|
||||||
|
Ok(false)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
pub mod arc;
|
pub mod arc;
|
||||||
|
|
||||||
mod traits;
|
mod traits;
|
||||||
pub use traits::{VehicleFactoryAdapter, VehicleInfo, VehicleQueryInfo};
|
pub use traits::{VehicleFactoryAdapter, VehicleInfo, VehicleQueryInfo, VehicleUploadInfo};
|
||||||
|
|||||||
@@ -2,6 +2,7 @@
|
|||||||
pub trait VehicleFactoryAdapter: Send + Sync + 'static {
|
pub trait VehicleFactoryAdapter: Send + Sync + 'static {
|
||||||
async fn vehicle(&self, id: u32) -> Result<Option<(VehicleInfo, VehicleQueryInfo)>, Box<dyn std::error::Error>>;
|
async fn vehicle(&self, id: u32) -> Result<Option<(VehicleInfo, VehicleQueryInfo)>, Box<dyn std::error::Error>>;
|
||||||
async fn list(&self, query: libfj::robocraft::ListQuery) -> Result<Vec<VehicleQueryInfo>, Box<dyn std::error::Error>>;
|
async fn list(&self, query: libfj::robocraft::ListQuery) -> Result<Vec<VehicleQueryInfo>, Box<dyn std::error::Error>>;
|
||||||
|
async fn upload(&self, vehicle: VehicleUploadInfo) -> Result<bool, Box<dyn std::error::Error>>;
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug, Clone)]
|
#[derive(Debug, Clone)]
|
||||||
@@ -50,3 +51,17 @@ pub struct VehicleQueryInfo {
|
|||||||
pub cosmetic_rating: f64,
|
pub cosmetic_rating: f64,
|
||||||
pub cube_amounts: std::collections::HashMap<u32, u32>,
|
pub cube_amounts: std::collections::HashMap<u32, u32>,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Debug)]
|
||||||
|
pub struct VehicleUploadInfo {
|
||||||
|
pub name: String,
|
||||||
|
pub description: String,
|
||||||
|
pub thumbnail: Vec<u8>,
|
||||||
|
pub added_by: String,
|
||||||
|
pub added_by_display_name: String,
|
||||||
|
pub cpu: u32,
|
||||||
|
pub total_robot_ranking: u32,
|
||||||
|
pub cube_data: Vec<u8>,
|
||||||
|
pub colour_data: Vec<u8>,
|
||||||
|
pub build_version: String,
|
||||||
|
}
|
||||||
|
|||||||
@@ -28,4 +28,4 @@ pub use rc_core::data::error_codes;
|
|||||||
//pub use rc_core::data::game_mode;
|
//pub use rc_core::data::game_mode;
|
||||||
pub mod score_multipliers;
|
pub mod score_multipliers;
|
||||||
//pub use rc_core::data::campaign;
|
//pub use rc_core::data::campaign;
|
||||||
pub mod crf;
|
pub use rc_core::data::crf;
|
||||||
|
|||||||
51
rc_services_room/src/operations/crf_upload.rs
Normal file
51
rc_services_room/src/operations/crf_upload.rs
Normal file
@@ -0,0 +1,51 @@
|
|||||||
|
use polariton_server::operations::{Operation, OperationCode};
|
||||||
|
use polariton::operation::{Typed, ParameterTable};
|
||||||
|
use rc_factory::VehicleFactoryAdapter;
|
||||||
|
|
||||||
|
const CODE: u8 = 96;
|
||||||
|
|
||||||
|
const DATA_PARAM_KEY: u8 = 101; // in; dict
|
||||||
|
const VERSION_PARAM_KEY: u8 = 99; // in; str
|
||||||
|
const SUCCESS_PARAM_KEY: u8 = 103; // out; bool
|
||||||
|
|
||||||
|
async fn do_handling(params: ParameterTable<()>, user: &crate::UserTy, factory: &std::sync::Arc<rc_core::factory::Factory>) -> Result<ParameterTable, i16> {
|
||||||
|
let mut params = params.to_dict();
|
||||||
|
if let Some(Typed::Str(version)) = params.remove(&VERSION_PARAM_KEY) {
|
||||||
|
if let Some(Typed::Dict(data)) = params.remove(&DATA_PARAM_KEY) {
|
||||||
|
let upload_info = crate::data::crf::UploadData::from_transmissibles(version.string, data)?;
|
||||||
|
let user_info = user.user()?;
|
||||||
|
let prepared = user_info.prepare_factory_upload(upload_info.into_core()).await?;
|
||||||
|
let success = factory.upload(prepared).await.map_err(|e| {
|
||||||
|
log::error!("Failed to upload to factory: {}", e);
|
||||||
|
rc_core::data::error_codes::WebServicesError::UnexpectedError as i16
|
||||||
|
})?;
|
||||||
|
params.insert(SUCCESS_PARAM_KEY, Typed::Bool(success));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Ok(params.into())
|
||||||
|
}
|
||||||
|
|
||||||
|
pub struct CrfUploadProvider {
|
||||||
|
factory: std::sync::Arc<rc_core::factory::Factory>,
|
||||||
|
}
|
||||||
|
|
||||||
|
#[async_trait::async_trait]
|
||||||
|
impl Operation<()> for CrfUploadProvider {
|
||||||
|
type User = crate::UserTy;
|
||||||
|
|
||||||
|
async fn handle_async(&self, params: polariton::operation::ParameterTable<()>, user: &Self::User) -> polariton::operation::OperationResponse<()> {
|
||||||
|
polariton_server::operations::result_to_op_resp::<CODE, ()>(do_handling(params, user, &self.factory).await)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OperationCode for CrfUploadProvider {
|
||||||
|
fn op_code() -> u8 {
|
||||||
|
CODE
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub(super) fn crf_upload_provider(factory: &std::sync::Arc<rc_core::factory::Factory>) -> CrfUploadProvider {
|
||||||
|
CrfUploadProvider {
|
||||||
|
factory: factory.to_owned(),
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -90,6 +90,7 @@ mod crf_earnings;
|
|||||||
mod crf_list_query;
|
mod crf_list_query;
|
||||||
mod crf_vehicle_data;
|
mod crf_vehicle_data;
|
||||||
mod crf_purchase;
|
mod crf_purchase;
|
||||||
|
mod crf_upload;
|
||||||
|
|
||||||
use polariton_server::operations::OperationsHandler;
|
use polariton_server::operations::OperationsHandler;
|
||||||
|
|
||||||
@@ -202,4 +203,5 @@ pub fn handler(init_ctx: &crate::InitConfig) -> OperationsHandler<crate::UserTy>
|
|||||||
.add(crf_list_query::crf_item_list_query_provider(&init_ctx.factory))
|
.add(crf_list_query::crf_item_list_query_provider(&init_ctx.factory))
|
||||||
.add(crf_vehicle_data::crf_item_data_provider(&init_ctx.factory))
|
.add(crf_vehicle_data::crf_item_data_provider(&init_ctx.factory))
|
||||||
.add(crf_purchase::crf_copy_to_bay_provider(&init_ctx.factory, init_ctx.parsers.weapon_order()))
|
.add(crf_purchase::crf_copy_to_bay_provider(&init_ctx.factory, init_ctx.parsers.weapon_order()))
|
||||||
|
.add(crf_upload::crf_upload_provider(&init_ctx.factory))
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user