fix(server): name the player on every played word, and bound the process

PlayedWord.player_id was declared and read by the client but never set by
the server, so a room of three or four never showed who played each word.
The chain byline now comes from the room, with a producer-side test.

The process also gains the ceilings it was missing: a cap on live rooms and
on open sockets, a per-connection frame-rate limit so a payload-less frame
is no longer free, and an opt-in trusted-proxy list so the join limiter can
tell players apart behind the documented reverse proxy instead of putting
them in one bucket. The typed word is sanitized before the engine stores it,
since every seat is shown it; a room exiting on its idle clock releases the
sessions still bound to it; the dictionary builder escapes its SQLite path
like the store does and renames over the old database instead of deleting
it first.
This commit is contained in:
tiennm99 committed 2026-09-21 00:38:09 +07:00
1 parent a5052fca3f
commit 442ced32cc
14 files changed
+494 -54

No files matched your search

+13 -5
View File
@@ -139,11 +139,19 @@ func Open(path string) (*Store, error) {
return s, nil
}
// dsn builds the SQLite URI. The path must be escaped: SQLite reads '#' as a
// URI fragment delimiter, so a bare path containing one silently opens a
// different (usually nonexistent) file and reports a confusing schema error.
func dsn(path string) string {
u := url.URL{Scheme: "file", Opaque: (&url.URL{Path: path}).EscapedPath(), RawQuery: "mode=ro"}
// dsn is the read-only URI the store opens with.
func dsn(path string) string { return DSN(path, true) }
// DSN builds a SQLite URI for path. The path must be escaped: SQLite reads
// '#' as a URI fragment delimiter, so a bare path containing one silently
// opens a different (usually nonexistent) file and reports a confusing schema
// error. Exported so the builder, which writes the file this package reads,
// spells the path the same way.
func DSN(path string, readOnly bool) string {
u := url.URL{Scheme: "file", Opaque: (&url.URL{Path: path}).EscapedPath()}
if readOnly {
u.RawQuery = "mode=ro"
}
return u.String()
}