feat(tester): migrate from gRPC to REST
This commit is contained in:
parent
6613b03b6c
commit
a560715ae8
40 changed files with 403 additions and 961 deletions
|
@ -1,17 +0,0 @@
|
|||
package contests
|
||||
|
||||
import (
|
||||
"context"
|
||||
contestv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/contest/v1"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type ContestHandlers interface {
|
||||
CreateContest(ctx context.Context, req *contestv1.CreateContestRequest) (*contestv1.CreateContestResponse, error)
|
||||
ReadContest(ctx context.Context, req *contestv1.ReadContestRequest) (*contestv1.ReadContestResponse, error)
|
||||
DeleteContest(ctx context.Context, req *contestv1.DeleteContestRequest) (*emptypb.Empty, error)
|
||||
AddTask(ctx context.Context, req *contestv1.AddTaskRequest) (*contestv1.AddTaskResponse, error)
|
||||
DeleteTask(ctx context.Context, req *contestv1.DeleteTaskRequest) (*emptypb.Empty, error)
|
||||
AddParticipant(ctx context.Context, req *contestv1.AddParticipantRequest) (*contestv1.AddParticipantResponse, error)
|
||||
DeleteParticipant(ctx context.Context, req *contestv1.DeleteParticipantRequest) (*emptypb.Empty, error)
|
||||
}
|
|
@ -1,83 +0,0 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/contests"
|
||||
contestv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/contest/v1"
|
||||
"git.sch9.ru/new_gate/ms-tester/pkg/utils"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type ContestHandlers struct {
|
||||
contestv1.UnimplementedContestServiceServer
|
||||
|
||||
contestUC contests.ContestUseCase
|
||||
}
|
||||
|
||||
func NewContestHandlers(gserver *grpc.Server, contestUC contests.ContestUseCase) {
|
||||
handlers := &ContestHandlers{contestUC: contestUC}
|
||||
|
||||
contestv1.RegisterContestServiceServer(gserver, handlers)
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) CreateContest(ctx context.Context, req *contestv1.CreateContestRequest) (*contestv1.CreateContestResponse, error) {
|
||||
id, err := h.contestUC.CreateContest(ctx, req.GetTitle())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &contestv1.CreateContestResponse{Id: id}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) ReadContest(ctx context.Context, req *contestv1.ReadContestRequest) (*contestv1.ReadContestResponse, error) {
|
||||
contest, err := h.contestUC.ReadContestById(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &contestv1.ReadContestResponse{Contest: &contestv1.ReadContestResponse_Contest{
|
||||
Id: *contest.Id,
|
||||
Title: *contest.Title,
|
||||
CreatedAt: utils.TimestampP(contest.CreatedAt),
|
||||
UpdatedAt: utils.TimestampP(contest.UpdatedAt),
|
||||
}}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) DeleteContest(ctx context.Context, req *contestv1.DeleteContestRequest) (*emptypb.Empty, error) {
|
||||
err := h.contestUC.DeleteContest(ctx, req.GetId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) AddTask(ctx context.Context, req *contestv1.AddTaskRequest) (*contestv1.AddTaskResponse, error) {
|
||||
id, err := h.contestUC.AddTask(ctx, req.GetContestId(), req.GetProblemId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &contestv1.AddTaskResponse{Id: id}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) DeleteTask(ctx context.Context, req *contestv1.DeleteTaskRequest) (*emptypb.Empty, error) {
|
||||
err := h.contestUC.DeleteTask(ctx, req.GetTaskId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) AddParticipant(ctx context.Context, req *contestv1.AddParticipantRequest) (*contestv1.AddParticipantResponse, error) {
|
||||
id, err := h.contestUC.AddParticipant(ctx, req.GetContestId(), req.GetUserId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &contestv1.AddParticipantResponse{Id: id}, nil
|
||||
}
|
||||
|
||||
func (h *ContestHandlers) DeleteParticipant(ctx context.Context, req *contestv1.DeleteParticipantRequest) (*emptypb.Empty, error) {
|
||||
err := h.contestUC.DeleteParticipant(ctx, req.GetParticipantId())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &emptypb.Empty{}, nil
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package contests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
|
@ -1,16 +0,0 @@
|
|||
package contests
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
)
|
||||
|
||||
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
|
||||
}
|
|
@ -1,13 +1,13 @@
|
|||
package models
|
||||
|
||||
type Language struct {
|
||||
Name string
|
||||
CompileCmd []string //source: src;result:executable
|
||||
RunCmd []string //source: executable
|
||||
}
|
||||
|
||||
var Languages = [...]Language{
|
||||
{Name: "gcc std=c90",
|
||||
CompileCmd: []string{"gcc", "src", "-std=c90", "-o", "executable"},
|
||||
RunCmd: []string{"executable"}},
|
||||
}
|
||||
//type Language struct {
|
||||
// Name string
|
||||
// CompileCmd []string //source: src;result:executable
|
||||
// RunCmd []string //source: executable
|
||||
//}
|
||||
//
|
||||
//var Languages = []Language{
|
||||
// {Name: "gcc std=c90",
|
||||
// CompileCmd: []string{"gcc", "src", "-std=c90", "-o", "executable"},
|
||||
// RunCmd: []string{"executable"}},
|
||||
//}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Participant struct {
|
||||
Id *int32 `db:"id"`
|
||||
UserId *int32 `db:"user_id"`
|
||||
ContestId *int32 `db:"contest_id"`
|
||||
Name *string `db:"name"`
|
||||
CreatedAt *time.Time `db:"created_at"`
|
||||
UpdatedAt *time.Time `db:"updated_at"`
|
||||
}
|
||||
//type Participant struct {
|
||||
// Id *int32 `db:"id"`
|
||||
// UserId *int32 `db:"user_id"`
|
||||
// ContestId *int32 `db:"contest_id"`
|
||||
// Name *string `db:"name"`
|
||||
// CreatedAt *time.Time `db:"created_at"`
|
||||
// UpdatedAt *time.Time `db:"updated_at"`
|
||||
//}
|
||||
|
|
|
@ -1,30 +1,26 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Result int32
|
||||
|
||||
const (
|
||||
NotTested Result = 1 // change only with schema change
|
||||
Accepted Result = 2
|
||||
WrongAnswer Result = 3
|
||||
PresentationError Result = 4
|
||||
CompilationError Result = 5
|
||||
MemoryLimitExceeded Result = 6
|
||||
TimeLimitExceeded Result = 7
|
||||
RuntimeError Result = 8
|
||||
SystemFailDuringTesting Result = 9
|
||||
Testing Result = 10
|
||||
)
|
||||
|
||||
var ErrBadResult = errors.New("bad result")
|
||||
|
||||
func (result Result) Valid() error {
|
||||
switch result {
|
||||
case NotTested, Accepted, TimeLimitExceeded, MemoryLimitExceeded, CompilationError, SystemFailDuringTesting:
|
||||
return nil
|
||||
}
|
||||
return ErrBadResult
|
||||
}
|
||||
//type Result int32
|
||||
//
|
||||
//const (
|
||||
// NotTested Result = 1 // change only with schema change
|
||||
// Accepted Result = 2
|
||||
// WrongAnswer Result = 3
|
||||
// PresentationError Result = 4
|
||||
// CompilationError Result = 5
|
||||
// MemoryLimitExceeded Result = 6
|
||||
// TimeLimitExceeded Result = 7
|
||||
// RuntimeError Result = 8
|
||||
// SystemFailDuringTesting Result = 9
|
||||
// Testing Result = 10
|
||||
//)
|
||||
//
|
||||
//var ErrBadResult = errors.New("bad result")
|
||||
//
|
||||
//func (result Result) Valid() error {
|
||||
// switch result {
|
||||
// case NotTested, Accepted, TimeLimitExceeded, MemoryLimitExceeded, CompilationError, SystemFailDuringTesting:
|
||||
// return nil
|
||||
// }
|
||||
// return ErrBadResult
|
||||
//}
|
||||
|
|
|
@ -1,52 +0,0 @@
|
|||
package models
|
||||
|
||||
import (
|
||||
"errors"
|
||||
)
|
||||
|
||||
type Role int32
|
||||
|
||||
const (
|
||||
RoleSpectator Role = 0
|
||||
RoleParticipant Role = 1
|
||||
RoleModerator Role = 2
|
||||
RoleAdmin Role = 3
|
||||
)
|
||||
|
||||
func (role Role) IsAdmin() bool {
|
||||
return role == RoleAdmin
|
||||
}
|
||||
|
||||
func (role Role) IsModerator() bool {
|
||||
return role == RoleModerator
|
||||
}
|
||||
|
||||
func (role Role) IsParticipant() bool {
|
||||
return role == RoleParticipant
|
||||
}
|
||||
|
||||
func (role Role) IsSpectator() bool {
|
||||
return role == RoleSpectator
|
||||
}
|
||||
|
||||
func (role Role) AtLeast(other Role) bool {
|
||||
return role >= other
|
||||
}
|
||||
|
||||
func (role Role) AtMost(other Role) bool {
|
||||
return role <= other
|
||||
}
|
||||
|
||||
var ErrBadRole = errors.New("bad role")
|
||||
|
||||
func (role Role) Valid() error {
|
||||
switch role {
|
||||
case RoleSpectator, RoleParticipant, RoleModerator, RoleAdmin:
|
||||
return nil
|
||||
}
|
||||
return ErrBadRole
|
||||
}
|
||||
|
||||
func (role Role) AsPointer() *Role {
|
||||
return &role
|
||||
}
|
|
@ -1,15 +1,13 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Solution struct {
|
||||
Id *int32 `db:"id"`
|
||||
TaskId *int32 `db:"task_id"`
|
||||
ParticipantId *int32 `db:"participant_id"`
|
||||
State *int32 `db:"state"`
|
||||
Score *int32 `db:"score"`
|
||||
Penalty *int32 `db:"penalty"`
|
||||
TotalScore *int32 `db:"total_score"`
|
||||
Language *int32 `db:"language"`
|
||||
CreatedAt *time.Time `db:"created_at"`
|
||||
}
|
||||
//type Solution struct {
|
||||
// Id *int32 `db:"id"`
|
||||
// TaskId *int32 `db:"task_id"`
|
||||
// ParticipantId *int32 `db:"participant_id"`
|
||||
// State *int32 `db:"state"`
|
||||
// Score *int32 `db:"score"`
|
||||
// Penalty *int32 `db:"penalty"`
|
||||
// TotalScore *int32 `db:"total_score"`
|
||||
// Language *int32 `db:"language"`
|
||||
// CreatedAt *time.Time `db:"created_at"`
|
||||
//}
|
||||
|
|
|
@ -1,12 +1,10 @@
|
|||
package models
|
||||
|
||||
import "time"
|
||||
|
||||
type Task struct {
|
||||
Id *int32 `db:"id"`
|
||||
ProblemId *int32 `db:"problem_id"`
|
||||
ContestId *int32 `db:"contest_id"`
|
||||
Position *int32 `db:"position"`
|
||||
CreatedAt *time.Time `db:"created_at"`
|
||||
UpdatedAt *time.Time `db:"updated_at"`
|
||||
}
|
||||
//type Task struct {
|
||||
// Id *int32 `db:"id"`
|
||||
// ProblemId *int32 `db:"problem_id"`
|
||||
// ContestId *int32 `db:"contest_id"`
|
||||
// Position *int32 `db:"position"`
|
||||
// CreatedAt *time.Time `db:"created_at"`
|
||||
// UpdatedAt *time.Time `db:"updated_at"`
|
||||
//}
|
||||
|
|
|
@ -1,13 +0,0 @@
|
|||
package problems
|
||||
|
||||
import (
|
||||
"context"
|
||||
problemv1 "git.sch9.ru/new_gate/ms-tester/pkg/go/gen/proto/problem/v1"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type Handlers interface {
|
||||
CreateProblem(ctx context.Context, req *problemv1.CreateProblemRequest) (*problemv1.CreateProblemResponse, error)
|
||||
ReadProblem(ctx context.Context, req *problemv1.ReadProblemRequest) (*problemv1.ReadProblemResponse, error)
|
||||
DeleteProblem(ctx context.Context, req *problemv1.DeleteProblemRequest) (*emptypb.Empty, error)
|
||||
}
|
|
@ -1,61 +0,0 @@
|
|||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
"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"
|
||||
"google.golang.org/protobuf/types/known/emptypb"
|
||||
)
|
||||
|
||||
type problemHandlers struct {
|
||||
problemv1.UnimplementedProblemServiceServer
|
||||
|
||||
problemUC problems.ProblemUseCase
|
||||
}
|
||||
|
||||
func NewProblemHandlers(gserver *grpc.Server, problemUC problems.ProblemUseCase) {
|
||||
handlers := &problemHandlers{problemUC: problemUC}
|
||||
|
||||
problemv1.RegisterProblemServiceServer(gserver, handlers)
|
||||
}
|
||||
|
||||
func (h *problemHandlers) CreateProblem(ctx context.Context, req *problemv1.CreateProblemRequest) (*problemv1.CreateProblemResponse, error) {
|
||||
id, err := h.problemUC.CreateProblem(ctx, req.GetTitle())
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return &problemv1.CreateProblemResponse{Id: id}, nil
|
||||
}
|
||||
|
||||
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,
|
||||
Title: *problem.Title,
|
||||
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: utils.TimestampP(problem.CreatedAt),
|
||||
UpdatedAt: utils.TimestampP(problem.UpdatedAt),
|
||||
},
|
||||
}, 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
|
||||
}
|
|
@ -1,57 +0,0 @@
|
|||
package rabbitmq
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/problems"
|
||||
"github.com/golang/protobuf/proto"
|
||||
amqp "github.com/rabbitmq/amqp091-go"
|
||||
"github.com/seaweedfs/seaweedfs/weed/pb/filer_pb"
|
||||
)
|
||||
|
||||
func NewNotificationSubscriber(ch *amqp.Channel, queueName string, instanceName string, problemUC problems.ProblemUseCase) {
|
||||
_, err := ch.QueueDeclare(
|
||||
queueName,
|
||||
true,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
if err != nil {
|
||||
panic(err)
|
||||
}
|
||||
|
||||
msgs, err := ch.Consume(
|
||||
queueName,
|
||||
instanceName,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
false,
|
||||
nil,
|
||||
)
|
||||
|
||||
if err != nil {
|
||||
panic(err) // FIXME
|
||||
}
|
||||
|
||||
go func() {
|
||||
for d := range msgs {
|
||||
err = d.Ack(false)
|
||||
if err != nil {
|
||||
panic(err) // FIXME
|
||||
}
|
||||
|
||||
msg := filer_pb.EventNotification{}
|
||||
|
||||
err = proto.Unmarshal(d.Body, &msg)
|
||||
if err != nil {
|
||||
panic(err) // FIXME
|
||||
}
|
||||
|
||||
fmt.Println(msg.String()) // TODO: instead, call appropriate problemUC handler
|
||||
}
|
||||
}()
|
||||
|
||||
return
|
||||
}
|
|
@ -1,12 +0,0 @@
|
|||
package problems
|
||||
|
||||
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
|
||||
}
|
|
@ -1,18 +0,0 @@
|
|||
package problems
|
||||
|
||||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
)
|
||||
|
||||
type ProblemPolicyAgent interface {
|
||||
CanCreateProblem(ctx context.Context) error
|
||||
CanReadProblem(ctx context.Context) error
|
||||
CanDeleteProblem(ctx context.Context) error
|
||||
}
|
||||
|
||||
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
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -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
|
||||
}
|
|
@ -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)
|
||||
}
|
||||
}
|
||||
}()
|
||||
}
|
145
internal/tester/delivery/rest/handlers.go
Normal file
145
internal/tester/delivery/rest/handlers.go
Normal 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,
|
||||
}},
|
||||
)
|
||||
}
|
|
@ -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
|
||||
}
|
||||
|
|
23
internal/tester/repository/error.go
Normal file
23
internal/tester/repository/error.go
Normal 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")
|
||||
}
|
|
@ -2,11 +2,7 @@ package repository
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
"git.sch9.ru/new_gate/ms-tester/pkg/utils"
|
||||
"github.com/jackc/pgerrcode"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -23,7 +19,7 @@ func NewContestRepository(db *sqlx.DB, logger *zap.Logger) *ContestRepository {
|
|||
}
|
||||
}
|
||||
|
||||
const createContestQuery = "INSERT INTO contest (title) VALUES (?) RETURNING id"
|
||||
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)
|
||||
|
@ -44,7 +40,7 @@ func (r *ContestRepository) CreateContest(ctx context.Context, title string) (in
|
|||
return id, nil
|
||||
}
|
||||
|
||||
const readContestByIdQuery = "SELECT * from contest WHERE id=? LIMIT 1"
|
||||
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
|
||||
|
@ -56,7 +52,7 @@ func (r *ContestRepository) ReadContestById(ctx context.Context, id int32) (*mod
|
|||
return &contest, nil
|
||||
}
|
||||
|
||||
const deleteContestQuery = "DELETE FROM contest WHERE id=?"
|
||||
const deleteContestQuery = "DELETE FROM contests WHERE id=?"
|
||||
|
||||
func (r *ContestRepository) DeleteContest(ctx context.Context, id int32) error {
|
||||
query := r.db.Rebind(deleteContestQuery)
|
||||
|
@ -68,7 +64,7 @@ func (r *ContestRepository) DeleteContest(ctx context.Context, id int32) error {
|
|||
return nil
|
||||
}
|
||||
|
||||
const addTaskQuery = "INSERT INTO task (problem_id, contest_id, position) VALUES (?, ?,COALESCE(SELECT MAX(position) FROM task WHERE contest_id = ? ,0) + 1) RETURNING id"
|
||||
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)
|
||||
|
@ -86,7 +82,7 @@ func (r *ContestRepository) AddTask(ctx context.Context, contestId int32, proble
|
|||
return id, nil
|
||||
}
|
||||
|
||||
const deleteTaskQuery = "DELETE FROM task WHERE id=?"
|
||||
const deleteTaskQuery = "DELETE FROM tasks WHERE id=?"
|
||||
|
||||
func (r *ContestRepository) DeleteTask(ctx context.Context, taskId int32) error {
|
||||
query := r.db.Rebind(deleteTaskQuery)
|
||||
|
@ -97,7 +93,7 @@ func (r *ContestRepository) DeleteTask(ctx context.Context, taskId int32) error
|
|||
return nil
|
||||
}
|
||||
|
||||
const addParticipantQuery = "INSERT INTO participant (user_id ,contest_id, name) VALUES (?, ?, ?) RETURNING id"
|
||||
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)
|
||||
|
@ -116,7 +112,7 @@ func (r *ContestRepository) AddParticipant(ctx context.Context, contestId int32,
|
|||
return id, nil
|
||||
}
|
||||
|
||||
const deleteParticipantQuery = "DELETE FROM participant WHERE id=?"
|
||||
const deleteParticipantQuery = "DELETE FROM participants WHERE id=?"
|
||||
|
||||
func (r *ContestRepository) DeleteParticipant(ctx context.Context, participantId int32) error {
|
||||
query := r.db.Rebind(deleteParticipantQuery)
|
||||
|
@ -126,18 +122,3 @@ func (r *ContestRepository) DeleteParticipant(ctx context.Context, participantId
|
|||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
|
@ -2,11 +2,7 @@ package repository
|
|||
|
||||
import (
|
||||
"context"
|
||||
"errors"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
"git.sch9.ru/new_gate/ms-tester/pkg/utils"
|
||||
"github.com/jackc/pgerrcode"
|
||||
"github.com/jackc/pgx/v5/pgconn"
|
||||
"github.com/jmoiron/sqlx"
|
||||
"go.uber.org/zap"
|
||||
)
|
||||
|
@ -66,18 +62,3 @@ func (r *ProblemRepository) DeleteProblem(ctx context.Context, id int32) error {
|
|||
|
||||
return nil
|
||||
}
|
||||
|
||||
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")
|
||||
}
|
|
@ -1 +0,0 @@
|
|||
package repository
|
|
@ -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
|
||||
}
|
||||
|
|
|
@ -2,16 +2,16 @@ package usecase
|
|||
|
||||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/contests"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/tester"
|
||||
)
|
||||
|
||||
type ContestUseCase struct {
|
||||
contestRepo contests.ContestRepository
|
||||
contestRepo tester.ContestRepository
|
||||
}
|
||||
|
||||
func NewContestUseCase(
|
||||
contestRepo contests.ContestRepository,
|
||||
contestRepo tester.ContestRepository,
|
||||
) *ContestUseCase {
|
||||
return &ContestUseCase{
|
||||
contestRepo: contestRepo,
|
|
@ -3,22 +3,21 @@ package usecase
|
|||
import (
|
||||
"context"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/models"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/problems"
|
||||
"git.sch9.ru/new_gate/ms-tester/pkg/external/pandoc"
|
||||
"git.sch9.ru/new_gate/ms-tester/internal/tester"
|
||||
)
|
||||
|
||||
type ProblemUseCase struct {
|
||||
problemRepo problems.ProblemPostgresRepository
|
||||
pandocClient pandoc.PandocClient
|
||||
problemRepo tester.ProblemPostgresRepository
|
||||
//pandocClient pandoc.PandocClient
|
||||
}
|
||||
|
||||
func NewProblemUseCase(
|
||||
problemRepo problems.ProblemPostgresRepository,
|
||||
pandocClient pandoc.PandocClient,
|
||||
problemRepo tester.ProblemPostgresRepository,
|
||||
// pandocClient pandoc.PandocClient,
|
||||
) *ProblemUseCase {
|
||||
return &ProblemUseCase{
|
||||
problemRepo: problemRepo,
|
||||
pandocClient: pandocClient,
|
||||
problemRepo: problemRepo,
|
||||
//pandocClient: pandocClient,
|
||||
}
|
||||
}
|
||||
|
|
@ -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
|
||||
}
|
Loading…
Add table
Add a link
Reference in a new issue