From c341b6c586a050be136f26de7bee3f2d977ba0ac Mon Sep 17 00:00:00 2001 From: Eason <30045503+Eason0729@users.noreply.github.com> Date: Thu, 22 Aug 2024 08:33:40 +0800 Subject: [PATCH] Cannot add problem to another contest if problem has been in contest that deleted (#66) * Fix bug children's foreign key not deleted * chore remove idea warning * Fix typo --- backend/src/endpoint/announcement.rs | 6 +- backend/src/endpoint/chat.rs | 4 +- backend/src/endpoint/contest.rs | 114 ++++++++++++++----------- backend/src/endpoint/education.rs | 6 +- backend/src/endpoint/imgur.rs | 2 +- backend/src/endpoint/problem.rs | 24 ++++-- backend/src/endpoint/submit.rs | 8 +- backend/src/endpoint/testcase.rs | 7 +- backend/src/endpoint/token.rs | 6 +- backend/src/endpoint/user.rs | 6 +- backend/src/util/error.rs | 7 +- judger/src/error.rs | 18 ++-- judger/src/filesystem/adapter/error.rs | 12 +-- judger/src/filesystem/adapter/fuse.rs | 27 +++--- judger/src/filesystem/adapter/reply.rs | 2 +- judger/src/filesystem/entry/mod.rs | 2 +- judger/src/filesystem/mod.rs | 4 +- judger/src/filesystem/resource.rs | 6 +- judger/src/filesystem/table.rs | 6 +- judger/src/language/spec/mod.rs | 2 +- judger/src/language/stage/judge.rs | 2 +- judger/src/language/stage/mod.rs | 10 +-- judger/src/language/stage/run.rs | 2 +- judger/src/sandbox/monitor/mem_cpu.rs | 2 +- judger/src/sandbox/monitor/mod.rs | 6 +- judger/src/sandbox/monitor/output.rs | 2 +- judger/src/sandbox/monitor/wrapper.rs | 6 +- judger/src/sandbox/process/lifetime.rs | 7 +- judger/src/sandbox/process/mod.rs | 4 +- judger/src/sandbox/process/nsjail.rs | 4 +- judger/src/server.rs | 21 ++--- 31 files changed, 177 insertions(+), 158 deletions(-) diff --git a/backend/src/endpoint/announcement.rs b/backend/src/endpoint/announcement.rs index d3dcdc4..2c664f9 100644 --- a/backend/src/endpoint/announcement.rs +++ b/backend/src/endpoint/announcement.rs @@ -175,7 +175,7 @@ impl Announcement for ArcServer { let id = *model.id.as_ref(); - tracing::info!(count.announcement = 1, id = id); + info!(count.announcement = 1, id = id); Ok(id.into()) }) @@ -197,7 +197,7 @@ impl Announcement for ArcServer { req.bound_check()?; req.get_or_insert(|req| async move { - tracing::trace!(id = req.id); + trace!(id = req.id); let mut model = Entity::find_by_id(req.id) .with_auth(&auth) @@ -242,7 +242,7 @@ impl Announcement for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.announcement = -1, id = req.id); + info!(counter.announcement = -1, id = req.id); Ok(()) } }) diff --git a/backend/src/endpoint/chat.rs b/backend/src/endpoint/chat.rs index 14b6f17..2357665 100644 --- a/backend/src/endpoint/chat.rs +++ b/backend/src/endpoint/chat.rs @@ -51,7 +51,7 @@ impl Chat for ArcServer { .map_err(Into::::into)?; let id = *model.id.as_ref(); - tracing::debug!(id = id, "chat_created"); + debug!(id = id, "chat_created"); Ok(id.into()) }) @@ -80,7 +80,7 @@ impl Chat for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.chat = -1, id = req.id); + info!(counter.chat = -1, id = req.id); Ok(()) } }) diff --git a/backend/src/endpoint/contest.rs b/backend/src/endpoint/contest.rs index 9ba8bdf..a31f7ef 100644 --- a/backend/src/endpoint/contest.rs +++ b/backend/src/endpoint/contest.rs @@ -1,9 +1,9 @@ use super::*; - use crate::entity::{ contest::{Paginator, *}, - *, + problem, *, }; +use sea_orm::sea_query::Expr; use grpc::backend::contest_server::*; @@ -164,7 +164,7 @@ impl Contest for ArcServer { let id = *model.id.as_ref(); - tracing::info!(count.contest = 1, id = id); + info!(count.contest = 1, id = id); Ok(id.into()) }) @@ -185,7 +185,7 @@ impl Contest for ArcServer { let (_, perm) = auth.assume_login()?; req.get_or_insert(|req| async move { - tracing::trace!(id = req.id); + trace!(id = req.id); let mut model = Entity::find_by_id(req.id).with_auth(&auth).write()? .one(self.db.deref()) @@ -238,6 +238,8 @@ impl Contest for ArcServer { let (auth, req) = self.rate_limit(req).in_current_span().await?; req.get_or_insert(|req| async move { + let txn = self.db.begin().await?; + let result = Entity::delete_by_id(req.id) .with_auth(&auth) .write()? @@ -246,12 +248,20 @@ impl Contest for ArcServer { .await .map_err(Into::::into)?; + problem::Entity::update_many() + .col_expr(problem::Column::ContestId, Expr::value(Value::Int(None))) + .filter(crate::entity::testcase::Column::ProblemId.eq(req.id)) + .exec(&txn) + .instrument(info_span!("remove_child")) + .await?; + + txn.commit().await.map_err(|_| Error::Retry)?; + if result.rows_affected == 0 { - Err(Error::NotInDB) - } else { - tracing::info!(counter.contest = -1, id = req.id); - Ok(()) + return Err(Error::NotInDB); } + info!(counter.contest = -1, id = req.id); + Ok(()) }) .await .with_grpc() @@ -260,47 +270,30 @@ impl Contest for ArcServer { #[instrument( skip_all, level = "info", - name = "oj.backend.Contest/join", + name = "oj.backend.Contest/publish", err(level = "debug", Display) )] - async fn join(&self, req: Request) -> Result, Status> { + async fn publish(&self, req: Request) -> Result, Status> { let (auth, req) = self.rate_limit(req).in_current_span().await?; - let (user_id, _) = auth.assume_login()?; req.get_or_insert(|req| async move { - let model = Entity::find_by_id(req.id) + let mut model = Entity::find_by_id(req.id) .with_auth(&auth) - .read()? + .write()? + .columns([Column::Id]) .one(self.db.deref()) .instrument(info_span!("fetch").or_current()) .await .map_err(Into::::into)? - .ok_or(Error::NotInDB)?; - // FIXME: abstract away password checking logic - - if let Some(tar) = model.password { - let password = req - .password - .as_ref() - .ok_or(Error::NotInPayload("password"))?; - if !self.crypto.hash_eq(password, &tar) { - return Err(Error::PermissionDeny("mismatched password")); - } - } - - let pivot = user_contest::ActiveModel { - user_id: ActiveValue::Set(user_id), - contest_id: ActiveValue::Set(model.id), - ..Default::default() - }; + .ok_or(Error::NotInDB)? + .into_active_model(); - pivot - .save(self.db.deref()) - .instrument(info_span!("insert_pviot").or_current()) - .await - .map_err(Into::::into)?; + model.public = ActiveValue::Set(true); - tracing::debug!(user_id = user_id, contest_id = req.id); + model + .update(self.db.deref()) + .instrument(info_span!("update").or_current()) + .await?; Ok(()) }) .await @@ -310,10 +303,10 @@ impl Contest for ArcServer { #[instrument( skip_all, level = "info", - name = "oj.backend.Contest/publish", + name = "oj.backend.Contest/unpublish", err(level = "debug", Display) )] - async fn publish(&self, req: Request) -> Result, Status> { + async fn unpublish(&self, req: Request) -> Result, Status> { let (auth, req) = self.rate_limit(req).in_current_span().await?; req.get_or_insert(|req| async move { @@ -328,7 +321,7 @@ impl Contest for ArcServer { .ok_or(Error::NotInDB)? .into_active_model(); - model.public = ActiveValue::Set(true); + model.public = ActiveValue::Set(false); model .update(self.db.deref()) @@ -343,30 +336,47 @@ impl Contest for ArcServer { #[instrument( skip_all, level = "info", - name = "oj.backend.Contest/unpublish", + name = "oj.backend.Contest/join", err(level = "debug", Display) )] - async fn unpublish(&self, req: Request) -> Result, Status> { + async fn join(&self, req: Request) -> Result, Status> { let (auth, req) = self.rate_limit(req).in_current_span().await?; + let (user_id, _) = auth.assume_login()?; req.get_or_insert(|req| async move { - let mut model = Entity::find_by_id(req.id) + let model = Entity::find_by_id(req.id) .with_auth(&auth) - .write()? - .columns([Column::Id]) + .read()? .one(self.db.deref()) .instrument(info_span!("fetch").or_current()) .await .map_err(Into::::into)? - .ok_or(Error::NotInDB)? - .into_active_model(); + .ok_or(Error::NotInDB)?; + // FIXME: abstract away password checking logic - model.public = ActiveValue::Set(false); + if let Some(tar) = model.password { + let password = req + .password + .as_ref() + .ok_or(Error::NotInPayload("password"))?; + if !self.crypto.hash_eq(password, &tar) { + return Err(Error::PermissionDeny("mismatched password")); + } + } - model - .update(self.db.deref()) - .instrument(info_span!("update").or_current()) - .await?; + let pivot = user_contest::ActiveModel { + user_id: ActiveValue::Set(user_id), + contest_id: ActiveValue::Set(model.id), + ..Default::default() + }; + + pivot + .save(self.db.deref()) + .instrument(info_span!("insert_pviot").or_current()) + .await + .map_err(Into::::into)?; + + debug!(user_id = user_id, contest_id = req.id); Ok(()) }) .await diff --git a/backend/src/endpoint/education.rs b/backend/src/endpoint/education.rs index ad58625..ea48d9e 100644 --- a/backend/src/endpoint/education.rs +++ b/backend/src/endpoint/education.rs @@ -104,7 +104,7 @@ impl Education for ArcServer { let id = *model.id.as_ref(); - tracing::info!(count.education = 1, id = id); + info!(count.education = 1, id = id); Ok(id.into()) }) @@ -123,7 +123,7 @@ impl Education for ArcServer { req.bound_check()?; req.get_or_insert(|req| async move { - tracing::trace!(id = req.id); + trace!(id = req.id); let mut model = Entity::find_by_id(req.id) .with_auth(&auth) .write()? @@ -167,7 +167,7 @@ impl Education for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.education = -1, id = req.id); + info!(counter.education = -1, id = req.id); Ok(()) } }) diff --git a/backend/src/endpoint/imgur.rs b/backend/src/endpoint/imgur.rs index ea1cd41..0a824b7 100644 --- a/backend/src/endpoint/imgur.rs +++ b/backend/src/endpoint/imgur.rs @@ -19,7 +19,7 @@ impl Image for ArcServer { req.get_or_insert(|req| async move { let url = self.imgur.upload(req.data).await?; - tracing::debug!(counter.image = 1, uri = url); + debug!(counter.image = 1, uri = url); Ok(UploadResponse { url }) }) .await diff --git a/backend/src/endpoint/problem.rs b/backend/src/endpoint/problem.rs index 7aa5228..56f15f8 100644 --- a/backend/src/endpoint/problem.rs +++ b/backend/src/endpoint/problem.rs @@ -1,7 +1,8 @@ use super::*; use grpc::backend::problem_server::*; +use sea_orm::sea_query::Expr; -use crate::entity::{contest, problem::Paginator, problem::*}; +use crate::entity::{contest, problem::Paginator, problem::*, testcase}; impl<'a> From> for ProblemFullInfo { fn from(value: WithAuth<'a, Model>) -> Self { @@ -139,7 +140,7 @@ impl Problem for ArcServer { let id = *model.id.as_ref(); - tracing::info!(count.problem = 1, id = id); + info!(count.problem = 1, id = id); Ok(id.into()) }) @@ -191,17 +192,28 @@ impl Problem for ArcServer { async fn remove(&self, req: Request) -> Result, Status> { let (auth, req) = self.rate_limit(req).in_current_span().await?; req.get_or_insert(|req| async move { + let txn = self.db.begin().await?; + let result = Entity::delete_by_id(req.id) .with_auth(&auth) .write()? - .exec(self.db.deref()) + .exec(&txn) .instrument(info_span!("remove").or_current()) - .await - .map_err(Into::::into)?; + .await?; + + testcase::Entity::update_many() + .col_expr(testcase::Column::ProblemId, Expr::value(Value::Int(None))) + .filter(testcase::Column::ProblemId.eq(req.id)) + .exec(&txn) + .instrument(info_span!("remove_child")) + .await?; + + txn.commit().await.map_err(|_| Error::Retry)?; if result.rows_affected == 0 { return Err(Error::NotInDB); } + info!(count.problem = -1, id = req.id); Ok(()) }) .await @@ -286,7 +298,7 @@ impl Problem for ArcServer { let mut model = model.ok_or(Error::NotInDB)?.into_active_model(); if let Some(x) = model.contest_id.into_value() { - tracing::debug!(old_id = x.to_string()); + debug!(old_id = x.to_string()); } model.contest_id = ActiveValue::Set(None); model diff --git a/backend/src/endpoint/submit.rs b/backend/src/endpoint/submit.rs index 06b3e23..6023018 100644 --- a/backend/src/endpoint/submit.rs +++ b/backend/src/endpoint/submit.rs @@ -91,11 +91,11 @@ impl Submit for ArcServer { async fn info(&self, req: Request) -> Result, Status> { let (auth, req) = self.rate_limit(req).in_current_span().await?; - tracing::debug!(id = req.id); + debug!(id = req.id); let model = Entity::read_filter(Entity::find_by_id(req.id), &auth)? .one(self.db.deref()) - .instrument(tracing::debug_span!("fetch").or_current()) + .instrument(debug_span!("fetch").or_current()) .await .map_err(Into::::into)? .ok_or(Error::NotInDB)?; @@ -156,7 +156,7 @@ impl Submit for ArcServer { .instrument(info_span!("construct_submit").or_current()) .await?; - tracing::info!(counter.submit = 1, id = id); + info!(counter.submit = 1, id = id); Ok(id.into()) }) @@ -189,7 +189,7 @@ impl Submit for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.submit = -1, id = req.id); + info!(counter.submit = -1, id = req.id); Ok(()) } }) diff --git a/backend/src/endpoint/testcase.rs b/backend/src/endpoint/testcase.rs index 77c2331..8aed017 100644 --- a/backend/src/endpoint/testcase.rs +++ b/backend/src/endpoint/testcase.rs @@ -102,7 +102,7 @@ impl Testcase for ArcServer { let id = *model.id.as_ref(); - tracing::info!(count.testcase = 1, id = id); + info!(count.testcase = 1, id = id); Ok(id.into()) }) @@ -121,7 +121,7 @@ impl Testcase for ArcServer { req.bound_check()?; req.get_or_insert(|req| async move { - tracing::trace!(id = req.id); + trace!(id = req.id); let mut model = Entity::write_filter(Entity::find_by_id(req.id), &auth)? .one(self.db.deref()) .instrument(info_span!("fetch").or_current()) @@ -162,7 +162,7 @@ impl Testcase for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.testcase = -1, id = req.id); + info!(counter.testcase = -1, id = req.id); Ok(()) } }) @@ -197,6 +197,7 @@ impl Testcase for ArcServer { let problem: problem::IdModel = problem.ok_or(Error::NotInDB)?; let mut model = model.ok_or(Error::NotInDB)?.into_active_model(); + // FIXME: use is_set(), be sure to know what Option in sea_orm said if let ActiveValue::Set(Some(v)) = model.problem_id { return Err(Error::AlreadyExist("testcase already linked")); } diff --git a/backend/src/endpoint/token.rs b/backend/src/endpoint/token.rs index ca106a3..d3be66a 100644 --- a/backend/src/endpoint/token.rs +++ b/backend/src/endpoint/token.rs @@ -77,7 +77,7 @@ impl Token for ArcServer { // FIXME: add request_id let (_, req) = self.rate_limit(req).in_current_span().await?; - tracing::debug!(username = req.username); + debug!(username = req.username); let model = user::Entity::find() .filter(user::Column::Username.eq(req.username)) @@ -99,7 +99,7 @@ impl Token for ArcServer { expiry: into_prost(expiry), })) } else { - tracing::trace!("password_mismatch"); + trace!("password_mismatch"); Err(Error::PermissionDeny("wrong password").into()) } } @@ -164,7 +164,7 @@ impl Token for ArcServer { .remove(token.to_string()) .in_current_span() .await?; - tracing::event!(Level::TRACE, token = token); + event!(Level::TRACE, token = token); return Ok(Response::new(())); } diff --git a/backend/src/endpoint/user.rs b/backend/src/endpoint/user.rs index c86fb14..b8efe38 100644 --- a/backend/src/endpoint/user.rs +++ b/backend/src/endpoint/user.rs @@ -118,7 +118,7 @@ impl User for ArcServer { let mut model: ActiveModel = Default::default(); - tracing::debug!(username = req.info.username); + debug!(username = req.info.username); let hash = self.crypto.hash(req.info.password.as_str()); @@ -133,7 +133,7 @@ impl User for ArcServer { .map_err(Into::::into)?; let id = *model.id.as_ref(); - tracing::info!(counter.user = 1, id = id); + info!(counter.user = 1, id = id); Ok(id.into()) }) @@ -213,7 +213,7 @@ impl User for ArcServer { if result.rows_affected == 0 { Err(Error::NotInDB) } else { - tracing::info!(counter.announcement = -1, id = req.id); + info!(counter.announcement = -1, id = req.id); Ok(()) } }) diff --git a/backend/src/util/error.rs b/backend/src/util/error.rs index 92461c1..9c9d449 100644 --- a/backend/src/util/error.rs +++ b/backend/src/util/error.rs @@ -33,8 +33,6 @@ pub enum Error { Unreachable(&'static str), #[error("Number too large(or small)")] NumberTooLarge, - // #[error("Buffer `{0}` too large")] - // BufferTooLarge(&'static str), #[error("`{0}` Already exist")] AlreadyExist(&'static str), #[error("require permission `{0}`")] @@ -47,6 +45,8 @@ pub enum Error { Judger(#[from] judger::Error), #[error("token error: `{0}`")] Token(#[from] token::Error), + #[error("retry later")] + Retry, } impl From for Error { @@ -103,6 +103,7 @@ impl From for Status { Error::Image(x) => report_internal!(error, "{}", x), Error::Judger(x) => x.into(), Error::Token(x) => x.into(), + Error::Retry => Status::aborted("Should retry"), } } } @@ -110,7 +111,7 @@ impl From for Status { /// Tracing information for error /// /// useful to log the tracing information to client -/// without exposing the server's internal erro +/// without exposing the server's internal error pub struct Tracing { trace_id: TraceId, span_id: SpanId, diff --git a/judger/src/error.rs b/judger/src/error.rs index 3225eee..2c155a8 100644 --- a/judger/src/error.rs +++ b/judger/src/error.rs @@ -8,8 +8,8 @@ pub enum Error { Io(#[from] std::io::Error), #[error("sandbox error: {0}")] Sandbox(#[from] SandboxError), - /// the program is running on a 32 bit platform, - /// and have a object reached [`u32::MAX`] + /// the program is running on a 32-bit platform, + /// and have an object reached [`u32::MAX`] #[error("32 bit problem")] Platform, } @@ -23,10 +23,10 @@ impl From for Status { #[derive(thiserror::Error, Debug)] pub enum ClientError { - #[error("invaild secret")] - InvaildSecret, - #[error("invaild language uuid")] - InvaildLanguageUuid, + #[error("invalid secret")] + InvalidSecret, + #[error("invalid language uuid")] + InvalidLanguageUuid, #[error("impossible memory requirement")] ImpossibleMemoryRequirement, } @@ -34,9 +34,9 @@ pub enum ClientError { impl From for Status { fn from(value: ClientError) -> Self { match value { - ClientError::InvaildSecret => Status::permission_denied("Invaild secret"), - ClientError::InvaildLanguageUuid => { - Status::failed_precondition("Invaild language uuid") + ClientError::InvalidSecret => Status::permission_denied("Invalid secret"), + ClientError::InvalidLanguageUuid => { + Status::failed_precondition("Invalid language uuid") } ClientError::ImpossibleMemoryRequirement => { Status::failed_precondition("Impossible memory requirement") diff --git a/judger/src/filesystem/adapter/error.rs b/judger/src/filesystem/adapter/error.rs index 0e10451..0c51c97 100644 --- a/judger/src/filesystem/adapter/error.rs +++ b/judger/src/filesystem/adapter/error.rs @@ -20,17 +20,17 @@ pub enum FuseError { #[error("unimplemented")] Unimplemented, #[error("missed inode")] - InvaildIno, + InvalidIno, #[error("missed handle")] HandleNotFound, - #[error("underlaying file error")] - Underlaying, + #[error("underlying file error")] + Underlying, #[error("invalid path")] InvalidPath, #[error("permission deny")] PermissionDeny, #[error("invalid argument")] - InvialdArg, + InvalidArg, #[error("Already exist")] AlreadyExist, } @@ -47,9 +47,9 @@ impl From for fuse3::Errno { log::info!("out of resource"); libc::ENOMEM } - FuseError::InvalidPath | FuseError::InvaildIno => libc::ENOENT, + FuseError::InvalidPath | FuseError::InvalidIno => libc::ENOENT, FuseError::PermissionDeny => libc::EACCES, - FuseError::InvialdArg => libc::EINVAL, + FuseError::InvalidArg => libc::EINVAL, FuseError::AlreadyExist => libc::EEXIST, err => { log::warn!("FUSE driver broken: {}", err); diff --git a/judger/src/filesystem/adapter/fuse.rs b/judger/src/filesystem/adapter/fuse.rs index 0e5b220..8d98c37 100644 --- a/judger/src/filesystem/adapter/fuse.rs +++ b/judger/src/filesystem/adapter/fuse.rs @@ -3,7 +3,6 @@ use std::{ffi::OsStr, num::NonZeroU32, path::Path, sync::Arc}; use bytes::Bytes; use futures_core::Future; use spin::Mutex; -use tokio::fs::metadata; use tokio::io::{AsyncRead, AsyncSeek}; use tokio::sync::Mutex as AsyncMutex; @@ -87,7 +86,7 @@ where async fn lookup(&self, req: Request, parent: u64, name: &OsStr) -> FuseResult { let tree = self.tree.lock(); - let parent_node = tree.get(parent as usize).ok_or(FuseError::InvaildIno)?; + let parent_node = tree.get(parent as usize).ok_or(FuseError::InvalidIno)?; let node = parent_node .get_by_component(name) .ok_or(FuseError::InvalidPath)?; @@ -122,7 +121,7 @@ where } async fn opendir(&self, _: Request, inode: u64, flags: u32) -> FuseResult { let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; if node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); } @@ -135,7 +134,7 @@ where // ignore write permission, because some application may open files // with write permission but never write let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; if node.get_value().kind() == FileType::Directory { return Err(FuseError::IsDir.into()); } @@ -152,7 +151,7 @@ where offset: i64, ) -> FuseResult>> { let tree = self.tree.lock(); - let node = tree.get(parent as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(parent as usize).ok_or(FuseError::InvalidIno)?; if node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); @@ -201,7 +200,7 @@ where _: u64, ) -> FuseResult>> { let tree = self.tree.lock(); - let node = tree.get(parent as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(parent as usize).ok_or(FuseError::InvalidIno)?; if node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); @@ -322,7 +321,7 @@ where _: u32, ) -> FuseResult<()> { let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; match node.get_value().kind() { FileType::Directory | FileType::NamedPipe | FileType::CharDevice => { @@ -342,7 +341,7 @@ where _: u32, ) -> FuseResult { let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; // FIXME: unsure about the inode Ok(reply_attr(&req, node.get_value(), inode)) } @@ -354,7 +353,7 @@ where _: SetAttr, ) -> FuseResult { let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; Ok(reply_attr(&req, node.get_value(), inode)) } async fn create( @@ -366,7 +365,7 @@ where flags: u32, ) -> FuseResult { let mut tree = self.tree.lock(); - let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvaildIno)?; + let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvalidIno)?; if parent_node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); } @@ -389,7 +388,7 @@ where _: u32, ) -> FuseResult { let mut tree = self.tree.lock(); - let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvaildIno)?; + let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvalidIno)?; if parent_node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); } @@ -401,18 +400,18 @@ where } async fn readlink(&self, _: Request, inode: Inode) -> FuseResult { let tree = self.tree.lock(); - let node = tree.get(inode as usize).ok_or(FuseError::InvaildIno)?; + let node = tree.get(inode as usize).ok_or(FuseError::InvalidIno)?; let link = node .get_value() .get_symlink() - .ok_or(FuseError::InvialdArg)?; + .ok_or(FuseError::InvalidArg)?; Ok(ReplyData { data: Bytes::copy_from_slice(link.as_encoded_bytes()), }) } async fn unlink(&self, _: Request, parent: Inode, name: &OsStr) -> FuseResult<()> { let mut tree = self.tree.lock(); - let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvaildIno)?; + let mut parent_node = tree.get_mut(parent as usize).ok_or(FuseError::InvalidIno)?; if parent_node.get_value().kind() != FileType::Directory { return Err(FuseError::NotDir.into()); } diff --git a/judger/src/filesystem/adapter/reply.rs b/judger/src/filesystem/adapter/reply.rs index 8de93a3..ed587a3 100644 --- a/judger/src/filesystem/adapter/reply.rs +++ b/judger/src/filesystem/adapter/reply.rs @@ -1,4 +1,4 @@ -//! collection of function that fill the value of +//! collection of function that fill with the value of //! reply packets back to fuse connection use std::{ffi::OsString, time::Duration}; diff --git a/judger/src/filesystem/entry/mod.rs b/judger/src/filesystem/entry/mod.rs index 8f83ea2..bb25b91 100644 --- a/judger/src/filesystem/entry/mod.rs +++ b/judger/src/filesystem/entry/mod.rs @@ -136,7 +136,7 @@ where pub async fn write(&mut self, offset: u64, data: &[u8], resource: &Resource) -> Option { // FIXME: consume logic should move somewhere else let required_size = data.len() as u64 + offset; - resource.comsume_other(required_size.saturating_sub(self.get_size()))?; + resource.consume_other(required_size.saturating_sub(self.get_size()))?; match self { Self::MemFile(block) => Some(block.write(offset, data).await.unwrap()), diff --git a/judger/src/filesystem/mod.rs b/judger/src/filesystem/mod.rs index 3393101..289ba14 100644 --- a/judger/src/filesystem/mod.rs +++ b/judger/src/filesystem/mod.rs @@ -1,5 +1,5 @@ -//! Filesystem module that is mountable(actuallly mount and -//! is accessible for user in this operation system) +//! Filesystem module that is mountable(actually mount and +//! is accessible for user in this operating system) mod adapter; mod entry; mod handle; diff --git a/judger/src/filesystem/resource.rs b/judger/src/filesystem/resource.rs index 55db660..0c3721a 100644 --- a/judger/src/filesystem/resource.rs +++ b/judger/src/filesystem/resource.rs @@ -11,7 +11,7 @@ impl Resource { Self(AtomicU64::new(cap)) } /// consume some amount of resource - pub fn comsume(&self, size: u32) -> Option<()> { + pub fn consume(&self, size: u32) -> Option<()> { let a = self.0.fetch_sub(size as u64, Ordering::AcqRel); if (a & (1 << 63)) != 0 { None @@ -23,8 +23,8 @@ impl Resource { /// /// return None if the resource is not enough or the size /// is out of range (greater than[`u32::MAX`]) - pub fn comsume_other>(&self, size: T) -> Option<()> { + pub fn consume_other>(&self, size: T) -> Option<()> { let size = size.try_into().ok()?; - self.comsume(size) + self.consume(size) } } diff --git a/judger/src/filesystem/table.rs b/judger/src/filesystem/table.rs index 8618192..ff18f47 100644 --- a/judger/src/filesystem/table.rs +++ b/judger/src/filesystem/table.rs @@ -294,7 +294,7 @@ mod test { use super::*; #[test] fn test_adj_table() { - let mut table = super::AdjTable::new(); + let mut table = AdjTable::new(); let mut root = table.insert_root(0); root.insert(OsStr::new("a").into(), 1); let mut b = root.insert(OsStr::new("b").into(), 2).unwrap(); @@ -306,7 +306,7 @@ mod test { } #[test] fn get_or_insert() { - let mut table = super::AdjTable::new(); + let mut table = AdjTable::new(); table.insert_root(0); table.insert_by_path( vec!["abc", "efg", "123", "456"] @@ -325,7 +325,7 @@ mod test { } #[test] fn parent_child_insert() { - let mut table = super::AdjTable::new(); + let mut table = AdjTable::new(); let mut root = table.insert_root(0); // inode 1 assert_eq!(root.get_id(), 1); let mut a = root.insert(OsStr::new("a").into(), 1).unwrap(); // inode 2 diff --git a/judger/src/language/spec/mod.rs b/judger/src/language/spec/mod.rs index 449910d..2d49a91 100644 --- a/judger/src/language/spec/mod.rs +++ b/judger/src/language/spec/mod.rs @@ -107,7 +107,7 @@ impl Spec { let mut raw: Raw = toml::from_str(content).unwrap(); raw.fill(); - // FIXME: use compsition instead + // FIXME: use composition instead Self { info: LangInfo::from(&raw), id: raw.id, diff --git a/judger/src/language/stage/judge.rs b/judger/src/language/stage/judge.rs index 6ec8099..1cb734b 100644 --- a/judger/src/language/stage/judge.rs +++ b/judger/src/language/stage/judge.rs @@ -43,7 +43,7 @@ impl Judger { } } } - AssertionMode::SkipContinousSpace => { + AssertionMode::SkipContinuousSpace => { // skip space and newline, continous space is consider same let output = output.iter().map(|x| match x { b'\n' | b' ' => b' ', diff --git a/judger/src/language/stage/mod.rs b/judger/src/language/stage/mod.rs index 41f755e..8af73dd 100644 --- a/judger/src/language/stage/mod.rs +++ b/judger/src/language/stage/mod.rs @@ -11,7 +11,7 @@ pub use run::Runner; /// internal status code, use to decouple the grpc status code /// -/// Status code is commonly use in OJ, it include example such as: AC, WA... +/// Status code is commonly use in OJ, it includes example such as: AC, WA... #[derive(Clone, Copy, PartialEq, Eq, Debug)] pub enum StatusCode { Accepted, @@ -27,7 +27,7 @@ pub enum StatusCode { /// internal assertion mode, use to decouple the grpc status code /// -/// Assertion mode reperesent how the output is compared +/// Assertion mode represent how the output is compared #[derive(Clone, Copy)] pub enum AssertionMode { /// Skip single space and newline @@ -36,10 +36,10 @@ pub enum AssertionMode { /// /// `a\nb` and `a\n\nb` are different SkipSpace, - /// Skip continous space and newline + /// Skip continuous space and newline /// /// `ab`, `a\nb` and `a\n\nb` are the same - SkipContinousSpace, + SkipContinuousSpace, /// Exact match Exact, } @@ -56,7 +56,7 @@ impl From for AssertionMode { match rule { JudgeMatchRule::ExactSame => AssertionMode::Exact, JudgeMatchRule::IgnoreSnl => AssertionMode::SkipSpace, - JudgeMatchRule::SkipSnl => AssertionMode::SkipContinousSpace, + JudgeMatchRule::SkipSnl => AssertionMode::SkipContinuousSpace, } } } diff --git a/judger/src/language/stage/run.rs b/judger/src/language/stage/run.rs index ebc9d78..bd674dc 100644 --- a/judger/src/language/stage/run.rs +++ b/judger/src/language/stage/run.rs @@ -46,7 +46,7 @@ impl Runner { /// See [`Context`] for more information struct RunCtx { spec: Arc, - path: std::path::PathBuf, + path: PathBuf, limit: Stat, } diff --git a/judger/src/sandbox/monitor/mem_cpu.rs b/judger/src/sandbox/monitor/mem_cpu.rs index 2856d7d..0cbe87a 100644 --- a/judger/src/sandbox/monitor/mem_cpu.rs +++ b/judger/src/sandbox/monitor/mem_cpu.rs @@ -126,7 +126,7 @@ impl super::Monitor for Monitor { /// get the final resource usage /// /// Please remember thatActively limit(notify) cpu resource is achieved - /// by polling the cgroup, therefore the delay requirespecial attention, + /// by polling the cgroup, therefore the delay require special attention, /// it is only guaranteed to below limitation provided + [`MONITOR_ACCURACY`]. async fn stat(self) -> Self::Resource { // FIXME: check running process, this line is commented out because of uncollected process diff --git a/judger/src/sandbox/monitor/mod.rs b/judger/src/sandbox/monitor/mod.rs index 08bac8f..eed17b6 100644 --- a/judger/src/sandbox/monitor/mod.rs +++ b/judger/src/sandbox/monitor/mod.rs @@ -24,7 +24,7 @@ lazy_static::lazy_static! { pub trait Monitor { type Resource; - /// wait for exhuast of resource + /// wait for exhaust of resource /// /// This function is cancel safe. async fn wait_exhaust(&mut self) -> MonitorKind { @@ -37,9 +37,9 @@ pub trait Monitor { tokio::time::sleep(Duration::from_millis(12)).await; } } - /// poll for exhuast of resource + /// poll for exhaust of resource /// - /// Implementor should do bith [`wait_exhaust`] and [`poll_exhaust`] + /// Implementor should do both [`wait_exhaust`] and [`poll_exhaust`] /// for better performance. fn poll_exhaust(&mut self) -> Option; /// get the resource usage diff --git a/judger/src/sandbox/monitor/output.rs b/judger/src/sandbox/monitor/output.rs index f5aaa46..b437446 100644 --- a/judger/src/sandbox/monitor/output.rs +++ b/judger/src/sandbox/monitor/output.rs @@ -82,7 +82,7 @@ mod test { #[tokio::test] async fn monitor_output_limit() { - let (mut stdin, stdout) = tokio::io::duplex(1024); + let (mut stdin, stdout) = duplex(1024); let mut monitor = Monitor::inner_new(9, stdout); stdin.write_all(b"1234567890").await.unwrap(); assert_eq!( diff --git a/judger/src/sandbox/monitor/wrapper.rs b/judger/src/sandbox/monitor/wrapper.rs index d58539b..3a18d0b 100644 --- a/judger/src/sandbox/monitor/wrapper.rs +++ b/judger/src/sandbox/monitor/wrapper.rs @@ -66,9 +66,9 @@ impl<'a> CgroupWrapper<'a> { /// get memory usage(statistics) pub fn memory(&self) -> Memory { let controller = self.0.controller_of::().unwrap(); - let kusage = controller.kmem_stat(); + let kernel_usage = controller.kmem_stat(); - let kernel = kusage.max_usage_in_bytes; + let kernel = kernel_usage.max_usage_in_bytes; let user = controller.memory_stat().max_usage_in_bytes; let total = kernel + user; @@ -96,7 +96,7 @@ impl CgroupWrapperOwned { } /// poll until cgroup is deleted /// - /// After the cgroup is empty(`tasks` is empty), the cgroup is can be delete safely + /// After the cgroup is empty(`tasks` is empty), the cgroup is can be deleted safely /// /// However, in some rare cases, the monitor is reading file in cgroup /// when the cgroup is about to be deleted, this will cause the cgroup to stay busy diff --git a/judger/src/sandbox/process/lifetime.rs b/judger/src/sandbox/process/lifetime.rs index ba86017..02b918c 100644 --- a/judger/src/sandbox/process/lifetime.rs +++ b/judger/src/sandbox/process/lifetime.rs @@ -9,7 +9,7 @@ use tokio::{ process::*, time, }; -/// A unlaunched process that is mounted with a filesystem +/// A not yet launched process that is mounted with a filesystem struct MountedProcess { context: C, fs: C::FS, @@ -84,10 +84,9 @@ impl Process { let root = self.fs.get_path(); // FIXME: check spec before unwrap let jail = self.context.get_args().next().unwrap(); - let unjailed = [root.as_ref().as_os_str(), jail].join(OsStr::new("")); - let unjailed = PathBuf::from(unjailed); + let real_path = PathBuf::from([root.as_ref().as_os_str(), jail].join(OsStr::new(""))); - let mut ancestors = unjailed.ancestors(); + let mut ancestors = real_path.ancestors(); ancestors.next().unwrap(); ancestors.next().unwrap().as_os_str().to_os_string() } diff --git a/judger/src/sandbox/process/mod.rs b/judger/src/sandbox/process/mod.rs index 7b1e026..f2ef3b0 100644 --- a/judger/src/sandbox/process/mod.rs +++ b/judger/src/sandbox/process/mod.rs @@ -1,6 +1,6 @@ -//! A module that provides a way to setup environment for a process and run. +//! A module that provides a way to set up environment for a process and run. //! -//! Using this module should be SAFE(can't launching a process without +//! Using this module should be SAFE(can't launch a process without //! explicit resource limitation) //! //! ```norun diff --git a/judger/src/sandbox/process/nsjail.rs b/judger/src/sandbox/process/nsjail.rs index 5d07766..9f9d768 100644 --- a/judger/src/sandbox/process/nsjail.rs +++ b/judger/src/sandbox/process/nsjail.rs @@ -14,7 +14,7 @@ pub trait Argument { fn get_args(self) -> impl Iterator>; } -/// factory pattern for conbinating arguments +/// factory pattern for combining arguments #[derive(Default)] pub struct ArgFactory { args: Vec>, @@ -31,7 +31,7 @@ impl ArgFactory { } } -/// base auguments for nsjail +/// base arguments for nsjail pub struct BaseArg; impl Argument for BaseArg { diff --git a/judger/src/server.rs b/judger/src/server.rs index 51d0e8b..f2ac022 100644 --- a/judger/src/server.rs +++ b/judger/src/server.rs @@ -16,7 +16,7 @@ use crate::{ const PLUGIN_PATH: &str = "plugins"; -fn check_secret(req: tonic::Request) -> Result { +fn check_secret(req: Request) -> Result { let (meta, _, payload) = req.into_parts(); if CONFIG.secret.is_none() { return Ok(payload); @@ -24,13 +24,13 @@ fn check_secret(req: tonic::Request) -> Result { let secret = CONFIG.secret.as_ref().unwrap(); if let Some(header) = meta.get("Authorization") { let secret = ["basic ", secret].concat().into_bytes(); - let vaild = header + let valid = header .as_bytes() .iter() .zip(secret.iter()) .map(|(&a, &b)| a == b) .reduce(|a, b| a && b); - if vaild.unwrap_or(false) { + if valid.unwrap_or(false) { return Ok(payload); } } @@ -64,12 +64,12 @@ impl Judger for Server { let cpu = payload.time; let source = payload.code; let uuid = - Uuid::from_str(&payload.lang_uid).map_err(|_| ClientError::InvaildLanguageUuid)?; + Uuid::from_str(&payload.lang_uid).map_err(|_| ClientError::InvalidLanguageUuid)?; let plugin = self .plugins .get(&uuid) - .ok_or(ClientError::InvaildLanguageUuid)?; + .ok_or(ClientError::InvalidLanguageUuid)?; let resource: u32 = plugin .get_memory_reserved(payload.memory) .try_into() @@ -106,7 +106,7 @@ impl Judger for Server { }))) } - async fn judger_info(&self, req: tonic::Request<()>) -> Result, Status> { + async fn judger_info(&self, req: Request<()>) -> Result, Status> { check_secret(req)?; let list = self .plugins @@ -123,10 +123,7 @@ impl Judger for Server { type ExecStream = tokio_stream::Once>; - async fn exec( - &self, - req: Request, - ) -> Result, tonic::Status> { + async fn exec(&self, req: Request) -> Result, Status> { let payload = check_secret(req)?; let memory = payload.memory; @@ -136,12 +133,12 @@ impl Judger for Server { let input = payload.input; let uuid = - Uuid::from_str(&payload.lang_uid).map_err(|_| ClientError::InvaildLanguageUuid)?; + Uuid::from_str(&payload.lang_uid).map_err(|_| ClientError::InvalidLanguageUuid)?; let plugin = self .plugins .get(&uuid) - .ok_or(ClientError::InvaildLanguageUuid)?; + .ok_or(ClientError::InvalidLanguageUuid)?; let resource: u32 = plugin .get_memory_reserved(payload.memory)