1// Copyright (C) 2023 The Qt Company Ltd.
2// SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only
3
4#include <QtGrpc/private/qgrpccommonoptions_p.h>
5#include <QtGrpc/qgrpcchanneloptions.h>
6#include <QtGrpc/qgrpcserializationformat.h>
7#include <QtGrpc/qtgrpcnamespace.h>
8
9#include <QtCore/qbytearray.h>
10#include <QtCore/qdebug.h>
11#include <QtCore/qvariant.h>
12
13QT_BEGIN_NAMESPACE
14
15using namespace Qt::StringLiterals;
16using namespace QtGrpc;
17
18/*!
19 \class QGrpcChannelOptions
20 \inmodule QtGrpc
21 \since 6.6
22 \brief The QGrpcChannelOptions class offers various options for fine-tuning
23 a gRPC channel.
24
25 QGrpcChannelOptions lets you customize a \gRPC channel. Some options apply
26 to all remote procedure calls (RPCs) that operate on the associated
27 channel, which is used to communicate with services.
28
29 Override options for specific RPCs with QGrpcCallOptions.
30
31 \code
32 QGrpcChannelOptions channelOpts;
33 // Apply common metadata to every RPC
34 channelOpts.setMetadata({
35 { "header" , "value1" },
36 { "header" , "value2" },
37 });
38 const auto &md = channelOpts.metadata(QtGrpc::MultiValue);
39 qDebug() << "Channel Metadata: " << md;
40
41 // Apply a 2-second deadline to every RPC
42 channelOpts.setDeadlineTimeout(2s);
43 qDebug() << "Channel timeout: " << channelOpts.deadlineTimeout();
44
45 // Configure SSL/TLS configuration
46 channelOpts.setSslConfiguration(QSslConfiguration());
47 \endcode
48
49
50 \note It is up to the channel's implementation to determine the specifics
51 of these options.
52*/
53
54class QGrpcChannelOptionsPrivate : public QGrpcCommonOptions
55{
56public:
57 QGrpcSerializationFormat serializationFormat;
58#if QT_CONFIG(ssl)
59 std::optional<QSslConfiguration> sslConfiguration;
60#endif
61};
62
63QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QGrpcChannelOptionsPrivate)
64
65/*!
66 Default-constructs an empty QGrpcChannelOptions.
67*/
68QGrpcChannelOptions::QGrpcChannelOptions() : d_ptr(new QGrpcChannelOptionsPrivate())
69{
70}
71
72/*!
73 Copy-constructs a QGrpcChannelOptions from \a other.
74*/
75QGrpcChannelOptions::QGrpcChannelOptions(const QGrpcChannelOptions &other) = default;
76
77/*!
78 Assigns \a other to this QGrpcChannelOptions and returns a reference to the
79 updated object.
80*/
81QGrpcChannelOptions &QGrpcChannelOptions::operator=(const QGrpcChannelOptions &other) = default;
82
83/*!
84 \fn QGrpcChannelOptions::QGrpcChannelOptions(QGrpcChannelOptions &&other)
85
86 Move-constructs a new QGrpcChannelOptions from \a other.
87
88 \include qtgrpc-shared.qdocinc move-note-desc
89*/
90
91/*!
92 \fn QGrpcChannelOptions &QGrpcChannelOptions::operator=(QGrpcChannelOptions &&other)
93
94 Move-assigns \a other to this QGrpcChannelOptions and returns a reference
95 to the updated object.
96
97 \include qtgrpc-shared.qdocinc move-note-desc
98*/
99
100/*!
101 \since 6.8
102 \fn void QGrpcChannelOptions::swap(QGrpcChannelOptions &other)
103
104 \include qtgrpc-shared.qdocinc swap-desc
105*/
106
107/*!
108 Destroys the QGrpcChannelOptions.
109*/
110QGrpcChannelOptions::~QGrpcChannelOptions() = default;
111
112/*!
113 \since 6.8
114 \include qtgrpc-shared.qdocinc qvariant-desc
115*/
116QGrpcChannelOptions::operator QVariant() const
117{
118 return QVariant::fromValue(value: *this);
119}
120
121/*!
122 \include qgrpccommonoptions.cpp set-deadline-timeout
123
124//! [channel-note]
125 \note Setting this field applies to all RPCs that operate on the channel,
126 except those overriden by
127//! [channel-note]
128 \l{QGrpcCallOptions::setDeadlineTimeout()}
129
130 \sa deadlineTimeout()
131*/
132QGrpcChannelOptions &QGrpcChannelOptions::setDeadlineTimeout(std::chrono::milliseconds timeout)
133{
134 if (d_ptr->deadlineTimeout() == timeout)
135 return *this;
136 d_ptr.detach();
137 Q_D(QGrpcChannelOptions);
138 d->setDeadlineTimeout(timeout);
139 return *this;
140}
141
142#if QT_DEPRECATED_SINCE(6, 13)
143
144/*!
145 \fn const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const &
146 \fn QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
147 \deprecated [6.13] Use \l{metadata(QtGrpc::MultiValue_t)}{metadata(QtGrpc::MultiValue)} instead.
148
149 \include qgrpccommonoptions.cpp metadata
150
151 \sa metadata(QtGrpc::MultiValue_t), setMetadata()
152*/
153const QHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata() const & noexcept
154{
155 Q_D(const QGrpcChannelOptions);
156 return d->metadata();
157}
158QHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata() &&
159{
160 Q_D(QGrpcChannelOptions);
161 if (d->ref.loadRelaxed() != 1) // return copy if shared
162 return d->metadata();
163 return std::move(*d_ptr).metadata();
164}
165
166/*!
167 \fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
168 \fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
169 \deprecated [6.13] Use the QMultiHash overload instead.
170
171 \include qgrpccommonoptions.cpp set-metadata
172
173//! [merge-md-note]
174 \note This metadata is included in every RPC made through the channel.
175 Channel metadata is \b{merged} with any call-specific metadata when the RPC
176 starts — see
177//! [merge-md-note]
178 \l{QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray,
179 QByteArray>&)}{QGrpcCallOptions::setMetadata(QMultiHash)}
180
181 \sa metadata()
182*/
183QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata)
184{
185 if (d_ptr->metadata() == metadata)
186 return *this;
187 d_ptr.detach();
188 Q_D(QGrpcChannelOptions);
189 d->setMetadata(metadata);
190 return *this;
191}
192QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata)
193{
194 if (d_ptr->metadata() == metadata)
195 return *this;
196 d_ptr.detach();
197 Q_D(QGrpcChannelOptions);
198 d->setMetadata(std::move(metadata));
199 return *this;
200}
201
202#endif // QT_DEPRECATED_SINCE(6, 13)
203
204/*!
205 \since 6.10
206 \fn const QMultiHash<QByteArray, QByteArray> &QGrpcChannelOptions::metadata(QtGrpc::MultiValue_t) const &
207 \fn QMultiHash<QByteArray, QByteArray> QGrpcChannelOptions::metadata(QtGrpc::MultiValue_t) &&
208
209 \include qgrpccommonoptions.cpp metadata-multi
210
211 \sa {setMetadata(const QMultiHash<QByteArray, QByteArray>&)}{setMetadata}
212*/
213const QMultiHash<QByteArray, QByteArray> &
214QGrpcChannelOptions::metadata(QtGrpc::MultiValue_t tag) const & noexcept
215{
216 Q_D(const QGrpcChannelOptions);
217 return d->metadata(tag);
218}
219
220QMultiHash<QByteArray, QByteArray>
221QGrpcChannelOptions::metadata(QtGrpc::MultiValue_t tag) &&
222{
223 Q_D(QGrpcChannelOptions);
224 if (d->ref.loadRelaxed() != 1)
225 return d->metadata(tag);
226 return std::move(*d_ptr).metadata(tag);
227}
228
229/*!
230 \since 6.10
231 \fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
232 \fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
233 \fn QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list)
234
235 \include qgrpccommonoptions.cpp set-metadata-multi
236
237 \include qgrpcchanneloptions.cpp merge-md-note
238 \l{QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray,
239 QByteArray>&)}{QGrpcCallOptions::setMetadata(QMultiHash)}
240
241 \sa metadata(QtGrpc::MultiValue_t)
242*/
243QGrpcChannelOptions &
244QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata)
245{
246 if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
247 return *this;
248 d_ptr.detach();
249 Q_D(QGrpcChannelOptions);
250 d->setMetadata(metadata);
251 return *this;
252}
253QGrpcChannelOptions &QGrpcChannelOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
254{
255 if (d_ptr->metadata(QtGrpc::MultiValue) == metadata)
256 return *this;
257 d_ptr.detach();
258 Q_D(QGrpcChannelOptions);
259 d->setMetadata(std::move(metadata));
260 return *this;
261}
262QGrpcChannelOptions &
263QGrpcChannelOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list)
264{
265 return setMetadata(QMultiHash<QByteArray, QByteArray>(list));
266}
267
268/*!
269 \include qgrpccommonoptions.cpp add-metadata
270
271 \include qgrpcchanneloptions.cpp merge-md-note
272 \l{QGrpcCallOptions::addMetadata()}
273*/
274QGrpcChannelOptions &QGrpcChannelOptions::addMetadata(QByteArrayView key, QByteArrayView value)
275{
276 if (d_ptr->containsMetadata(key, value))
277 return *this;
278 d_ptr.detach();
279 Q_D(QGrpcChannelOptions);
280 d->addMetadata(key: key.toByteArray(), value: value.toByteArray());
281 return *this;
282}
283
284/*!
285 \include qgrpccommonoptions.cpp filterServerMetadata
286 \sa QGrpcCallOptions::filterServerMetadata()
287*/
288std::optional<bool> QGrpcChannelOptions::filterServerMetadata() const noexcept
289{
290 Q_D(const QGrpcChannelOptions);
291 return d->filterServerMetadata();
292}
293
294/*!
295 \include qgrpccommonoptions.cpp setFilterServerMetadata
296
297 \include qgrpcchanneloptions.cpp channel-note
298 \l{QGrpcCallOptions::filterServerMetadata}
299
300 \sa QGrpcCallOptions::setFilterServerMetadata()
301*/
302QGrpcChannelOptions &QGrpcChannelOptions::setFilterServerMetadata(bool value)
303{
304 if (filterServerMetadata() == value)
305 return *this;
306 d_ptr.detach();
307 Q_D(QGrpcChannelOptions);
308 d->setFilterServerMetadata(value);
309 return *this;
310}
311
312/*!
313 \since 6.8
314
315 Sets the serialization \a format for the channel and returns a reference to
316 the updated object.
317*/
318QGrpcChannelOptions &
319QGrpcChannelOptions::setSerializationFormat(const QGrpcSerializationFormat &format)
320{
321 if (d_ptr->serializationFormat == format)
322 return *this;
323 d_ptr.detach();
324 Q_D(QGrpcChannelOptions);
325 d->serializationFormat = format;
326 return *this;
327}
328
329/*!
330 Returns the timeout duration that is used to calculate the deadline for the
331 channel.
332
333 If this field is unset, returns an empty \c {std::optional}.
334*/
335std::optional<std::chrono::milliseconds> QGrpcChannelOptions::deadlineTimeout() const noexcept
336{
337 Q_D(const QGrpcChannelOptions);
338 return d->deadlineTimeout();
339}
340
341/*!
342 \since 6.8
343
344 Returns the serialization format used by the channel.
345
346 If this field is unset, returns a \l {QtGrpc::SerializationFormat::}
347 {Default} constructed serialization format.
348 */
349QGrpcSerializationFormat QGrpcChannelOptions::serializationFormat() const
350{
351 Q_D(const QGrpcChannelOptions);
352 return d->serializationFormat;
353}
354
355#if QT_CONFIG(ssl)
356/*!
357 Sets the \a sslConfiguration for the channel and returns a reference to the
358 updated object.
359*/
360QGrpcChannelOptions &
361QGrpcChannelOptions::setSslConfiguration(const QSslConfiguration &sslConfiguration)
362{
363 if (d_ptr->sslConfiguration == sslConfiguration)
364 return *this;
365 d_ptr.detach();
366 Q_D(QGrpcChannelOptions);
367 d->sslConfiguration = sslConfiguration;
368 return *this;
369}
370
371/*!
372 Returns the SSL configuration for the channel.
373
374 If this field is unset, returns an empty \c {std::optional}.
375*/
376std::optional<QSslConfiguration> QGrpcChannelOptions::sslConfiguration() const
377{
378 Q_D(const QGrpcChannelOptions);
379 return d->sslConfiguration;
380}
381#endif
382
383#ifndef QT_NO_DEBUG_STREAM
384/*!
385 \since 6.8
386 \fn QDebug QGrpcChannelOptions::operator<<(QDebug debug, const QGrpcChannelOptions &chOpts)
387
388 Writes \a chOpts to the specified stream \a debug.
389*/
390QDebug operator<<(QDebug debug, const QGrpcChannelOptions &chOpts)
391{
392 const QDebugStateSaver save(debug);
393 debug.nospace().noquote();
394 debug << "QGrpcChannelOptions(deadline: " << chOpts.deadlineTimeout()
395 << ", metadata: " << chOpts.metadata(tag: QtGrpc::MultiValue)
396 << ", serializationFormat: " << chOpts.serializationFormat().suffix()
397 << ", sslConfiguration: ";
398# if QT_CONFIG(ssl)
399 if (chOpts.sslConfiguration())
400 debug << "available";
401 else
402 debug << std::nullopt;
403# else
404 debug << "unsupported";
405# endif
406 debug << ')';
407 return debug;
408}
409#endif
410
411QT_END_NAMESPACE
412

source code of qtgrpc/src/grpc/qgrpcchanneloptions.cpp