Add more client info flags to module API (#2868)

Adding more client flags in the information populated by
`ValkeyModule_GetClientInfoById()`:

    VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY
    VALKEYMODULE_CLIENTINFO_FLAG_REPLICA
    VALKEYMODULE_CLIENTINFO_FLAG_MONITOR
    VALKEYMODULE_CLIENTINFO_FLAG_MODULE
    VALKEYMODULE_CLIENTINFO_FLAG_AUTHENTICATED
    VALKEYMODULE_CLIENTINFO_FLAG_EVER_AUTHENTICATED
    VALKEYMODULE_CLIENTINFO_FLAG_FAKE

Closes #2590

---------

Signed-off-by: martinrvisser <mvisser@hotmail.com>
Signed-off-by: martinrvisser <martinrvisser@users.noreply.github.com>
Signed-off-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
Co-authored-by: Viktor Söderqvist <viktor.soderqvist@est.tech>
This commit is contained in:
martinrvisser
2026-02-09 15:56:18 +01:00
committed by GitHub
parent 185d2ad7d9
commit 87caeb7646
4 changed files with 88 additions and 12 deletions
+21 -1
View File
@@ -3847,6 +3847,13 @@ int modulePopulateClientInfoStructure(void *ci, client *client, int structver) {
if (client->flag.blocked) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_BLOCKED;
if (client->conn->type == connectionTypeTls()) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_SSL;
if (client->flag.readonly) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_READONLY;
if (client->flag.primary) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY;
if (client->flag.replica) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_REPLICA;
if (client->flag.monitor) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_MONITOR;
if (client->flag.module) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_MODULE;
if (client->flag.authenticated) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_AUTHENTICATED;
if (client->flag.ever_authenticated) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_EVER_AUTHENTICATED;
if (client->flag.fake) ci1->flags |= VALKEYMODULE_CLIENTINFO_FLAG_FAKE;
int port;
connAddrPeerName(client->conn, ci1->addr, sizeof(ci1->addr), &port);
@@ -3907,8 +3914,21 @@ int modulePopulateReplicationInfoStructure(void *ri, int structver) {
* VALKEYMODULE_CLIENTINFO_FLAG_UNIXSOCKET Client using unix domain socket.
* VALKEYMODULE_CLIENTINFO_FLAG_MULTI Client in MULTI state.
* VALKEYMODULE_CLIENTINFO_FLAG_READONLY Client in ReadOnly state.
* VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY Client is a fake client used
* for applying replicated
* commands from the primary.
* VALKEYMODULE_CLIENTINFO_FLAG_MONITOR Client in monitor mode.
* VALKEYMODULE_CLIENTINFO_FLAG_MODULE Client is a module.
* VALKEYMODULE_CLIENTINFO_FLAG_AUTHENTICATED
* Client has been authenticated.
* VALKEYMODULE_CLIENTINFO_FLAG_EVER_AUTHENTICATED
* Client has successfully been
* authenticated in its lifetime.
* VALKEYMODULE_CLIENTINFO_FLAG_FAKE Fake clients are internal to valkey.
*
* However passing NULL is a way to just check if the client exists in case
* Note: The flags VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY and below were added in Valkey 9.1.
*
* Passing NULL is a way to just check if the client exists in case
* we are not interested in any additional information.
*
* This is the correct usage when we want the client info structure
+10 -2
View File
@@ -172,7 +172,7 @@ typedef struct ValkeyModuleStreamID {
#define VALKEYMODULE_CTX_FLAGS_MULTI (1 << 1)
/* The instance is a primary */
#define VALKEYMODULE_CTX_FLAGS_PRIMARY (1 << 2)
/* The instance is a replic */
/* The instance is a replica */
#define VALKEYMODULE_CTX_FLAGS_REPLICA (1 << 3)
/* The instance is read-only (usually meaning it's a replica as well) */
#define VALKEYMODULE_CTX_FLAGS_READONLY (1 << 4)
@@ -674,7 +674,8 @@ static const ValkeyModuleEvent ValkeyModuleEvent_ReplicationRoleChanged = {VALKE
#define VALKEYMODULE_SUBEVENT_ATOMIC_SLOT_MIGRATION_EXPORT_COMPLETED 5
#define _VALKEYMODULE_SUBEVENT_ATOMIC_SLOT_MIGRATION_NEXT 6
/* ValkeyModuleClientInfo flags. */
/* ValkeyModuleClientInfo flags.
* Note: flags VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY and below were added in Valkey 9.1 */
#define VALKEYMODULE_CLIENTINFO_FLAG_SSL (1 << 0)
#define VALKEYMODULE_CLIENTINFO_FLAG_PUBSUB (1 << 1)
#define VALKEYMODULE_CLIENTINFO_FLAG_BLOCKED (1 << 2)
@@ -682,6 +683,13 @@ static const ValkeyModuleEvent ValkeyModuleEvent_ReplicationRoleChanged = {VALKE
#define VALKEYMODULE_CLIENTINFO_FLAG_UNIXSOCKET (1 << 4)
#define VALKEYMODULE_CLIENTINFO_FLAG_MULTI (1 << 5)
#define VALKEYMODULE_CLIENTINFO_FLAG_READONLY (1 << 6)
#define VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY (1 << 7)
#define VALKEYMODULE_CLIENTINFO_FLAG_REPLICA (1 << 8)
#define VALKEYMODULE_CLIENTINFO_FLAG_MONITOR (1 << 9)
#define VALKEYMODULE_CLIENTINFO_FLAG_MODULE (1 << 10)
#define VALKEYMODULE_CLIENTINFO_FLAG_AUTHENTICATED (1 << 11)
#define VALKEYMODULE_CLIENTINFO_FLAG_EVER_AUTHENTICATED (1 << 12)
#define VALKEYMODULE_CLIENTINFO_FLAG_FAKE (1 << 13)
/* Here we take all the structures that the module pass to the core
* and the other way around. Notably the list here contains the structures
+9 -2
View File
@@ -306,14 +306,21 @@ int test_clientinfo(ValkeyModuleCtx *ctx, ValkeyModuleString **argv, int argc)
ValkeyModule_ReplyWithArray(ctx, 10);
char flags[512];
snprintf(flags, sizeof(flags) - 1, "%s:%s:%s:%s:%s:%s:%s",
snprintf(flags, sizeof(flags) - 1, "%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s:%s",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_SSL ? "ssl" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_PUBSUB ? "pubsub" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_BLOCKED ? "blocked" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_TRACKING ? "tracking" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_UNIXSOCKET ? "unixsocket" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_MULTI ? "multi" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_READONLY ? "readonly" : "");
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_READONLY ? "readonly" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_PRIMARY ? "primary" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_REPLICA ? "replica" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_MONITOR ? "monitor" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_MODULE ? "module" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_AUTHENTICATED ? "authenticated" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_EVER_AUTHENTICATED ? "ever_authenticated" : "",
ci.flags & VALKEYMODULE_CLIENTINFO_FLAG_FAKE ? "fake" : "");
ValkeyModule_ReplyWithCString(ctx, "flags");
ValkeyModule_ReplyWithCString(ctx, flags);
+48 -7
View File
@@ -97,31 +97,72 @@ start_server {overrides {save {900 1}} tags {"modules"}} {
assert { $was_set == 0 }
}
proc parse_client_flags {flags} {
set flag_list [split $flags ":"]
set parsed_flags {}
# Just collect all non-empty flags
foreach flag $flag_list {
if {$flag ne ""} {
lappend parsed_flags $flag
}
}
return $parsed_flags
}
test {test module clientinfo api} {
# Test basic sanity and SSL flag
set info [r test.clientinfo]
set ssl_flag [expr $::tls ? {"ssl:"} : {":"}]
assert { [dict get $info db] == 9 }
assert { [dict get $info flags] == "${ssl_flag}:::::" }
set flags [parse_client_flags [dict get $info flags]]
# Check initial state - should have auth flags, maybe SSL
if {$::tls} {
assert { "ssl" in $flags }
}
assert { "authenticated" in $flags }
assert { "ever_authenticated" in $flags }
assert { "multi" ni $flags }
assert { "tracking" ni $flags }
assert { "readonly" ni $flags }
# Test MULTI flag
r multi
r test.clientinfo
set info [lindex [r exec] 0]
assert { [dict get $info flags] == "${ssl_flag}::::multi:" }
set flags [parse_client_flags [dict get $info flags]]
assert { "multi" in $flags }
assert { "authenticated" in $flags }
assert { "ever_authenticated" in $flags }
# Test TRACKING flag
r client tracking on
set info [r test.clientinfo]
assert { [dict get $info flags] == "${ssl_flag}::tracking:::" }
set flags [parse_client_flags [dict get $info flags]]
assert { "tracking" in $flags }
assert { "multi" ni $flags }
assert { "authenticated" in $flags }
assert { "ever_authenticated" in $flags }
r CLIENT TRACKING off
# Test READONLY flag
r readonly
set info [r test.clientinfo]
assert { [dict get $info flags] == "${ssl_flag}:::::readonly" }
set flags [parse_client_flags [dict get $info flags]]
assert { "readonly" in $flags }
assert { "tracking" ni $flags }
assert { "multi" ni $flags }
assert { "authenticated" in $flags }
assert { "ever_authenticated" in $flags }
r readwrite
set info [r test.clientinfo]
assert { [dict get $info flags] == "${ssl_flag}:::::" }
set flags [parse_client_flags [dict get $info flags]]
assert { "readonly" ni $flags }
assert { "authenticated" in $flags }
assert { "ever_authenticated" in $flags }
}
test {tracking with rm_call sanity} {