mirror of
https://github.com/valkey-io/valkey.git
synced 2026-05-06 05:26:42 -04:00
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:
+21
-1
@@ -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
@@ -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
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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} {
|
||||
|
||||
Reference in New Issue
Block a user