-
Notifications
You must be signed in to change notification settings - Fork 2
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
Showing
25 changed files
with
331 additions
and
779 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
pub mod http; | ||
pub mod rclone; | ||
pub mod platform; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,99 @@ | ||
use super::http::HttpClient; | ||
use judge_core::{compiler::Language, judge::result::JudgeResultInfo}; | ||
|
||
pub struct PlatformClient { | ||
client: HttpClient, | ||
} | ||
|
||
impl PlatformClient { | ||
pub fn new(base_url: String) -> Self { | ||
Self { | ||
client: HttpClient::new(base_url), | ||
} | ||
} | ||
|
||
pub async fn pick_task(&self) -> Result<JudgeTask, anyhow::Error> { | ||
pick_task(&self.client).await | ||
} | ||
|
||
pub async fn report_task( | ||
&self, | ||
stream_id: &str, | ||
results: Vec<JudgeResultInfo>, | ||
) -> Result<(), anyhow::Error> { | ||
report_task(&self.client, stream_id, results).await | ||
} | ||
} | ||
|
||
#[derive(Deserialize, Debug)] | ||
pub struct JudgeTask { | ||
#[serde(rename = "submissionUID")] | ||
pub submission_uid: String, | ||
#[serde(rename = "problemSlug")] | ||
pub problem_slug: String, | ||
pub code: String, | ||
pub language: Language, | ||
#[serde(rename = "redisStreamID")] | ||
pub redis_stream_id: String, | ||
} | ||
#[derive(Serialize)] | ||
struct PickTaskBody { | ||
consumer: String, | ||
} | ||
#[derive(Deserialize, Debug)] | ||
struct PickTaskResponse { | ||
task: JudgeTask, | ||
} | ||
|
||
async fn pick_task(client: &HttpClient) -> Result<JudgeTask, anyhow::Error> { | ||
let pick_url = "/task/pick"; | ||
let body = PickTaskBody { | ||
consumer: "".to_string(), | ||
}; | ||
let response = client.post(pick_url.to_string()).json(&body).send().await?; | ||
|
||
match response.status() { | ||
reqwest::StatusCode::OK => Ok(response.json::<PickTaskResponse>().await?.task), | ||
_ => Err(anyhow::anyhow!("Queue is empty")), | ||
} | ||
} | ||
|
||
#[derive(Serialize)] | ||
struct ReportTaskBody { | ||
consumer: String, | ||
stream_id: String, | ||
verdict_json: String, | ||
} | ||
#[derive(Deserialize, Debug)] | ||
struct ReportTaskResponse { | ||
message: String, | ||
} | ||
|
||
async fn report_task( | ||
client: &HttpClient, | ||
stream_id: &str, | ||
results: Vec<JudgeResultInfo>, | ||
) -> Result<(), anyhow::Error> { | ||
let report_url = "/task/report"; | ||
let body = ReportTaskBody { | ||
consumer: "".to_string(), | ||
stream_id: stream_id.to_owned(), | ||
verdict_json: serde_json::to_string(&results).unwrap(), | ||
}; | ||
let response = client | ||
.post(report_url.to_string()) | ||
.json(&body) | ||
.send() | ||
.await?; | ||
|
||
match response.status() { | ||
reqwest::StatusCode::OK => { | ||
log::debug!( | ||
"Report message: {:?}", | ||
response.json::<ReportTaskResponse>().await?.message | ||
); | ||
Ok(()) | ||
} | ||
_ => Err(anyhow::anyhow!("Report Failed")), | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
use anyhow::{self, Error}; | ||
use std::path::PathBuf; | ||
use std::process::Command; | ||
|
||
pub struct RcloneClient { | ||
config_path: PathBuf, | ||
} | ||
|
||
impl RcloneClient { | ||
pub fn new(config_path: PathBuf) -> Self { | ||
Self { config_path } | ||
} | ||
|
||
pub fn is_avaliable(&self) -> bool { | ||
let status = Command::new("rclone") | ||
.arg("--config") | ||
.arg(format!("{}", self.config_path.to_string_lossy())) | ||
.arg("ls") | ||
.arg("minio:") | ||
.status() | ||
.expect("Failed to rclone"); | ||
|
||
status.success() | ||
} | ||
|
||
pub fn sync_bucket(&self, bucket_name: &str, target_dir: PathBuf) -> Result<(), Error> { | ||
let status = Command::new("rclone") | ||
.arg("--config") | ||
.arg(format!("{}", self.config_path.to_string_lossy())) | ||
.arg("sync") | ||
.arg(format!("minio:{}", bucket_name)) | ||
.arg(format!("{}", target_dir.to_string_lossy())) | ||
.status() | ||
.expect("Failed to rclone"); | ||
if status.success() { | ||
Ok(()) | ||
} else { | ||
Err(anyhow::anyhow!("rclone sync failed, please check config.")) | ||
} | ||
} | ||
} |
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
File renamed without changes.
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,50 @@ | ||
mod agent; | ||
mod env; | ||
mod error; | ||
mod handler; | ||
mod worker; | ||
|
||
#[macro_use] | ||
extern crate serde_derive; | ||
extern crate lazy_static; | ||
|
||
use actix_web::{web::Data, App, HttpServer}; | ||
|
||
#[actix_web::main] // or #[tokio::main] | ||
async fn main() -> std::io::Result<()> { | ||
let opt = env::load_option(); | ||
env::setup_logger(); | ||
|
||
// TODO: Send heartbeat here to a remote host | ||
|
||
let worker = match worker::JudgeWorker::new( | ||
opt.base_url, | ||
opt.interval as u64, | ||
opt.rclone_config, | ||
opt.problem_package_dir.clone(), | ||
) { | ||
Ok(maybe_worker) => { | ||
if let Some(worker) = maybe_worker { | ||
worker | ||
} else { | ||
log::error!("Failed to create worker"); | ||
return Ok(()); | ||
} | ||
} | ||
Err(e) => { | ||
log::error!("Failed to create worker: {:?}", e); | ||
return Ok(()); | ||
} | ||
}; | ||
tokio::spawn(async move { worker.run().await }); | ||
|
||
HttpServer::new(move || { | ||
App::new() | ||
.wrap(actix_web::middleware::Logger::default()) | ||
.app_data(Data::new(opt.problem_package_dir.clone())) | ||
.configure(handler::route) | ||
}) | ||
.bind(("0.0.0.0", opt.port))? | ||
.run() | ||
.await | ||
} |
Oops, something went wrong.