✨ 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 { 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 { |   try { | ||||||
|     const client = createClient( |     const client = createClient( | ||||||
|       Deno.env.get('SUPABASE_URL') ?? '', |       Deno.env.get("SUPABASE_URL") ?? "", | ||||||
|       Deno.env.get('SUPABASE_ANON_KEY') ?? '', |       Deno.env.get("SUPABASE_SERVICE_ROLE_KEY") ?? "" | ||||||
|       { global: { headers: { Authorization: req.headers.get('Authorization')! } } } |     ); | ||||||
|     ) |  | ||||||
|  |  | ||||||
|     const { data, error } = await client |     const { data, error } = await client | ||||||
|       .from('challenges') |       .from("challenges") | ||||||
|       .select<any, any>('*') |       .select<any, any>("*") | ||||||
|       .eq('status', 'submitted') |       .eq("status", "submitted") | ||||||
|  |       .limit(20); | ||||||
|  |  | ||||||
|     if (error) { |     if (error) { | ||||||
|       throw error |       throw error; | ||||||
|     } |     } | ||||||
|  |  | ||||||
|     return new Response(JSON.stringify({ data }), { |     let counter = 0; | ||||||
|       headers: { 'Content-Type': 'application/json' }, |     for (const item of data) { | ||||||
|       status: 200, |       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) { |   } 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