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/qgrpcoperationcontext_p.h>
6#include <QtGrpc/qgrpcoperationcontext.h>
7#include <QtGrpc/qgrpcstatus.h>
8
9#include <QtProtobuf/qprotobufserializer.h>
10
11#include <QtCore/private/qobject_p.h>
12#include <QtCore/qbytearray.h>
13#include <QtCore/qbytearrayview.h>
14#include <QtCore/qlatin1stringview.h>
15
16#include <utility>
17
18QT_BEGIN_NAMESPACE
19
20/*!
21 \class QGrpcOperationContext
22 \inmodule QtGrpc
23 \since 6.7
24 \brief The QGrpcOperationContext class provides context for communication
25 between an individual \gRPC operation and a channel.
26
27 QGrpcOperationContext is constructed internally when a remote procedure call
28 (RPC) is requested, mediating interaction between the client's operation
29 request and the channel's operation outcome.
30
31 RPCs requested on the client interface return specializations of
32 QGrpcOperation, such as QGrpcCallReply, QGrpcServerStream,
33 QGrpcClientStream, or QGrpcBidiStream. These classes are implicitly
34 integrated with the underlying QGrpcOperationContext counterpart.
35
36 \note Don't use this class directly unless implementing a custom channel.
37
38 The signals contained within this class are used to build the communication
39 between the client-facing QGrpcOperation and the QAbstractGrpcChannel
40 implementation. These operations are asynchronous in nature, and multiple
41 RPCs can operate on the same channel concurrently. Channels typically treat
42 all operations the same, and it is the channel's responsibility to
43 correctly support and restrict the subset of features its RPC type
44 supports.
45
46 Signals which should only be emitted by the channel's implementation are:
47 \list
48 \li finished()
49 \li messageReceived()
50 \endlist
51
52 Signals which will be emitted by QGrpcOperation and its specializations are:
53 \list
54 \li cancelRequested()
55 \li writeMessageRequested()
56 \li writesDoneRequested()
57 \endlist
58
59 Custom implementations of QAbstractGrpcChannel must handle the client's
60 signals, as no default signal handling is provided, and emit their own
61 signals accordingly.
62*/
63
64/*!
65 \fn void QGrpcOperationContext::finished(const QGrpcStatus &status)
66
67 This signal should be emitted by the channel when an RPC finishes.
68
69 It usually means that the server sent a \a status for the requested RPC and
70 closed the connection. Implementations of QAbstractGrpcChannel should
71 detect this situation and emit the signal.
72
73 After receiving this signal, no further communication should occur through
74 this operation context. The client side may then safely delete the
75 corresponding RPC object.
76
77 \note This signal is implicitly connected to the QGrpcOperation counterpart.
78
79 \sa QGrpcOperation::finished
80*/
81
82/*!
83 \fn void QGrpcOperationContext::messageReceived(const QByteArray &data)
84
85 This signal should be emitted by the channel when a new chunk of \a data is
86 received from the server.
87
88 For client streams and unary calls, this means that the single and final
89 response has arrived and communication is about to finish.
90
91 For server and bidirectional streams, this signal should be continuously
92 emitted by the channel upon receiving each new messages.
93
94 \note This signal is implicitly connected to the QGrpcOperation
95 counterpart.
96
97 \sa QGrpcServerStream::messageReceived
98 \sa QGrpcBidiStream::messageReceived
99*/
100
101/*!
102 \fn void QGrpcOperationContext::cancelRequested()
103
104 This signal is emitted by QGrpcOperation when requesting cancellation of the
105 communication.
106
107 The channel is expected to connect its cancellation logic to this signal
108 and attempt to cancel the RPC and finish it with a
109 \l{QtGrpc::StatusCode::}{Cancelled} status code. Successful cancellation
110 cannot be guaranteed. Further processing of the data received from a
111 channel is not required and should be avoided.
112
113 \sa QGrpcOperation::cancel
114*/
115
116/*!
117 \fn void QGrpcOperationContext::writeMessageRequested(const QByteArray &data)
118
119 This signal is emitted by QGrpcClientStream or QGrpcBidiStream when it has
120 serialized \a data ready for a channel to deliver.
121
122 The channel is expected to connect its writing logic to this signal and wrap
123 the serialized data in channel-related headers before writing it to the
124 wire.
125
126 \sa QGrpcClientStream::writeMessage
127 \sa QGrpcBidiStream::writeMessage
128*/
129
130/*!
131 \fn void QGrpcOperationContext::writesDoneRequested()
132
133 This signal is emitted by QGrpcClientStream or QGrpcBidiStream to indicate
134 that it's done writing messages. The channel should respond to this by
135 half-closing the stream.
136
137 \note After receiving this signal no more write operations are permitted
138 for the streaming RPCs. The server can still send messages, which should be
139 forwarded with messageReceived().
140
141 \sa QGrpcClientStream::writesDone
142 \sa QGrpcBidiStream::writesDone
143*/
144
145/*!
146 \internal
147
148 Constructs an operation context with \a method and \a service name. The
149 initial serialized message \a arg is used to start a call with the \a
150 options and the selected \a serializer used for the RPC.
151
152 \note This class can only be constructed by QAbstractGrpcChannel.
153*/
154QGrpcOperationContext::QGrpcOperationContext(QLatin1StringView method, QLatin1StringView service,
155 QByteArrayView arg, const QGrpcCallOptions &options,
156 std::shared_ptr<QAbstractProtobufSerializer>
157 serializer,
158 PrivateConstructor /*unused*/)
159 : QObject(*new QGrpcOperationContextPrivate(method, service, arg, options,
160 std::move(serializer)))
161{
162}
163
164/*!
165 Destroys the operation-context.
166*/
167QGrpcOperationContext::~QGrpcOperationContext() = default;
168
169/*!
170 Returns the method name of the service associated with this
171 operation-context.
172*/
173QLatin1StringView QGrpcOperationContext::method() const noexcept
174{
175 Q_D(const QGrpcOperationContext);
176 return d->method;
177}
178
179/*!
180 Returns the service name associated with this operation-context.
181*/
182QLatin1StringView QGrpcOperationContext::service() const noexcept
183{
184 Q_D(const QGrpcOperationContext);
185 return d->service;
186}
187
188/*!
189 Returns the serialized argument that is utilized by this operation-context.
190*/
191QByteArrayView QGrpcOperationContext::argument() const noexcept
192{
193 Q_D(const QGrpcOperationContext);
194 return d->argument;
195}
196
197/*!
198 Returns the call options that is utilized by this operation-context.
199
200 For channel-wide options, see QGrpcChannelOptions.
201*/
202const QGrpcCallOptions &QGrpcOperationContext::callOptions() const & noexcept
203{
204 Q_D(const QGrpcOperationContext);
205 return d->options;
206}
207
208/*!
209 Returns the serializer of this operation-context
210*/
211std::shared_ptr<const QAbstractProtobufSerializer>
212QGrpcOperationContext::serializer() const
213{
214 Q_D(const QGrpcOperationContext);
215 return d->serializer;
216}
217
218#if QT_DEPRECATED_SINCE(6, 13)
219
220/*!
221 \deprecated [6.13] Use serverInitialMetadata() and serverTrailingMetadata() instead.
222
223 \include qgrpcoperation.cpp serverInitialMetadata
224 \note This method is used implicitly by QGrpcOperation.
225
226 \sa serverInitialMetadata() QGrpcOperation::serverInitialMetadata()
227*/
228const QHash<QByteArray, QByteArray> &QGrpcOperationContext::serverMetadata() const & noexcept
229{
230 Q_D(const QGrpcOperationContext);
231 return d->deprServerInitialMetadata;
232}
233
234/*!
235 \fn void QGrpcOperationContext::setServerMetadata(const QHash<QByteArray, QByteArray> &metadata)
236 \fn void QGrpcOperationContext::setServerMetadata(QHash<QByteArray, QByteArray> &&metadata)
237 \deprecated [6.13] Use setServerInitialMetadata() instead.
238
239 Sets the metadata received from the server at the start of the RPC.
240
241 \sa setServerInitialMetadata()
242*/
243void QGrpcOperationContext::setServerMetadata(const QHash<QByteArray, QByteArray> &metadata)
244{
245 Q_D(QGrpcOperationContext);
246 if (d->deprServerInitialMetadata == metadata)
247 return;
248 d->deprServerInitialMetadata = metadata;
249 d->serverInitialMetadata = QMultiHash<QByteArray, QByteArray>(metadata);
250}
251void QGrpcOperationContext::setServerMetadata(QHash<QByteArray, QByteArray> &&metadata)
252{
253 Q_D(QGrpcOperationContext);
254 if (d->deprServerInitialMetadata == metadata)
255 return;
256 d->deprServerInitialMetadata = std::move(metadata);
257 d->serverInitialMetadata = QMultiHash<QByteArray, QByteArray>(d->deprServerInitialMetadata);
258}
259
260#endif // QT_DEPRECATED_SINCE(6, 13)
261
262/*!
263 \since 6.10
264
265 \include qgrpcoperation.cpp serverInitialMetadata
266 \note This method is used implicitly by QGrpcOperation.
267
268 \sa QGrpcOperation::serverInitialMetadata() serverTrailingMetadata()
269*/
270const QMultiHash<QByteArray, QByteArray> &
271QGrpcOperationContext::serverInitialMetadata() const & noexcept
272{
273 Q_D(const QGrpcOperationContext);
274 return d->serverInitialMetadata;
275}
276
277/*!
278 \since 6.10
279
280 Sets the \a metadata received from the server at the start of the RPC.
281
282 \sa serverInitialMetadata()
283*/
284void QGrpcOperationContext::setServerInitialMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
285{
286 Q_D(QGrpcOperationContext);
287 if (d->serverInitialMetadata == metadata)
288 return;
289 d->serverInitialMetadata = std::move(metadata);
290#if QT_DEPRECATED_SINCE(6, 13)
291 d->deprServerInitialMetadata = QtGrpcPrivate::toHash(multiHash: d->serverInitialMetadata);
292#endif
293}
294
295/*!
296 \since 6.10
297
298 \include qgrpcoperation.cpp serverTrailingMetadata
299 \note This method is used implicitly by QGrpcOperation.
300
301 \sa QGrpcOperation::serverTrailingMetadata() setServerTrailingMetadata()
302*/
303const QMultiHash<QByteArray, QByteArray> &
304QGrpcOperationContext::serverTrailingMetadata() const & noexcept
305{
306 Q_D(const QGrpcOperationContext);
307 return d->serverTrailingMetadata;
308}
309
310/*!
311 \since 6.10
312
313 Sets the trailing \a metadata received from the server after all response
314 messages.
315
316 \sa serverTrailingMetadata()
317*/
318void QGrpcOperationContext::setServerTrailingMetadata(QMultiHash<QByteArray, QByteArray> &&metadata)
319{
320 Q_D(QGrpcOperationContext);
321 if (d->serverTrailingMetadata == metadata)
322 return;
323 d->serverTrailingMetadata = std::move(metadata);
324}
325
326/*!
327 Returns the meta type of the RPC result message.
328 */
329QMetaType QGrpcOperationContext::responseMetaType() const
330{
331 Q_D(const QGrpcOperationContext);
332 return d->responseMetaType;
333}
334
335/*!
336 Stores the \a metaType of the RPC result message.
337*/
338void QGrpcOperationContext::setResponseMetaType(QMetaType metaType)
339{
340 Q_D(QGrpcOperationContext);
341 d->responseMetaType = metaType;
342}
343
344// For future extensions
345bool QGrpcOperationContext::event(QEvent *event)
346{
347 return QObject::event(event);
348}
349
350QT_END_NAMESPACE
351
352#include "moc_qgrpcoperationcontext.cpp"
353

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