generated from VLADIMIR/template
add screens.go
This commit is contained in:
@@ -0,0 +1,270 @@
|
||||
package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"strconv"
|
||||
"time"
|
||||
|
||||
"evening_detective_server/internal/modules/processor_jwt"
|
||||
"evening_detective_server/internal/modules/roles"
|
||||
"evening_detective_server/internal/repos/screen_sessions_repo"
|
||||
proto "evening_detective_server/proto"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/grpc/codes"
|
||||
"google.golang.org/grpc/status"
|
||||
)
|
||||
|
||||
func (s *server) CreateScreenSession(ctx context.Context, _ *proto.CreateScreenSessionReq) (*proto.CreateScreenSessionRsp, error) {
|
||||
token := uuid.New().String()
|
||||
id, err := s.screenRepo.Create(ctx, hashScreenToken(token))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось создать сессию экрана")
|
||||
}
|
||||
return &proto.CreateScreenSessionRsp{ScreenId: fmt.Sprint(id), AccessToken: token}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetScreenState(ctx context.Context, req *proto.GetScreenStateReq) (*proto.GetScreenStateRsp, error) {
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hashScreenToken(req.AccessToken))
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить состояние экрана")
|
||||
}
|
||||
state := screenState(session)
|
||||
s.enrichScreenState(ctx, session, state)
|
||||
return &proto.GetScreenStateRsp{State: state}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetGameScreens(ctx context.Context, req *proto.GetGameScreensReq) (*proto.GetGameScreensRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор игры")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
sessions, err := s.screenRepo.ListByGame(ctx, int(req.GameId))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить экраны игры")
|
||||
}
|
||||
states := make([]*proto.ScreenState, 0, len(sessions))
|
||||
for _, session := range sessions {
|
||||
states = append(states, screenState(session))
|
||||
}
|
||||
return &proto.GetGameScreensRsp{Screens: states}, nil
|
||||
}
|
||||
|
||||
func (s *server) BindScreen(ctx context.Context, req *proto.BindScreenReq) (*proto.BindScreenRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" || req.GameId <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные привязки")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if _, err = s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
hash := hashScreenToken(req.AccessToken)
|
||||
if err = s.screenRepo.Bind(ctx, id, int(req.GameId), hash); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось привязать экран")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hash)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить состояние экрана")
|
||||
}
|
||||
state := screenState(session)
|
||||
s.enrichScreenState(ctx, session, state)
|
||||
return &proto.BindScreenRsp{State: state}, nil
|
||||
}
|
||||
|
||||
func (s *server) UnbindScreen(ctx context.Context, req *proto.UnbindScreenReq) (*proto.UnbindScreenRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if err = s.screenRepo.Unbind(ctx, id); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "экран не найден")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось отвязать экран")
|
||||
}
|
||||
return &proto.UnbindScreenRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) SetScreenSound(ctx context.Context, req *proto.SetScreenSoundReq) (*proto.SetScreenSoundRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if err = s.screenRepo.SetSound(ctx, id, req.SoundEnabled); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "экран не найден")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось назначить экран со звуком")
|
||||
}
|
||||
return &proto.SetScreenSoundRsp{}, nil
|
||||
}
|
||||
|
||||
func canManageScreens(ctx context.Context) bool {
|
||||
claims, ok := ctx.Value("claims").(*processor_jwt.JWTClaims)
|
||||
if !ok || claims == nil {
|
||||
return false
|
||||
}
|
||||
return roles.HasRole(claims, roles.Organizer) || roles.HasRole(claims, roles.Author)
|
||||
}
|
||||
|
||||
func hashScreenToken(token string) string {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return base64.RawURLEncoding.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func screenState(session *screen_sessions_repo.ScreenSession) *proto.ScreenState {
|
||||
state := &proto.ScreenState{
|
||||
Id: fmt.Sprint(session.ID),
|
||||
Status: "disconnected",
|
||||
SoundEnabled: session.Sound,
|
||||
Mode: proto.ScreenMode(session.Mode),
|
||||
StateVersion: session.Version,
|
||||
PositionMs: session.Position,
|
||||
Command: proto.ScreenCommand(session.Command),
|
||||
Volume: session.Volume,
|
||||
}
|
||||
if time.Since(session.LastSeen) <= 5*time.Second {
|
||||
state.Status = "connected"
|
||||
}
|
||||
if session.GameID != nil {
|
||||
gameID := int32(*session.GameID)
|
||||
state.GameId = &gameID
|
||||
if state.Mode == proto.ScreenMode_SCREEN_MODE_UNSPECIFIED {
|
||||
state.Mode = proto.ScreenMode_SCREEN_MODE_COVER
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (s *server) enrichScreenState(ctx context.Context, session *screen_sessions_repo.ScreenSession, state *proto.ScreenState) {
|
||||
if session.GameID == nil {
|
||||
return
|
||||
}
|
||||
game, err := s.gameService.GetGameMedia(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
state.GameName = game.Name
|
||||
if game.Scenario != nil && game.Scenario.Image != nil {
|
||||
state.CoverImage = *game.Scenario.Image
|
||||
}
|
||||
if game.Scenario != nil && game.Scenario.Story != nil {
|
||||
state.BackgroundImage = game.Scenario.Story.Background
|
||||
if game.Scenario.Story.Introduction != nil {
|
||||
state.IntroAudio = game.Scenario.Story.Introduction.Audio
|
||||
}
|
||||
if game.Scenario.Story.Conclusion != nil {
|
||||
state.ConclusionVideo = game.Scenario.Story.Conclusion.Video
|
||||
}
|
||||
}
|
||||
if state.BackgroundImage == "" {
|
||||
state.BackgroundImage = state.CoverImage
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) SetScreenMode(ctx context.Context, req *proto.SetScreenModeReq) (*proto.SetScreenModeRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 || req.Mode == proto.ScreenMode_SCREEN_MODE_UNSPECIFIED {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный режим экрана")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if err := s.screenRepo.SetMode(ctx, int(req.GameId), int32(req.Mode)); err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось изменить режим экранов")
|
||||
}
|
||||
return &proto.SetScreenModeRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) SendScreenCommand(ctx context.Context, req *proto.SendScreenCommandReq) (*proto.SendScreenCommandRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 || req.Command == proto.ScreenCommand_SCREEN_COMMAND_UNSPECIFIED {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная команда экрана")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if req.PositionMs < 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная позиция")
|
||||
}
|
||||
if req.Volume < 0 || req.Volume > 100 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная громкость")
|
||||
}
|
||||
if err := s.screenRepo.SetCommand(ctx, int(req.GameId), int32(req.Command), req.PositionMs, req.Volume); err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось сохранить позицию экранов")
|
||||
}
|
||||
return &proto.SendScreenCommandRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetScreenResults(ctx context.Context, req *proto.GetScreenResultsReq) (*proto.GetScreenResultsRsp, error) {
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hashScreenToken(req.AccessToken))
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
if err != nil || session.GameID == nil {
|
||||
return nil, status.Error(codes.FailedPrecondition, "экран не привязан к игре")
|
||||
}
|
||||
game, err := s.gameService.GetGame(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if game.Status != "finish" {
|
||||
return nil, status.Error(codes.FailedPrecondition, "результаты доступны после завершения игры")
|
||||
}
|
||||
results, err := s.gameService.GetGameResults(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить результаты")
|
||||
}
|
||||
return &proto.GetScreenResultsRsp{Questions: mapResultsQuestions(results.Questions), Teams: mapTeamResults(results.Teams)}, nil
|
||||
}
|
||||
@@ -2,14 +2,10 @@ package app
|
||||
|
||||
import (
|
||||
"context"
|
||||
"crypto/sha256"
|
||||
"encoding/base64"
|
||||
"errors"
|
||||
"fmt"
|
||||
"net/netip"
|
||||
"strconv"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"evening_detective_server/docs"
|
||||
"evening_detective_server/internal/modules/file_storage"
|
||||
@@ -28,7 +24,6 @@ import (
|
||||
"evening_detective_server/internal/services/users_service"
|
||||
proto "evening_detective_server/proto"
|
||||
|
||||
"github.com/google/uuid"
|
||||
"google.golang.org/genproto/googleapis/api/httpbody"
|
||||
"google.golang.org/grpc"
|
||||
"google.golang.org/grpc/codes"
|
||||
@@ -71,126 +66,6 @@ func NewServer(
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) CreateScreenSession(ctx context.Context, _ *proto.CreateScreenSessionReq) (*proto.CreateScreenSessionRsp, error) {
|
||||
token := uuid.New().String()
|
||||
id, err := s.screenRepo.Create(ctx, hashScreenToken(token))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось создать сессию экрана")
|
||||
}
|
||||
return &proto.CreateScreenSessionRsp{ScreenId: fmt.Sprint(id), AccessToken: token}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetScreenState(ctx context.Context, req *proto.GetScreenStateReq) (*proto.GetScreenStateRsp, error) {
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hashScreenToken(req.AccessToken))
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить состояние экрана")
|
||||
}
|
||||
state := screenState(session)
|
||||
s.enrichScreenState(ctx, session, state)
|
||||
return &proto.GetScreenStateRsp{State: state}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetGameScreens(ctx context.Context, req *proto.GetGameScreensReq) (*proto.GetGameScreensRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор игры")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
sessions, err := s.screenRepo.ListByGame(ctx, int(req.GameId))
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить экраны игры")
|
||||
}
|
||||
states := make([]*proto.ScreenState, 0, len(sessions))
|
||||
for _, session := range sessions {
|
||||
states = append(states, screenState(session))
|
||||
}
|
||||
return &proto.GetGameScreensRsp{Screens: states}, nil
|
||||
}
|
||||
|
||||
func (s *server) BindScreen(ctx context.Context, req *proto.BindScreenReq) (*proto.BindScreenRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" || req.GameId <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные привязки")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if _, err = s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
hash := hashScreenToken(req.AccessToken)
|
||||
if err = s.screenRepo.Bind(ctx, id, int(req.GameId), hash); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось привязать экран")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hash)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить состояние экрана")
|
||||
}
|
||||
state := screenState(session)
|
||||
s.enrichScreenState(ctx, session, state)
|
||||
return &proto.BindScreenRsp{State: state}, nil
|
||||
}
|
||||
|
||||
func (s *server) UnbindScreen(ctx context.Context, req *proto.UnbindScreenReq) (*proto.UnbindScreenRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if err = s.screenRepo.Unbind(ctx, id); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "экран не найден")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось отвязать экран")
|
||||
}
|
||||
return &proto.UnbindScreenRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) SetScreenSound(ctx context.Context, req *proto.SetScreenSoundReq) (*proto.SetScreenSoundRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.ScreenId == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
if err = s.screenRepo.SetSound(ctx, id, req.SoundEnabled); err != nil {
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.NotFound, "экран не найден")
|
||||
}
|
||||
return nil, status.Error(codes.Internal, "не удалось назначить экран со звуком")
|
||||
}
|
||||
return &proto.SetScreenSoundRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetGameMap(ctx context.Context, req *proto.GetGameMapReq) (*proto.GetGameMapRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
@@ -273,136 +148,6 @@ func (s *server) UpdateGameMapItem(ctx context.Context, req *proto.UpdateGameMap
|
||||
return &proto.UpdateGameMapItemRsp{}, nil
|
||||
}
|
||||
|
||||
func canManageScreens(ctx context.Context) bool {
|
||||
claims, ok := ctx.Value("claims").(*processor_jwt.JWTClaims)
|
||||
if !ok || claims == nil {
|
||||
return false
|
||||
}
|
||||
return roles.HasRole(claims, roles.Organizer) || roles.HasRole(claims, roles.Author)
|
||||
}
|
||||
|
||||
func hashScreenToken(token string) string {
|
||||
sum := sha256.Sum256([]byte(token))
|
||||
return base64.RawURLEncoding.EncodeToString(sum[:])
|
||||
}
|
||||
|
||||
func screenState(session *screen_sessions_repo.ScreenSession) *proto.ScreenState {
|
||||
state := &proto.ScreenState{
|
||||
Id: fmt.Sprint(session.ID),
|
||||
Status: "disconnected",
|
||||
SoundEnabled: session.Sound,
|
||||
Mode: proto.ScreenMode(session.Mode),
|
||||
StateVersion: session.Version,
|
||||
PositionMs: session.Position,
|
||||
Command: proto.ScreenCommand(session.Command),
|
||||
Volume: session.Volume,
|
||||
}
|
||||
if time.Since(session.LastSeen) <= 5*time.Second {
|
||||
state.Status = "connected"
|
||||
}
|
||||
if session.GameID != nil {
|
||||
gameID := int32(*session.GameID)
|
||||
state.GameId = &gameID
|
||||
if state.Mode == proto.ScreenMode_SCREEN_MODE_UNSPECIFIED {
|
||||
state.Mode = proto.ScreenMode_SCREEN_MODE_COVER
|
||||
}
|
||||
}
|
||||
return state
|
||||
}
|
||||
|
||||
func (s *server) enrichScreenState(ctx context.Context, session *screen_sessions_repo.ScreenSession, state *proto.ScreenState) {
|
||||
if session.GameID == nil {
|
||||
return
|
||||
}
|
||||
game, err := s.gameService.GetGameMedia(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return
|
||||
}
|
||||
state.GameName = game.Name
|
||||
if game.Scenario != nil && game.Scenario.Image != nil {
|
||||
state.CoverImage = *game.Scenario.Image
|
||||
}
|
||||
if game.Scenario != nil && game.Scenario.Story != nil {
|
||||
state.BackgroundImage = game.Scenario.Story.Background
|
||||
if game.Scenario.Story.Introduction != nil {
|
||||
state.IntroAudio = game.Scenario.Story.Introduction.Audio
|
||||
}
|
||||
if game.Scenario.Story.Conclusion != nil {
|
||||
state.ConclusionVideo = game.Scenario.Story.Conclusion.Video
|
||||
}
|
||||
}
|
||||
if state.BackgroundImage == "" {
|
||||
state.BackgroundImage = state.CoverImage
|
||||
}
|
||||
}
|
||||
|
||||
func (s *server) SetScreenMode(ctx context.Context, req *proto.SetScreenModeReq) (*proto.SetScreenModeRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 || req.Mode == proto.ScreenMode_SCREEN_MODE_UNSPECIFIED {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный режим экрана")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if err := s.screenRepo.SetMode(ctx, int(req.GameId), int32(req.Mode)); err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось изменить режим экранов")
|
||||
}
|
||||
return &proto.SetScreenModeRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) SendScreenCommand(ctx context.Context, req *proto.SendScreenCommandReq) (*proto.SendScreenCommandRsp, error) {
|
||||
if !canManageScreens(ctx) {
|
||||
return nil, status.Error(codes.PermissionDenied, "permission denied")
|
||||
}
|
||||
if req == nil || req.GameId <= 0 || req.Command == proto.ScreenCommand_SCREEN_COMMAND_UNSPECIFIED {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная команда экрана")
|
||||
}
|
||||
if _, err := s.gameService.GetGame(ctx, int(req.GameId)); err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if req.PositionMs < 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная позиция")
|
||||
}
|
||||
if req.Volume < 0 || req.Volume > 100 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректная громкость")
|
||||
}
|
||||
if err := s.screenRepo.SetCommand(ctx, int(req.GameId), int32(req.Command), req.PositionMs, req.Volume); err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось сохранить позицию экранов")
|
||||
}
|
||||
return &proto.SendScreenCommandRsp{}, nil
|
||||
}
|
||||
|
||||
func (s *server) GetScreenResults(ctx context.Context, req *proto.GetScreenResultsReq) (*proto.GetScreenResultsRsp, error) {
|
||||
if req == nil || req.ScreenId == "" || req.AccessToken == "" {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректные данные экрана")
|
||||
}
|
||||
id, err := strconv.Atoi(req.ScreenId)
|
||||
if err != nil || id <= 0 {
|
||||
return nil, status.Error(codes.InvalidArgument, "некорректный идентификатор экрана")
|
||||
}
|
||||
session, err := s.screenRepo.Get(ctx, id, hashScreenToken(req.AccessToken))
|
||||
if errors.Is(err, screen_sessions_repo.ErrScreenNotFound) {
|
||||
return nil, status.Error(codes.Unauthenticated, "недействительная сессия экрана")
|
||||
}
|
||||
if err != nil || session.GameID == nil {
|
||||
return nil, status.Error(codes.FailedPrecondition, "экран не привязан к игре")
|
||||
}
|
||||
game, err := s.gameService.GetGame(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.NotFound, "игра не найдена")
|
||||
}
|
||||
if game.Status != "finish" {
|
||||
return nil, status.Error(codes.FailedPrecondition, "результаты доступны после завершения игры")
|
||||
}
|
||||
results, err := s.gameService.GetGameResults(ctx, *session.GameID)
|
||||
if err != nil {
|
||||
return nil, status.Error(codes.Internal, "не удалось получить результаты")
|
||||
}
|
||||
return &proto.GetScreenResultsRsp{Questions: mapResultsQuestions(results.Questions), Teams: mapTeamResults(results.Teams)}, nil
|
||||
}
|
||||
|
||||
func (s *server) Ping(_ context.Context, _ *proto.PingReq) (*proto.PingRsp, error) {
|
||||
return &proto.PingRsp{}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user