feat(tester): migrate from gRPC to REST

This commit is contained in:
Vyacheslav1557 2025-02-25 18:40:05 +05:00
parent 6613b03b6c
commit a560715ae8
40 changed files with 403 additions and 961 deletions

View file

@ -1,10 +1,21 @@
package tester
import (
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/tester/v1"
"google.golang.org/grpc"
testerv1 "git.sch9.ru/new_gate/ms-tester/proto/tester/v1"
"github.com/gofiber/fiber/v2"
)
type Handlers interface {
CreateSolution(*testerv1.CreateSolutionRequest, grpc.ServerStreamingServer[testerv1.TestingState]) error
ListContests(c *fiber.Ctx) error
CreateContest(c *fiber.Ctx) error
DeleteContest(c *fiber.Ctx, id int32) error
GetContest(c *fiber.Ctx, id int32) error
DeleteParticipant(c *fiber.Ctx, id int32, params testerv1.DeleteParticipantParams) error
AddParticipant(c *fiber.Ctx, id int32, params testerv1.AddParticipantParams) error
DeleteTask(c *fiber.Ctx, id int32, params testerv1.DeleteTaskParams) error
AddTask(c *fiber.Ctx, id int32, params testerv1.AddTaskParams) error
ListProblems(c *fiber.Ctx) error
CreateProblem(c *fiber.Ctx) error
DeleteProblem(c *fiber.Ctx, id int32) error
GetProblem(c *fiber.Ctx, id int32) error
}

View file

@ -1,41 +0,0 @@
package grpc
import (
"git.sch9.ru/new_gate/ms-tester/internal/tester"
testerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/tester/v1"
"google.golang.org/grpc"
)
func NewTesterHandlers(gserver *grpc.Server, testerUC tester.TesterUseCase) {
handlers := &testerHandlers{
testerUC: testerUC,
}
testerv1.RegisterTesterServiceServer(gserver, handlers)
}
type testerHandlers struct {
testerv1.UnimplementedTesterServiceServer
testerUC tester.TesterUseCase
}
func (h *testerHandlers) CreateSolution(req *testerv1.CreateSolutionRequest, stream testerv1.TesterService_CreateSolutionServer) error {
id, err := h.testerUC.CreateSolution(stream.Context(), req.GetTaskId(), req.GetSolution(), req.GetLanguage())
if err != nil {
return err
}
ch, err := h.testerUC.ProcessTesting(stream.Context(), id)
if err != nil {
return err
}
for state := range ch {
err = stream.Send(&testerv1.TestingState{Msg: state})
if err != nil {
return err
}
}
return nil
}

View file

@ -1,107 +0,0 @@
package rabbitmq
import (
"context"
"fmt"
"git.sch9.ru/new_gate/ms-tester/internal/tester"
runnerv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/runner/v1"
"github.com/golang/protobuf/proto"
amqp "github.com/rabbitmq/amqp091-go"
)
func NewTesterProducer(ch *amqp.Channel, tQueueName string, rQueueName string, testerUC tester.TesterUseCase) {
_, err := ch.QueueDeclare(
tQueueName,
true,
false,
false,
false,
nil,
)
if err != nil {
panic(err)
}
go func() {
for d := range testerUC.TestingChannel() {
for i := 0; i < 15; i++ {
msg := runnerv1.Instruction{
Instruction: &runnerv1.Instruction_Run{
Run: &runnerv1.Run{
SolutionId: d,
TestId: 0,
BindingKey: rQueueName,
},
}}
body, err := proto.Marshal(&msg)
if err != nil {
panic(err)
}
err = ch.Publish(
"",
tQueueName,
false,
false,
amqp.Publishing{
ContentType: "text/plain",
Body: body,
},
)
if err != nil {
panic(err)
}
}
}
}()
return
}
func NewTesterConsumer(ch *amqp.Channel, rQueueName string, instanceName string, testerUC tester.TesterUseCase) {
_, err := ch.QueueDeclare(
rQueueName,
true,
false,
false,
false,
nil,
)
if err != nil {
panic(err)
}
msgs, err := ch.Consume(
rQueueName,
"",
false,
true, // each tester must have exclusive results queue
false,
false,
nil,
)
if err != nil {
panic(err)
}
go func() {
for d := range msgs {
err = d.Ack(false)
if err != nil {
panic(err)
}
msg := runnerv1.Result{}
err = proto.Unmarshal(d.Body, &msg)
if err != nil {
panic(err)
}
fmt.Println(msg.String())
err = testerUC.ProcessResult(context.Background(), msg.GetRun().SolutionId, msg.GetRun().String())
if err != nil {
fmt.Println(err)
}
}
}()
}

View file

@ -0,0 +1,145 @@
package rest
import (
"git.sch9.ru/new_gate/ms-tester/internal/tester"
testerv1 "git.sch9.ru/new_gate/ms-tester/proto/tester/v1"
"github.com/gofiber/fiber/v2"
)
type TesterHandlers struct {
problemsUC tester.ProblemUseCase
contestsUC tester.ContestUseCase
}
func NewTesterHandlers(problemsUC tester.ProblemUseCase, contestsUC tester.ContestRepository) *TesterHandlers {
return &TesterHandlers{
problemsUC: problemsUC,
contestsUC: contestsUC,
}
}
func (h *TesterHandlers) ListContests(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusNotImplemented)
}
func (h *TesterHandlers) ListProblems(c *fiber.Ctx) error {
return c.SendStatus(fiber.StatusNotImplemented)
}
func (h *TesterHandlers) CreateContest(c *fiber.Ctx) error {
id, err := h.contestsUC.CreateContest(c.Context(), "Название контеста")
if err != nil {
return err
}
return c.JSON(testerv1.CreateContestResponse{
Id: id,
})
}
func (h *TesterHandlers) DeleteContest(c *fiber.Ctx, id int32) error {
err := h.contestsUC.DeleteContest(c.Context(), id)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusOK)
}
func (h *TesterHandlers) GetContest(c *fiber.Ctx, id int32) error {
contest, err := h.contestsUC.ReadContestById(c.Context(), id)
if err != nil {
return err
}
return c.JSON(testerv1.GetContestResponse{
Contest: testerv1.Contest{
Id: *contest.Id,
Title: *contest.Title,
CreatedAt: *contest.CreatedAt,
UpdatedAt: *contest.UpdatedAt,
},
})
}
func (h *TesterHandlers) DeleteParticipant(c *fiber.Ctx, id int32, params testerv1.DeleteParticipantParams) error {
err := h.contestsUC.DeleteParticipant(c.Context(), params.ParticipantId)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusOK)
}
func (h *TesterHandlers) AddParticipant(c *fiber.Ctx, id int32, params testerv1.AddParticipantParams) error {
id, err := h.contestsUC.AddParticipant(c.Context(), id, params.UserId)
if err != nil {
return err
}
return c.JSON(testerv1.AddParticipantResponse{
Id: id,
})
}
func (h *TesterHandlers) DeleteTask(c *fiber.Ctx, id int32, params testerv1.DeleteTaskParams) error {
err := h.contestsUC.DeleteTask(c.Context(), params.TaskId)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusOK)
}
func (h *TesterHandlers) AddTask(c *fiber.Ctx, id int32, params testerv1.AddTaskParams) error {
id, err := h.contestsUC.AddTask(c.Context(), id, params.ProblemId)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusNotImplemented)
}
func (h *TesterHandlers) CreateProblem(c *fiber.Ctx) error {
id, err := h.problemsUC.CreateProblem(c.Context(), "Название задачи")
if err != nil {
return err
}
return c.JSON(testerv1.CreateProblemResponse{
Id: id,
})
}
func (h *TesterHandlers) DeleteProblem(c *fiber.Ctx, id int32) error {
err := h.problemsUC.DeleteProblem(c.Context(), id)
if err != nil {
return err
}
return c.SendStatus(fiber.StatusOK)
}
func (h *TesterHandlers) GetProblem(c *fiber.Ctx, id int32) error {
problem, err := h.problemsUC.ReadProblemById(c.Context(), id)
if err != nil {
return err
}
return c.JSON(
testerv1.GetProblemResponse{Problem: testerv1.Problem{
Id: *problem.Id,
Legend: *problem.Legend,
InputFormat: *problem.InputFormat,
OutputFormat: *problem.OutputFormat,
Notes: *problem.Notes,
Tutorial: *problem.Tutorial,
LatexSummary: *problem.LatexSummary,
TimeLimit: *problem.TimeLimit,
MemoryLimit: *problem.MemoryLimit,
CreatedAt: *problem.CreatedAt,
UpdatedAt: *problem.UpdatedAt,
}},
)
}

View file

@ -1,4 +1,22 @@
package tester
type TesterRepository interface {
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
)
type ProblemPostgresRepository interface {
CreateProblem(ctx context.Context, title string) (int32, error)
ReadProblemById(ctx context.Context, id int32) (*models.Problem, error)
DeleteProblem(ctx context.Context, id int32) error
}
type ContestRepository interface {
CreateContest(ctx context.Context, title string) (int32, error)
ReadContestById(ctx context.Context, id int32) (*models.Contest, error)
DeleteContest(ctx context.Context, id int32) error
AddTask(ctx context.Context, contestId int32, taskId int32) (int32, error)
DeleteTask(ctx context.Context, taskId int32) error
AddParticipant(ctx context.Context, contestId int32, userId int32) (int32, error)
DeleteParticipant(ctx context.Context, participantId int32) error
}

View file

@ -0,0 +1,23 @@
package repository
import (
"errors"
"git.sch9.ru/new_gate/ms-tester/pkg/utils"
"github.com/jackc/pgerrcode"
"github.com/jackc/pgx/v5/pgconn"
)
func handlePgErr(err error) error {
var pgErr *pgconn.PgError
if !errors.As(err, &pgErr) {
return utils.StorageError(err, utils.ErrUnknown, "unexpected error from postgres")
}
if pgerrcode.IsIntegrityConstraintViolation(pgErr.Code) {
// TODO: probably should specify which constraint
return utils.StorageError(err, utils.ErrConflict, pgErr.Message)
}
if pgerrcode.IsNoData(pgErr.Code) {
return utils.StorageError(err, utils.ErrNotFound, pgErr.Message)
}
return utils.StorageError(err, utils.ErrUnimplemented, "unimplemented error")
}

View file

@ -0,0 +1,124 @@
package repository
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
)
type ContestRepository struct {
db *sqlx.DB
logger *zap.Logger
}
func NewContestRepository(db *sqlx.DB, logger *zap.Logger) *ContestRepository {
return &ContestRepository{
db: db,
logger: logger,
}
}
const createContestQuery = "INSERT INTO contests (title) VALUES (?) RETURNING id"
func (r *ContestRepository) CreateContest(ctx context.Context, title string) (int32, error) {
query := r.db.Rebind(createContestQuery)
rows, err := r.db.QueryxContext(ctx, query, title)
if err != nil {
return 0, handlePgErr(err)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
}
return id, nil
}
const readContestByIdQuery = "SELECT * from contests WHERE id=? LIMIT 1"
func (r *ContestRepository) ReadContestById(ctx context.Context, id int32) (*models.Contest, error) {
var contest models.Contest
query := r.db.Rebind(readContestByIdQuery)
err := r.db.GetContext(ctx, &contest, query, id)
if err != nil {
return nil, handlePgErr(err)
}
return &contest, nil
}
const deleteContestQuery = "DELETE FROM contests WHERE id=?"
func (r *ContestRepository) DeleteContest(ctx context.Context, id int32) error {
query := r.db.Rebind(deleteContestQuery)
_, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return handlePgErr(err)
}
return nil
}
const addTaskQuery = "INSERT INTO tasks (problem_id, contest_id, position) VALUES (?, ?,COALESCE(SELECT MAX(position) FROM task WHERE contest_id = ? ,0) + 1) RETURNING id"
func (r *ContestRepository) AddTask(ctx context.Context, contestId int32, problem_id int32) (int32, error) {
query := r.db.Rebind(addTaskQuery)
rows, err := r.db.QueryxContext(ctx, query, problem_id, contestId, contestId)
if err != nil {
return 0, handlePgErr(err)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
}
return id, nil
}
const deleteTaskQuery = "DELETE FROM tasks WHERE id=?"
func (r *ContestRepository) DeleteTask(ctx context.Context, taskId int32) error {
query := r.db.Rebind(deleteTaskQuery)
_, err := r.db.ExecContext(ctx, query, taskId)
if err != nil {
return handlePgErr(err)
}
return nil
}
const addParticipantQuery = "INSERT INTO participants (user_id ,contest_id, name) VALUES (?, ?, ?) RETURNING id"
func (r *ContestRepository) AddParticipant(ctx context.Context, contestId int32, userId int32) (int32, error) {
query := r.db.Rebind(addParticipantQuery)
name := ""
rows, err := r.db.QueryxContext(ctx, query, contestId, userId, name)
if err != nil {
return 0, handlePgErr(err)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, err
}
return id, nil
}
const deleteParticipantQuery = "DELETE FROM participants WHERE id=?"
func (r *ContestRepository) DeleteParticipant(ctx context.Context, participantId int32) error {
query := r.db.Rebind(deleteParticipantQuery)
_, err := r.db.ExecContext(ctx, query, participantId)
if err != nil {
return handlePgErr(err)
}
return nil
}

View file

@ -0,0 +1,154 @@
package repository
import (
"context"
"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"testing"
)
func TestContestRepository_CreateContest(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid contest creation", func(t *testing.T) {
title := "Contest title"
rows := sqlmock.NewRows([]string{"id"}).AddRow(1)
mock.ExpectQuery(sqlxDB.Rebind(createContestQuery)).WithArgs(title).WillReturnRows(rows)
id, err := contestRepo.CreateContest(context.Background(), title)
require.NoError(t, err)
require.Equal(t, int32(1), id)
})
}
func TestContestRepository_DeleteContest(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid contest deletion", func(t *testing.T) {
id := int32(1)
rows := sqlmock.NewResult(1, 1)
mock.ExpectExec(sqlxDB.Rebind(deleteContestQuery)).WithArgs(id).WillReturnResult(rows)
err = contestRepo.DeleteContest(context.Background(), id)
require.NoError(t, err)
})
}
func TestContestRepository_AddTask(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid task additional", func(t *testing.T) {
taskId := int32(1)
contestId := int32(1)
rows := sqlmock.NewRows([]string{"id"}).AddRow(1)
mock.ExpectQuery(sqlxDB.Rebind(addTaskQuery)).WithArgs(taskId, contestId, contestId).WillReturnRows(rows)
id, err := contestRepo.AddTask(context.Background(), contestId, taskId)
require.NoError(t, err)
require.Equal(t, int32(1), id)
})
}
func TestContestRepository_DeleteTask(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid task deletion", func(t *testing.T) {
id := int32(1)
rows := sqlmock.NewResult(1, 1)
mock.ExpectExec(sqlxDB.Rebind(deleteTaskQuery)).WithArgs(id).WillReturnResult(rows)
err = contestRepo.DeleteTask(context.Background(), id)
require.NoError(t, err)
})
}
func TestContestRepository_AddParticipant(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid participant addition", func(t *testing.T) {
contestId := int32(1)
userId := int32(1)
name := ""
rows := sqlmock.NewRows([]string{"id"}).AddRow(1)
mock.ExpectQuery(sqlxDB.Rebind(addParticipantQuery)).WithArgs(contestId, userId, name).WillReturnRows(rows)
id, err := contestRepo.AddParticipant(context.Background(), contestId, userId)
require.NoError(t, err)
require.Equal(t, int32(1), id)
})
}
func TestContestRepository_DeleteParticipant(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
contestRepo := NewContestRepository(sqlxDB, zap.NewNop())
t.Run("valid participant deletion", func(t *testing.T) {
id := int32(1)
rows := sqlmock.NewResult(1, 1)
mock.ExpectExec(sqlxDB.Rebind(deleteParticipantQuery)).WithArgs(id).WillReturnResult(rows)
err = contestRepo.DeleteParticipant(context.Background(), id)
require.NoError(t, err)
})
}

View file

@ -0,0 +1,64 @@
package repository
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"github.com/jmoiron/sqlx"
"go.uber.org/zap"
)
type ProblemRepository struct {
db *sqlx.DB
logger *zap.Logger
}
func NewProblemRepository(db *sqlx.DB, logger *zap.Logger) *ProblemRepository {
return &ProblemRepository{
db: db,
logger: logger,
}
}
const createProblemQuery = "INSERT INTO problems (title) VALUES (?) RETURNING id"
func (r *ProblemRepository) CreateProblem(ctx context.Context, title string) (int32, error) {
query := r.db.Rebind(createProblemQuery)
rows, err := r.db.QueryxContext(ctx, query, title)
if err != nil {
return 0, handlePgErr(err)
}
defer rows.Close()
var id int32
rows.Next()
err = rows.Scan(&id)
if err != nil {
return 0, handlePgErr(err)
}
return id, nil
}
const readProblemQuery = "SELECT * from problems WHERE id=? LIMIT 1"
func (r *ProblemRepository) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error) {
var problem models.Problem
query := r.db.Rebind(readProblemQuery)
err := r.db.GetContext(ctx, &problem, query, id)
if err != nil {
return nil, handlePgErr(err)
}
return &problem, nil
}
const deleteProblemQuery = "DELETE FROM problems WHERE id=?"
func (r *ProblemRepository) DeleteProblem(ctx context.Context, id int32) error {
query := r.db.Rebind(deleteProblemQuery)
_, err := r.db.ExecContext(ctx, query, id)
if err != nil {
return handlePgErr(err)
}
return nil
}

View file

@ -0,0 +1,58 @@
package repository
import (
"context"
"github.com/DATA-DOG/go-sqlmock"
"github.com/jmoiron/sqlx"
"github.com/stretchr/testify/require"
"go.uber.org/zap"
"testing"
)
func TestProblemRepository_CreateProblem(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
problemRepo := NewProblemRepository(sqlxDB, zap.NewNop())
t.Run("valid problem creation", func(t *testing.T) {
title := "Problem title"
rows := sqlmock.NewRows([]string{"id"}).AddRow(1)
mock.ExpectQuery(sqlxDB.Rebind(createProblemQuery)).WithArgs(title).WillReturnRows(rows)
id, err := problemRepo.CreateProblem(context.Background(), title)
require.NoError(t, err)
require.Equal(t, int32(1), id)
})
}
func TestProblemRepository_DeleteProblem(t *testing.T) {
t.Parallel()
db, mock, err := sqlmock.New(sqlmock.QueryMatcherOption(sqlmock.QueryMatcherEqual))
require.NoError(t, err)
defer db.Close()
sqlxDB := sqlx.NewDb(db, "sqlmock")
defer sqlxDB.Close()
problemRepo := NewProblemRepository(sqlxDB, zap.NewNop())
t.Run("valid problem deletion", func(t *testing.T) {
id := int32(1)
rows := sqlmock.NewResult(1, 1)
mock.ExpectExec(sqlxDB.Rebind(deleteProblemQuery)).WithArgs(id).WillReturnResult(rows)
err = problemRepo.DeleteProblem(context.Background(), id)
require.NoError(t, err)
})
}

View file

@ -1 +0,0 @@
package repository

View file

@ -2,11 +2,21 @@ package tester
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
)
type TesterUseCase interface {
CreateSolution(ctx context.Context, taskId int32, solution string, language int32) (int32, error)
ProcessTesting(ctx context.Context, solutionId int32) (<-chan string, error)
ProcessResult(ctx context.Context, solutionId int32, result string) error
TestingChannel() chan int32
type ProblemUseCase interface {
CreateProblem(ctx context.Context, title string) (int32, error)
ReadProblemById(ctx context.Context, id int32) (*models.Problem, error)
DeleteProblem(ctx context.Context, id int32) error
}
type ContestUseCase interface {
CreateContest(ctx context.Context, title string) (int32, error)
ReadContestById(ctx context.Context, id int32) (*models.Contest, error)
DeleteContest(ctx context.Context, id int32) error
AddTask(ctx context.Context, contestId int32, taskId int32) (int32, error)
DeleteTask(ctx context.Context, taskId int32) error
AddParticipant(ctx context.Context, contestId int32, userId int32) (int32, error)
DeleteParticipant(ctx context.Context, participantId int32) error
}

View file

@ -0,0 +1,47 @@
package usecase
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"git.sch9.ru/new_gate/ms-tester/internal/tester"
)
type ContestUseCase struct {
contestRepo tester.ContestRepository
}
func NewContestUseCase(
contestRepo tester.ContestRepository,
) *ContestUseCase {
return &ContestUseCase{
contestRepo: contestRepo,
}
}
func (uc *ContestUseCase) CreateContest(ctx context.Context, title string) (int32, error) {
return uc.contestRepo.CreateContest(ctx, title)
}
func (uc *ContestUseCase) ReadContestById(ctx context.Context, id int32) (*models.Contest, error) {
return uc.contestRepo.ReadContestById(ctx, id)
}
func (uc *ContestUseCase) DeleteContest(ctx context.Context, id int32) error {
return uc.contestRepo.DeleteContest(ctx, id)
}
func (uc *ContestUseCase) AddTask(ctx context.Context, contestId int32, taskId int32) (id int32, err error) {
return uc.contestRepo.AddTask(ctx, contestId, taskId)
}
func (uc *ContestUseCase) DeleteTask(ctx context.Context, taskId int32) error {
return uc.contestRepo.DeleteTask(ctx, taskId)
}
func (uc *ContestUseCase) AddParticipant(ctx context.Context, contestId int32, userId int32) (id int32, err error) {
return uc.contestRepo.AddParticipant(ctx, contestId, userId)
}
func (uc *ContestUseCase) DeleteParticipant(ctx context.Context, participantId int32) error {
return uc.contestRepo.DeleteParticipant(ctx, participantId)
}

View file

@ -0,0 +1,34 @@
package usecase
import (
"context"
"git.sch9.ru/new_gate/ms-tester/internal/models"
"git.sch9.ru/new_gate/ms-tester/internal/tester"
)
type ProblemUseCase struct {
problemRepo tester.ProblemPostgresRepository
//pandocClient pandoc.PandocClient
}
func NewProblemUseCase(
problemRepo tester.ProblemPostgresRepository,
// pandocClient pandoc.PandocClient,
) *ProblemUseCase {
return &ProblemUseCase{
problemRepo: problemRepo,
//pandocClient: pandocClient,
}
}
func (u *ProblemUseCase) CreateProblem(ctx context.Context, title string) (int32, error) {
return u.problemRepo.CreateProblem(ctx, title)
}
func (u *ProblemUseCase) ReadProblemById(ctx context.Context, id int32) (*models.Problem, error) {
return u.problemRepo.ReadProblemById(ctx, id)
}
func (u *ProblemUseCase) DeleteProblem(ctx context.Context, id int32) error {
return u.problemRepo.DeleteProblem(ctx, id)
}

View file

@ -1,107 +0,0 @@
package usecase
import (
"context"
"errors"
"fmt"
"math/rand"
"sync"
)
const (
MaxSimultaneousTestingProcesses = 5000
MaxMessagesPerSolution = 500
)
type TesterUseCase struct {
publicChannels sync.Map
privateChannels sync.Map
testingChannel chan int32
}
func NewTesterUseCase() *TesterUseCase {
return &TesterUseCase{
testingChannel: make(chan int32, MaxSimultaneousTestingProcesses),
}
}
func (u *TesterUseCase) CreateSolution(ctx context.Context, taskId int32, solution string, language int32) (int32, error) {
return rand.Int31(), nil
}
func (u *TesterUseCase) ProcessTesting(ctx context.Context, solutionId int32) (<-chan string, error) {
u.testingChannel <- solutionId
publicChannel := u.newPublicChannel(solutionId)
go func() {
privateChannel := u.newPrivateChannel(solutionId)
defer func() {
err := u.closeAndDeletePrivateChannel(solutionId)
if err != nil {
panic(err)
}
err = u.closeAndDeletePublicChannel(solutionId)
if err != nil {
panic(err)
}
}()
c := 0
for res := range privateChannel {
c += 1
publicChannel <- res
if c == 15 {
fmt.Println("finished")
break
}
}
}()
return publicChannel, nil
}
func (u *TesterUseCase) ProcessResult(ctx context.Context, solutionId int32, result string) error {
ch, ok := u.privateChannels.Load(solutionId)
if !ok {
return errors.New("")
}
ch.(chan string) <- result
return nil
}
func (u *TesterUseCase) TestingChannel() chan int32 {
return u.testingChannel
}
func (u *TesterUseCase) newPublicChannel(solutionId int32) chan string {
userCh := make(chan string, MaxMessagesPerSolution)
u.publicChannels.Store(solutionId, userCh)
return userCh
}
func (u *TesterUseCase) newPrivateChannel(solutionId int32) chan string {
userCh := make(chan string, MaxMessagesPerSolution)
u.privateChannels.Store(solutionId, userCh)
return userCh
}
func (u *TesterUseCase) closeAndDeletePublicChannel(solutionId int32) error {
ch, ok := u.publicChannels.Load(solutionId)
if !ok {
return errors.New("")
}
close(ch.(chan string))
u.publicChannels.Delete(solutionId)
return nil
}
func (u *TesterUseCase) closeAndDeletePrivateChannel(solutionId int32) error {
ch, ok := u.privateChannels.Load(solutionId)
if !ok {
return errors.New("")
}
close(ch.(chan string))
u.privateChannels.Delete(solutionId)
return nil
}