-
Notifications
You must be signed in to change notification settings - Fork 3
Open
Description
package main
import (
"encoding/json"
"fmt"
"io/ioutil"
"log"
"math/rand"
"net/http"
"os"
"os/exec"
"path/filepath"
"strings"
"sync"
"time"
"bufio"
)
var uploadDir = "uploads"
var logFile = "execution_log.json"
func init() {
os.MkdirAll(uploadDir, os.ModePerm)
}
type Language struct {
Extension string
Compile string
Run string
}
var languages = map[string]Language{
"cpp": {".cpp", "g++ {file} -o {output}", "./{output}"},
"go": {".go", "go build -o {output} {file}", "./{output}"},
"java": {".java", "javac {file}", "java -cp {dir} {classname}"},
}
type ExecutionResult struct {
SubmissionID string `json:"submission_id"`
ExecutionTime float64 `json:"execution_time"`
Error string `json:"error,omitempty"`
}
var wg sync.WaitGroup
func executeCommand(command string, timeout time.Duration) (float64, error) {
start := time.Now()
cmd := exec.Command("bash", "-c", command)
err := cmd.Run()
if err != nil {
return 0, err
}
return time.Since(start).Seconds(), nil
}
func logExecutionResult(result ExecutionResult) {
file, err := os.OpenFile(logFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
if err != nil {
log.Printf("Error opening log file: %v", err)
return
}
defer file.Close()
data, _ := json.Marshal(result)
file.Write(data)
file.Write([]byte("\n"))
}
func submitHandler(w http.ResponseWriter, r *http.Request) {
lang := r.URL.Query().Get("lang")
if _, exists := languages[lang]; !exists {
http.Error(w, "Unsupported language", http.StatusBadRequest)
return
}
r.ParseMultipartForm(10 << 20)
file, handler, err := r.FormFile("file")
if err != nil {
http.Error(w, "File upload error", http.StatusInternalServerError)
return
}
defer file.Close()
ext := languages[lang].Extension
submissionID := fmt.Sprintf("%d", rand.Int())
filePath := filepath.Join(uploadDir, submissionID+ext)
outputPath := strings.TrimSuffix(filePath, ext) + ".out"
fileBytes, err := ioutil.ReadAll(file)
if err != nil {
http.Error(w, "Error reading file", http.StatusInternalServerError)
return
}
if err := ioutil.WriteFile(filePath, fileBytes, 0644); err != nil {
http.Error(w, "Error saving file", http.StatusInternalServerError)
return
}
langConfig := languages[lang]
compileCmd := strings.ReplaceAll(langConfig.Compile, "{file}", filePath)
compileCmd = strings.ReplaceAll(compileCmd, "{output}", outputPath)
compileCmd = strings.ReplaceAll(compileCmd, "{dir}", uploadDir)
compileCmd = strings.ReplaceAll(compileCmd, "{classname}", strings.TrimSuffix(handler.Filename, ext))
go func() {
wg.Add(1)
defer wg.Done()
_, err := executeCommand(compileCmd, 10*time.Second)
if err != nil {
logExecutionResult(ExecutionResult{SubmissionID: submissionID, Error: err.Error()})
return
}
runCmd := strings.ReplaceAll(langConfig.Run, "{output}", outputPath)
execTime, err := executeCommand(runCmd, 10*time.Second)
if err != nil {
logExecutionResult(ExecutionResult{SubmissionID: submissionID, Error: err.Error()})
return
}
os.Remove(filePath)
os.Remove(outputPath)
logExecutionResult(ExecutionResult{SubmissionID: submissionID, ExecutionTime: execTime})
}()
fmt.Fprintf(w, "{\"submission_id\": \"%s\"}", submissionID)
}
func getResultHandler(w http.ResponseWriter, r *http.Request) {
submissionID := r.URL.Query().Get("submission_id")
if submissionID == "" {
http.Error(w, "Submission ID required", http.StatusBadRequest)
return
}
file, err := os.Open(logFile)
if err != nil {
http.Error(w, "Error opening log file", http.StatusInternalServerError)
return
}
defer file.Close()
scanner := bufio.NewScanner(file)
for scanner.Scan() {
var result ExecutionResult
json.Unmarshal(scanner.Bytes(), &result)
if result.SubmissionID == submissionID {
w.Header().Set("Content-Type", "application/json")
json.NewEncoder(w).Encode(result)
return
}
}
http.Error(w, "Result not found", http.StatusNotFound)
}
func main() {
http.HandleFunc("/submit", submitHandler)
http.HandleFunc("/result", getResultHandler)
fmt.Println("Server started on :8080")
log.Fatal(http.ListenAndServe(":8080", nil))
}Metadata
Metadata
Assignees
Labels
No labels