package grpc import ( "context" "git.sch9.ru/new_gate/models" "git.sch9.ru/new_gate/ms-tester/internal/problems" problemv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/problem/v1" "git.sch9.ru/new_gate/ms-tester/pkg/utils" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "google.golang.org/protobuf/types/known/emptypb" "io" "os" ) type problemHandlers struct { problemv1.UnimplementedProblemServiceServer problemUC problems.ProblemUseCase } func (h *problemHandlers) CreateProblem(server problemv1.ProblemService_CreateProblemServer) error { ctx := server.Context() if err := h.problemUC.CanCreateProblem(ctx); err != nil { return err } req, err := server.Recv() // receive problem if err != nil { return utils.TransportError(err, utils.ErrBadInput, "can't receive problem") } problem := req.GetProblem() if problem == nil { return utils.TransportError(nil, utils.ErrBadInput, "empty problem") } p := &models.Problem{ Name: utils.AsStringP(problem.Name), Description: utils.AsStringP(problem.Description), TimeLimit: utils.AsInt32P(problem.TimeLimit), MemoryLimit: utils.AsInt32P(problem.MemoryLimit), } ch := readChunks(ctx, server) err = writeChunks(ctx, ch) // temp stub if err != nil { return err // FIXME } id, err := h.problemUC.CreateProblem(ctx, p) // FIXME if err != nil { return err } err = server.SendAndClose(&problemv1.CreateProblemResponse{ Id: id, }) if err != nil { return utils.TransportError(err, utils.ErrBadInput, "can't send response") } return nil } func writeChunks(ctx context.Context, chunks <-chan []byte) error { // use s3 // FIXME: use ctx? f, err := os.Create("out.txt") // FIXME: uuidv4 as initial temp name? if err != nil { return err } defer f.Close() var off int64 = 0 for chunk := range chunks { _, err = f.WriteAt(chunk, off) if err != nil { return err } off += int64(len(chunk)) } // TODO: rename file to its hash return nil } func readChunks(ctx context.Context, server problemv1.ProblemService_CreateProblemServer) <-chan []byte { ch := make(chan []byte) go func() { defer close(ch) for { select { case <-ctx.Done(): return // FIXME default: req, err := server.Recv() if err != nil { if err == io.EOF { return // FIXME } if status.Code(err) == codes.Canceled { return // FIXME } continue } test := req.GetTest() if test == nil { return // FIXME } ch <- test.Chunk } } }() return ch } func (h *problemHandlers) ReadProblem(ctx context.Context, req *problemv1.ReadProblemRequest) (*problemv1.ReadProblemResponse, error) { problem, err := h.problemUC.ReadProblemById(ctx, req.GetId()) if err != nil { return nil, err } return &problemv1.ReadProblemResponse{ Problem: &problemv1.ReadProblemResponse_Problem{ Id: *problem.Id, Name: *problem.Name, Description: *problem.Description, TimeLimit: *problem.TimeLimit, MemoryLimit: *problem.MemoryLimit, CreatedAt: utils.TimestampP(problem.CreatedAt), UpdatedAt: utils.TimestampP(problem.UpdatedAt), }, }, nil } //func (h *problemHandlers) UpdateProblem(ctx context.Context, req *problemv1.UpdateProblemRequest) (*emptypb.Empty, error) { // problem := req.GetProblem() // if problem == nil { // return nil, status.Errorf(codes.Unknown, "") // FIXME // } // err := s.problemService.UpdateProblem( // ctx, // &models.Problem{ // Id: utils.AsInt32P(problem.Id), // Name: problem.Name, // Description: problem.Description, // TimeLimit: problem.TimeLimit, // MemoryLimit: problem.MemoryLimit, // }, // ) // if err != nil { // return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME // } // // return &emptypb.Empty{}, nil //} func (h *problemHandlers) DeleteProblem(ctx context.Context, req *problemv1.DeleteProblemRequest) (*emptypb.Empty, error) { err := h.problemUC.DeleteProblem(ctx, req.GetId()) if err != nil { return nil, err } return &emptypb.Empty{}, nil }