feat: add pandoc

This commit is contained in:
Vyacheslav1557 2024-08-18 05:07:31 +05:00
parent 5832e83460
commit b35fd29049
5 changed files with 227 additions and 93 deletions

61
internal/lib/pandoc.go Normal file
View file

@ -0,0 +1,61 @@
package lib
import (
"bytes"
"encoding/json"
"io"
"net/http"
)
type PandocClient struct {
client *http.Client
address string
}
func NewPandocClient(client *http.Client, address string) *PandocClient {
return &PandocClient{
client: client,
address: address,
}
}
type convertRequest struct {
Text string `json:"text"`
From string `json:"from"`
To string `json:"to"`
}
func (client *PandocClient) convert(text, from, to string) (string, error) {
body, err := json.Marshal(convertRequest{
Text: text,
From: from,
To: to,
})
if err != nil {
return "", err
}
buf := bytes.NewBuffer(body)
resp, err := client.client.Post(client.address, "application/json", buf)
if err != nil {
return "", err
}
defer resp.Body.Close()
if resp.StatusCode != http.StatusOK {
return "", err
}
body, err = io.ReadAll(resp.Body)
if err != nil {
return "", err
}
return string(body), nil
}
func (client *PandocClient) ConvertLatexToHtml5(text string) (string, error) {
return client.convert(text, "latex", "html5")
}

View file

@ -12,39 +12,49 @@ type ProblemStorage interface {
DeleteProblem(ctx context.Context, id int32) error DeleteProblem(ctx context.Context, id int32) error
} }
type PandocClient interface {
ConvertLatexToHtml5(text string) (string, error)
}
type ProblemService struct { type ProblemService struct {
problemStorage ProblemStorage problemStorage ProblemStorage
pandocClient PandocClient
} }
func NewProblemService( func NewProblemService(
problemStorage ProblemStorage, problemStorage ProblemStorage,
pandocClient PandocClient,
) *ProblemService { ) *ProblemService {
return &ProblemService{ return &ProblemService{
problemStorage: problemStorage, problemStorage: problemStorage,
pandocClient: pandocClient,
} }
} }
func (service *ProblemService) CreateProblem(ctx context.Context, problem *models.Problem) (int32, error) { func (service *ProblemService) CreateProblem(ctx context.Context, problem *models.Problem, ch <-chan []byte) (int32, error) {
userId := ctx.Value("user_id").(int32) userId := ctx.Value("user_id").(int32)
panic("access control is not implemented yet") html, err := service.pandocClient.ConvertLatexToHtml5(*problem.Description)
if err != nil {
return 0, err
}
panic("access control is not implemented yet")
return service.problemStorage.CreateProblem(ctx, problem) return service.problemStorage.CreateProblem(ctx, problem)
} }
func (service *ProblemService) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error) { func (service *ProblemService) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error) {
userId := ctx.Value("user_id").(int32) userId := ctx.Value("user_id").(int32)
panic("access control is not implemented yet") panic("access control is not implemented yet")
return service.problemStorage.ReadProblemById(ctx, id) return service.problemStorage.ReadProblemById(ctx, id)
} }
func (service *ProblemService) UpdateProblem(ctx context.Context, problem *models.Problem) error { func (service *ProblemService) UpdateProblem(ctx context.Context, problem *models.Problem) error {
userId := ctx.Value("user_id").(int32) userId := ctx.Value("user_id").(int32)
panic("access control is not implemented yet") panic("access control is not implemented yet")
return service.problemStorage.UpdateProblem(ctx, problem) return service.problemStorage.UpdateProblem(ctx, problem)
} }
func (service *ProblemService) DeleteProblem(ctx context.Context, id int32) error { func (service *ProblemService) DeleteProblem(ctx context.Context, id int32) error {
userId := ctx.Value("user_id").(int32) userId := ctx.Value("user_id").(int32)
panic("access control is not implemented yet") panic("access control is not implemented yet")
return service.problemStorage.DeleteProblem(ctx, id) return service.problemStorage.DeleteProblem(ctx, id)
} }

View file

@ -0,0 +1,145 @@
package transport
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/lib"
"git.sch9.ru/new_gate/ms-tester/internal/models"
problemv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/problem/v1"
sessionv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/session/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
"io"
)
func (s *TesterServer) CreateProblem(server problemv1.ProblemService_CreateProblemServer) error {
ctx := server.Context()
req, err := server.Recv() // receive token
if err != nil {
return err // FIXME
}
token := req.GetToken()
userId, err := s.sessionClient.Read(ctx, &sessionv1.ReadSessionRequest{
Token: token,
})
if err != nil {
return err // FIXME
}
ctx = context.WithValue(ctx, "user_id", userId.GetUserId())
req, err = server.Recv() // receive problem
if err != nil {
return err // FIXME
}
problem := req.GetProblem()
if problem == nil {
return status.Errorf(codes.Unknown, "") // FIXME
}
p := &models.Problem{
Name: lib.AsStringP(problem.Name),
Description: lib.AsStringP(problem.Description),
TimeLimit: lib.AsInt32P(problem.TimeLimit),
MemoryLimit: lib.AsInt32P(problem.MemoryLimit),
}
ch := readChunks(ctx, server)
id, err := s.problemService.CreateProblem(ctx, p, ch)
if err != nil {
return status.Errorf(codes.Unknown, "") // FIXME
}
err = server.SendAndClose(&problemv1.CreateProblemResponse{
Id: id,
})
if err != nil {
return err // FIXME
}
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 (s *TesterServer) ReadProblem(ctx context.Context, req *problemv1.ReadProblemRequest) (*problemv1.ReadProblemResponse, error) {
problem, err := s.problemService.ReadProblemById(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &problemv1.ReadProblemResponse{
Problem: &problemv1.ReadProblemResponse_Problem{
Id: *problem.Id,
Name: *problem.Name,
Description: *problem.Description,
TimeLimit: *problem.TimeLimit,
MemoryLimit: *problem.MemoryLimit,
CreatedAt: AsTimestampP(problem.CreatedAt),
UpdatedAt: AsTimestampP(problem.UpdatedAt),
},
}, nil
}
//func (s *TesterServer) 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: lib.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 (s *TesterServer) DeleteProblem(ctx context.Context, req *problemv1.DeleteProblemRequest) (*emptypb.Empty, error) {
err := s.problemService.DeleteProblem(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}

View file

@ -3,8 +3,8 @@ package transport
import ( import (
"context" "context"
"git.sch9.ru/new_gate/ms-tester/internal/models" "git.sch9.ru/new_gate/ms-tester/internal/models"
problemv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/problem/v1"
sessionv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/session/v1" sessionv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/session/v1"
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/tester/v1"
"go.uber.org/zap" "go.uber.org/zap"
"google.golang.org/protobuf/types/known/timestamppb" "google.golang.org/protobuf/types/known/timestamppb"
"time" "time"
@ -13,8 +13,8 @@ import (
) )
type ProblemService interface { type ProblemService interface {
CreateProblem(ctx context.Context, problem *models.Problem) (int32, error) CreateProblem(ctx context.Context, problem *models.Problem, ch <-chan []byte) (int32, error) // FIXME: specify chan type
ReadProblem(ctx context.Context, id int32) (*models.Problem, error) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error)
UpdateProblem(ctx context.Context, problem *models.Problem) error UpdateProblem(ctx context.Context, problem *models.Problem) error
DeleteProblem(ctx context.Context, id int32) error DeleteProblem(ctx context.Context, id int32) error
} }
@ -27,7 +27,7 @@ type SessionClient interface {
} }
type TesterServer struct { type TesterServer struct {
testerv1.UnimplementedTesterServiceServer problemv1.UnimplementedProblemServiceServer
problemService ProblemService problemService ProblemService
sessionClient SessionClient sessionClient SessionClient
@ -51,7 +51,7 @@ func NewTesterServer(
grpc.UnaryInterceptor(server.AuthInterceptor()), grpc.UnaryInterceptor(server.AuthInterceptor()),
) )
testerv1.RegisterTesterServiceServer(grpcServer, server) problemv1.RegisterProblemServiceServer(grpcServer, server)
return server return server
} }

View file

@ -1,82 +0,0 @@
package transport
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/lib"
"git.sch9.ru/new_gate/ms-tester/internal/models"
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/tester/v1"
"google.golang.org/grpc/codes"
"google.golang.org/grpc/status"
"google.golang.org/protobuf/types/known/emptypb"
)
func (s *TesterServer) CreateProblem(ctx context.Context, req *testerv1.CreateProblemRequest) (*testerv1.CreateProblemResponse, error) {
problem := req.GetProblem()
if problem == nil {
return nil, status.Errorf(codes.Unknown, "") // FIXME
}
id, err := s.problemService.CreateProblem(
ctx,
&models.Problem{
Name: lib.AsStringP(problem.Name),
Description: lib.AsStringP(problem.Description),
TimeLimit: lib.AsInt32P(problem.TimeLimit),
MemoryLimit: lib.AsInt32P(problem.MemoryLimit),
},
)
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &testerv1.CreateProblemResponse{
Id: id,
}, nil
}
func (s *TesterServer) ReadProblem(ctx context.Context, req *testerv1.ReadProblemRequest) (*testerv1.ReadProblemResponse, error) {
problem, err := s.problemService.ReadProblem(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &testerv1.ReadProblemResponse{
Problem: &testerv1.ReadProblemResponse_Problem{
Id: *problem.Id,
Name: *problem.Name,
Description: *problem.Description,
TimeLimit: *problem.TimeLimit,
MemoryLimit: *problem.MemoryLimit,
CreatedAt: AsTimestampP(problem.CreatedAt),
UpdatedAt: AsTimestampP(problem.UpdatedAt),
},
}, nil
}
func (s *TesterServer) UpdateProblem(ctx context.Context, req *testerv1.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: lib.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 (s *TesterServer) DeleteProblem(ctx context.Context, req *testerv1.DeleteProblemRequest) (*emptypb.Empty, error) {
err := s.problemService.DeleteProblem(ctx, req.GetId())
if err != nil {
return nil, status.Errorf(codes.Unknown, err.Error()) // FIXME
}
return &emptypb.Empty{}, nil
}