QcRateLimiter Class
Token buckets of one player, one per kind of spammable message (decision E-091). More...
| Header: | #include <server/core/QcRateLimiter.h> |
Public Types
Public Functions
| bool | allow(QcRateLimiter::Kind kind, qint64 nowNs) |
| quint64 | takeDropReport(QcRateLimiter::Kind kind, qint64 nowNs) |
Static Public Members
| bool | isUnlimited(const QcMessage &message) |
| const int | kindCount |
| std::optional<QcRateLimiter::Kind> | kindOf(const QcMessage &message) |
| QcRateLimiter::Limit | limit(QcRateLimiter::Kind kind) |
| const std::array<QcRateLimiter::Limit, kindCount> | limits |
| const char * | name(QcRateLimiter::Kind kind) |
| const qint64 | reportIntervalNs |
Detailed Description
A bucket starts full, refills with the players' time of the server (QcServerClock::playerTimeNs: real time at every tick rate and during a sprint, deterministic in tests) and pays one token per message; a message finding its bucket empty is dropped. The limits lie well above what the real client sends while playing.
Member Type Documentation
enum class QcRateLimiter::Kind
The kinds of spammable messages, one bucket each.
| Constant | Value | Description |
|---|---|---|
QcRateLimiter::Kind::Mining | 0 | StartMining, CancelMining, FinishMining (the client sends at most three per tick, 60 per second; the limit leaves a clear margin, a dropped StartMining or FinishMining gets its true block back). |
QcRateLimiter::Kind::Use | 1 | UseItem, UseEntity, ConsumeItem, ThrowItem, the press of DrawLauncher (one per click). |
QcRateLimiter::Kind::AttackEntity | 2 | AttackEntity (one per click). |
QcRateLimiter::Kind::Chat | 3 | Chat lines and commands. |
QcRateLimiter::Kind::Drop | 4 | DropItem: dropping items from the hotbar (each spawns an item entity). |
QcRateLimiter::Kind::Inventory | 5 | Inventory, crafting and machine screen actions; mouse drags and the wheel send many. The pause menu's PauseRequest counts here too (decision E-877). |
QcRateLimiter::Kind::Appearance | 6 | A new look is sent again to every player who sees the player. |
QcRateLimiter::Kind::Switch | 7 | Levers, buttons and repeaters switched by hand (paid inside a Use, decision E-339): every switch starts work in the circuits, so spamming a lever is bounded separately. |
QcRateLimiter::Kind::Sign | 8 | Lines written on a sign (decision E-766); each change goes to every player who has the sign's chunk. |
QcRateLimiter::Kind::Admin | 9 | Admin requests and subscriptions of operators (decision E-848): each may run a command or build a report of the whole server. |
QcRateLimiter::Kind::Latency | 10 | Latency probes (decision E-886): the client sends two per second; each costs an echo. |
Member Function Documentation
bool QcRateLimiter::allow(QcRateLimiter::Kind kind, qint64 nowNs)
Takes a token of kind at nowNs (players' time). Returns false when the bucket is empty (the drop is counted).
[static] bool QcRateLimiter::isUnlimited(const QcMessage &message)
Returns whether message is one of the client messages that are deliberately not limited here: PlayerInput has its own budget, Hello, Respawn, Disconnect and the release or cancel of DrawLauncher are harmless, LoginResponse is accepted once before the client plays (the connection limits of QcNetworkServer bound logins), Pong only answers the server's own Ping, DebugSubscribe is state (the latest one counts and must never be dropped; the debug data itself comes at a fixed pace, decision E-225). Every other client message needs a bucket.
[static] std::optional<QcRateLimiter::Kind> QcRateLimiter::kindOf(const QcMessage &message)
Returns the bucket the client message message pays into; std::nullopt for messages that are not limited here.
[static constexpr] QcRateLimiter::Limit QcRateLimiter::limit(QcRateLimiter::Kind kind)
Returns the limit of kind.
[static] const char *QcRateLimiter::name(QcRateLimiter::Kind kind)
Returns the name of kind as the log shows it ("mining", "use", ...).
quint64 QcRateLimiter::takeDropReport(QcRateLimiter::Kind kind, qint64 nowNs)
Returns the drops of kind not yet reported, when a report is due at nowNs (then they count as reported); 0 otherwise.
Member Variable Documentation
const int QcRateLimiter::kindCount
The number of kinds.
const std::array<QcRateLimiter::Limit, kindCount> QcRateLimiter::limits
The limits by kind, in the order of Kind.
const qint64 QcRateLimiter::reportIntervalNs
Drops are logged at most this often per player and kind (the first one at once).