validator: convert to gRPC

This commit is contained in:
2025-07-19 03:39:09 -07:00
parent bdfe16ed39
commit 746ac8e8a7
15 changed files with 280 additions and 220 deletions

View File

@@ -4,7 +4,7 @@ use crate::rbx_util::{get_mapinfo,get_root_instance,read_dom,ReadDomError,GameID
use heck::{ToSnakeCase,ToTitleCase};
use rbx_dom_weak::Instance;
use submissions_api::types::Check;
use rust_grpc::validator::Check;
#[allow(dead_code)]
#[derive(Debug)]
@@ -640,27 +640,27 @@ impl<D:std::fmt::Display> std::fmt::Display for Duplicates<D>{
macro_rules! passed{
($name:literal)=>{
Check{
Name:$name,
Summary:String::new(),
Passed:true,
name:$name.to_owned(),
summary:String::new(),
passed:true,
}
}
}
macro_rules! summary{
($name:literal,$summary:expr)=>{
Check{
Name:$name,
Summary:$summary,
Passed:false,
name:$name.to_owned(),
summary:$summary,
passed:false,
}
};
}
macro_rules! summary_format{
($name:literal,$fmt:literal)=>{
Check{
Name:$name,
Summary:format!($fmt),
Passed:false,
name:$name.to_owned(),
summary:format!($fmt),
passed:false,
}
};
}
@@ -813,7 +813,7 @@ impl MapCheck<'_>{
summary_format!("UnanchoredParts","{count} unanchored {plural}: {context}")
}
};
Ok(MapCheckList{checks:Box::new([
Ok(MapCheckList{checks:vec![
model_class,
model_name,
display_name,
@@ -831,13 +831,13 @@ impl MapCheck<'_>{
missing_wormhole_in,
duplicate_wormhole_out,
unanchored_parts,
])})
]})
}
}
#[derive(serde::Serialize)]
pub struct MapCheckList{
pub checks:Box<[Check;17]>,
pub checks:Vec<Check>,
}
pub struct CheckListAndVersion{

View File

@@ -5,7 +5,7 @@ use crate::nats_types::CheckMapfixRequest;
#[derive(Debug)]
pub enum Error{
Check(crate::check::Error),
ApiActionMapfixCheck(submissions_api::Error),
ApiActionMapfixCheck(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -22,13 +22,13 @@ impl crate::message_handler::MessageHandler{
// update the mapfix depending on the result
match check_result{
Ok(CheckListAndVersion{status:Ok(map_info),version})=>{
self.api.action_mapfix_submitted(
submissions_api::types::ActionMapfixSubmittedRequest{
MapfixID:mapfix_id,
ModelVersion:version,
DisplayName:map_info.display_name,
Creator:map_info.creator,
GameID:map_info.game_id.into(),
self.mapfixes.set_status_submitted(
rust_grpc::validator::SubmittedRequest{
id:mapfix_id,
model_version:version,
display_name:map_info.display_name,
creator:map_info.creator,
game_id:map_info.game_id as u32,
}
).await.map_err(Error::ApiActionMapfixCheck)?;
@@ -36,29 +36,31 @@ impl crate::message_handler::MessageHandler{
return Ok(());
},
// update the mapfix model status to request changes
Ok(CheckListAndVersion{status:Err(check_list),..})=>self.api.create_mapfix_audit_check_list(
submissions_api::types::CreateMapfixAuditCheckListRequest{
MapfixID:mapfix_id,
CheckList:check_list.checks.as_slice(),
}
).await.map_err(Error::ApiActionMapfixCheck)?,
Ok(CheckListAndVersion{status:Err(check_list),..})=>{
self.mapfixes.create_audit_checklist(
rust_grpc::validator::AuditChecklistRequest{
id:mapfix_id,
check_list:check_list.checks,
}
).await.map_err(Error::ApiActionMapfixCheck)?;
},
// update the mapfix model status to request changes
Err(e)=>{
// log error
println!("[check_mapfix] Error: {e}");
self.api.create_mapfix_audit_error(
submissions_api::types::CreateMapfixAuditErrorRequest{
MapfixID:mapfix_id,
ErrorMessage:e.to_string(),
self.mapfixes.create_audit_error(
rust_grpc::validator::AuditErrorRequest{
id:mapfix_id,
error_message:e.to_string(),
}
).await.map_err(Error::ApiActionMapfixCheck)?;
},
}
self.api.action_mapfix_request_changes(
submissions_api::types::ActionMapfixRequestChangesRequest{
MapfixID:mapfix_id,
self.mapfixes.set_status_request_changes(
rust_grpc::validator::MapfixId{
id:mapfix_id,
}
).await.map_err(Error::ApiActionMapfixCheck)?;

View File

@@ -5,7 +5,7 @@ use crate::nats_types::CheckSubmissionRequest;
#[derive(Debug)]
pub enum Error{
Check(crate::check::Error),
ApiActionSubmissionCheck(submissions_api::Error),
ApiActionSubmissionCheck(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -23,13 +23,13 @@ impl crate::message_handler::MessageHandler{
match check_result{
// update the submission model status to submitted
Ok(CheckListAndVersion{status:Ok(map_info),version})=>{
self.api.action_submission_submitted(
submissions_api::types::ActionSubmissionSubmittedRequest{
SubmissionID:submission_id,
ModelVersion:version,
DisplayName:map_info.display_name,
Creator:map_info.creator,
GameID:map_info.game_id.into(),
self.submissions.set_status_submitted(
rust_grpc::validator::SubmittedRequest{
id:submission_id,
model_version:version,
display_name:map_info.display_name,
creator:map_info.creator,
game_id:map_info.game_id as u32,
}
).await.map_err(Error::ApiActionSubmissionCheck)?;
@@ -37,29 +37,31 @@ impl crate::message_handler::MessageHandler{
return Ok(());
},
// update the submission model status to request changes
Ok(CheckListAndVersion{status:Err(check_list),..})=>self.api.create_submission_audit_check_list(
submissions_api::types::CreateSubmissionAuditCheckListRequest{
SubmissionID:submission_id,
CheckList:check_list.checks.as_slice(),
Ok(CheckListAndVersion{status:Err(check_list),..})=>{
self.submissions.create_audit_checklist(
rust_grpc::validator::AuditChecklistRequest{
id:submission_id,
check_list:check_list.checks,
}
).await.map_err(Error::ApiActionSubmissionCheck)?,
).await.map_err(Error::ApiActionSubmissionCheck)?;
},
// update the submission model status to request changes
Err(e)=>{
// log error
println!("[check_submission] Error: {e}");
self.api.create_submission_audit_error(
submissions_api::types::CreateSubmissionAuditErrorRequest{
SubmissionID:submission_id,
ErrorMessage:e.to_string(),
self.submissions.create_audit_error(
rust_grpc::validator::AuditErrorRequest{
id:submission_id,
error_message:e.to_string(),
}
).await.map_err(Error::ApiActionSubmissionCheck)?;
},
}
self.api.action_submission_request_changes(
submissions_api::types::ActionSubmissionRequestChangesRequest{
SubmissionID:submission_id,
self.submissions.set_status_request_changes(
rust_grpc::validator::SubmissionId{
id:submission_id,
}
).await.map_err(Error::ApiActionSubmissionCheck)?;

View File

@@ -5,7 +5,7 @@ use crate::create::CreateRequest;
#[derive(Debug)]
pub enum Error{
Create(crate::create::Error),
ApiActionMapfixCreate(submissions_api::Error),
ApiActionMapfixCreate(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -22,22 +22,22 @@ impl crate::message_handler::MessageHandler{
}).await.map_err(Error::Create)?;
// call create on api
self.api.create_mapfix(submissions_api::types::CreateMapfixRequest{
OperationID:create_info.OperationID,
AssetOwner:create_request.AssetOwner as i64,
DisplayName:create_request.DisplayName.as_deref().unwrap_or_default(),
Creator:create_request.Creator.as_deref().unwrap_or_default(),
self.mapfixes.create(rust_grpc::validator::MapfixCreate{
operation_id:create_info.OperationID,
asset_owner:create_request.AssetOwner,
display_name:create_request.DisplayName.unwrap_or_default(),
creator:create_request.Creator.unwrap_or_default(),
// not great TODO: make this great
GameID:create_request.GameID.unwrap_or(crate::rbx_util::GameID::Bhop).into(),
AssetID:create_info.ModelID,
AssetVersion:create_request.AssetVersion,
TargetAssetID:create_info.TargetAssetID,
Description:create_info.Description.as_str(),
game_id:create_request.GameID.unwrap_or(crate::rbx_util::GameID::Bhop) as u32,
asset_id:create_info.ModelID,
asset_version:create_request.AssetVersion,
target_asset_id:create_info.TargetAssetID,
description:create_info.Description,
}).await.map_err(Error::ApiActionMapfixCreate)?;
Ok(())
}
pub async fn create_mapfix(&self,create_info:CreateMapfixRequest)->Result<(),submissions_api::Error>{
pub async fn create_mapfix(&self,create_info:CreateMapfixRequest)->Result<(),tonic::Status>{
let operation_id=create_info.OperationID;
let create_result=self.create_mapfix_inner(create_info).await;
@@ -46,9 +46,9 @@ impl crate::message_handler::MessageHandler{
// log error
println!("[create_mapfix] Error: {e}");
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
OperationID:operation_id,
StatusMessage:e.to_string(),
self.operations.fail(rust_grpc::validator::OperationFailRequest{
operation_id,
status_message:e.to_string(),
}).await?;
}

View File

@@ -6,7 +6,7 @@ use crate::rbx_util::GameID;
#[derive(Debug)]
pub enum Error{
Create(crate::create::Error),
ApiActionSubmissionCreate(submissions_api::Error),
ApiActionSubmissionCreate(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -23,35 +23,35 @@ impl crate::message_handler::MessageHandler{
// grab values from submission form, otherwise try to fill blanks from map data
let display_name=if create_info.DisplayName.is_empty(){
create_request.DisplayName.as_deref().unwrap_or_default()
create_request.DisplayName.unwrap_or_default()
}else{
create_info.DisplayName.as_str()
create_info.DisplayName
};
let creator=if create_info.Creator.is_empty(){
create_request.Creator.as_deref().unwrap_or_default()
create_request.Creator.unwrap_or_default()
}else{
create_info.Creator.as_str()
create_info.Creator
};
let game_id=create_info.GameID.try_into().ok().or(create_request.GameID).unwrap_or(GameID::Bhop);
// call create on api
self.api.create_submission(submissions_api::types::CreateSubmissionRequest{
OperationID:create_info.OperationID,
AssetOwner:create_request.AssetOwner as i64,
DisplayName:display_name,
Creator:creator,
GameID:game_id.into(),
AssetID:create_info.ModelID,
AssetVersion:create_request.AssetVersion,
Status:create_info.Status,
Roles:create_info.Roles,
self.submissions.create(rust_grpc::validator::SubmissionCreate{
operation_id:create_info.OperationID,
asset_owner:create_request.AssetOwner,
display_name:display_name,
creator:creator,
game_id:game_id as u32,
asset_id:create_info.ModelID,
asset_version:create_request.AssetVersion,
status:create_info.Status,
roles:create_info.Roles,
}).await.map_err(Error::ApiActionSubmissionCreate)?;
Ok(())
}
pub async fn create_submission(&self,create_info:CreateSubmissionRequest)->Result<(),submissions_api::Error>{
pub async fn create_submission(&self,create_info:CreateSubmissionRequest)->Result<(),tonic::Status>{
let operation_id=create_info.OperationID;
let create_result=self.create_submission_inner(create_info).await;
@@ -60,9 +60,9 @@ impl crate::message_handler::MessageHandler{
// log error
println!("[create_submission] Error: {e}");
self.api.action_operation_failed(submissions_api::types::ActionOperationFailedRequest{
OperationID:operation_id,
StatusMessage:e.to_string(),
self.operations.fail(rust_grpc::validator::OperationFailRequest{
operation_id:operation_id,
status_message:e.to_string(),
}).await?;
}

View File

@@ -1,10 +1,12 @@
use futures::StreamExt;
mod download;
mod grpc;
mod rbx_util;
mod message_handler;
mod nats_types;
mod download;
mod types;
mod check;
mod check_mapfix;
mod check_submission;
@@ -20,7 +22,7 @@ mod validate_submission;
#[allow(dead_code)]
#[derive(Debug)]
pub enum StartupError{
API(submissions_api::ReqwestError),
API(tonic::transport::Error),
NatsConnect(async_nats::ConnectError),
NatsGetStream(async_nats::jetstream::context::GetStreamError),
NatsConsumer(async_nats::jetstream::stream::ConsumerError),
@@ -55,7 +57,14 @@ async fn main()->Result<(),StartupError>{
// maps-service api
let api_host_internal=std::env::var("API_HOST_INTERNAL").expect("API_HOST_INTERNAL env required");
let api=submissions_api::internal::Context::new(api_host_internal).map_err(StartupError::API)?;
let (mapfixes,operations,scripts,script_policy,submissions)=tokio::try_join!(
crate::grpc::mapfixes::ValidatorMapfixesServiceClient::connect(api_host_internal.clone()),
crate::grpc::operations::ValidatorOperationsServiceClient::connect(api_host_internal.clone()),
crate::grpc::scripts::ValidatorScriptsServiceClient::connect(api_host_internal.clone()),
crate::grpc::script_policy::ValidatorScriptPolicyServiceClient::connect(api_host_internal.clone()),
crate::grpc::submissions::ValidatorSubmissionsServiceClient::connect(api_host_internal.clone()),
).map_err(StartupError::API)?;
let message_handler=message_handler::MessageHandler::new(cloud_context,cookie_context,group_id,mapfixes,operations,scripts,script_policy,submissions);
// nats
let nats_host=std::env::var("NATS_HOST").expect("NATS_HOST env required");
@@ -88,14 +97,12 @@ async fn main()->Result<(),StartupError>{
consumer.messages().await.map_err(StartupError::NatsStream)
};
let message_handler=message_handler::MessageHandler::new(cloud_context,cookie_context,group_id,api);
// run futures
let mut messages=nats_fut.await?;
// Create a signal listener for SIGTERM
let mut sig_term=tokio::signal::unix::signal(tokio::signal::unix::SignalKind::terminate()).expect("Failed to create SIGTERM signal listener");
// run futures
let mut messages=nats_fut.await?;
// process up to PARALLEL_REQUESTS in parallel
let main_loop=async move{
static SEM:tokio::sync::Semaphore=tokio::sync::Semaphore::const_new(PARALLEL_REQUESTS);

View File

@@ -5,8 +5,8 @@ pub enum HandleMessageError{
DoubleAck(async_nats::Error),
Json(serde_json::Error),
UnknownSubject(String),
CreateMapfix(submissions_api::Error),
CreateSubmission(submissions_api::Error),
CreateMapfix(tonic::Status),
CreateSubmission(tonic::Status),
CheckMapfix(crate::check_mapfix::Error),
CheckSubmission(crate::check_submission::Error),
UploadMapfix(crate::upload_mapfix::Error),
@@ -31,7 +31,11 @@ pub struct MessageHandler{
pub(crate) cloud_context:rbx_asset::cloud::Context,
pub(crate) cookie_context:rbx_asset::cookie::Context,
pub(crate) group_id:Option<u64>,
pub(crate) api:submissions_api::internal::Context,
pub(crate) mapfixes:crate::grpc::mapfixes::Service,
pub(crate) operations:crate::grpc::operations::Service,
pub(crate) scripts:crate::grpc::scripts::Service,
pub(crate) script_policy:crate::grpc::script_policy::Service,
pub(crate) submissions:crate::grpc::submissions::Service,
}
impl MessageHandler{
@@ -39,13 +43,21 @@ impl MessageHandler{
cloud_context:rbx_asset::cloud::Context,
cookie_context:rbx_asset::cookie::Context,
group_id:Option<u64>,
api:submissions_api::internal::Context,
mapfixes:crate::grpc::mapfixes::ValidatorMapfixesServiceClient,
operations:crate::grpc::operations::ValidatorOperationsServiceClient,
scripts:crate::grpc::scripts::ValidatorScriptsServiceClient,
script_policy:crate::grpc::script_policy::ValidatorScriptPolicyServiceClient,
submissions:crate::grpc::submissions::ValidatorSubmissionsServiceClient,
)->Self{
Self{
cloud_context,
cookie_context,
group_id,
api,
mapfixes:crate::grpc::mapfixes::Service::new(mapfixes),
operations:crate::grpc::operations::Service::new(operations),
scripts:crate::grpc::scripts::Service::new(scripts),
script_policy:crate::grpc::script_policy::Service::new(script_policy),
submissions:crate::grpc::submissions::Service::new(submissions),
}
}
pub async fn handle_message_result(&self,message_result:MessageResult)->Result<(),HandleMessageError>{

View File

@@ -1,5 +1,3 @@
use submissions_api::types::{SubmissionID,MapfixID,OperationID};
// These represent the information needed in the nats message
// to perform the operation, not necessarily the over-the-wire format
@@ -10,7 +8,7 @@ use submissions_api::types::{SubmissionID,MapfixID,OperationID};
#[derive(serde::Deserialize)]
pub struct CreateSubmissionRequest{
// operation_id is passed back in the response message
pub OperationID:OperationID,
pub OperationID:u32,
pub ModelID:u64,
pub DisplayName:String,
pub Creator:String,
@@ -23,7 +21,7 @@ pub struct CreateSubmissionRequest{
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct CreateMapfixRequest{
pub OperationID:OperationID,
pub OperationID:u32,
pub ModelID:u64,
pub TargetAssetID:u64,
pub Description:String,
@@ -32,7 +30,7 @@ pub struct CreateMapfixRequest{
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct CheckSubmissionRequest{
pub SubmissionID:SubmissionID,
pub SubmissionID:u64,
pub ModelID:u64,
pub SkipChecks:bool,
}
@@ -40,7 +38,7 @@ pub struct CheckSubmissionRequest{
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct CheckMapfixRequest{
pub MapfixID:MapfixID,
pub MapfixID:u64,
pub ModelID:u64,
pub SkipChecks:bool,
}
@@ -49,7 +47,7 @@ pub struct CheckMapfixRequest{
#[derive(serde::Deserialize)]
pub struct ValidateSubmissionRequest{
// submission_id is passed back in the response message
pub SubmissionID:SubmissionID,
pub SubmissionID:u64,
pub ModelID:u64,
pub ModelVersion:u64,
pub ValidatedModelID:Option<u64>,
@@ -59,7 +57,7 @@ pub struct ValidateSubmissionRequest{
#[derive(serde::Deserialize)]
pub struct ValidateMapfixRequest{
// submission_id is passed back in the response message
pub MapfixID:MapfixID,
pub MapfixID:u64,
pub ModelID:u64,
pub ModelVersion:u64,
pub ValidatedModelID:Option<u64>,
@@ -69,7 +67,7 @@ pub struct ValidateMapfixRequest{
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct UploadSubmissionRequest{
pub SubmissionID:SubmissionID,
pub SubmissionID:u64,
pub ModelID:u64,
pub ModelVersion:u64,
pub ModelName:String,
@@ -78,7 +76,7 @@ pub struct UploadSubmissionRequest{
#[allow(nonstandard_style)]
#[derive(serde::Deserialize)]
pub struct UploadMapfixRequest{
pub MapfixID:MapfixID,
pub MapfixID:u64,
pub ModelID:u64,
pub ModelVersion:u64,
pub TargetAssetID:u64,

View File

@@ -37,15 +37,7 @@ pub enum GameID{
Surf=2,
FlyTrials=5,
}
impl From<GameID> for submissions_api::types::GameID{
fn from(value:GameID)->Self{
match value{
GameID::Bhop=>submissions_api::types::GameID::Bhop,
GameID::Surf=>submissions_api::types::GameID::Surf,
GameID::FlyTrials=>submissions_api::types::GameID::FlyTrials,
}
}
}
#[derive(Debug)]
pub struct ParseGameIDError;
impl std::str::FromStr for GameID{

43
validation/src/types.rs Normal file
View File

@@ -0,0 +1,43 @@
use rust_grpc::validator::ResourceType;
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)]
pub struct MapfixID(pub(crate)u64);
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)]
pub struct SubmissionID(pub(crate)u64);
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)]
pub struct OperationID(pub(crate)u64);
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)]
pub struct ResourceID(pub(crate)u64);
#[derive(Clone,Copy,Debug,Hash,Eq,PartialEq,serde::Serialize,serde::Deserialize)]
pub struct ScriptID(pub(crate)u64);
pub struct StupidPolicy(pub(crate)rust_grpc::validator::Policy);
#[derive(Debug)]
pub struct StupidPolicyError;
impl TryFrom<i32> for StupidPolicy{
type Error=StupidPolicyError;
fn try_from(value:i32)->Result<Self,Self::Error>{
Ok(Self(match value{
0=>rust_grpc::validator::Policy::None,
1=>rust_grpc::validator::Policy::Allowed,
2=>rust_grpc::validator::Policy::Blocked,
3=>rust_grpc::validator::Policy::Delete,
4=>rust_grpc::validator::Policy::Replace,
_=>return Err(StupidPolicyError),
}))
}
}
#[derive(Clone,Copy,Debug)]
pub enum Resource{
Submission(SubmissionID),
Mapfix(MapfixID),
}
impl Resource{
pub fn split(self)->(ResourceType,ResourceID){
match self{
Resource::Mapfix(MapfixID(mapfix_id))=>(ResourceType::Mapfix,ResourceID(mapfix_id)),
Resource::Submission(SubmissionID(submission_id))=>(ResourceType::Submission,ResourceID(submission_id)),
}
}
}

View File

@@ -8,7 +8,7 @@ pub enum Error{
IO(std::io::Error),
Json(serde_json::Error),
Upload(rbx_asset::cookie::UploadError),
ApiActionMapfixUploaded(submissions_api::Error),
ApiActionMapfixUploaded(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -41,8 +41,8 @@ impl crate::message_handler::MessageHandler{
// that's it, the database entry does not need to be changed.
// mark mapfix as uploaded, TargetAssetID is unchanged
self.api.action_mapfix_uploaded(submissions_api::types::ActionMapfixUploadedRequest{
MapfixID:upload_info.MapfixID,
self.mapfixes.set_status_uploaded(rust_grpc::validator::MapfixId{
id:upload_info.MapfixID,
}).await.map_err(Error::ApiActionMapfixUploaded)?;
Ok(())

View File

@@ -9,7 +9,7 @@ pub enum Error{
Json(serde_json::Error),
Create(rbx_asset::cookie::CreateError),
SystemTime(std::time::SystemTimeError),
ApiActionSubmissionUploaded(submissions_api::Error),
ApiActionSubmissionUploaded(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -39,9 +39,9 @@ impl crate::message_handler::MessageHandler{
},model_data).await.map_err(Error::Create)?;
// note the asset id of the created model for later release, and mark the submission as uploaded
self.api.action_submission_uploaded(submissions_api::types::ActionSubmissionUploadedRequest{
SubmissionID:upload_info.SubmissionID,
UploadedAssetID:upload_response.AssetId,
self.submissions.set_status_uploaded(rust_grpc::validator::StatusUploadedRequest{
id:upload_info.SubmissionID,
uploaded_asset_id:upload_response.AssetId,
}).await.map_err(Error::ApiActionSubmissionUploaded)?;
Ok(())

View File

@@ -3,7 +3,7 @@ use crate::nats_types::ValidateMapfixRequest;
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error{
ApiActionMapfixValidate(submissions_api::Error),
ApiActionMapfixValidate(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -21,24 +21,24 @@ impl crate::message_handler::MessageHandler{
match &validate_result{
Ok(())=>{
// update the mapfix model status to validated
self.api.action_mapfix_validated(
mapfix_id
).await.map_err(Error::ApiActionMapfixValidate)?;
self.mapfixes.set_status_validated(rust_grpc::validator::MapfixId{
id:mapfix_id,
}).await.map_err(Error::ApiActionMapfixValidate)?;
},
Err(e)=>{
// log error
println!("[validate_mapfix] Error: {e}");
self.api.create_mapfix_audit_error(
submissions_api::types::CreateMapfixAuditErrorRequest{
MapfixID:mapfix_id,
ErrorMessage:e.to_string(),
self.mapfixes.create_audit_error(
rust_grpc::validator::AuditErrorRequest{
id:mapfix_id,
error_message:e.to_string(),
}
).await.map_err(Error::ApiActionMapfixValidate)?;
// update the mapfix model status to accepted
self.api.action_mapfix_accepted(submissions_api::types::ActionMapfixAcceptedRequest{
MapfixID:mapfix_id,
self.mapfixes.set_status_failed(rust_grpc::validator::MapfixId{
id:mapfix_id,
}).await.map_err(Error::ApiActionMapfixValidate)?;
},
}

View File

@@ -3,7 +3,7 @@ use crate::nats_types::ValidateSubmissionRequest;
#[allow(dead_code)]
#[derive(Debug)]
pub enum Error{
ApiActionSubmissionValidate(submissions_api::Error),
ApiActionSubmissionValidate(tonic::Status),
}
impl std::fmt::Display for Error{
fn fmt(&self,f:&mut std::fmt::Formatter<'_>)->std::fmt::Result{
@@ -21,24 +21,24 @@ impl crate::message_handler::MessageHandler{
match &validate_result{
Ok(())=>{
// update the submission model status to validated
self.api.action_submission_validated(
submission_id
).await.map_err(Error::ApiActionSubmissionValidate)?;
self.submissions.set_status_validated(rust_grpc::validator::SubmissionId{
id:submission_id,
}).await.map_err(Error::ApiActionSubmissionValidate)?;
},
Err(e)=>{
// log error
println!("[validate_submission] Error: {e}");
self.api.create_submission_audit_error(
submissions_api::types::CreateSubmissionAuditErrorRequest{
SubmissionID:submission_id,
ErrorMessage:e.to_string(),
self.submissions.create_audit_error(
rust_grpc::validator::AuditErrorRequest{
id:submission_id,
error_message:e.to_string(),
}
).await.map_err(Error::ApiActionSubmissionValidate)?;
// update the submission model status to accepted
self.api.action_submission_accepted(submissions_api::types::ActionSubmissionAcceptedRequest{
SubmissionID:submission_id,
self.submissions.set_status_failed(rust_grpc::validator::SubmissionId{
id:submission_id,
}).await.map_err(Error::ApiActionSubmissionValidate)?;
},
}

View File

@@ -1,33 +1,20 @@
use futures::TryStreamExt;
use submissions_api::types::Resource;
use rust_grpc::validator::Policy;
use crate::download::download_asset_version;
use crate::rbx_util::{read_dom,static_ustr,ReadDomError};
use crate::types::{MapfixID,ScriptID,StupidPolicy,StupidPolicyError,SubmissionID,Resource,ResourceID};
const SCRIPT_CONCURRENCY:usize=16;
enum Policy{
None,
Allowed,
Blocked,
Delete,
Replace(String),
}
struct NamePolicy{
name:String,
policy:Policy,
}
fn source_has_illegal_keywords(source:&str)->bool{
source.contains("getfenv")||source.contains("require")
}
fn hash_source(source:&str)->String{
fn hash_source(source:&str)->u64{
let mut hasher=siphasher::sip::SipHasher::new();
std::hash::Hasher::write(&mut hasher,source.as_bytes());
let hash=std::hash::Hasher::finish(&hasher);
format!("{:016x}",hash)
std::hash::Hasher::finish(&hasher)
}
#[allow(dead_code)]
@@ -40,17 +27,18 @@ pub enum Error{
submitted:u64,
},
ScriptFlaggedIllegalKeyword(String),
ScriptBlocked(Option<submissions_api::types::ScriptID>),
ScriptNotYetReviewed(Option<submissions_api::types::ScriptID>),
ScriptBlocked(Option<ScriptID>),
ScriptNotYetReviewed(Option<ScriptID>),
Download(crate::download::Error),
ModelFileDecode(ReadDomError),
ApiGetScriptPolicyFromHash(submissions_api::types::ScriptPolicySingleItemError),
ApiGetScript(submissions_api::Error),
ApiCreateScript(submissions_api::Error),
ApiCreateScriptPolicy(submissions_api::Error),
ApiGetScriptFromHash(submissions_api::types::ScriptSingleItemError),
ApiUpdateMapfixModel(submissions_api::Error),
ApiUpdateSubmissionModel(submissions_api::Error),
ApiGetScriptPolicyFromHash(crate::grpc::error::ScriptPolicySingleItemError),
ApiGetScript(tonic::Status),
StupidPolicy(StupidPolicyError),
ApiCreateScript(tonic::Status),
ApiCreateScriptPolicy(tonic::Status),
ApiGetScriptFromHash(crate::grpc::error::ScriptSingleItemError),
ApiUpdateMapfixModel(tonic::Status),
ApiUpdateSubmissionModel(tonic::Status),
ModelFileRootMustHaveOneChild,
ModelFileChildRefIsNil,
ModelFileEncode(rbx_binary::EncodeError),
@@ -78,7 +66,7 @@ impl From<crate::nats_types::ValidateMapfixRequest> for ValidateRequest{
ModelID:value.ModelID,
ModelVersion:value.ModelVersion,
ValidatedModelID:value.ValidatedModelID,
Resource:Resource::Mapfix(value.MapfixID),
Resource:Resource::Mapfix(MapfixID(value.MapfixID)),
}
}
}
@@ -88,13 +76,27 @@ impl From<crate::nats_types::ValidateSubmissionRequest> for ValidateRequest{
ModelID:value.ModelID,
ModelVersion:value.ModelVersion,
ValidatedModelID:value.ValidatedModelID,
Resource:Resource::Submission(value.SubmissionID),
Resource:Resource::Submission(SubmissionID(value.SubmissionID)),
}
}
}
impl crate::message_handler::MessageHandler{
pub async fn validate_inner(&self,validate_info:ValidateRequest)->Result<(),Error>{
enum OwnedPolicy{
None,
Allowed,
Blocked,
Delete,
Replace(String),
}
struct NamePolicy{
name:String,
policy:OwnedPolicy,
}
// discover asset creator and latest version
let info=self.cloud_context.get_asset_info(
rbx_asset::cloud::GetAssetLatestRequest{asset_id:validate_info.ModelID}
@@ -144,7 +146,7 @@ impl crate::message_handler::MessageHandler{
// policy will be fetched from the database to replace the default policy
script_map.insert(source.clone(),NamePolicy{
name:get_partial_path(&dom,script),
policy:Policy::None,
policy:OwnedPolicy::None,
});
}
}
@@ -157,40 +159,42 @@ impl crate::message_handler::MessageHandler{
let hash=hash_source(source.as_str());
// fetch the script policy
let script_policy=self.api.get_script_policy_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptPolicyFromHash)?;
let script_policy=self.script_policy.get_from_hash(
hash,
).await.map_err(Error::ApiGetScriptPolicyFromHash)?;
// write the policy to the script_map, fetching the replacement code if necessary
if let Some(script_policy)=script_policy{
*policy=match script_policy.Policy{
submissions_api::types::Policy::None=>Policy::None,
submissions_api::types::Policy::Allowed=>Policy::Allowed,
submissions_api::types::Policy::Blocked=>Policy::Blocked,
submissions_api::types::Policy::Delete=>Policy::Delete,
submissions_api::types::Policy::Replace=>{
let script=self.api.get_script(submissions_api::types::GetScriptRequest{
ScriptID:script_policy.ToScriptID,
*policy=match script_policy.policy.try_into(){
Ok(StupidPolicy(Policy::None))=>OwnedPolicy::None,
Ok(StupidPolicy(Policy::Allowed))=>OwnedPolicy::Allowed,
Ok(StupidPolicy(Policy::Blocked))=>OwnedPolicy::Blocked,
Ok(StupidPolicy(Policy::Delete))=>OwnedPolicy::Delete,
Ok(StupidPolicy(Policy::Replace))=>{
let script=self.scripts.get(rust_grpc::validator::ScriptId{
id:script_policy.to_script_id,
}).await.map_err(Error::ApiGetScript)?;
Policy::Replace(script.Source)
OwnedPolicy::Replace(script.source)
},
// WHY DOES PROTOBUF NOT HAVE EMBEDDED ENUMS
Err(e)=>return Err(Error::StupidPolicy(e)),
};
}else{
let (resource_type,resource_id)=validate_info.Resource.split();
let (resource_type,ResourceID(resource_id))=validate_info.Resource.split();
// upload the script
let script=self.api.create_script(submissions_api::types::CreateScriptRequest{
Name:name.as_str(),
Source:source.as_str(),
ResourceType:resource_type,
ResourceID:Some(resource_id),
let script=self.scripts.create(rust_grpc::validator::ScriptCreate{
name:name.clone(),
source:source.clone(),
resource_type:resource_type as i32,
resource_id:Some(resource_id),
}).await.map_err(Error::ApiCreateScript)?;
// create a None policy (pending review by yours truly)
self.api.create_script_policy(submissions_api::types::CreateScriptPolicyRequest{
ToScriptID:script.ScriptID,
FromScriptID:script.ScriptID,
Policy:submissions_api::types::Policy::None,
self.script_policy.create(rust_grpc::validator::ScriptPolicyCreate{
to_script_id:script.id,
from_script_id:script.id,
policy:rust_grpc::validator::Policy::None as i32,
}).await.map_err(Error::ApiCreateScriptPolicy)?;
}
@@ -204,29 +208,29 @@ impl crate::message_handler::MessageHandler{
if let Some(script)=dom.get_by_ref_mut(script_ref){
if let Some(rbx_dom_weak::types::Variant::String(source))=script.properties.get_mut(&source_property){
match script_map.get(source.as_str()).map(|p|&p.policy){
Some(Policy::Blocked)=>{
Some(OwnedPolicy::Blocked)=>{
let hash=hash_source(source.as_str());
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptBlocked(script.map(|s|s.ID)));
let script=self.scripts.get_from_hash(
hash,
).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptBlocked(script.map(|s|ScriptID(s.id))));
},
None
|Some(Policy::None)
|Some(OwnedPolicy::None)
=>{
let hash=hash_source(source.as_str());
let script=self.api.get_script_from_hash(submissions_api::types::HashRequest{
hash:hash.as_str(),
}).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptNotYetReviewed(script.map(|s|s.ID)));
let script=self.scripts.get_from_hash(
hash,
).await.map_err(Error::ApiGetScriptFromHash)?;
return Err(Error::ScriptNotYetReviewed(script.map(|s|ScriptID(s.id))));
},
Some(Policy::Allowed)=>(),
Some(Policy::Delete)=>{
Some(OwnedPolicy::Allowed)=>(),
Some(OwnedPolicy::Delete)=>{
modified=true;
// delete script
dom.destroy(script_ref);
},
Some(Policy::Replace(replacement))=>{
Some(OwnedPolicy::Replace(replacement))=>{
modified=true;
*source=replacement.clone();
},
@@ -278,20 +282,20 @@ impl crate::message_handler::MessageHandler{
};
match validate_info.Resource{
Resource::Mapfix(mapfix_id)=>{
Resource::Mapfix(MapfixID(mapfix_id))=>{
// update the mapfix to use the validated model
self.api.update_mapfix_validated_model(submissions_api::types::UpdateMapfixModelRequest{
MapfixID:mapfix_id,
ModelID:validated_model_id,
ModelVersion:validated_model_version,
self.mapfixes.set_validated_model(rust_grpc::validator::ValidatedModelRequest{
id:mapfix_id,
validated_model_id,
validated_model_version,
}).await.map_err(Error::ApiUpdateMapfixModel)?;
},
Resource::Submission(submission_id)=>{
Resource::Submission(SubmissionID(submission_id))=>{
// update the submission to use the validated model
self.api.update_submission_validated_model(submissions_api::types::UpdateSubmissionModelRequest{
SubmissionID:submission_id,
ModelID:validated_model_id,
ModelVersion:validated_model_version,
self.submissions.set_validated_model(rust_grpc::validator::ValidatedModelRequest{
id:submission_id,
validated_model_id,
validated_model_version,
}).await.map_err(Error::ApiUpdateSubmissionModel)?;
},
}