userver
C++ Async Framework
Toggle main menu visibility
Loading...
Searching...
No Matches
source.hpp
Go to the documentation of this file.
1
#
pragma
once
2
3
/// @file userver/dynamic_config/source.hpp
4
/// @brief @copybrief dynamic_config::Source
5
6
#
include
<
optional
>
7
#
include
<
string_view
>
8
#
include
<
utility
>
9
10
#
include
<
userver
/
compiler
/
impl
/
lifetime
.
hpp
>
11
#
include
<
userver
/
concurrent
/
async_event_source
.
hpp
>
12
#
include
<
userver
/
dynamic_config
/
snapshot
.
hpp
>
13
#
include
<
userver
/
utils
/
assert
.
hpp
>
14
15
USERVER_NAMESPACE_BEGIN
16
17
namespace
dynamic_config {
18
19
/// Owns a snapshot of a config variable. You may use operator* or operator->
20
/// to access the config variable.
21
template
<
typename
VariableType>
22
class
VariableSnapshotPtr
final
{
23
public
:
24
VariableSnapshotPtr(VariableSnapshotPtr&&) =
delete
;
25
VariableSnapshotPtr& operator=(VariableSnapshotPtr&&) =
delete
;
26
27
const
VariableType& operator*()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
*variable_; }
28
const
VariableType& operator*() && { ReportMisuse(); }
29
30
const
VariableType* operator->()
const
& USERVER_IMPL_LIFETIME_BOUND {
return
variable_; }
31
const
VariableType* operator->() && { ReportMisuse(); }
32
33
private
:
34
[[noreturn]]
static
void
ReportMisuse() {
35
static_assert
(!
sizeof
(VariableType),
"keep the pointer before using, please"
);
36
}
37
38
explicit
VariableSnapshotPtr(Snapshot&& snapshot,
const
Key
<VariableType>& key)
39
: snapshot_(std::move(snapshot)),
40
variable_(&snapshot_[key])
41
{}
42
43
// for the constructor
44
friend
class
Source;
45
46
Snapshot snapshot_;
47
const
VariableType* variable_;
48
};
49
50
/// @brief Helper class for subscribing to dynamic-config updates with a custom
51
/// callback.
52
///
53
/// Stores information about the last update that occurred.
54
///
55
/// @param previous `dynamic_config::Snapshot` of the previous config or
56
/// `std::nullopt` if this update event is the first for the subscriber.
57
struct
Diff
final
{
58
std::optional<Snapshot> previous;
59
Snapshot current;
60
61
template
<
typename
... Keys>
62
bool
HasConfigsChanged(
const
Keys&... keys)
const
{
63
if
(!previous) {
64
return
true
;
65
}
66
67
UASSERT
(!current.GetData().IsEmpty());
68
UASSERT
(!previous->GetData().IsEmpty());
69
70
const
bool
is_equal = (
true
&& ... && ((*previous)[keys] == current[keys]));
71
return
!is_equal;
72
}
73
};
74
75
/// @ingroup userver_clients
76
///
77
/// @brief A client for easy dynamic config fetching in components.
78
///
79
/// After construction, dynamic_config::Source
80
/// can be copied around and passed to clients or child helper classes.
81
///
82
/// Usually retrieved from components::DynamicConfig component.
83
///
84
/// Typical usage:
85
/// @snippet components/component_sample_test.cpp Sample user component runtime config source
86
class
Source
final
{
87
public
:
88
using
SnapshotEventSource =
concurrent
::
AsyncEventSource
<
const
Snapshot&>;
89
using
DiffEventSource =
concurrent
::
AsyncEventSource
<
const
Diff&>;
90
91
/// For internal use only. Obtain using components::DynamicConfig or
92
/// dynamic_config::StorageMock instead.
93
explicit
Source
(impl::StorageData& storage);
94
95
// trivially copyable
96
Source(
const
Source&) =
default
;
97
Source(Source&&) =
default
;
98
Source& operator=(
const
Source&) =
default
;
99
Source& operator=(Source&&) =
default
;
100
101
Snapshot GetSnapshot()
const
;
102
103
template
<
typename
VariableType>
104
VariableSnapshotPtr<VariableType> GetSnapshot(
const
Key
<VariableType>& key)
const
{
105
return
VariableSnapshotPtr{GetSnapshot(), key};
106
}
107
108
template
<
typename
VariableType>
109
VariableType GetCopy(
const
Key
<VariableType>& key)
const
{
110
const
auto
snapshot = GetSnapshot();
111
return
snapshot[key];
112
}
113
114
/// Subscribes to dynamic-config updates using a member function. Also
115
/// immediately invokes the function with the current config snapshot (this
116
/// invocation will be executed synchronously).
117
///
118
/// @note Callbacks occur in full accordance with
119
/// `components::DynamicConfigClientUpdater` options.
120
///
121
/// @param obj the subscriber, which is the owner of the listener method, and
122
/// is also used as the unique identifier of the subscription
123
/// @param name the name of the subscriber, for diagnostic purposes
124
/// @param func the listener method, named `OnConfigUpdate` by convention.
125
/// @returns a `concurrent::AsyncEventSubscriberScope` controlling the
126
/// subscription, which should be stored as a member in the subscriber;
127
/// `Unsubscribe` should be called explicitly
128
///
129
/// @see based on concurrent::AsyncEventSource engine
130
template
<
typename
Class>
131
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
132
Class* obj,
133
std::string_view name,
134
void
(Class::*func)(
const
dynamic_config::Snapshot& config)
135
) {
136
return
DoUpdateAndListen(
137
concurrent
::FunctionId(obj),
138
name,
139
[obj, func](
const
dynamic_config::Snapshot& config) { (obj->*func)(config); }
140
);
141
}
142
143
/// @brief Subscribes to dynamic-config updates with information about the
144
/// current and previous states.
145
///
146
/// Subscribes to dynamic-config updates using a member function, named
147
/// `OnConfigUpdate` by convention. Also constructs `dynamic_config::Diff`
148
/// object using `std::nullopt` and current config snapshot, then immediately
149
/// invokes the function with it (this invocation will be executed
150
/// synchronously).
151
///
152
/// @note Callbacks occur in full accordance with
153
/// `components::DynamicConfigClientUpdater` options.
154
///
155
/// @warning In debug mode the last notification for any subscriber will be
156
/// called with `std::nullopt` and current config snapshot.
157
///
158
/// Example usage:
159
/// @snippet dynamic_config/config_test.cpp Custom subscription for dynamic config update
160
///
161
/// @param obj the subscriber, which is the owner of the listener method, and
162
/// is also used as the unique identifier of the subscription
163
/// @param name the name of the subscriber, for diagnostic purposes
164
/// @param func the listener method, named `OnConfigUpdate` by convention.
165
/// @returns a `concurrent::AsyncEventSubscriberScope` controlling the
166
/// subscription, which should be stored as a member in the subscriber;
167
/// `Unsubscribe` should be called explicitly
168
///
169
/// @see based on concurrent::AsyncEventSource engine
170
///
171
/// @see dynamic_config::Diff
172
template
<
typename
Class>
173
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
174
Class* obj,
175
std::string_view name,
176
void
(Class::*func)(
const
dynamic_config::Diff& diff)
177
) {
178
return
DoUpdateAndListen(
concurrent
::FunctionId(obj), name, [obj, func](
const
dynamic_config::Diff& diff) {
179
(obj->*func)(diff);
180
});
181
}
182
183
/// @brief Subscribes to updates of a subset of all configs.
184
///
185
/// Subscribes to dynamic-config updates using a member function, named
186
/// `OnConfigUpdate` by convention. The function will be invoked if at least
187
/// one of the configs has been changed since the previous invocation. So at
188
/// the first time immediately invokes the function with the current config
189
/// snapshot (this invocation will be executed synchronously).
190
///
191
/// @note Callbacks occur only if one of the passed config is changed. This is
192
/// true under any components::DynamicConfigClientUpdater options.
193
///
194
/// @warning To use this function, configs must have the `operator==`.
195
///
196
/// @param obj the subscriber, which is the owner of the listener method, and
197
/// is also used as the unique identifier of the subscription
198
/// @param name the name of the subscriber, for diagnostic purposes
199
/// @param func the listener method, named `OnConfigUpdate` by convention.
200
/// @param keys config objects, specializations of `dynamic_config::Key`.
201
/// @returns a `concurrent::AsyncEventSubscriberScope` controlling the
202
/// subscription, which should be stored as a member in the subscriber;
203
/// `Unsubscribe` should be called explicitly
204
///
205
/// @see based on concurrent::AsyncEventSource engine
206
template
<
typename
Class,
typename
... Keys>
207
concurrent
::AsyncEventSubscriberScope
UpdateAndListen
(
208
Class* obj,
209
std::string_view name,
210
void
(Class::*func)(
const
dynamic_config::Snapshot& config),
211
const
Keys&... keys
212
) {
213
auto
wrapper = [obj, func, &keys...](
const
Diff& diff) {
214
if
(!diff.HasConfigsChanged(keys...)) {
215
return
;
216
}
217
(obj->*func)(diff.current);
218
};
219
return
DoUpdateAndListen(
concurrent
::FunctionId(obj), name, std::move(wrapper));
220
}
221
222
SnapshotEventSource& GetEventChannel();
223
224
private
:
225
concurrent
::AsyncEventSubscriberScope DoUpdateAndListen(
226
concurrent
::FunctionId id,
227
std::string_view name,
228
SnapshotEventSource::Function&& func
229
);
230
231
concurrent
::AsyncEventSubscriberScope DoUpdateAndListen(
232
concurrent
::FunctionId id,
233
std::string_view name,
234
DiffEventSource::Function&& func
235
);
236
237
impl::StorageData* storage_;
238
};
239
240
}
// namespace dynamic_config
241
242
USERVER_NAMESPACE_END
userver
dynamic_config
source.hpp
Generated on
for userver by
Doxygen
1.17.0