mirror of
https://github.com/MeiK2333/river.git
synced 2025-11-04 14:49:40 +08:00
添加基本运行流程
This commit is contained in:
parent
ef62042fdf
commit
fdaeb0c7e0
@ -16,6 +16,8 @@ tower = "0.3"
|
||||
serde = { version = "1.0", features = ["derive"] }
|
||||
serde_json = "1.0"
|
||||
rand = "0.7"
|
||||
tempfile = "3"
|
||||
libc = "0.2"
|
||||
|
||||
[build-dependencies]
|
||||
tonic-build ={ version = "0.3" }
|
||||
|
||||
@ -45,13 +45,18 @@ message JudgeResponse {
|
||||
CompileError = 6;
|
||||
PresentationError = 7;
|
||||
SystemError = 8;
|
||||
Pending = 9;
|
||||
Compiling = 10;
|
||||
Running = 11;
|
||||
}
|
||||
JudgeResult result = 3;
|
||||
int32 errno = 4;
|
||||
int32 exit_code = 5;
|
||||
string stdout = 6;
|
||||
string stderr = 7;
|
||||
string errmsg = 8;
|
||||
enum JudgeStatus {
|
||||
Pending = 0;
|
||||
Compiling = 1;
|
||||
Running = 2;
|
||||
Ended = 3;
|
||||
}
|
||||
JudgeStatus status = 9;
|
||||
}
|
||||
|
||||
31
src/error.rs
Normal file
31
src/error.rs
Normal file
@ -0,0 +1,31 @@
|
||||
use crate::river::judge_response::{JudgeResult, JudgeStatus};
|
||||
use crate::river::JudgeResponse;
|
||||
use std::fmt;
|
||||
use std::result;
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum Error {}
|
||||
|
||||
pub type Result<T> = result::Result<T, Error>;
|
||||
|
||||
impl fmt::Display for Error {
|
||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
||||
match *self {
|
||||
_ => write!(f, "{:?}", self),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub fn system_error(err: Error) -> JudgeResponse {
|
||||
JudgeResponse {
|
||||
time_used: 0,
|
||||
memory_used: 0,
|
||||
result: JudgeResult::SystemError as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "".into(),
|
||||
stderr: "".into(),
|
||||
errmsg: format!("{}", err).into(),
|
||||
status: JudgeStatus::Ended as i32,
|
||||
}
|
||||
}
|
||||
73
src/judger.rs
Normal file
73
src/judger.rs
Normal file
@ -0,0 +1,73 @@
|
||||
use super::error::Result;
|
||||
use crate::river::judge_response::{JudgeResult, JudgeStatus};
|
||||
use crate::river::{JudgeRequest, JudgeResponse};
|
||||
|
||||
pub async fn judger(request: &JudgeRequest) -> Result<JudgeResponse> {
|
||||
return Ok(JudgeResponse {
|
||||
time_used: request.time_limit,
|
||||
memory_used: 2,
|
||||
result: JudgeResult::Accepted as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "stdout".into(),
|
||||
stderr: "stderr".into(),
|
||||
errmsg: "".into(),
|
||||
status: JudgeStatus::Ended as i32,
|
||||
});
|
||||
}
|
||||
|
||||
pub async fn compile(request: &JudgeRequest) -> Result<JudgeResponse> {
|
||||
return Ok(JudgeResponse {
|
||||
time_used: request.time_limit,
|
||||
memory_used: 2,
|
||||
result: JudgeResult::Accepted as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "stdout".into(),
|
||||
stderr: "stderr".into(),
|
||||
errmsg: "".into(),
|
||||
status: JudgeStatus::Ended as i32,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn pending() -> JudgeResponse {
|
||||
JudgeResponse {
|
||||
time_used: 0,
|
||||
memory_used: 0,
|
||||
result: JudgeResult::Accepted as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "".into(),
|
||||
stderr: "".into(),
|
||||
errmsg: "".into(),
|
||||
status: JudgeStatus::Pending as i32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn running() -> JudgeResponse {
|
||||
JudgeResponse {
|
||||
time_used: 0,
|
||||
memory_used: 0,
|
||||
result: JudgeResult::Accepted as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "".into(),
|
||||
stderr: "".into(),
|
||||
errmsg: "".into(),
|
||||
status: JudgeStatus::Running as i32,
|
||||
}
|
||||
}
|
||||
|
||||
pub fn compiling() -> JudgeResponse {
|
||||
JudgeResponse {
|
||||
time_used: 0,
|
||||
memory_used: 0,
|
||||
result: JudgeResult::Accepted as i32,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "".into(),
|
||||
stderr: "".into(),
|
||||
errmsg: "".into(),
|
||||
status: JudgeStatus::Compiling as i32,
|
||||
}
|
||||
}
|
||||
48
src/main.rs
48
src/main.rs
@ -1,14 +1,20 @@
|
||||
#![recursion_limit = "256"]
|
||||
|
||||
use crate::river::judge_response::JudgeResult;
|
||||
use futures::StreamExt;
|
||||
use futures_core::Stream;
|
||||
use river::river_server::{River, RiverServer};
|
||||
use river::{JudgeRequest, JudgeResponse};
|
||||
use std::pin::Pin;
|
||||
use tokio::time::{delay_for, Duration};
|
||||
use tonic::transport::Server;
|
||||
use tonic::{Request, Response, Status};
|
||||
|
||||
mod error;
|
||||
mod judger;
|
||||
mod process;
|
||||
|
||||
pub mod river {
|
||||
tonic::include_proto!("river"); // The string specified here must match the proto package name
|
||||
tonic::include_proto!("river");
|
||||
}
|
||||
|
||||
#[derive(Debug, Default)]
|
||||
@ -26,18 +32,36 @@ impl River for RiverService {
|
||||
let mut stream = request.into_inner();
|
||||
|
||||
let output = async_stream::try_stream! {
|
||||
while let Some(note) = stream.next().await {
|
||||
yield river::JudgeResponse {
|
||||
time_used: 1,
|
||||
memory_used: 2,
|
||||
result: 0,
|
||||
errno: 0,
|
||||
exit_code: 0,
|
||||
stdout: "stdout".into(),
|
||||
stderr: "stderr".into(),
|
||||
let mut need_compile = true;
|
||||
while let Some(req) = stream.next().await {
|
||||
// TODO: 使用锁或者资源量等机制限制并发
|
||||
yield judger::pending();
|
||||
let req = req?;
|
||||
|
||||
// 首次获取流进行编译
|
||||
if need_compile {
|
||||
yield judger::compiling();
|
||||
let result = match judger::compile(&req).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => error::system_error(e)
|
||||
};
|
||||
// 如果编译错误,则不进行后续流程
|
||||
if result.result != JudgeResult::Accepted as i32 {
|
||||
yield result;
|
||||
break;
|
||||
}
|
||||
}
|
||||
need_compile = false;
|
||||
|
||||
yield judger::running();
|
||||
let result = match judger::judger(&req).await {
|
||||
Ok(res) => res,
|
||||
Err(e) => error::system_error(e)
|
||||
};
|
||||
delay_for(Duration::from_millis(10000)).await;
|
||||
|
||||
yield result;
|
||||
}
|
||||
while let Some(_) = stream.next().await {}
|
||||
};
|
||||
|
||||
Ok(Response::new(Box::pin(output) as Self::JudgeStream))
|
||||
|
||||
41
src/process.rs
Normal file
41
src/process.rs
Normal file
@ -0,0 +1,41 @@
|
||||
use libc;
|
||||
use std::future::Future;
|
||||
use std::pin::Pin;
|
||||
use std::task::{Context, Poll};
|
||||
use std::thread;
|
||||
use std::time::Duration;
|
||||
|
||||
pub struct Process {
|
||||
pub pid: i32,
|
||||
pub time_limit: i32,
|
||||
pub read_time_limit: i32,
|
||||
pub memory_limit: i32,
|
||||
pub stdin_fd: i32,
|
||||
pub stdout_fd: i32,
|
||||
pub stderr_fd: i32,
|
||||
pub cmd: str,
|
||||
}
|
||||
|
||||
impl Future for Process {
|
||||
type Output = &'static str;
|
||||
|
||||
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<&'static str> {
|
||||
let mut status = 0;
|
||||
unsafe {
|
||||
// TODO: fork、修改用户、组、设置限制,exec 等等
|
||||
// TODO: seccomp 等保证安全
|
||||
let _pid = libc::waitpid(self.pid, &mut status, libc::WNOHANG);
|
||||
}
|
||||
if status != 0 {
|
||||
return Poll::Ready("");
|
||||
}
|
||||
let waker = cx.waker().clone();
|
||||
|
||||
thread::spawn(move || {
|
||||
thread::sleep(Duration::from_millis(3000));
|
||||
waker.wake();
|
||||
});
|
||||
|
||||
Poll::Pending
|
||||
}
|
||||
}
|
||||
Loading…
Reference in New Issue
Block a user