1 | // Copyright (C) 2024 The Qt Company Ltd. |
2 | // SPDX-License-Identifier: LicenseRef-Qt-Commercial OR GPL-3.0-only |
3 | |
4 | #ifndef QQMLGRPCFUNCTIONALHANDLERS_H |
5 | #define QQMLGRPCFUNCTIONALHANDLERS_H |
6 | |
7 | #include <QtGrpcQuick/qtgrpcquickexports.h> |
8 | |
9 | #include <QtGrpc/qgrpccallreply.h> |
10 | #include <QtGrpc/qgrpcstream.h> |
11 | |
12 | #include <QtQml/qqmlengine.h> |
13 | |
14 | #include <QtCore/qobject.h> |
15 | #include <QtCore/qtconfigmacros.h> |
16 | |
17 | QT_BEGIN_NAMESPACE |
18 | |
19 | namespace QtGrpcQuickFunctional { |
20 | |
21 | Q_ALWAYS_INLINE void validateEngineAndOperation(QJSEngine *jsEngine, QGrpcOperation *operation) |
22 | { |
23 | Q_ASSERT(jsEngine != nullptr); |
24 | Q_ASSERT(operation != nullptr); |
25 | } |
26 | |
27 | template <typename Ret> |
28 | std::optional<QJSValue> readMessageToJSValue(QJSEngine *jsEngine, QGrpcOperation *operation) |
29 | { |
30 | QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operation); |
31 | |
32 | if (std::optional<Ret> result = operation->read<Ret>()) |
33 | return jsEngine->toScriptValue(*result); |
34 | return std::nullopt; |
35 | } |
36 | |
37 | Q_GRPCQUICK_EXPORT |
38 | void handleReceivedMessageImpl(QJSEngine *jsEngine, std::optional<QJSValue> message, |
39 | const QJSValue &successCallback, const QJSValue &errorCallback); |
40 | |
41 | template <typename Ret> |
42 | void handleReceivedMessage(QJSEngine *jsEngine, QGrpcOperation *operation, |
43 | const QJSValue &successCallback, const QJSValue &errorCallback) |
44 | { |
45 | auto message = QtGrpcQuickFunctional::readMessageToJSValue<Ret>(jsEngine, operation); |
46 | QtGrpcQuickFunctional::handleReceivedMessageImpl(jsEngine, message: std::move(message), successCallback, |
47 | errorCallback); |
48 | } |
49 | |
50 | Q_GRPCQUICK_EXPORT |
51 | bool checkReceivedStatus(QJSEngine *jsEngine, const QGrpcStatus &status, |
52 | const QJSValue &errorCallback); |
53 | |
54 | Q_GRPCQUICK_EXPORT |
55 | void connectMultipleReceiveOperationFinished(QJSEngine *jsEngine, |
56 | std::unique_ptr<QGrpcOperation> &&operation, |
57 | const QJSValue &successCallback, |
58 | const QJSValue &errorCallback); |
59 | |
60 | template <typename Ret> |
61 | void connectSingleReceiveOperationFinished(QJSEngine *jsEngine, |
62 | std::unique_ptr<QGrpcOperation> &&operation, |
63 | const QJSValue &successCallback, |
64 | const QJSValue &errorCallback) |
65 | { |
66 | auto *operationPtr = operation.get(); |
67 | QtGrpcQuickFunctional::validateEngineAndOperation(jsEngine, operation: operationPtr); |
68 | |
69 | auto finishConnection = std::make_shared<QMetaObject::Connection>(); |
70 | *finishConnection = QObject:: |
71 | connect(operationPtr, &QGrpcCallReply::finished, jsEngine, |
72 | [jsEngine, successCallback, errorCallback, finishConnection, |
73 | operation = std::move(operation)](const QGrpcStatus &status) { |
74 | // We take 'operation' by copy so that its lifetime |
75 | // is extended until this lambda is destroyed. |
76 | if (QtGrpcQuickFunctional::checkReceivedStatus(jsEngine, status, |
77 | errorCallback)) { |
78 | QtGrpcQuickFunctional::handleReceivedMessage<Ret>(jsEngine, operation.get(), |
79 | successCallback, |
80 | errorCallback); |
81 | } |
82 | QObject::disconnect(*finishConnection); |
83 | }); |
84 | } |
85 | |
86 | template <typename Ret> |
87 | void makeCallConnections(QJSEngine *jsEngine, std::unique_ptr<QGrpcCallReply> &&reply, |
88 | const QJSValue &finishCallback, const QJSValue &errorCallback) |
89 | { |
90 | QtGrpcQuickFunctional::connectSingleReceiveOperationFinished<Ret>(jsEngine, std::move(reply), |
91 | finishCallback, |
92 | errorCallback); |
93 | } |
94 | |
95 | template <typename Ret> |
96 | void makeServerStreamConnections(QJSEngine *jsEngine, std::unique_ptr<QGrpcServerStream> &&stream, |
97 | const QJSValue &messageCallback, const QJSValue &finishCallback, |
98 | const QJSValue &errorCallback) |
99 | { |
100 | QObject::connect(stream.get(), &QGrpcServerStream::messageReceived, jsEngine, |
101 | [streamPtr = stream.get(), messageCallback, jsEngine, errorCallback]() { |
102 | QtGrpcQuickFunctional::handleReceivedMessage<Ret>(jsEngine, streamPtr, |
103 | messageCallback, |
104 | errorCallback); |
105 | }); |
106 | QtGrpcQuickFunctional::connectMultipleReceiveOperationFinished(jsEngine, operation: std::move(stream), |
107 | successCallback: finishCallback, errorCallback); |
108 | } |
109 | |
110 | template <typename Ret> |
111 | void makeClientStreamConnections(QJSEngine *jsEngine, std::unique_ptr<QGrpcClientStream> &&stream, |
112 | const QJSValue &finishCallback, const QJSValue &errorCallback) |
113 | { |
114 | QtGrpcQuickFunctional::connectSingleReceiveOperationFinished<Ret>(jsEngine, std::move(stream), |
115 | finishCallback, |
116 | errorCallback); |
117 | } |
118 | |
119 | template <typename Ret> |
120 | void makeBidiStreamConnections(QJSEngine *jsEngine, std::unique_ptr<QGrpcBidiStream> &&stream, |
121 | const QJSValue &messageCallback, const QJSValue &finishCallback, |
122 | const QJSValue &errorCallback) |
123 | { |
124 | QObject::connect(stream.get(), &QGrpcBidiStream::messageReceived, jsEngine, |
125 | [streamPtr = stream.get(), messageCallback, jsEngine, errorCallback] { |
126 | QtGrpcQuickFunctional::handleReceivedMessage<Ret>(jsEngine, streamPtr, |
127 | messageCallback, |
128 | errorCallback); |
129 | }); |
130 | QtGrpcQuickFunctional::connectMultipleReceiveOperationFinished(jsEngine, operation: std::move(stream), |
131 | successCallback: finishCallback, errorCallback); |
132 | } |
133 | |
134 | } // namespace QtGrpcQuickFunctional |
135 | |
136 | QT_END_NAMESPACE |
137 | |
138 | #endif // QQMLGRPCFUNCTIONALHANDLERS_H |
139 | |