| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320 |
- package postgres
- import (
- "context"
- "errors"
- "fmt"
- "time"
- "github.com/jackc/pgx/v5"
- )
- type Session struct {
- ID string
- SessionPublicID string
- UserID string
- EventID string
- EventReleaseID string
- ReleasePublicID *string
- ConfigLabel *string
- ManifestURL *string
- ManifestChecksum *string
- DeviceKey string
- ClientType string
- AssignmentMode *string
- VariantID *string
- VariantName *string
- RouteCode *string
- Status string
- SessionTokenHash string
- SessionTokenExpiresAt time.Time
- LaunchedAt time.Time
- StartedAt *time.Time
- EndedAt *time.Time
- EventPublicID *string
- EventDisplayName *string
- }
- type FinishSessionParams struct {
- SessionID string
- Status string
- }
- func (s *Store) GetSessionByPublicID(ctx context.Context, sessionPublicID string) (*Session, error) {
- row := s.pool.QueryRow(ctx, `
- SELECT
- gs.id,
- gs.session_public_id,
- gs.user_id,
- gs.event_id,
- gs.event_release_id,
- er.release_public_id,
- er.config_label,
- er.manifest_url,
- er.manifest_checksum_sha256,
- gs.device_key,
- gs.client_type,
- gs.assignment_mode,
- gs.variant_id,
- gs.variant_name,
- gs.route_code,
- gs.status,
- gs.session_token_hash,
- gs.session_token_expires_at,
- gs.launched_at,
- gs.started_at,
- gs.ended_at,
- e.event_public_id,
- e.display_name
- FROM game_sessions gs
- JOIN events e ON e.id = gs.event_id
- JOIN event_releases er ON er.id = gs.event_release_id
- WHERE gs.session_public_id = $1
- LIMIT 1
- `, sessionPublicID)
- return scanSession(row)
- }
- func (s *Store) GetSessionByPublicIDForUpdate(ctx context.Context, tx Tx, sessionPublicID string) (*Session, error) {
- row := tx.QueryRow(ctx, `
- SELECT
- gs.id,
- gs.session_public_id,
- gs.user_id,
- gs.event_id,
- gs.event_release_id,
- er.release_public_id,
- er.config_label,
- er.manifest_url,
- er.manifest_checksum_sha256,
- gs.device_key,
- gs.client_type,
- gs.assignment_mode,
- gs.variant_id,
- gs.variant_name,
- gs.route_code,
- gs.status,
- gs.session_token_hash,
- gs.session_token_expires_at,
- gs.launched_at,
- gs.started_at,
- gs.ended_at,
- e.event_public_id,
- e.display_name
- FROM game_sessions gs
- JOIN events e ON e.id = gs.event_id
- JOIN event_releases er ON er.id = gs.event_release_id
- WHERE gs.session_public_id = $1
- FOR UPDATE
- `, sessionPublicID)
- return scanSession(row)
- }
- func (s *Store) ListSessionsByUserID(ctx context.Context, userID string, limit int) ([]Session, error) {
- if limit <= 0 || limit > 100 {
- limit = 20
- }
- rows, err := s.pool.Query(ctx, `
- SELECT
- gs.id,
- gs.session_public_id,
- gs.user_id,
- gs.event_id,
- gs.event_release_id,
- er.release_public_id,
- er.config_label,
- er.manifest_url,
- er.manifest_checksum_sha256,
- gs.device_key,
- gs.client_type,
- gs.assignment_mode,
- gs.variant_id,
- gs.variant_name,
- gs.route_code,
- gs.status,
- gs.session_token_hash,
- gs.session_token_expires_at,
- gs.launched_at,
- gs.started_at,
- gs.ended_at,
- e.event_public_id,
- e.display_name
- FROM game_sessions gs
- JOIN events e ON e.id = gs.event_id
- JOIN event_releases er ON er.id = gs.event_release_id
- WHERE gs.user_id = $1
- ORDER BY gs.created_at DESC
- LIMIT $2
- `, userID, limit)
- if err != nil {
- return nil, fmt.Errorf("list sessions by user id: %w", err)
- }
- defer rows.Close()
- var sessions []Session
- for rows.Next() {
- session, err := scanSessionFromRows(rows)
- if err != nil {
- return nil, err
- }
- sessions = append(sessions, *session)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate sessions by user id: %w", err)
- }
- return sessions, nil
- }
- func (s *Store) ListSessionsByUserAndEvent(ctx context.Context, userID, eventID string, limit int) ([]Session, error) {
- if limit <= 0 || limit > 100 {
- limit = 20
- }
- rows, err := s.pool.Query(ctx, `
- SELECT
- gs.id,
- gs.session_public_id,
- gs.user_id,
- gs.event_id,
- gs.event_release_id,
- er.release_public_id,
- er.config_label,
- er.manifest_url,
- er.manifest_checksum_sha256,
- gs.device_key,
- gs.client_type,
- gs.assignment_mode,
- gs.variant_id,
- gs.variant_name,
- gs.route_code,
- gs.status,
- gs.session_token_hash,
- gs.session_token_expires_at,
- gs.launched_at,
- gs.started_at,
- gs.ended_at,
- e.event_public_id,
- e.display_name
- FROM game_sessions gs
- JOIN events e ON e.id = gs.event_id
- JOIN event_releases er ON er.id = gs.event_release_id
- WHERE gs.user_id = $1
- AND gs.event_id = $2
- ORDER BY gs.created_at DESC
- LIMIT $3
- `, userID, eventID, limit)
- if err != nil {
- return nil, fmt.Errorf("list sessions by user and event: %w", err)
- }
- defer rows.Close()
- var sessions []Session
- for rows.Next() {
- session, err := scanSessionFromRows(rows)
- if err != nil {
- return nil, err
- }
- sessions = append(sessions, *session)
- }
- if err := rows.Err(); err != nil {
- return nil, fmt.Errorf("iterate sessions by user and event: %w", err)
- }
- return sessions, nil
- }
- func (s *Store) StartSession(ctx context.Context, tx Tx, sessionID string) error {
- _, err := tx.Exec(ctx, `
- UPDATE game_sessions
- SET status = CASE WHEN status = 'launched' THEN 'running' ELSE status END,
- started_at = COALESCE(started_at, NOW())
- WHERE id = $1
- `, sessionID)
- if err != nil {
- return fmt.Errorf("start session: %w", err)
- }
- return nil
- }
- func (s *Store) FinishSession(ctx context.Context, tx Tx, params FinishSessionParams) error {
- _, err := tx.Exec(ctx, `
- UPDATE game_sessions
- SET status = $2,
- started_at = COALESCE(started_at, NOW()),
- ended_at = COALESCE(ended_at, NOW())
- WHERE id = $1
- `, params.SessionID, params.Status)
- if err != nil {
- return fmt.Errorf("finish session: %w", err)
- }
- return nil
- }
- func scanSession(row pgx.Row) (*Session, error) {
- var session Session
- err := row.Scan(
- &session.ID,
- &session.SessionPublicID,
- &session.UserID,
- &session.EventID,
- &session.EventReleaseID,
- &session.ReleasePublicID,
- &session.ConfigLabel,
- &session.ManifestURL,
- &session.ManifestChecksum,
- &session.DeviceKey,
- &session.ClientType,
- &session.AssignmentMode,
- &session.VariantID,
- &session.VariantName,
- &session.RouteCode,
- &session.Status,
- &session.SessionTokenHash,
- &session.SessionTokenExpiresAt,
- &session.LaunchedAt,
- &session.StartedAt,
- &session.EndedAt,
- &session.EventPublicID,
- &session.EventDisplayName,
- )
- if errors.Is(err, pgx.ErrNoRows) {
- return nil, nil
- }
- if err != nil {
- return nil, fmt.Errorf("scan session: %w", err)
- }
- return &session, nil
- }
- func scanSessionFromRows(rows pgx.Rows) (*Session, error) {
- var session Session
- err := rows.Scan(
- &session.ID,
- &session.SessionPublicID,
- &session.UserID,
- &session.EventID,
- &session.EventReleaseID,
- &session.ReleasePublicID,
- &session.ConfigLabel,
- &session.ManifestURL,
- &session.ManifestChecksum,
- &session.DeviceKey,
- &session.ClientType,
- &session.AssignmentMode,
- &session.VariantID,
- &session.VariantName,
- &session.RouteCode,
- &session.Status,
- &session.SessionTokenHash,
- &session.SessionTokenExpiresAt,
- &session.LaunchedAt,
- &session.StartedAt,
- &session.EndedAt,
- &session.EventPublicID,
- &session.EventDisplayName,
- )
- if err != nil {
- return nil, fmt.Errorf("scan session row: %w", err)
- }
- return &session, nil
- }
|