| 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/private/qtgrpclogging_p.h> |
| 6 | #include <QtGrpc/qgrpccalloptions.h> |
| 7 | |
| 8 | #include <QtCore/qbytearray.h> |
| 9 | #include <QtCore/qdebug.h> |
| 10 | #include <QtCore/qvariant.h> |
| 11 | |
| 12 | QT_BEGIN_NAMESPACE |
| 13 | |
| 14 | using namespace Qt::StringLiterals; |
| 15 | |
| 16 | /*! |
| 17 | \class QGrpcCallOptions |
| 18 | \inmodule QtGrpc |
| 19 | \brief The QGrpcCallOptions class offers various options for fine-tuning |
| 20 | individual RPCs. |
| 21 | \since 6.6 |
| 22 | |
| 23 | QGrpcCallOptions lets you customize individual remote procedure calls (RPCs). |
| 24 | The generated client interface provides access points to pass the QGrpcCallOptions. |
| 25 | These options supersede the ones set via QGrpcChannelOptions. |
| 26 | |
| 27 | To configure the default options shared by RPCs, use QGrpcChannelOptions. |
| 28 | |
| 29 | \code |
| 30 | QGrpcCallOptions callOpts; |
| 31 | // Set the metadata for an individial RPC |
| 32 | callOpts.setMetadata({ |
| 33 | { "header" , "value1" }, |
| 34 | { "header" , "value2" }, |
| 35 | }); |
| 36 | const auto &md = callOpts.metadata(QtGrpc::MultiValue); |
| 37 | qDebug() << "Call Metadata: " << md; |
| 38 | |
| 39 | // Set a 2-second deadline for an individial RPC |
| 40 | callOpts.setDeadlineTimeout(2s); |
| 41 | qDebug() << "Call timeout: " << callOpts.deadlineTimeout(); |
| 42 | \endcode |
| 43 | */ |
| 44 | |
| 45 | class QGrpcCallOptionsPrivate : public QGrpcCommonOptions |
| 46 | { |
| 47 | public: |
| 48 | QGrpcCallOptionsPrivate() = default; |
| 49 | }; |
| 50 | |
| 51 | QT_DEFINE_QESDP_SPECIALIZATION_DTOR(QGrpcCallOptionsPrivate) |
| 52 | |
| 53 | /*! |
| 54 | Default-constructs an empty QGrpcCallOptions. |
| 55 | */ |
| 56 | QGrpcCallOptions::QGrpcCallOptions() : d_ptr(new QGrpcCallOptionsPrivate()) |
| 57 | { |
| 58 | } |
| 59 | |
| 60 | /*! |
| 61 | Destroys the QGrpcCallOptions. |
| 62 | */ |
| 63 | QGrpcCallOptions::~QGrpcCallOptions() = default; |
| 64 | |
| 65 | /*! |
| 66 | Copy-constructs a QGrpcCallOptions from \a other. |
| 67 | */ |
| 68 | QGrpcCallOptions::QGrpcCallOptions(const QGrpcCallOptions &other) = default; |
| 69 | |
| 70 | /*! |
| 71 | Assigns \a other to this QGrpcCallOptions and returns a reference to the |
| 72 | updated object. |
| 73 | */ |
| 74 | QGrpcCallOptions &QGrpcCallOptions::operator=(const QGrpcCallOptions &other) = default; |
| 75 | |
| 76 | /*! |
| 77 | \fn QGrpcCallOptions::QGrpcCallOptions(QGrpcCallOptions &&other) |
| 78 | |
| 79 | Move-constructs a new QGrpcCallOptions from \a other. |
| 80 | |
| 81 | \include qtgrpc-shared.qdocinc move-note-desc |
| 82 | */ |
| 83 | |
| 84 | /*! |
| 85 | \fn QGrpcCallOptions &QGrpcCallOptions::operator=(QGrpcCallOptions &&other) |
| 86 | |
| 87 | Move-assigns \a other to this QGrpcCallOptions and returns a reference to |
| 88 | the updated object. |
| 89 | |
| 90 | \include qtgrpc-shared.qdocinc move-note-desc |
| 91 | */ |
| 92 | |
| 93 | /*! |
| 94 | \since 6.8 |
| 95 | |
| 96 | \include qtgrpc-shared.qdocinc qvariant-desc |
| 97 | */ |
| 98 | QGrpcCallOptions::operator QVariant() const |
| 99 | { |
| 100 | return QVariant::fromValue(value: *this); |
| 101 | } |
| 102 | |
| 103 | /*! |
| 104 | \since 6.8 |
| 105 | \fn void QGrpcCallOptions::swap(QGrpcCallOptions &other) |
| 106 | |
| 107 | \include qtgrpc-shared.qdocinc swap-desc |
| 108 | */ |
| 109 | |
| 110 | /*! |
| 111 | \include qgrpccommonoptions.cpp set-deadline-timeout |
| 112 | |
| 113 | \note Setting this field \b{overrides} the corresponding channel options field |
| 114 | — see \l{QGrpcChannelOptions::setDeadlineTimeout()} |
| 115 | |
| 116 | \sa deadlineTimeout() |
| 117 | */ |
| 118 | QGrpcCallOptions &QGrpcCallOptions::setDeadlineTimeout(std::chrono::milliseconds timeout) |
| 119 | { |
| 120 | if (d_ptr->deadlineTimeout() == timeout) |
| 121 | return *this; |
| 122 | d_ptr.detach(); |
| 123 | Q_D(QGrpcCallOptions); |
| 124 | d->setDeadlineTimeout(timeout); |
| 125 | return *this; |
| 126 | } |
| 127 | |
| 128 | /*! |
| 129 | \include qgrpccommonoptions.cpp deadline-timeout |
| 130 | */ |
| 131 | std::optional<std::chrono::milliseconds> QGrpcCallOptions::deadlineTimeout() const noexcept |
| 132 | { |
| 133 | Q_D(const QGrpcCallOptions); |
| 134 | return d->deadlineTimeout(); |
| 135 | } |
| 136 | |
| 137 | #if QT_DEPRECATED_SINCE(6, 13) |
| 138 | |
| 139 | /*! |
| 140 | \fn const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const & |
| 141 | \fn QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() && |
| 142 | \deprecated [6.13] Use the QMultiHash overload instead. |
| 143 | |
| 144 | \include qgrpccommonoptions.cpp metadata |
| 145 | |
| 146 | \sa setMetadata() |
| 147 | */ |
| 148 | const QHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata() const & noexcept |
| 149 | { |
| 150 | Q_D(const QGrpcCallOptions); |
| 151 | return d->metadata(); |
| 152 | } |
| 153 | QHash<QByteArray, QByteArray> QGrpcCallOptions::metadata() && |
| 154 | { |
| 155 | Q_D(QGrpcCallOptions); |
| 156 | if (d->ref.loadRelaxed() != 1) |
| 157 | return d->metadata(); |
| 158 | return std::move(*d_ptr).metadata(); |
| 159 | } |
| 160 | |
| 161 | /*! |
| 162 | \fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata) |
| 163 | \fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata) |
| 164 | \deprecated [6.13] Use the QMultiHash overload instead. |
| 165 | |
| 166 | \include qgrpccommonoptions.cpp set-metadata |
| 167 | |
| 168 | //! [merge-md-note] |
| 169 | \note Call metadata is \b{merged} with any channel-level metadata when the |
| 170 | RPC starts — see |
| 171 | //! [merge-md-note] |
| 172 | \l{QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, |
| 173 | QByteArray>&)}{QGrpcChannelOptions::setMetadata(QMultiHash)}. |
| 174 | |
| 175 | \sa metadata() |
| 176 | */ |
| 177 | QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QHash<QByteArray, QByteArray> &metadata) |
| 178 | { |
| 179 | if (d_ptr->metadata() == metadata) |
| 180 | return *this; |
| 181 | d_ptr.detach(); |
| 182 | Q_D(QGrpcCallOptions); |
| 183 | d->setMetadata(metadata); |
| 184 | return *this; |
| 185 | } |
| 186 | QGrpcCallOptions &QGrpcCallOptions::setMetadata(QHash<QByteArray, QByteArray> &&metadata) |
| 187 | { |
| 188 | if (d_ptr->metadata() == metadata) |
| 189 | return *this; |
| 190 | d_ptr.detach(); |
| 191 | Q_D(QGrpcCallOptions); |
| 192 | d->setMetadata(std::move(metadata)); |
| 193 | return *this; |
| 194 | } |
| 195 | |
| 196 | #endif // QT_DEPRECATED_SINCE(6, 13) |
| 197 | |
| 198 | /*! |
| 199 | \since 6.10 |
| 200 | \fn const QMultiHash<QByteArray, QByteArray> &QGrpcCallOptions::metadata(QtGrpc::MultiValue_t) const & |
| 201 | \fn QMultiHash<QByteArray, QByteArray> QGrpcCallOptions::metadata(QtGrpc::MultiValue_t) && |
| 202 | |
| 203 | \include qgrpccommonoptions.cpp metadata-multi |
| 204 | |
| 205 | \sa {setMetadata(const QMultiHash<QByteArray, QByteArray>&)}{setMetadata} |
| 206 | */ |
| 207 | const QMultiHash<QByteArray, QByteArray> & |
| 208 | QGrpcCallOptions::metadata(QtGrpc::MultiValue_t tag) const & noexcept |
| 209 | { |
| 210 | Q_D(const QGrpcCallOptions); |
| 211 | return d->metadata(tag); |
| 212 | } |
| 213 | QMultiHash<QByteArray, QByteArray> QGrpcCallOptions::metadata(QtGrpc::MultiValue_t tag) && |
| 214 | { |
| 215 | Q_D(QGrpcCallOptions); |
| 216 | if (d->ref.loadRelaxed() != 1) |
| 217 | return d->metadata(tag); |
| 218 | return std::move(*d_ptr).metadata(tag); |
| 219 | } |
| 220 | |
| 221 | /*! |
| 222 | \since 6.10 |
| 223 | \fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata) |
| 224 | \fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata) |
| 225 | \fn QGrpcCallOptions &QGrpcCallOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> metadata) |
| 226 | |
| 227 | \include qgrpccommonoptions.cpp set-metadata-multi |
| 228 | |
| 229 | \include qgrpccalloptions.cpp merge-md-note |
| 230 | \l{QGrpcChannelOptions::setMetadata(const QMultiHash<QByteArray, |
| 231 | QByteArray>&)}{QGrpcChannelOptions::setMetadata(QMultiHash)}. |
| 232 | |
| 233 | \sa metadata(QtGrpc::MultiValue_t) |
| 234 | */ |
| 235 | QGrpcCallOptions &QGrpcCallOptions::setMetadata(const QMultiHash<QByteArray, QByteArray> &metadata) |
| 236 | { |
| 237 | if (d_ptr->metadata(QtGrpc::MultiValue) == metadata) |
| 238 | return *this; |
| 239 | d_ptr.detach(); |
| 240 | Q_D(QGrpcCallOptions); |
| 241 | d->setMetadata(metadata); |
| 242 | return *this; |
| 243 | } |
| 244 | QGrpcCallOptions &QGrpcCallOptions::setMetadata(QMultiHash<QByteArray, QByteArray> &&metadata) |
| 245 | { |
| 246 | if (d_ptr->metadata(QtGrpc::MultiValue) == metadata) |
| 247 | return *this; |
| 248 | d_ptr.detach(); |
| 249 | Q_D(QGrpcCallOptions); |
| 250 | d->setMetadata(std::move(metadata)); |
| 251 | return *this; |
| 252 | } |
| 253 | QGrpcCallOptions & |
| 254 | QGrpcCallOptions::setMetadata(std::initializer_list<std::pair<QByteArray, QByteArray>> list) |
| 255 | { |
| 256 | return setMetadata(QMultiHash<QByteArray, QByteArray>(list)); |
| 257 | } |
| 258 | |
| 259 | /*! |
| 260 | \include qgrpccommonoptions.cpp add-metadata |
| 261 | |
| 262 | \include qgrpccalloptions.cpp merge-md-note |
| 263 | \l{QGrpcChannelOptions::addMetadata()} |
| 264 | */ |
| 265 | QGrpcCallOptions &QGrpcCallOptions::addMetadata(QByteArrayView key, QByteArrayView value) |
| 266 | { |
| 267 | if (d_ptr->containsMetadata(key, value)) |
| 268 | return *this; |
| 269 | d_ptr.detach(); |
| 270 | Q_D(QGrpcCallOptions); |
| 271 | d->addMetadata(key: key.toByteArray(), value: value.toByteArray()); |
| 272 | return *this; |
| 273 | } |
| 274 | |
| 275 | /*! |
| 276 | \include qgrpccommonoptions.cpp filterServerMetadata |
| 277 | \sa QGrpcChannelOptions::filterServerMetadata() |
| 278 | */ |
| 279 | std::optional<bool> QGrpcCallOptions::filterServerMetadata() const noexcept |
| 280 | { |
| 281 | Q_D(const QGrpcCallOptions); |
| 282 | return d->filterServerMetadata(); |
| 283 | } |
| 284 | |
| 285 | /*! |
| 286 | \include qgrpccommonoptions.cpp setFilterServerMetadata |
| 287 | \note Setting this field \b{overrides} the corresponding channel options |
| 288 | field — see \l{QGrpcChannelOptions::setFilterServerMetadata()} |
| 289 | |
| 290 | \sa QGrpcChannelOptions::setFilterServerMetadata() |
| 291 | */ |
| 292 | QGrpcCallOptions &QGrpcCallOptions::setFilterServerMetadata(bool value) |
| 293 | { |
| 294 | if (d_ptr->filterServerMetadata() == value) |
| 295 | return *this; |
| 296 | d_ptr.detach(); |
| 297 | Q_D(QGrpcCallOptions); |
| 298 | d->setFilterServerMetadata(value); |
| 299 | return *this; |
| 300 | } |
| 301 | |
| 302 | #ifndef QT_NO_DEBUG_STREAM |
| 303 | /*! |
| 304 | \since 6.8 |
| 305 | \fn QDebug QGrpcCallOptions::operator<<(QDebug debug, const QGrpcCallOptions &callOpts) |
| 306 | |
| 307 | Writes \a callOpts to the specified stream \a debug. |
| 308 | */ |
| 309 | QDebug operator<<(QDebug debug, const QGrpcCallOptions &callOpts) |
| 310 | { |
| 311 | const QDebugStateSaver save(debug); |
| 312 | debug.nospace().noquote(); |
| 313 | debug << "QGrpcCallOptions(deadline: " << callOpts.deadlineTimeout() |
| 314 | << ", metadata: " << callOpts.metadata(tag: QtGrpc::MultiValue) << ')'; |
| 315 | return debug; |
| 316 | } |
| 317 | #endif |
| 318 | |
| 319 | QT_END_NAMESPACE |
| 320 | |