1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
#[cfg(feature = "i-tracking")]
use crate::types::{client::Toggle, MultipleStrings};
use crate::{
commands,
error::Error,
interfaces::{ClientLike, FredResult},
types::{
client::{ClientKillFilter, ClientKillType, ClientPauseKind, ClientReplyFlag},
config::Server,
ClientUnblockFlag,
FromValue,
Value,
},
};
use bytes_utils::Str;
use fred_macros::rm_send_if;
use futures::Future;
use std::collections::HashMap;
/// Functions that implement the [client](https://redis.io/commands#connection) interface.
#[rm_send_if(feature = "glommio")]
pub trait ClientInterface: ClientLike + Sized {
/// Return the ID of the current connection.
///
/// Note: Against a clustered deployment this will return the ID of a random connection. See
/// [connection_ids](Self::connection_ids) for more information.
///
/// <https://redis.io/commands/client-id>
fn client_id<R>(&self) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::client::client_id(self).await?.convert() }
}
/// Read the connection IDs for the active connections to each server.
///
/// The returned map contains each server's `host:port` and the result of calling `CLIENT ID` on the connection.
///
/// Note: despite being async this function will return cached information from the client if possible.
fn connection_ids(&self) -> HashMap<Server, i64> {
self.inner().backchannel.connection_ids.lock().clone()
}
/// The command returns information and statistics about the current client connection in a mostly human readable
/// format.
///
/// <https://redis.io/commands/client-info>
fn client_info<R>(&self) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::client::client_info(self).await?.convert() }
}
/// Close a given connection or set of connections.
///
/// <https://redis.io/commands/client-kill>
fn client_kill<R>(&self, filters: Vec<ClientKillFilter>) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::client::client_kill(self, filters).await?.convert() }
}
/// The CLIENT LIST command returns information and statistics about the client connections server in a mostly human
/// readable format.
///
/// <https://redis.io/commands/client-list>
fn client_list<R, I>(
&self,
r#type: Option<ClientKillType>,
ids: Option<Vec<String>>,
) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::client::client_list(self, r#type, ids).await?.convert() }
}
/// The CLIENT GETNAME returns the name of the current connection as set by CLIENT SETNAME.
///
/// <https://redis.io/commands/client-getname>
fn client_getname<R>(&self) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::client::client_getname(self).await?.convert() }
}
/// Assign a name to the current connection.
///
/// **Note: The client automatically generates a unique name for each client that is shared by all underlying
/// connections. Use `self.id() to read the automatically generated name.**
///
/// <https://redis.io/commands/client-setname>
fn client_setname<S>(&self, name: S) -> impl Future<Output = FredResult<()>> + Send
where
S: Into<Str> + Send,
{
async move {
into!(name);
commands::client::client_setname(self, name).await
}
}
/// CLIENT PAUSE is a connections control command able to suspend all the Redis clients for the specified amount of
/// time (in milliseconds).
///
/// <https://redis.io/commands/client-pause>
fn client_pause(&self, timeout: i64, mode: Option<ClientPauseKind>) -> impl Future<Output = FredResult<()>> + Send {
async move { commands::client::client_pause(self, timeout, mode).await }
}
/// CLIENT UNPAUSE is used to resume command processing for all clients that were paused by CLIENT PAUSE.
///
/// <https://redis.io/commands/client-unpause>
fn client_unpause(&self) -> impl Future<Output = FredResult<()>> + Send {
async move { commands::client::client_unpause(self).await }
}
/// The CLIENT REPLY command controls whether the server will reply the client's commands. The following modes are
/// available:
///
/// <https://redis.io/commands/client-reply>
fn client_reply(&self, flag: ClientReplyFlag) -> impl Future<Output = FredResult<()>> + Send {
async move { commands::client::client_reply(self, flag).await }
}
/// This command can unblock, from a different connection, a client blocked in a blocking operation, such as for
/// instance BRPOP or XREAD or WAIT.
///
/// Note: this command is sent on a backchannel connection and will work even when the main connection is blocked.
///
/// <https://redis.io/commands/client-unblock>
fn client_unblock<R, S>(&self, id: S, flag: Option<ClientUnblockFlag>) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
S: Into<Value> + Send,
{
async move {
into!(id);
commands::client::client_unblock(self, id, flag).await?.convert()
}
}
/// A convenience function to unblock any blocked connection on this client.
fn unblock_self(&self, flag: Option<ClientUnblockFlag>) -> impl Future<Output = FredResult<()>> + Send {
async move { commands::client::unblock_self(self, flag).await }
}
/// Returns message.
///
/// <https://redis.io/docs/latest/commands/echo>
fn echo<R, M>(&self, message: M) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
M: TryInto<Value> + Send,
M::Error: Into<Error> + Send,
{
async move {
try_into!(message);
commands::client::echo(self, message).await?.convert()
}
}
/// This command enables the tracking feature of the Redis server that is used for server assisted client side
/// caching.
///
/// <https://redis.io/commands/client-tracking/>
///
/// This function is designed to work against a specific server, either via a centralized server config or
/// [with_options](crate::interfaces::ClientLike::with_options). See
/// [crate::interfaces::TrackingInterface::start_tracking] for a version that works with all server deployment
/// modes.
#[cfg(feature = "i-tracking")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-tracking")))]
fn client_tracking<R, T, P>(
&self,
toggle: T,
redirect: Option<i64>,
prefixes: P,
bcast: bool,
optin: bool,
optout: bool,
noloop: bool,
) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
T: TryInto<Toggle> + Send,
T::Error: Into<Error> + Send,
P: Into<MultipleStrings> + Send,
{
async move {
try_into!(toggle);
into!(prefixes);
commands::tracking::client_tracking(self, toggle, redirect, prefixes, bcast, optin, optout, noloop)
.await?
.convert()
}
}
/// The command returns information about the current client connection's use of the server assisted client side
/// caching feature.
///
/// <https://redis.io/commands/client-trackinginfo/>
#[cfg(feature = "i-tracking")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-tracking")))]
fn client_trackinginfo<R>(&self) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::tracking::client_trackinginfo(self).await?.convert() }
}
/// This command returns the client ID we are redirecting our tracking notifications to.
///
/// <https://redis.io/commands/client-getredir/>
#[cfg(feature = "i-tracking")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-tracking")))]
fn client_getredir<R>(&self) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::tracking::client_getredir(self).await?.convert() }
}
/// This command controls the tracking of the keys in the next command executed by the connection, when tracking is
/// enabled in OPTIN or OPTOUT mode.
///
/// <https://redis.io/commands/client-caching/>
///
/// This function is designed to work against a specific server. See
/// [with_options](crate::interfaces::ClientLike::with_options) for a variation that works with all deployment
/// types.
#[cfg(feature = "i-tracking")]
#[cfg_attr(docsrs, doc(cfg(feature = "i-tracking")))]
fn client_caching<R>(&self, enabled: bool) -> impl Future<Output = FredResult<R>> + Send
where
R: FromValue,
{
async move { commands::tracking::client_caching(self, enabled).await?.convert() }
}
}