Добавить серверную логику таймера экранов

This commit is contained in:
2026-09-21 18:17:15 +07:00
parent 458bf320d4
commit 002c4b26b4
4 changed files with 181 additions and 24 deletions
+79 -14
View File
@@ -12,15 +12,20 @@ import (
var ErrScreenNotFound = errors.New("Экран не найден")
type ScreenSession struct {
ID int
GameID *int
Sound bool
LastSeen time.Time
Mode int32
Version int64
Position int64
Command int32
Volume int32
ID int
GameID *int
Sound bool
LastSeen time.Time
Mode int32
Version int64
Position int64
Command int32
Volume int32
TimerLabel string
TimerDurationSeconds int64
TimerRemainingSeconds int64
TimerState int32
TimerEndsAt *time.Time
}
type ScreenSessionsRepo struct {
@@ -43,10 +48,12 @@ func (r *ScreenSessionsRepo) Create(ctx context.Context, tokenHash string) (int,
func (r *ScreenSessionsRepo) Get(ctx context.Context, id int, tokenHash string) (*ScreenSession, error) {
session := &ScreenSession{ID: id}
err := r.pool.QueryRow(ctx, `
SELECT game_id, sound_enabled, last_seen_at, mode, state_version, position_ms, command, volume
SELECT game_id, sound_enabled, last_seen_at, mode, state_version, position_ms, command, volume,
timer_label, timer_duration_seconds, timer_remaining_seconds, timer_state, timer_ends_at
FROM screen_sessions
WHERE id = $1 AND access_token_hash = $2`, id, tokenHash).
Scan(&session.GameID, &session.Sound, &session.LastSeen, &session.Mode, &session.Version, &session.Position, &session.Command, &session.Volume)
Scan(&session.GameID, &session.Sound, &session.LastSeen, &session.Mode, &session.Version, &session.Position, &session.Command, &session.Volume,
&session.TimerLabel, &session.TimerDurationSeconds, &session.TimerRemainingSeconds, &session.TimerState, &session.TimerEndsAt)
if errors.Is(err, pgx.ErrNoRows) {
return nil, ErrScreenNotFound
}
@@ -63,7 +70,8 @@ func (r *ScreenSessionsRepo) Get(ctx context.Context, id int, tokenHash string)
func (r *ScreenSessionsRepo) ListByGame(ctx context.Context, gameID int) ([]*ScreenSession, error) {
rows, err := r.pool.Query(ctx, `
SELECT id, game_id, sound_enabled, last_seen_at, mode, state_version, position_ms, command, volume
SELECT id, game_id, sound_enabled, last_seen_at, mode, state_version, position_ms, command, volume,
timer_label, timer_duration_seconds, timer_remaining_seconds, timer_state, timer_ends_at
FROM screen_sessions
WHERE game_id = $1
ORDER BY id`, gameID)
@@ -75,7 +83,8 @@ func (r *ScreenSessionsRepo) ListByGame(ctx context.Context, gameID int) ([]*Scr
var sessions []*ScreenSession
for rows.Next() {
session := &ScreenSession{}
if err := rows.Scan(&session.ID, &session.GameID, &session.Sound, &session.LastSeen, &session.Mode, &session.Version, &session.Position, &session.Command, &session.Volume); err != nil {
if err := rows.Scan(&session.ID, &session.GameID, &session.Sound, &session.LastSeen, &session.Mode, &session.Version, &session.Position, &session.Command, &session.Volume,
&session.TimerLabel, &session.TimerDurationSeconds, &session.TimerRemainingSeconds, &session.TimerState, &session.TimerEndsAt); err != nil {
return nil, err
}
sessions = append(sessions, session)
@@ -98,6 +107,52 @@ func (r *ScreenSessionsRepo) SetCommand(ctx context.Context, gameID int, command
return err
}
func (r *ScreenSessionsRepo) SetTimer(ctx context.Context, gameID int, duration int64, label string) error {
_, err := r.pool.Exec(ctx, `
UPDATE screen_sessions
SET mode = 7,
timer_label = $2,
timer_duration_seconds = $3,
timer_remaining_seconds = $3,
timer_state = 1,
timer_ends_at = NULL,
command = 0,
state_version = state_version + 1,
updated_at = NOW()
WHERE game_id = $1`, gameID, label, duration)
return err
}
func (r *ScreenSessionsRepo) SetTimerCommand(ctx context.Context, gameID int, command int32) error {
_, err := r.pool.Exec(ctx, `
UPDATE screen_sessions
SET timer_remaining_seconds = CASE
WHEN $2 = 8 THEN timer_duration_seconds
WHEN $2 = 9 AND timer_ends_at IS NOT NULL THEN GREATEST(0, FLOOR(EXTRACT(EPOCH FROM (timer_ends_at - NOW())))::BIGINT)
WHEN $2 = 11 THEN timer_duration_seconds
ELSE timer_remaining_seconds
END,
timer_state = CASE
WHEN $2 = 8 THEN 2
WHEN $2 = 9 THEN CASE WHEN timer_ends_at IS NULL OR timer_ends_at > NOW() THEN 3 ELSE 4 END
WHEN $2 = 10 THEN CASE WHEN timer_remaining_seconds > 0 THEN 2 ELSE 4 END
WHEN $2 = 11 THEN 1
ELSE timer_state
END,
timer_ends_at = CASE
WHEN $2 = 8 THEN NOW() + make_interval(secs => timer_duration_seconds)
WHEN $2 = 9 OR $2 = 11 THEN NULL
WHEN $2 = 10 AND timer_remaining_seconds > 0 THEN NOW() + make_interval(secs => timer_remaining_seconds)
ELSE timer_ends_at
END,
mode = 7,
command = $2,
state_version = state_version + 1,
updated_at = NOW()
WHERE game_id = $1`, gameID, command)
return err
}
func (r *ScreenSessionsRepo) Bind(ctx context.Context, id, gameID int, tokenHash string) error {
result, err := r.pool.Exec(ctx, `
UPDATE screen_sessions
@@ -115,7 +170,17 @@ func (r *ScreenSessionsRepo) Bind(ctx context.Context, id, gameID int, tokenHash
func (r *ScreenSessionsRepo) Unbind(ctx context.Context, id int) error {
result, err := r.pool.Exec(ctx, `
UPDATE screen_sessions
SET game_id = NULL, mode = 1, command = 0, position_ms = 0, state_version = state_version + 1, updated_at = NOW()
SET game_id = NULL,
mode = 1,
command = 0,
position_ms = 0,
timer_label = 'Перерыв',
timer_duration_seconds = 600,
timer_remaining_seconds = 600,
timer_state = 1,
timer_ends_at = NULL,
state_version = state_version + 1,
updated_at = NOW()
WHERE id = $1`, id)
if err != nil {
return err