mirror of
https://github.com/tiennm99/noitu.git
synced 2026-10-13 22:16:20 +00:00
pointsFor now returns the named terms behind a word's total alongside the total itself, trimmed from the trailing term when the maxPointsPerWord cap bites, so PlayedWord.parts always sums exactly to points. ClaimDeadEnd lets the player to act say a syllable has no answer instead of waiting out the clock; the room checks HasLegalMove and settles it exactly as a timeout would, or refuses with the clock untouched. dictionary.Store gains a diacritic-stripped index built at Open, so MoveRejected.suggestion can offer the one real word a typo differs from by tone marks alone. ReportWord is validated and rate-limited on the session, logged with the room's own context, and answered with WordReported.
92 lines
3.7 KiB
Go
92 lines
3.7 KiB
Go
package wsapi
|
|
|
|
import "expvar"
|
|
|
|
// metricSet is the process's answer to "how is the game actually being
|
|
// played" — the question plans/reports/brainstormer-260921-0016 names as
|
|
// unanswerable with nothing but a dozen scattered slog calls. It is exposed
|
|
// at GET /debug/vars, but only when the operator opts in by setting
|
|
// NOITU_DEBUG_ADDR to a separate listen address: see cmd/noitu-server/main.go.
|
|
// Nothing here is read anywhere in the game logic — a counter that fed a
|
|
// decision back into play would need its own tests for correctness, not just
|
|
// for visibility.
|
|
//
|
|
// expvar's registry is a process-wide singleton by design (see the stdlib
|
|
// package doc), so these are package-level rather than server-instance
|
|
// fields: a second *Server in the same process — every wsapi test — shares
|
|
// one set of counters rather than fighting to register a second one under the
|
|
// same name.
|
|
type metricSet struct {
|
|
connectionsOpen *expvar.Int
|
|
connectionsTotal *expvar.Int
|
|
|
|
// roomsLive and roomsTotal are keyed "bot" or "pvp".
|
|
roomsLive *expvar.Map
|
|
roomsTotal *expvar.Map
|
|
|
|
// gamesStarted and gamesFinished are keyed the same way.
|
|
gamesStarted *expvar.Map
|
|
gamesFinished *expvar.Map
|
|
|
|
wordsSubmitted *expvar.Int
|
|
wordsAccepted *expvar.Int
|
|
// wordsRejected is keyed by game.RejectReason.String(), which is also
|
|
// what the word_rejected log line's reason field carries — one reason
|
|
// vocabulary rather than two.
|
|
wordsRejected *expvar.Map
|
|
|
|
// eliminations is keyed by the wire GameEndReason string, since that is
|
|
// the one place "the reconnect window ran out" is told apart from "they
|
|
// resigned" — both are game.EndResigned to the engine underneath.
|
|
eliminations *expvar.Map
|
|
|
|
chatLines *expvar.Int
|
|
|
|
// deadEndClaims is keyed "true" or "false": whether the claimed position
|
|
// actually had no legal move.
|
|
deadEndClaims *expvar.Map
|
|
// wordsReported counts accepted ReportWord messages — never the refused
|
|
// ones, which cost the sender an error and nothing else.
|
|
wordsReported *expvar.Int
|
|
|
|
// joinsRefused is keyed by the same UI error code the client is sent —
|
|
// "too_many_attempts", "room_not_found" or "room_full" — so a reader
|
|
// checking this counter against the frontend copy is checking against the
|
|
// same string, not a second name for it.
|
|
joinsRefused *expvar.Map
|
|
|
|
// botMoves is keyed by bot.Difficulty.String().
|
|
botMoves *expvar.Map
|
|
|
|
resumesAttempted *expvar.Int
|
|
resumesSucceeded *expvar.Int
|
|
}
|
|
|
|
// metrics is the one instance every call site writes through. Built at
|
|
// package init rather than lazily, so every counter exists — reading at zero
|
|
// — from the moment the process starts, whether or not NOITU_DEBUG_ADDR is
|
|
// ever set.
|
|
var metrics = newMetricSet()
|
|
|
|
func newMetricSet() *metricSet {
|
|
return &metricSet{
|
|
connectionsOpen: expvar.NewInt("noitu_connections_open"),
|
|
connectionsTotal: expvar.NewInt("noitu_connections_total"),
|
|
roomsLive: expvar.NewMap("noitu_rooms_live"),
|
|
roomsTotal: expvar.NewMap("noitu_rooms_total"),
|
|
gamesStarted: expvar.NewMap("noitu_games_started"),
|
|
gamesFinished: expvar.NewMap("noitu_games_finished"),
|
|
wordsSubmitted: expvar.NewInt("noitu_words_submitted"),
|
|
wordsAccepted: expvar.NewInt("noitu_words_accepted"),
|
|
wordsRejected: expvar.NewMap("noitu_words_rejected"),
|
|
eliminations: expvar.NewMap("noitu_eliminations"),
|
|
chatLines: expvar.NewInt("noitu_chat_lines"),
|
|
deadEndClaims: expvar.NewMap("noitu_dead_end_claims"),
|
|
wordsReported: expvar.NewInt("noitu_words_reported"),
|
|
joinsRefused: expvar.NewMap("noitu_joins_refused"),
|
|
botMoves: expvar.NewMap("noitu_bot_moves"),
|
|
resumesAttempted: expvar.NewInt("noitu_resumes_attempted"),
|
|
resumesSucceeded: expvar.NewInt("noitu_resumes_succeeded"),
|
|
}
|
|
}
|