Skip to content

Commit

Permalink
Add support for lobby filtering
Browse files Browse the repository at this point in the history
  • Loading branch information
erikdubbelboer and koenbollen committed May 10, 2024
1 parent e92409c commit 059377b
Show file tree
Hide file tree
Showing 11 changed files with 212 additions and 30 deletions.
24 changes: 24 additions & 0 deletions cmd/testproxy/main.go
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,15 @@ package main

import (
"context"
"io"
"net"
"net/http"
"os"
"os/signal"
"syscall"
"time"

"github.com/jackc/pgx/v5/pgxpool"
"github.com/koenbollen/logging"
"github.com/poki/netlib/internal/util"
"go.uber.org/zap"
Expand All @@ -23,6 +26,15 @@ func main() {
defer logger.Info("fin")
ctx = logging.WithLogger(ctx, logger)

db, err := pgxpool.New(ctx, os.Getenv("DATABASE_URL"))
if err != nil {
logger.Fatal("failed to connect", zap.Error(err))
}

if err := db.Ping(ctx); err != nil {
logger.Fatal("failed to ping db", zap.Error(err))
}

connections := make(map[string]net.Conn)
interrupts := make(map[string]bool)
http.HandleFunc("/create", func(w http.ResponseWriter, r *http.Request) {
Expand Down Expand Up @@ -85,6 +97,18 @@ func main() {
delete(connections, id)
}
})
http.HandleFunc("/sql", func(w http.ResponseWriter, r *http.Request) {
sql, err := io.ReadAll(r.Body)
if err != nil {
panic(err)
}

// This process is only ran during tests.
_, err = db.Exec(ctx, string(sql))
if err != nil {
panic(err)
}
})

addr := util.Getenv("ADDR", ":8080")
server := &http.Server{
Expand Down
55 changes: 49 additions & 6 deletions features/lobbies.feature
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ Feature: Lobby Discovery

Background:
Given the "signaling" backend is running
And the "testproxy" backend is running

Scenario: List empty lobby set
Given "green" is connected and ready for game "f666036d-d9e1-4d70-b0c3-4a68b24a9884"
Expand All @@ -21,15 +22,15 @@ Feature: Lobby Discovery
And "blue" is connected and ready for game "f666036d-d9e1-4d70-b0c3-4a68b24a9884"

When "blue" creates a lobby with these settings:
"""
"""json
{
"public": true
}
"""
And "blue" receives the network event "lobby" with the argument "prb67ouj837u"

When "green" requests all lobbies
Then "green" should have received only these lobbies
Then "green" should have received only these lobbies:
| code | playerCount |
| prb67ouj837u | 1 |

Expand All @@ -39,26 +40,68 @@ Feature: Lobby Discovery
And "yellow" is connected and ready for game "f666036d-d9e1-4d70-b0c3-4a68b24a9884"

When "blue" creates a lobby with these settings:
"""
"""json
{
"public": true
}
"""
And "blue" receives the network event "lobby" with the argument "dhgp75mn2bll"
And "yellow" creates a lobby with these settings:
"""
"""json
{
"public": false
}
"""
And "yellow" receives the network event "lobby" with the argument "1qva9vyurwbbl"

When "green" requests all lobbies
Then "green" should have received only these lobbies
Then "green" should have received only these lobbies:
| code | playerCount | public |
| dhgp75mn2bll | 1 | true |

Scenario: Filter on playerCount
Given "green" is connected and ready for game "f666036d-d9e1-4d70-b0c3-4a68b24a9884"
And these lobbies exist:
| code | game | playerCount | public |
| 0qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 1 | true |
| 1qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 2 | false |
| 2qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 3 | true |
| 3qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 4 | true |
| 4qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 5 | true |
| 5qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 6 | true |
| 6qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 7 | false |
| 7qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 8 | true |
| 8qva9vyurwbbl | 54fa57d5-b4bd-401d-981d-2c13de99be27 | 9 | true |
| 9qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 10 | true |

When "green" requests lobbies with this filter:
"""json
{
"playerCount": {"$gte": 5}
}
"""
Then "green" should have received only these lobbies:
| code | playerCount | public |
| 4qva9vyurwbbl | 5 | true |
| 5qva9vyurwbbl | 6 | true |
| 7qva9vyurwbbl | 8 | true |
| 9qva9vyurwbbl | 10 | true |

Scenario: Filter on customData
Given "green" is connected and ready for game "f666036d-d9e1-4d70-b0c3-4a68b24a9884"
And these lobbies exist:
| code | game | playerCount | meta | public | created_at |
| 0qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 1 | {"map": "de_nuke"} | true | 2020-01-01 |
| 1qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 1 | {"map": "de_dust"} | true | 2020-01-02 |
| 2qva9vyurwbbl | f666036d-d9e1-4d70-b0c3-4a68b24a9884 | 1 | {"map": "de_nuke"} | true | 2020-01-03 |


When "green" requests lobbies with this filter:
"""json
{
"map": "de_nuke",
"createdAt": {"$gte": "2020-01-02"}
}
"""
Then "green" should have received only these lobbies:
| code |
| 2qva9vyurwbbl |
20 changes: 14 additions & 6 deletions features/support/steps/backend.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,21 +5,29 @@ import { World } from '../world'
Given('the {string} backend is running', async function (this: World, backend: string) {
return await new Promise(resolve => {
const port = 10000 + Math.ceil(Math.random() * 1000)
const env: NodeJS.ProcessEnv = {
...process.env,
ADDR: `127.0.0.1:${port}`,
ENV: 'test'
}

if (this.databaseURL === undefined) {
env.DATABASE_URL = this.databaseURL
}

const prc = spawn(`/tmp/netlib-cucumber-${backend}`, [], {
windowsHide: true,
env: {
...process.env,
ADDR: `127.0.0.1:${port}`,
ENV: 'test'
}
env
})
prc.stderr.setEncoding('utf8')
prc.stderr.on('data', (data: string) => {
const lines = data.split('\n')
lines.forEach(line => {
try {
const entry = JSON.parse(line)
if (entry.message === 'listening') {
if (entry.message === 'using database') {
this.databaseURL = entry.url
} else if (entry.message === 'listening') {
resolve(undefined)
}
} catch (_) {
Expand Down
57 changes: 56 additions & 1 deletion features/support/steps/network.ts
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,52 @@ Given('{string} are joined in a lobby', async function (this: World, playerNames
}
})

Given('these lobbies exist:', async function (this: World, lobbies: DataTable) {
if (this.testproxyURL === undefined) {
throw new Error('testproxy not active')
}

const columns: string[] = []
const values: string[] = []

lobbies.hashes().forEach(row => {
const v: string[] = []

Object.keys(row).forEach(key => {
const value = row[key] as string
if (key === 'playerCount') {
if (!columns.includes('peers')) {
columns.push('peers')
}

const n = parseInt(value, 10)
const peers: string[] = []

for (let i = 0; i < n; i++) {
peers.push(`'peer${i}'`)
}

v.push(`ARRAY [${peers.join(', ')}]`)
} else {
if (!columns.includes(key)) {
columns.push(key)
}

v.push(`'${value}'`)
}
})

values.push(`(${v.join(', ')})`)
})

console.log('INSERT INTO lobbies (' + columns.join(', ') + ') VALUES ' + values.join(', '))

await fetch(`${this.testproxyURL}/sql`, {
method: 'POST',
body: 'INSERT INTO lobbies (' + columns.join(', ') + ') VALUES ' + values.join(', ')
})
})

When('{string} creates a network for game {string}', function (this: World, playerName: string, gameID: string) {
this.createPlayer(playerName, gameID)
})
Expand Down Expand Up @@ -106,6 +152,15 @@ When('{string} requests all lobbies', async function (this: World, playerName: s
player.lastReceivedLobbies = lobbies
})

When('{string} requests lobbies with this filter:', async function (this: World, playerName: string, filter: string) {
const player = this.players.get(playerName)
if (player == null) {
return 'no such player'
}
const lobbies = await player.network.list(filter)
player.lastReceivedLobbies = lobbies
})

Then('{string} receives the network event {string}', async function (this: World, playerName: string, eventName: string) {
const player = this.players.get(playerName)
if (player == null) {
Expand Down Expand Up @@ -160,7 +215,7 @@ Then('{string} should receive {int} lobbies', function (this: World, playerName:
return player.lastReceivedLobbies?.length === expectedLobbyCount
})

Then('{string} should have received only these lobbies', function (this: World, playerName: string, expectedLobbies: DataTable) {
Then('{string} should have received only these lobbies:', function (this: World, playerName: string, expectedLobbies: DataTable) {
const player = this.players.get(playerName)
if (player == null) {
throw new Error('no such player')
Expand Down
1 change: 1 addition & 0 deletions features/support/world.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ export class World extends CucumberWorld {
public signalingURL?: string
public testproxyURL?: string
public useTestProxy: boolean = false
public databaseURL?: string

public players: Map<string, Player> = new Map<string, Player>()

Expand Down
3 changes: 2 additions & 1 deletion go.mod
Original file line number Diff line number Diff line change
@@ -1,12 +1,13 @@
module github.com/poki/netlib

go 1.20
go 1.22.2

require (
github.com/golang-migrate/migrate/v4 v4.16.2
github.com/jackc/pgx/v5 v5.4.2
github.com/koenbollen/logging v0.0.0-20230520102501-e01d64214504
github.com/ory/dockertest/v3 v3.10.0
github.com/poki/mongodb-filter-to-postgres v0.0.0-20240503105833-0b1842cffb65
github.com/rs/cors v1.9.0
github.com/rs/xid v1.5.0
go.uber.org/zap v1.24.0
Expand Down
Loading

0 comments on commit 059377b

Please sign in to comment.