func gradeAndUploadResults( ctx *common.Context, client *http.Client, uploadURL string, run *common.Run, finished chan<- error, ) error { requestBody := NewChannelBuffer() defer requestBody.CloseChannel() multipartWriter := multipart.NewWriter(requestBody) defer multipartWriter.Close() go func() { defer requestBody.Close() req, err := http.NewRequest("POST", uploadURL, requestBody) if err != nil { finished <- err close(finished) return } req.Header.Add("Content-Type", multipartWriter.FormDataContentType()) response, err := client.Do(req) if err != nil { finished <- err close(finished) return } response.Body.Close() finished <- nil close(finished) }() result, err := gradeRun(ctx, client, run, multipartWriter) if err != nil { // Still try to send the details ctx.Log.Error("Error grading run", "err", err) result = &runner.RunResult{ Verdict: "JE", MaxScore: run.MaxScore, } } // Send results. resultWriter, err := multipartWriter.CreateFormFile("file", "details.json") if err != nil { ctx.Log.Error("Error sending details.json", "err", err) return err } encoder := json.NewEncoder(resultWriter) if err := encoder.Encode(result); err != nil { ctx.Log.Error("Error encoding details.json", "err", err) return err } // Send uncompressed logs. logsBuffer := ctx.LogBuffer() if logsBuffer != nil { logsWriter, err := multipartWriter.CreateFormFile("file", "logs.txt") if err != nil { ctx.Log.Error("Error creating logs.txt", "err", err) return err } if _, err = logsWriter.Write(logsBuffer); err != nil { ctx.Log.Error("Error sending logs.txt", "err", err) } } // Send uncompressed tracing data. traceBuffer := ctx.TraceBuffer() if traceBuffer != nil { tracingWriter, err := multipartWriter.CreateFormFile("file", "tracing.json") if err != nil { ctx.Log.Error("Error creating tracing.json", "err", err) return err } if _, err = tracingWriter.Write(traceBuffer); err != nil { ctx.Log.Error("Error sending tracing.json", "err", err) return err } } return nil }