✨ Challenge Judgement
This commit is contained in:
		
							
								
								
									
										6
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								.idea/inspectionProfiles/Project_Default.xml
									
									
									
										generated
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <component name="InspectionProjectProfileManager"> | ||||
|   <profile version="1.0"> | ||||
|     <option name="myName" value="Project Default" /> | ||||
|     <inspection_tool class="ExceptionCaughtLocallyJS" enabled="false" level="WARNING" enabled_by_default="false" /> | ||||
|   </profile> | ||||
| </component> | ||||
							
								
								
									
										1
									
								
								supabase/functions/.env
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										1
									
								
								supabase/functions/.env
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1 @@ | ||||
| JUDGE0_ENDPOINT=http://192.168.50.83:2358 | ||||
							
								
								
									
										44
									
								
								supabase/functions/fresh-challenges/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								supabase/functions/fresh-challenges/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,44 @@ | ||||
| import { createClient } from "https://esm.sh/@supabase/supabase-js"; | ||||
|  | ||||
| // http://127.0.0.1:54321/functions/v1/fresh-challenges | ||||
| // Auto get judging status from remote lawyers | ||||
|  | ||||
| Deno.serve(async (req) => { | ||||
|   try { | ||||
|     const client = createClient( | ||||
|       Deno.env.get("SUPABASE_URL") ?? "", | ||||
|       Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "" | ||||
|     ); | ||||
|  | ||||
|     const body = await req.json(); | ||||
|  | ||||
|     const { data } = await client | ||||
|       .from("challenges") | ||||
|       .select<any, any>("*") | ||||
|       .eq("status", "judging") | ||||
|       .eq("id", body.id) | ||||
|       .single(); | ||||
|  | ||||
|     if (data == null || data?.details?.submissions == null) { | ||||
|       return new Response(String("Unable to find the challenge with the id in the request."), { status: 400 }); | ||||
|     } | ||||
|  | ||||
|     const tokens = data?.details?.submissions | ||||
|       .map((item: { token: string }) => item.token) | ||||
|       .join(","); | ||||
|  | ||||
|     const resp = await fetch( | ||||
|       Deno.env.get("JUDGE0_ENDPOINT") + `/submissions/batch?tokens=${tokens}`, | ||||
|       { method: "GET" } | ||||
|     ); | ||||
|  | ||||
|     const result = await resp.json(); | ||||
|  | ||||
|     return new Response(JSON.stringify({ result }), { | ||||
|       headers: { "Content-Type": "application/json" }, | ||||
|       status: 200 | ||||
|     }); | ||||
|   } catch (err) { | ||||
|     return new Response(String(err?.message ?? err), { status: 500 }); | ||||
|   } | ||||
| }); | ||||
| @@ -1,39 +1,58 @@ | ||||
| import { createClient } from "https://esm.sh/@supabase/supabase-js"; | ||||
| import { runChallenge } from "./runners/index.ts"; | ||||
|  | ||||
| Deno.serve(async (req) => { | ||||
| // http://127.0.0.1:54321/functions/v1/judge-challenges | ||||
| // Judge all status is submitted challenges | ||||
|  | ||||
| Deno.serve(async (_) => { | ||||
|   try { | ||||
|     const client = createClient( | ||||
|       Deno.env.get('SUPABASE_URL') ?? '', | ||||
|       Deno.env.get('SUPABASE_ANON_KEY') ?? '', | ||||
|       { global: { headers: { Authorization: req.headers.get('Authorization')! } } } | ||||
|     ) | ||||
|       Deno.env.get("SUPABASE_URL") ?? "", | ||||
|       Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "" | ||||
|     ); | ||||
|  | ||||
|     const { data, error } = await client | ||||
|       .from('challenges') | ||||
|       .select<any, any>('*') | ||||
|       .eq('status', 'submitted') | ||||
|       .from("challenges") | ||||
|       .select<any, any>("*") | ||||
|       .eq("status", "submitted") | ||||
|       .limit(20); | ||||
|  | ||||
|     if (error) { | ||||
|       throw error | ||||
|       throw error; | ||||
|     } | ||||
|  | ||||
|     return new Response(JSON.stringify({ data }), { | ||||
|       headers: { 'Content-Type': 'application/json' }, | ||||
|       status: 200, | ||||
|     }) | ||||
|     let counter = 0; | ||||
|     for (const item of data) { | ||||
|       const { data: problem } = await client | ||||
|         .from("problems") | ||||
|         .select<any, any>("*") | ||||
|         .eq("id", item.problem) | ||||
|         .single(); | ||||
|  | ||||
|       if (problem == null) { | ||||
|         throw new Error("Problem was not found."); | ||||
|       } | ||||
|  | ||||
|       const { data: cases } = await client | ||||
|         .from("problem_cases") | ||||
|         .select<any, any>("*") | ||||
|         .eq("problem", problem.id); | ||||
|  | ||||
|       const result = await runChallenge(item, problem, cases); | ||||
|  | ||||
|       await client | ||||
|         .from("challenges") | ||||
|         .update<any>({ status: result.status === "skipped" ? "finished" : "judging", details: result }) | ||||
|         .eq("id", item.id); | ||||
|  | ||||
|       counter++; | ||||
|     } | ||||
|  | ||||
|     return new Response(JSON.stringify({ judged: counter }), { | ||||
|       headers: { "Content-Type": "application/json" }, | ||||
|       status: 200 | ||||
|     }); | ||||
|   } catch (err) { | ||||
|     return new Response(String(err?.message ?? err), { status: 500 }) | ||||
|     return new Response(String(err?.message ?? err), { status: 500 }); | ||||
|   } | ||||
| }); | ||||
|  | ||||
| /* To invoke locally: | ||||
|  | ||||
|   1. Run `supabase start` (see: https://supabase.com/docs/reference/cli/supabase-start) | ||||
|   2. Make an HTTP request: | ||||
|  | ||||
|   curl -i --location --request POST 'http://127.0.0.1:54321/functions/v1/judge-challenges' \ | ||||
|     --header 'Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpc3MiOiJzdXBhYmFzZS1kZW1vIiwicm9sZSI6ImFub24iLCJleHAiOjE5ODM4MTI5OTZ9.CRXP1A7WOeoJeXxjNni43kdQwgnWNReilDMblYTn_I0' \ | ||||
|     --header 'Content-Type: application/json' \ | ||||
|     --data '{"name":"Functions"}' | ||||
|  | ||||
| */ | ||||
|   | ||||
							
								
								
									
										10
									
								
								supabase/functions/judge-challenges/runners/index.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										10
									
								
								supabase/functions/judge-challenges/runners/index.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,10 @@ | ||||
| import { runProgramChallenge } from "./programming.ts"; | ||||
|  | ||||
| export async function runChallenge(challenge: any, problem: any, cases: any) { | ||||
|   switch (problem.type) { | ||||
|     case "programming": | ||||
|       return await runProgramChallenge(challenge, problem, cases) | ||||
|     default: | ||||
|       throw new Error("Unsupported problem type.") | ||||
|   } | ||||
| } | ||||
							
								
								
									
										40
									
								
								supabase/functions/judge-challenges/runners/programming.ts
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										40
									
								
								supabase/functions/judge-challenges/runners/programming.ts
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,40 @@ | ||||
| export async function runProgramChallenge(challenge: any, problem: any, cases: any[]) { | ||||
|   const languages: { [id: string]: number } = { | ||||
|     "cpp": 54 | ||||
|   }; | ||||
|  | ||||
|   const code = challenge.answers?.code; | ||||
|   const language = challenge.answers?.language; | ||||
|   if (!code || !language || !cases || Object.keys(languages).indexOf(language) < 0) { | ||||
|     return { | ||||
|       status: "skipped", | ||||
|       submissions: null | ||||
|     }; | ||||
|   } | ||||
|  | ||||
|   const idx = languages[language]; | ||||
|   const submissions = cases.map((item: any) => { | ||||
|     return { | ||||
|       "language_id": idx, | ||||
|       "source_code": challenge.answers?.code, | ||||
|       "expected_output": item?.stdout, | ||||
|       "stdin": code | ||||
|     }; | ||||
|   }); | ||||
|  | ||||
|   const resp = await fetch( | ||||
|     Deno.env.get("JUDGE0_ENDPOINT") + "/submissions/batch", | ||||
|     { | ||||
|       method: "POST", | ||||
|       headers: { "Content-Type": "application/json" }, | ||||
|       body: JSON.stringify({ submissions }) | ||||
|     } | ||||
|   ); | ||||
|  | ||||
|   const result = await resp.json(); | ||||
|  | ||||
|   return { | ||||
|     status: "judging", | ||||
|     submissions: result | ||||
|   }; | ||||
| } | ||||
		Reference in New Issue
	
	Block a user