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
//! Command-dispatch extension hook.
//!
//! The cluster substrate ships the parser, the dispatcher, and
//! the standard data-plane commands (GET / SET / HSET / ...).
//! Layered surfaces - notably the RediSearch FT.* commands -
//! plug in via the [`CommandExtension`] trait so the substrate
//! does not need to know about them at compile time.
//!
//! # Lifecycle
//!
//! 1. The embedder constructs a
//! [`crate::embed::ServerBuilder`].
//! 2. The embedder (or a helper crate such as
//! `dynomite-search`) attaches a [`CommandExtension`] via
//! [`crate::embed::ServerBuilder::with_command_extension`]
//! or [`crate::embed::ServerBuilder::set_command_extension`].
//! 3. The dispatcher consults the extension in the hot path:
//! * For commands the parser tags as
//! [`crate::msg::MsgType::ReqRedisFtCreate`] /
//! [`crate::msg::MsgType::ReqRedisFtSearch`] /
//! [`crate::msg::MsgType::ReqRedisFtInfo`] /
//! [`crate::msg::MsgType::ReqRedisFtList`] /
//! [`crate::msg::MsgType::ReqRedisFtDropindex`] /
//! [`crate::msg::MsgType::ReqRedisFtRegex`] /
//! [`crate::msg::MsgType::ReqRedisFtUnknown`] the
//! dispatcher checks
//! [`CommandExtension::handles_msg_type`] and, if true,
//! delegates execution to
//! [`CommandExtension::try_dispatch`].
//! * Every HSET request is offered to
//! [`CommandExtension::try_intercept_hset`] before the
//! standard fan-out path runs.
//! 4. When no extension is wired the dispatcher behaves
//! exactly as it did before this hook existed: FT.* keywords
//! are forwarded to the local datastore (which typically
//! rejects them with `-ERR unknown command`).
//!
//! Implementations are object-safe; the dispatcher holds an
//! [`std::sync::Arc<dyn CommandExtension>`] and clones the
//! handle freely across tasks.
use Debug;
use crateMsgType;
/// Outcome of [`CommandExtension::try_intercept_hset`].
///
/// The HSET interception path runs before the dispatcher's
/// routing planner. The extension can either absorb the write
/// (the standard storage write still fires; the engine just
/// got a free side-effect), reject it with a structured error
/// reply, or pass through.
/// Pluggable command-dispatch hook.
///
/// Implementors short-circuit dispatcher routing for the
/// command families they own; everything else falls through
/// to the standard substrate. See the module-level docs for
/// the lifecycle and the standard-library hook used by
/// `dynomite-search`.