Skip to content

Commit f7c1175

Browse files
committed
Clean empty, day old, lobbies on a 30min timer.
(also snuck in the disabling of websocket compression, see coder/websocket#218 (comment))
1 parent acd7e42 commit f7c1175

File tree

3 files changed

+54
-21
lines changed

3 files changed

+54
-21
lines changed

internal/signaling/handler.go

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ import (
44
"context"
55
"encoding/json"
66
"net/http"
7-
"strings"
87
"sync"
98
"time"
109

@@ -19,12 +18,32 @@ import (
1918

2019
const MaxConnectionTime = 1 * time.Hour
2120

21+
const LobbyCleanInterval = 30 * time.Minute
22+
const LobbyCleanThreshold = 24 * time.Hour
23+
2224
func Handler(ctx context.Context, store stores.Store, cloudflare *cloudflare.CredentialsClient) (*sync.WaitGroup, http.HandlerFunc) {
2325
manager := &TimeoutManager{
2426
Store: store,
2527
}
2628
go manager.Run(ctx)
2729

30+
go func() {
31+
logger := logging.GetLogger(ctx)
32+
ticker := time.NewTicker(LobbyCleanInterval)
33+
defer ticker.Stop()
34+
for {
35+
select {
36+
case <-ticker.C:
37+
logger.Info("cleaning empty lobbies")
38+
if err := store.CleanEmptyLobbies(ctx, time.Now().Add(-LobbyCleanThreshold)); err != nil {
39+
logger.Error("failed to clean empty lobbies", zap.Error(err))
40+
}
41+
case <-ctx.Done():
42+
return
43+
}
44+
}
45+
}()
46+
2847
wg := &sync.WaitGroup{}
2948
return wg, http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
3049
ctx := r.Context()
@@ -34,17 +53,10 @@ func Handler(ctx context.Context, store stores.Store, cloudflare *cloudflare.Cre
3453
ctx, cancel := context.WithTimeout(ctx, MaxConnectionTime)
3554
defer cancel()
3655

37-
userAgentLower := strings.ToLower(r.Header.Get("User-Agent"))
38-
isSafari := strings.Contains(userAgentLower, "safari") && !strings.Contains(userAgentLower, "chrome") && !strings.Contains(userAgentLower, "android")
3956
acceptOptions := &websocket.AcceptOptions{
40-
// Allow any origin/game to connect.
41-
InsecureSkipVerify: true,
42-
}
43-
44-
if isSafari {
45-
acceptOptions.CompressionMode = websocket.CompressionDisabled
57+
InsecureSkipVerify: true, // Allow any origin/game to connect.
58+
CompressionMode: websocket.CompressionDisabled,
4659
}
47-
4860
conn, err := websocket.Accept(w, r, acceptOptions)
4961
if err != nil {
5062
util.ErrorAndAbort(w, r, http.StatusBadRequest, "", err)

internal/signaling/stores/postgres.go

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -151,11 +151,12 @@ func (s *PostgresStore) CreateLobby(ctx context.Context, game, lobbyCode, peerID
151151
logger.Warn("peer id too long", zap.String("peerID", peerID))
152152
return ErrInvalidPeerID
153153
}
154+
now := util.Now(ctx)
154155
res, err := s.DB.Exec(ctx, `
155-
INSERT INTO lobbies (code, game, public)
156-
VALUES ($1, $2, true)
156+
INSERT INTO lobbies (code, game, public, created_at, updated_at)
157+
VALUES ($1, $2, true, $3, $3)
157158
ON CONFLICT DO NOTHING
158-
`, lobbyCode, game)
159+
`, lobbyCode, game, now)
159160
if err != nil {
160161
return err
161162
}
@@ -171,6 +172,9 @@ func (s *PostgresStore) JoinLobby(ctx context.Context, game, lobbyCode, peerID s
171172
logger.Warn("peer id too long", zap.String("peerID", peerID))
172173
return nil, ErrInvalidPeerID
173174
}
175+
176+
now := util.Now(ctx)
177+
174178
tx, err := s.DB.Begin(ctx)
175179
if err != nil {
176180
return nil, err
@@ -200,10 +204,12 @@ func (s *PostgresStore) JoinLobby(ctx context.Context, game, lobbyCode, peerID s
200204

201205
_, err = tx.Exec(ctx, `
202206
UPDATE lobbies
203-
SET peers = array_append(peers, $1)
204-
WHERE code = $2
205-
AND game = $3
206-
`, peerID, lobbyCode, game)
207+
SET
208+
peers = array_append(peers, $1),
209+
updated_at = $2
210+
WHERE code = $3
211+
AND game = $4
212+
`, peerID, now, lobbyCode, game)
207213
if err != nil {
208214
return nil, err
209215
}
@@ -232,14 +238,18 @@ func (s *PostgresStore) IsPeerInLobby(ctx context.Context, game, lobbyCode, peer
232238
}
233239

234240
func (s *PostgresStore) LeaveLobby(ctx context.Context, game, lobbyCode, peerID string) ([]string, error) {
241+
now := util.Now(ctx)
242+
235243
var peerlist []string
236244
err := s.DB.QueryRow(ctx, `
237245
UPDATE lobbies
238-
SET peers = array_remove(peers, $1)
239-
WHERE code = $2
240-
AND game = $3
246+
SET
247+
peers = array_remove(peers, $1),
248+
updated_at = $2
249+
WHERE code = $3
250+
AND game = $4
241251
RETURNING peers
242-
`, peerID, lobbyCode, game).Scan(&peerlist)
252+
`, peerID, now, lobbyCode, game).Scan(&peerlist)
243253
if err != nil && !errors.Is(err, pgx.ErrNoRows) {
244254
return nil, err
245255
}
@@ -387,3 +397,12 @@ func (s *PostgresStore) ClaimNextTimedOutPeer(ctx context.Context, threshold tim
387397

388398
return true, tx.Commit(ctx)
389399
}
400+
401+
func (s *PostgresStore) CleanEmptyLobbies(ctx context.Context, olderThan time.Time) error {
402+
_, err := s.DB.Exec(ctx, `
403+
DELETE FROM lobbies
404+
WHERE updated_at < $1
405+
AND peers = '{}'
406+
`, olderThan)
407+
return err
408+
}

internal/signaling/stores/shared.go

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -29,6 +29,8 @@ type Store interface {
2929
TimeoutPeer(ctx context.Context, peerID, secret, gameID string, lobbies []string) error
3030
ReconnectPeer(ctx context.Context, peerID, secret, gameID string) (bool, error)
3131
ClaimNextTimedOutPeer(ctx context.Context, threshold time.Duration, callback func(peerID, gameID string, lobbies []string) error) (bool, error)
32+
33+
CleanEmptyLobbies(ctx context.Context, olderThan time.Time) error
3234
}
3335

3436
type Lobby struct {

0 commit comments

Comments
 (0)