add competition service (it`s broken, I will fix it later)
This commit is contained in:
@@ -0,0 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"datarush/internal/competition/config"
|
||||
"datarush/internal/competition/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
srv := server.New(cfg)
|
||||
|
||||
if err := srv.Start(); err != nil {
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("shutting down competition server...")
|
||||
srv.Stop()
|
||||
log.Println("competition server stopped")
|
||||
}
|
||||
@@ -1,6 +1,32 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"log"
|
||||
"os"
|
||||
"os/signal"
|
||||
"syscall"
|
||||
|
||||
"datarush/internal/lms/config"
|
||||
"datarush/internal/lms/server"
|
||||
)
|
||||
|
||||
func main() {
|
||||
cfg, err := config.Load()
|
||||
if err != nil {
|
||||
log.Fatalf("failed to load config: %v", err)
|
||||
}
|
||||
|
||||
srv := server.New(cfg)
|
||||
|
||||
if err := srv.Start(); err != nil {
|
||||
log.Fatalf("failed to start server: %v", err)
|
||||
}
|
||||
|
||||
quit := make(chan os.Signal, 1)
|
||||
signal.Notify(quit, syscall.SIGINT, syscall.SIGTERM)
|
||||
<-quit
|
||||
|
||||
log.Println("shutting down auth server...")
|
||||
srv.Stop()
|
||||
log.Println("core server stopped")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,74 @@
|
||||
package config
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"os"
|
||||
"strconv"
|
||||
|
||||
"github.com/joho/godotenv"
|
||||
)
|
||||
|
||||
type Config struct {
|
||||
GRPCPort int
|
||||
GRPCEnableReflection bool
|
||||
HTTPPort int
|
||||
LogLevel string
|
||||
DBHost string
|
||||
DBPort int
|
||||
DBUser string
|
||||
DBPassword string
|
||||
DBName string
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
_ = godotenv.Load()
|
||||
|
||||
return &Config{
|
||||
GRPCPort: mustGetInt("COMPETITION_GRPC_PORT", 50053),
|
||||
GRPCEnableReflection: mustGetBool("COMPETITION_GRPC_ENABLE_REFLECTION", false),
|
||||
HTTPPort: mustGetInt("COMPETITION_HTTP_PORT", 8082),
|
||||
LogLevel: getEnv("LOG_LEVEL", "info"),
|
||||
DBHost: getEnv("POSTGRES_HOST", "localhost"),
|
||||
DBPort: mustGetInt("POSTGRES_PORT", 5432),
|
||||
DBUser: getEnv("POSTGRES_USERNAME", "postgres"),
|
||||
DBPassword: getEnv("POSTGRES_PASSWORD", "postgres"),
|
||||
DBName: getEnv("POSTGRES_DATABASE", "postgres"),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func getEnv(key, def string) string {
|
||||
if val := os.Getenv(key); val != "" {
|
||||
return val
|
||||
}
|
||||
return def
|
||||
}
|
||||
|
||||
func mustGetInt(key string, def int) int {
|
||||
val := getEnv(key, strconv.Itoa(def))
|
||||
n, err := strconv.Atoi(val)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid int for %s: %v", key, err)
|
||||
}
|
||||
return n
|
||||
}
|
||||
|
||||
func mustGetBool(key string, def bool) bool {
|
||||
val := getEnv(key, strconv.FormatBool(def))
|
||||
b, err := strconv.ParseBool(val)
|
||||
if err != nil {
|
||||
log.Fatalf("invalid bool for %s: %v", key, err)
|
||||
}
|
||||
return b
|
||||
}
|
||||
|
||||
func (c Config) BuildPostgresConnStr() string {
|
||||
return fmt.Sprintf("host=%s port=%d user=%s password=%s dbname=%s sslmode=disable",
|
||||
c.DBHost, c.DBPort, c.DBUser, c.DBPassword, c.DBName)
|
||||
}
|
||||
|
||||
func (c Config) BuildPostgresDSN() string {
|
||||
return fmt.Sprintf("postgresql://%s:%s@%s/%s?sslmode=disable",
|
||||
c.DBUser, c.DBPassword, net.JoinHostPort(c.DBHost, strconv.Itoa(c.DBPort)), c.DBName)
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
package domain
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"time"
|
||||
|
||||
"github.com/go-playground/validator/v10"
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type CompetitionState string
|
||||
|
||||
const (
|
||||
CompetitionStateUnspecified CompetitionState = "UNSPECIFIED"
|
||||
CompetitionStateDraft CompetitionState = "DRAFT"
|
||||
CompetitionStateNotStarted CompetitionState = "NOT_STARTED"
|
||||
CompetitionStateStarted CompetitionState = "STARTED"
|
||||
CompetitionStateFinished CompetitionState = "FINISHED"
|
||||
CompetitionStateArchived CompetitionState = "ARCHIVED"
|
||||
)
|
||||
|
||||
type ParticipationType string
|
||||
|
||||
const (
|
||||
ParticipationTypeUnspecified ParticipationType = "UNSPECIFIED"
|
||||
ParticipationTypeIndividual ParticipationType = "INDIVIDUAL"
|
||||
ParticipationTypeTeam ParticipationType = "TEAM"
|
||||
)
|
||||
|
||||
type CompetitionType string
|
||||
|
||||
const (
|
||||
CompetitionTypeUnspecified CompetitionType = "UNSPECIFIED"
|
||||
CompetitionTypeEducative CompetitionType = "EDUCATIVE"
|
||||
CompetitionTypeCompetitive CompetitionType = "COMPETITIVE"
|
||||
)
|
||||
|
||||
type Competition struct {
|
||||
ID uuid.UUID
|
||||
State CompetitionState
|
||||
Title string
|
||||
Description string
|
||||
ImageURL *string
|
||||
StartTime time.Time
|
||||
EndTime time.Time
|
||||
Type CompetitionType
|
||||
ParticipationType ParticipationType
|
||||
CreatedAt time.Time
|
||||
UpdatedAt time.Time
|
||||
}
|
||||
|
||||
|
||||
func NewCompetition(id uuid.UUID, state CompetitionState, title string, description string, imageURL *string, startTime time.Time, endTime time.Time, tpe CompetitionType, participationType ParticipationType, createdAt time.Time, updatedAt time.Time) *Competition {
|
||||
return &Competition{
|
||||
ID: id,
|
||||
State: state,
|
||||
Title: title,
|
||||
Description: description,
|
||||
ImageURL: imageURL,
|
||||
StartTime: startTime,
|
||||
EndTime: endTime,
|
||||
Type: tpe,
|
||||
ParticipationType: participationType,
|
||||
CreatedAt: createdAt,
|
||||
UpdatedAt: updatedAt,
|
||||
}
|
||||
}
|
||||
|
||||
func (c *Competition) Validate() error {
|
||||
validate := validator.New()
|
||||
|
||||
return fmt.Errorf("%w: %w", ErrInvalidCompetitionData, validate.Struct(c))
|
||||
}
|
||||
@@ -0,0 +1,8 @@
|
||||
package domain
|
||||
|
||||
import "errors"
|
||||
|
||||
var (
|
||||
ErrCompetitionNotFound = errors.New("competition not found")
|
||||
ErrInvalidCompetitionData = errors.New("invalid competition data")
|
||||
)
|
||||
@@ -0,0 +1,199 @@
|
||||
package grpc
|
||||
|
||||
import (
|
||||
"context"
|
||||
|
||||
"datarush/internal/competition/domain"
|
||||
pb "datarush/pkg/api/competition"
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/types/known/timestamppb"
|
||||
"strings"
|
||||
)
|
||||
|
||||
// ICompetitionService defines the interface for business logic.
|
||||
// It works with domain models.
|
||||
type ICompetitionService interface {
|
||||
CreateCompetition(ctx context.Context, comp *domain.Competition) (*domain.Competition, error)
|
||||
GetCompetition(ctx context.Context, id uuid.UUID) (*domain.Competition, error)
|
||||
EditCompetition(ctx context.Context, comp *domain.Competition) (*domain.Competition, error)
|
||||
DeleteCompetition(ctx context.Context, id uuid.UUID) error
|
||||
ListCompetitions(ctx context.Context, pageSize int32, pageToken int32, state *domain.CompetitionState, isParticipating *bool, searchQuery *string) (competitions []domain.Competition, totalCount int32, nextPageToken int32, err error)
|
||||
ChangeCompetitionState(ctx context.Context, id uuid.UUID, state domain.CompetitionState) (*domain.Competition, error)
|
||||
}
|
||||
|
||||
type CompetitionHandler struct {
|
||||
pb.UnimplementedCompetitionServiceServer
|
||||
service ICompetitionService
|
||||
}
|
||||
|
||||
func NewCompetitionHandler(s ICompetitionService) *CompetitionHandler {
|
||||
return &CompetitionHandler{service: s}
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) CreateCompetition(ctx context.Context, req *pb.Competition) (*pb.Competition, error) {
|
||||
domainComp, err := toDomainCompetition(req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "failed to map competition: %v", err)
|
||||
}
|
||||
|
||||
createdComp, err := h.service.CreateCompetition(ctx, domainComp)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to create competition: %v", err)
|
||||
}
|
||||
|
||||
return fromDomainCompetition(createdComp), nil
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) GetCompetition(ctx context.Context, req *pb.GetCompetitionRequest) (*pb.Competition, error) {
|
||||
id, err := uuid.Parse(req.GetCompetitionId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid competition id format")
|
||||
}
|
||||
comp, err := h.service.GetCompetition(ctx, id)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.NotFound, "failed to get competition: %v", err)
|
||||
}
|
||||
return fromDomainCompetition(comp), nil
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) EditCompetition(ctx context.Context, req *pb.Competition) (*pb.Competition, error) {
|
||||
domainComp, err := toDomainCompetition(req)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "failed to map competition: %v", err)
|
||||
}
|
||||
|
||||
updatedComp, err := h.service.EditCompetition(ctx, domainComp)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to edit competition: %v", err)
|
||||
}
|
||||
|
||||
return fromDomainCompetition(updatedComp), nil
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) DeleteCompetition(ctx context.Context, req *pb.DeleteCompetitionRequest) (*pb.DeleteCompetitionResponse, error) {
|
||||
id, err := uuid.Parse(req.GetCompetitionId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid competition id format")
|
||||
}
|
||||
if err := h.service.DeleteCompetition(ctx, id); err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to delete competition: %v", err)
|
||||
}
|
||||
return &pb.DeleteCompetitionResponse{Success: true}, nil
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) ListCompetitions(ctx context.Context, req *pb.ListCompetitionsRequest) (*pb.ListCompetitionsResponse, error) {
|
||||
var state *domain.CompetitionState
|
||||
if req.State != nil {
|
||||
s := toDomainCompetitionState(*req.State)
|
||||
state = &s
|
||||
}
|
||||
|
||||
var searchQuery *string
|
||||
if req.SearchQuery != nil {
|
||||
searchQuery = req.SearchQuery
|
||||
}
|
||||
|
||||
competitions, totalCount, nextPageToken, err := h.service.ListCompetitions(ctx, req.PageSize, req.PageToken, state, req.IsParticipating, searchQuery)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to list competitions: %v", err)
|
||||
}
|
||||
|
||||
pbCompetitions := make([]*pb.Competition, len(competitions))
|
||||
for i, c := range competitions {
|
||||
pbCompetitions[i] = fromDomainCompetition(&c)
|
||||
}
|
||||
|
||||
return &pb.ListCompetitionsResponse{
|
||||
Competitions: pbCompetitions,
|
||||
TotalCount: totalCount,
|
||||
NextPageToken: nextPageToken,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (h *CompetitionHandler) ChangeCompetitionState(ctx context.Context, req *pb.ChangeCompetitionStateRequest) (*pb.Competition, error) {
|
||||
id, err := uuid.Parse(req.GetCompetitionId())
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid competition id format")
|
||||
}
|
||||
|
||||
comp, err := h.service.ChangeCompetitionState(ctx, id, toDomainCompetitionState(req.GetState()))
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.Internal, "failed to change competition state: %v", err)
|
||||
}
|
||||
return fromDomainCompetition(comp), nil
|
||||
}
|
||||
|
||||
|
||||
func toDomainCompetition(c *pb.Competition) (*domain.Competition, error) {
|
||||
if c == nil {
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
var id uuid.UUID
|
||||
var err error
|
||||
if c.Id != "" {
|
||||
id, err = uuid.Parse(c.Id)
|
||||
if err != nil {
|
||||
return nil, status.Errorf(codes.InvalidArgument, "invalid id format")
|
||||
}
|
||||
}
|
||||
|
||||
return &domain.Competition{
|
||||
ID: id,
|
||||
State: toDomainCompetitionState(c.State),
|
||||
Title: c.Title,
|
||||
Description: c.Description,
|
||||
ImageURL: c.ImageUrl,
|
||||
StartTime: c.StartTime.AsTime(),
|
||||
EndTime: c.EndTime.AsTime(),
|
||||
Type: toDomainCompetitionType(c.Type),
|
||||
ParticipationType: toDomainParticipationType(c.ParticipationType),
|
||||
CreatedAt: c.CreatedAt.AsTime(),
|
||||
UpdatedAt: c.UpdatedAt.AsTime(),
|
||||
}, nil
|
||||
}
|
||||
|
||||
func fromDomainCompetition(c *domain.Competition) *pb.Competition {
|
||||
if c == nil {
|
||||
return nil
|
||||
}
|
||||
return &pb.Competition{
|
||||
Id: c.ID.String(),
|
||||
State: fromDomainCompetitionState(c.State),
|
||||
Title: c.Title,
|
||||
Description: c.Description,
|
||||
ImageUrl: c.ImageURL,
|
||||
StartTime: timestamppb.New(c.StartTime),
|
||||
EndTime: timestamppb.New(c.EndTime),
|
||||
Type: fromDomainCompetitionType(c.Type),
|
||||
ParticipationType: fromDomainParticipationType(c.ParticipationType),
|
||||
CreatedAt: timestamppb.New(c.CreatedAt),
|
||||
UpdatedAt: timestamppb.New(c.UpdatedAt),
|
||||
}
|
||||
}
|
||||
|
||||
func toDomainCompetitionState(s pb.CompetitionState) domain.CompetitionState {
|
||||
return domain.CompetitionState(strings.TrimPrefix(s.String(), "COMPETITION_STATE_"))
|
||||
}
|
||||
|
||||
func fromDomainCompetitionState(s domain.CompetitionState) pb.CompetitionState {
|
||||
return pb.CompetitionState(pb.CompetitionState_value["COMPETITION_STATE_"+string(s)])
|
||||
}
|
||||
|
||||
func toDomainParticipationType(pt pb.ParticipationType) domain.ParticipationType {
|
||||
return domain.ParticipationType(strings.TrimPrefix(pt.String(), "PARTICIPATION_TYPE_"))
|
||||
}
|
||||
|
||||
func fromDomainParticipationType(pt domain.ParticipationType) pb.ParticipationType {
|
||||
return pb.ParticipationType(pb.ParticipationType_value["PARTICIPATION_TYPE_"+string(pt)])
|
||||
}
|
||||
|
||||
func toDomainCompetitionType(ct pb.CompetitionType) domain.CompetitionType {
|
||||
return domain.CompetitionType(strings.TrimPrefix(ct.String(), "COMPETITION_TYPE_"))
|
||||
}
|
||||
|
||||
func fromDomainCompetitionType(ct domain.CompetitionType) pb.CompetitionType {
|
||||
return pb.CompetitionType(pb.CompetitionType_value["COMPETITION_TYPE_"+string(ct)])
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
package repository
|
||||
|
||||
import (
|
||||
"context"
|
||||
"datarush/internal/competition/domain"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
|
||||
type ListCompetitionsOptions struct {
|
||||
Page int
|
||||
PageSize int
|
||||
State *domain.CompetitionState
|
||||
IsParticipating *bool
|
||||
SearchQuery *string
|
||||
}
|
||||
|
||||
type CompetitionRepository interface {
|
||||
Create(ctx context.Context, competition *domain.Competition) error
|
||||
Get(ctx context.Context, id uuid.UUID) (*domain.Competition, error)
|
||||
Update(ctx context.Context, competition *domain.Competition) error
|
||||
Delete(ctx context.Context, id uuid.UUID) error
|
||||
List(ctx context.Context, opts ListCompetitionsOptions) ([]domain.Competition, int, error)
|
||||
ChangeState(ctx context.Context, id uuid.UUID, state domain.CompetitionState) (*domain.Competition, error)
|
||||
}
|
||||
@@ -0,0 +1,240 @@
|
||||
package postgres
|
||||
|
||||
import (
|
||||
"context"
|
||||
"database/sql"
|
||||
"datarush/internal/competition/domain"
|
||||
"datarush/internal/competition/repository"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"github.com/redis/go-redis/v9"
|
||||
)
|
||||
|
||||
const (
|
||||
competitionCachePrefix = "competition:"
|
||||
)
|
||||
|
||||
|
||||
type CompetitionRepository struct {
|
||||
db *sql.DB
|
||||
redisClient *redis.Client
|
||||
cacheEnabled bool
|
||||
}
|
||||
|
||||
|
||||
func NewCompetitionRepository(db *sql.DB, redisClient *redis.Client, cacheEnabled bool) repository.CompetitionRepository {
|
||||
return &CompetitionRepository{
|
||||
db: db,
|
||||
redisClient: redisClient,
|
||||
cacheEnabled: cacheEnabled,
|
||||
}
|
||||
}
|
||||
|
||||
func (r *CompetitionRepository) cacheKey(id string) string {
|
||||
return competitionCachePrefix + id
|
||||
}
|
||||
|
||||
func (r *CompetitionRepository) Create(ctx context.Context, competition *domain.Competition) error {
|
||||
query := `INSERT INTO competitions (id, state, title, description, image_url, start_time, end_time, type, participation_type, created_at, updated_at)
|
||||
VALUES ($1, $2, $3, $4, $5, $6, $7, $8, $9, $10, $11)`
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
competition.ID,
|
||||
competition.State,
|
||||
competition.Title,
|
||||
competition.Description,
|
||||
competition.ImageURL,
|
||||
competition.StartTime,
|
||||
competition.EndTime,
|
||||
competition.Type,
|
||||
competition.ParticipationType,
|
||||
competition.CreatedAt,
|
||||
competition.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.cacheEnabled {
|
||||
data, err := json.Marshal(competition)
|
||||
if err == nil {
|
||||
r.redisClient.Set(ctx, r.cacheKey(competition.ID.String()), data, 10*time.Minute).Err()
|
||||
}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func (r *CompetitionRepository) Get(ctx context.Context, id uuid.UUID) (*domain.Competition, error) {
|
||||
if r.cacheEnabled {
|
||||
val, err := r.redisClient.Get(ctx, r.cacheKey(id.String())).Result()
|
||||
if err == nil {
|
||||
var competition domain.Competition
|
||||
if json.Unmarshal([]byte(val), &competition) == nil {
|
||||
return &competition, nil
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
query := `SELECT id, state, title, description, image_url, start_time, end_time, type, participation_type, created_at, updated_at FROM competitions WHERE id = $1`
|
||||
row := r.db.QueryRowContext(ctx, query, id)
|
||||
|
||||
var competition domain.Competition
|
||||
err := row.Scan(
|
||||
&competition.ID,
|
||||
&competition.State,
|
||||
&competition.Title,
|
||||
&competition.Description,
|
||||
&competition.ImageURL,
|
||||
&competition.StartTime,
|
||||
&competition.EndTime,
|
||||
&competition.Type,
|
||||
&competition.ParticipationType,
|
||||
&competition.CreatedAt,
|
||||
&competition.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.cacheEnabled {
|
||||
data, err := json.Marshal(&competition)
|
||||
if err == nil {
|
||||
r.redisClient.Set(ctx, r.cacheKey(id.String()), data, 10*time.Minute).Err()
|
||||
}
|
||||
}
|
||||
|
||||
return &competition, nil
|
||||
}
|
||||
|
||||
func (r *CompetitionRepository) Update(ctx context.Context, competition *domain.Competition) error {
|
||||
query := `UPDATE competitions SET
|
||||
state = $2, title = $3, description = $4, image_url = $5, start_time = $6, end_time = $7, type = $8, participation_type = $9, updated_at = $10
|
||||
WHERE id = $1`
|
||||
_, err := r.db.ExecContext(ctx, query,
|
||||
competition.ID,
|
||||
competition.State,
|
||||
competition.Title,
|
||||
competition.Description,
|
||||
competition.ImageURL,
|
||||
competition.StartTime,
|
||||
competition.EndTime,
|
||||
competition.Type,
|
||||
competition.ParticipationType,
|
||||
competition.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.cacheEnabled {
|
||||
r.redisClient.Del(ctx, r.cacheKey(competition.ID.String())).Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (r *CompetitionRepository) Delete(ctx context.Context, id uuid.UUID) error {
|
||||
query := `DELETE FROM competitions WHERE id = $1`
|
||||
_, err := r.db.ExecContext(ctx, query, id)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if r.cacheEnabled {
|
||||
r.redisClient.Del(ctx, r.cacheKey(id.String())).Err()
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
func (r *CompetitionRepository) List(ctx context.Context, opts repository.ListCompetitionsOptions) ([]*domain.Competition, int, error) {
|
||||
var args []interface{}
|
||||
var whereClauses []string
|
||||
argId := 1
|
||||
|
||||
if opts.State != nil {
|
||||
whereClauses = append(whereClauses, fmt.Sprintf("state = $%d", argId))
|
||||
args = append(args, *opts.State)
|
||||
argId++
|
||||
}
|
||||
if opts.SearchQuery != nil {
|
||||
whereClauses = append(whereClauses, fmt.Sprintf("title ILIKE $%d", argId))
|
||||
args = append(args, "%"+*opts.SearchQuery+"%")
|
||||
argId++
|
||||
}
|
||||
|
||||
if opts.IsParticipating != nil {
|
||||
userID, ok := ctx.Value("user_id").(uuid.UUID)
|
||||
if !ok {
|
||||
return nil, 0, fmt.Errorf("user not authenticated or user_id not in context")
|
||||
}
|
||||
|
||||
if *opts.IsParticipating {
|
||||
whereClauses = append(whereClauses, fmt.Sprintf("id IN (SELECT competition_id FROM competition_participants WHERE user_id = $%d)", argId))
|
||||
} else {
|
||||
whereClauses = append(whereClauses, fmt.Sprintf("id NOT IN (SELECT competition_id FROM competition_participants WHERE user_id = $%d)", argId))
|
||||
}
|
||||
args = append(args, userID)
|
||||
argId++
|
||||
}
|
||||
|
||||
where := ""
|
||||
if len(whereClauses) > 0 {
|
||||
where = "WHERE " + strings.Join(whereClauses, " AND ")
|
||||
}
|
||||
|
||||
countQuery := "SELECT COUNT(*) FROM competitions " + where
|
||||
var total int
|
||||
if err := r.db.QueryRowContext(ctx, countQuery, args...).Scan(&total); err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
|
||||
query := fmt.Sprintf(`SELECT id, state, title, description, image_url, start_time, end_time, type, participation_type, created_at, updated_at FROM competitions %s ORDER BY created_at DESC LIMIT $%d OFFSET $%d`, where, argId, argId+1)
|
||||
args = append(args, opts.PageSize, opts.Page*opts.PageSize)
|
||||
|
||||
rows, err := r.db.QueryContext(ctx, query, args...)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
defer rows.Close()
|
||||
|
||||
var competitions []*domain.Competition
|
||||
for rows.Next() {
|
||||
var c domain.Competition
|
||||
err := rows.Scan(
|
||||
&c.ID,
|
||||
&c.State,
|
||||
&c.Title,
|
||||
&c.Description,
|
||||
&c.ImageURL,
|
||||
&c.StartTime,
|
||||
&c.EndTime,
|
||||
&c.Type,
|
||||
&c.ParticipationType,
|
||||
&c.CreatedAt,
|
||||
&c.UpdatedAt,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, 0, err
|
||||
}
|
||||
competitions = append(competitions, &c)
|
||||
}
|
||||
|
||||
return competitions, total, nil
|
||||
}
|
||||
func (r *CompetitionRepository) ChangeState(ctx context.Context, id uuid.UUID, state domain.CompetitionState) (*domain.Competition, error) {
|
||||
query := `UPDATE competitions SET state = $1, updated_at = $2 WHERE id = $3`
|
||||
now := time.Now()
|
||||
_, err := r.db.ExecContext(ctx, query, state, now, id)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
if r.cacheEnabled {
|
||||
r.redisClient.Del(ctx, r.cacheKey(id.String())).Err()
|
||||
}
|
||||
|
||||
return r.Get(ctx, id)
|
||||
}
|
||||
@@ -0,0 +1,143 @@
|
||||
package server
|
||||
|
||||
import (
|
||||
"context"
|
||||
"fmt"
|
||||
"log"
|
||||
"net"
|
||||
"net/http"
|
||||
"time"
|
||||
|
||||
"datarush/internal/competition/config"
|
||||
grpcHandlers "datarush/internal/competition/handler/grpc"
|
||||
"datarush/internal/competition/repository/postgres"
|
||||
"datarush/internal/competition/service"
|
||||
pb "datarush/pkg/api/competition"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/jmoiron/sqlx"
|
||||
_ "github.com/lib/pq"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/credentials/insecure"
|
||||
"google.golang.org/grpc/reflection"
|
||||
)
|
||||
|
||||
const (
|
||||
httpReadTimeout = 10 * time.Second
|
||||
httpWriteTimeout = 10 * time.Second
|
||||
httpIdleTimeout = 60 * time.Second
|
||||
)
|
||||
|
||||
type Server struct {
|
||||
grpcServer *grpc.Server
|
||||
httpServer *http.Server
|
||||
config *config.Config
|
||||
db *sqlx.DB
|
||||
}
|
||||
|
||||
func New(cfg *config.Config) *Server {
|
||||
return &Server{
|
||||
config: cfg,
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) Start() error {
|
||||
db, err := sqlx.Connect("postgres", s.config.BuildPostgresConnStr())
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to connect to postgres: %w", err)
|
||||
}
|
||||
s.db = db
|
||||
|
||||
go func() {
|
||||
if err := s.startGRPCServer(); err != nil {
|
||||
log.Fatalf("failed to start gRPC server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
go func() {
|
||||
if err := s.startHTTPServer(); err != nil {
|
||||
log.Fatalf("failed to start HTTP server: %v", err)
|
||||
}
|
||||
}()
|
||||
|
||||
log.Println("competition service started")
|
||||
return nil
|
||||
}
|
||||
|
||||
func (s *Server) startGRPCServer() error {
|
||||
lis, err := net.Listen("tcp", fmt.Sprintf(":%d", s.config.GRPCPort))
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to listen on grpc port: %w", err)
|
||||
}
|
||||
|
||||
s.grpcServer = grpc.NewServer()
|
||||
s.registerGRPCServices()
|
||||
|
||||
log.Printf("starting gRPC server on port %d", s.config.GRPCPort)
|
||||
return s.grpcServer.Serve(lis)
|
||||
}
|
||||
|
||||
func (s *Server) registerGRPCServices() {
|
||||
compRepo := postgres.NewCompetitionRepository(s.db.DB, nil, false)
|
||||
compService := service.NewService(compRepo)
|
||||
compHandler := grpcHandlers.NewCompetitionHandler(compService)
|
||||
|
||||
pb.RegisterCompetitionServiceServer(s.grpcServer, compHandler)
|
||||
|
||||
if s.config.GRPCEnableReflection {
|
||||
reflection.Register(s.grpcServer)
|
||||
}
|
||||
}
|
||||
|
||||
func (s *Server) startHTTPServer() error {
|
||||
ctx := context.Background()
|
||||
ctx, cancel := context.WithCancel(ctx)
|
||||
defer cancel()
|
||||
|
||||
mux := runtime.NewServeMux()
|
||||
opts := []grpc.DialOption{grpc.WithTransportCredentials(insecure.NewCredentials())}
|
||||
grpcEndpoint := fmt.Sprintf("localhost:%d", s.config.GRPCPort)
|
||||
|
||||
err := pb.RegisterCompetitionServiceHandlerFromEndpoint(ctx, mux, grpcEndpoint, opts)
|
||||
if err != nil {
|
||||
return fmt.Errorf("failed to register http handlers: %w", err)
|
||||
}
|
||||
|
||||
s.httpServer = &http.Server{
|
||||
Addr: fmt.Sprintf(":%d", s.config.HTTPPort),
|
||||
Handler: mux,
|
||||
ReadTimeout: httpReadTimeout,
|
||||
WriteTimeout: httpWriteTimeout,
|
||||
IdleTimeout: httpIdleTimeout,
|
||||
}
|
||||
|
||||
log.Printf("starting HTTP server on port %d", s.config.HTTPPort)
|
||||
return s.httpServer.ListenAndServe()
|
||||
}
|
||||
|
||||
func (s *Server) Stop() {
|
||||
log.Println("shutting down competition server...")
|
||||
|
||||
// Shutdown HTTP server
|
||||
if s.httpServer != nil {
|
||||
ctx, cancel := context.WithTimeout(context.Background(), 5*time.Second)
|
||||
defer cancel()
|
||||
if err := s.httpServer.Shutdown(ctx); err != nil {
|
||||
log.Printf("failed to shutdown HTTP server gracefully: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
// Shutdown gRPC server
|
||||
if s.grpcServer != nil {
|
||||
s.grpcServer.GracefulStop()
|
||||
}
|
||||
|
||||
// Close database connection
|
||||
if s.db != nil {
|
||||
if err := s.db.Close(); err != nil {
|
||||
log.Printf("failed to close database connection: %v", err)
|
||||
}
|
||||
}
|
||||
|
||||
log.Println("competition server stopped")
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
package service
|
||||
|
||||
import (
|
||||
"context"
|
||||
"time"
|
||||
|
||||
"datarush/internal/competition/domain"
|
||||
"datarush/internal/competition/repository"
|
||||
|
||||
"github.com/google/uuid"
|
||||
)
|
||||
|
||||
type Service struct {
|
||||
repo repository.CompetitionRepository
|
||||
}
|
||||
|
||||
func NewService(repo repository.CompetitionRepository) *Service {
|
||||
return &Service{repo: repo}
|
||||
}
|
||||
|
||||
func (s *Service) CreateCompetition(ctx context.Context, comp *domain.Competition) (*domain.Competition, error) {
|
||||
now := time.Now()
|
||||
if comp.ID == uuid.Nil {
|
||||
comp.ID = uuid.New()
|
||||
}
|
||||
comp.CreatedAt = now
|
||||
comp.UpdatedAt = now
|
||||
|
||||
if err := s.repo.Create(ctx, comp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return comp, nil
|
||||
}
|
||||
|
||||
func (s *Service) GetCompetition(ctx context.Context, id uuid.UUID) (*domain.Competition, error) {
|
||||
return s.repo.Get(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) EditCompetition(ctx context.Context, comp *domain.Competition) (*domain.Competition, error) {
|
||||
comp.UpdatedAt = time.Now()
|
||||
if err := s.repo.Update(ctx, comp); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return s.repo.Get(ctx, comp.ID)
|
||||
}
|
||||
|
||||
func (s *Service) DeleteCompetition(ctx context.Context, id uuid.UUID) error {
|
||||
return s.repo.Delete(ctx, id)
|
||||
}
|
||||
|
||||
func (s *Service) ListCompetitions(ctx context.Context, pageSize int32, pageToken int32, state *domain.CompetitionState, isParticipating *bool, searchQuery *string) ([]domain.Competition, int32, int32, error) {
|
||||
opts := repository.ListCompetitionsOptions{
|
||||
Page: int(pageToken),
|
||||
PageSize: int(pageSize),
|
||||
State: state,
|
||||
IsParticipating: isParticipating,
|
||||
SearchQuery: searchQuery,
|
||||
}
|
||||
|
||||
competitions, total, err := s.repo.List(ctx, opts)
|
||||
if err != nil {
|
||||
return nil, 0, 0, err
|
||||
}
|
||||
|
||||
var nextPageToken int32
|
||||
if (opts.Page+1)*opts.PageSize < total {
|
||||
nextPageToken = int32(opts.Page + 1)
|
||||
}
|
||||
|
||||
return competitions, int32(total), nextPageToken, nil
|
||||
}
|
||||
|
||||
func (s *Service) ChangeCompetitionState(ctx context.Context, id uuid.UUID, state domain.CompetitionState) (*domain.Competition, error) {
|
||||
return s.repo.ChangeState(ctx, id, state)
|
||||
}
|
||||
@@ -23,6 +23,7 @@ type Config struct {
|
||||
DBName string
|
||||
RedisURI string
|
||||
AuthGRPCAddr string
|
||||
CacheEnabled bool
|
||||
}
|
||||
|
||||
func Load() (*Config, error) {
|
||||
@@ -41,6 +42,7 @@ func Load() (*Config, error) {
|
||||
DBName: getEnv("POSTGRES_DATABASE", "postgres"),
|
||||
RedisURI: getEnv("REDIS_URI", "redis://localhost:6379"),
|
||||
AuthGRPCAddr: getEnv("AUTH_GRPC_ADDR", "localhost:50052"),
|
||||
CacheEnabled: mustGetBool("CACHE_ENABLED", true),
|
||||
}, nil
|
||||
}
|
||||
|
||||
|
||||
@@ -94,8 +94,6 @@ func registerAuthService(ctx context.Context, gwmux *runtime.ServeMux, authAddr
|
||||
}
|
||||
|
||||
func registerAuthHandlerFromEndpoint(ctx context.Context, gwmux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) error {
|
||||
// We'll import the proto and register it here
|
||||
// For now, this is a placeholder that will be called from gateway integration
|
||||
return nil
|
||||
}
|
||||
func getDatabase(cfg config.Config) (*sqlx.DB, error) {
|
||||
|
||||
@@ -7,12 +7,23 @@
|
||||
package competition
|
||||
|
||||
import (
|
||||
"context"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/runtime"
|
||||
"github.com/grpc-ecosystem/grpc-gateway/v2/utilities"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/grpclog"
|
||||
"google.golang.org/grpc/metadata"
|
||||
"google.golang.org/grpc/status"
|
||||
"google.golang.org/protobuf/proto"
|
||||
protoreflect "google.golang.org/protobuf/reflect/protoreflect"
|
||||
protoimpl "google.golang.org/protobuf/runtime/protoimpl"
|
||||
timestamppb "google.golang.org/protobuf/types/known/timestamppb"
|
||||
reflect "reflect"
|
||||
sync "sync"
|
||||
unsafe "unsafe"
|
||||
"reflect"
|
||||
"sync"
|
||||
)
|
||||
|
||||
const (
|
||||
@@ -775,3 +786,207 @@ func file_api_proto_competition_proto_init() {
|
||||
file_api_proto_competition_proto_goTypes = nil
|
||||
file_api_proto_competition_proto_depIdxs = nil
|
||||
}
|
||||
|
||||
func RegisterCompetitionServiceHandler(ctx context.Context, mux *runtime.ServeMux, conn *grpc.ClientConn) error {
|
||||
return RegisterCompetitionServiceHandlerClient(ctx, mux, NewCompetitionServiceClient(conn))
|
||||
}
|
||||
|
||||
|
||||
func RegisterCompetitionServiceHandlerClient(ctx context.Context, mux *runtime.ServeMux, client CompetitionServiceClient) error {
|
||||
var err error
|
||||
err = mux.Handle("POST", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "competitions"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/CreateCompetition", runtime.WithHTTPPathPattern("/v1/competitions"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_CreateCompetition_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_CreateCompetition_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mux.Handle("GET", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "competitions", "competition_id"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/GetCompetition", runtime.WithHTTPPathPattern("/v1/competitions/{competition_id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_GetCompetition_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_GetCompetition_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mux.Handle("PUT", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "competitions", "id"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/EditCompetition", runtime.WithHTTPPathPattern("/v1/competitions/{id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_EditCompetition_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_EditCompetition_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mux.Handle("DELETE", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2}, []string{"v1", "competitions", "competition_id"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/DeleteCompetition", runtime.WithHTTPPathPattern("/v1/competitions/{competition_id}"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_DeleteCompetition_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_DeleteCompetition_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mux.Handle("GET", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1}, []string{"v1", "competitions"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/ListCompetitions", runtime.WithHTTPPathPattern("/v1/competitions"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_ListCompetitions_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_ListCompetitions_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
err = mux.Handle("POST", runtime.MustPattern(runtime.NewPattern(1, []int{2, 0, 2, 1, 1, 0, 4, 1, 5, 2, 2, 3}, []string{"v1", "competitions", "competition_id", "state"}, "")), func(w http.ResponseWriter, req *http.Request, pathParams map[string]string) {
|
||||
ctx, cancel := context.WithCancel(req.Context())
|
||||
defer cancel()
|
||||
inboundMarshaler, outboundMarshaler := runtime.MarshalerForRequest(mux, req)
|
||||
var err error
|
||||
var annotatedContext context.Context
|
||||
annotatedContext, err = runtime.AnnotateContext(ctx, mux, req, "/competition.CompetitionService/ChangeCompetitionState", runtime.WithHTTPPathPattern("/v1/competitions/{competition_id}/state"))
|
||||
if err != nil {
|
||||
runtime.HTTPError(ctx, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
resp, md, err := request_CompetitionService_ChangeCompetitionState_0(annotatedContext, inboundMarshaler, client, req, pathParams)
|
||||
annotatedContext = runtime.NewServerMetadataContext(annotatedContext, md)
|
||||
if err != nil {
|
||||
runtime.HTTPError(annotatedContext, mux, outboundMarshaler, w, req, err)
|
||||
return
|
||||
}
|
||||
|
||||
forward_CompetitionService_ChangeCompetitionState_0(annotatedContext, mux, outboundMarshaler, w, req, resp, mux.GetForwardResponseOptions()...)
|
||||
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
func RegisterCompetitionServiceHandlerFromEndpoint(ctx context.Context, mux *runtime.ServeMux, endpoint string, opts []grpc.DialOption) (err error) {
|
||||
conn, err := grpc.DialContext(ctx, endpoint, opts...)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
defer func() {
|
||||
if err != nil {
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
return
|
||||
}
|
||||
go func() {
|
||||
<-ctx.Done()
|
||||
if cerr := conn.Close(); cerr != nil {
|
||||
grpclog.Infof("Failed to close conn to %s: %v", endpoint, cerr)
|
||||
}
|
||||
}()
|
||||
}()
|
||||
|
||||
return RegisterCompetitionServiceHandler(ctx, mux, conn)
|
||||
}
|
||||
|
||||
func request_CompetitionService_CreateCompetition_0(ctx context.Context, marshaler runtime.Marshaler, client CompetitionServiceClient, req *http.Request, pathParams map[string]string) (proto.Message, runtime.ServerMetadata, error) {
|
||||
var protoReq Competition
|
||||
var metadata runtime.ServerMetadata
|
||||
|
||||
newReader, berr := utilities.IOReaderFactory(req.Body)
|
||||
if berr != nil {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", berr)
|
||||
}
|
||||
if err := marshaler.NewDecoder(newReader()).Decode(&protoReq); err != nil && err != io.EOF {
|
||||
return nil, metadata, status.Errorf(codes.InvalidArgument, "%v", err)
|
||||
}
|
||||
|
||||
msg, err := client.CreateCompetition(ctx, &protoReq, grpc.Header(&metadata.HeaderMD), grpc.Trailer(&metadata.TrailerMD))
|
||||
return msg, metadata, err
|
||||
|
||||
}
|
||||
|
||||
func forward_CompetitionService_CreateCompetition_0(ctx context.Context, mux *runtime.ServeMux, marshaler runtime.Marshaler, w http.ResponseWriter, req *http.Request, resp proto.Message, opts ...func(context.Context, http.ResponseWriter, proto.Message)) {
|
||||
runtime.ForwardResponseMessage(ctx, mux, marshaler, w, req, resp, opts...)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user