yum-mirror/slang

Making it easier to work with shaders

git clone https://git.yummers.dev/yum-mirror/slang

Ellie Hermaszewskaformatf65d756bf

master
10.1 KiB286 linesraw
1#ifndef SLANG_COMPILER_CORE_JSON_RPC_CONNECTION_H
2#define SLANG_COMPILER_CORE_JSON_RPC_CONNECTION_H
3
4#include "../../source/core/slang-http.h"
5#include "../../source/core/slang-process.h"
6#include "slang-diagnostic-sink.h"
7#include "slang-json-diagnostics.h"
8#include "slang-json-rpc.h"
9#include "slang-json-value.h"
10#include "slang-source-loc.h"
11#include "slang-test-server-protocol.h"
12
13namespace Slang
14{
15
16/* A type to handle communication via the JSON-RPC protocol.
17
18Uses Rtti to be able to convert between native and JSON types.
19Provides methods that work on the JSON-RPC protocol, these methods contain 'RPC' and can only
20use the JSON-RPC protocol types. These types will hold items that can vary (like parameters)
21in JSONValue parameters. Code can use regular JSON functions to access/process.
22
23Doing conversions to native types and JSON manually can be a fairly monotonous task. To avoid this
24effort Rtti and JSON<->Rtti conversions can be used. For example sendCall will send a JSON-RPC
25'call' method, with the parameters being converted from some native type. For this to work the type
26T must be determinable via GetRttiType<T>, and T must only contain types that JSON<->Rtti conversion
27supports.
28*/
29class JSONRPCConnection : public RefObject
30{
31public:
32    enum class CallStyle
33    {
34        Default, ///< The default
35        Object,  ///< Params are passed as an object
36        Array,   ///< Params are passed as an array
37    };
38
39    /// An init function must be called before use
40    /// If a process is implementing the server it should be passed in if the process needs to shut
41    /// down if the connection does
42    SlangResult init(
43        HTTPPacketConnection* connection,
44        CallStyle callStyle = CallStyle::Default,
45        Process* process = nullptr);
46
47    /// Initialize using stdin/out streams for input/output.
48    SlangResult initWithStdStreams(
49        CallStyle callStyle = CallStyle::Default,
50        Process* process = nullptr);
51
52    /// Disconnect. May block while server shuts down
53    void disconnect();
54
55    SlangResult checkArrayObjectWrap(
56        const JSONValue& srcArgs,
57        const RttiInfo* dstArgsRttiInfo,
58        void* dstArgs,
59        const JSONValue& id);
60
61    /// Convert value to dst. Will write response on fails
62    SlangResult toNativeOrSendError(
63        const JSONValue& value,
64        const RttiInfo* info,
65        void* dst,
66        const JSONValue& id);
67
68    template<typename T>
69    SlangResult toNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id)
70    {
71        return toNativeOrSendError(value, GetRttiInfo<T>::get(), data, id);
72    }
73
74    /// Convert value to dst.
75    /// The 'Args' aspect here is to handle Args/Params in JSON-RPC which can be specified as an
76    /// array or object style. This call will automatically handle either case. toNativeOrSendError
77    /// does not assume the thing being converted is args, and so doesn't allow such a
78    /// transformation. Will write error response on failure.
79    SlangResult toNativeArgsOrSendError(
80        const JSONValue& srcArgs,
81        const RttiInfo* dstArgsRttiInfo,
82        void* dstArgs,
83        const JSONValue& id);
84
85    template<typename T>
86    SlangResult toNativeArgsOrSendError(const JSONValue& srcArgs, T* dstArgs, const JSONValue& id)
87    {
88        return toNativeArgsOrSendError(srcArgs, GetRttiInfo<T>::get(), dstArgs, id);
89    }
90
91    template<typename T>
92    SlangResult toValidNativeOrSendError(const JSONValue& value, T* data, const JSONValue& id);
93
94    /// Send a RPC response (ie should only be one of the JSONRPC classes)
95    SlangResult sendRPC(const RttiInfo* info, const void* data);
96    template<typename T>
97    SlangResult sendRPC(const T* data)
98    {
99        return sendRPC(GetRttiInfo<T>::get(), (const void*)data);
100    }
101
102    /// Send an error
103    SlangResult sendError(JSONRPC::ErrorCode code, const JSONValue& id);
104    SlangResult sendError(
105        JSONRPC::ErrorCode errorCode,
106        const UnownedStringSlice& msg,
107        const JSONValue& id);
108
109    /// Send a 'call'
110    /// Uses the default CallStyle as set when init
111    SlangResult sendCall(
112        const UnownedStringSlice& method,
113        const RttiInfo* argsRttiInfo,
114        const void* args,
115        const JSONValue& id = JSONValue());
116    template<typename T>
117    SlangResult sendCall(
118        const UnownedStringSlice& method,
119        const T* args,
120        const JSONValue& id = JSONValue())
121    {
122        return sendCall(method, GetRttiInfo<T>::get(), (const void*)args, id);
123    }
124
125    /// Send a 'call'
126    /// Uses the call mechanism specified in callStyle. It is valid to pass as Default.
127    SlangResult sendCall(
128        CallStyle callStyle,
129        const UnownedStringSlice& method,
130        const RttiInfo* argsRttiInfo,
131        const void* args,
132        const JSONValue& id = JSONValue());
133    template<typename T>
134    SlangResult sendCall(
135        CallStyle callStyle,
136        const UnownedStringSlice& method,
137        const T* args,
138        const JSONValue& id = JSONValue())
139    {
140        return sendCall(callStyle, method, GetRttiInfo<T>::get(), (const void*)args, id);
141    }
142
143    /// Send a call, wheret there are no arguments
144    SlangResult sendCall(const UnownedStringSlice& method, const JSONValue& id = JSONValue());
145
146    template<typename T>
147    SlangResult sendResult(const T* result, const JSONValue& id)
148    {
149        return sendResult(GetRttiInfo<T>::get(), (const void*)result, id);
150    }
151    SlangResult sendResult(const RttiInfo* rttiInfo, const void* result, const JSONValue& id);
152
153    /// Try to read a message. Will return if message is not available.
154    SlangResult tryReadMessage();
155
156    /// Will block for message/result up to time
157    SlangResult waitForResult(Int timeOutInMs = -1);
158
159    /// If we have an JSON-RPC message m_jsonRoot the root.
160    bool hasMessage() const { return m_jsonRoot.isValid(); }
161
162    /// If there is a message returns kind of JSON RPC message
163    JSONRPCMessageType getMessageType();
164
165    /// Get JSON-RPC message (ie one of JSONRPC classes)
166    template<typename T>
167    SlangResult getRPC(T* out)
168    {
169        return getRPC(GetRttiInfo<T>::get(), (void*)out);
170    }
171    SlangResult getRPC(const RttiInfo* rttiInfo, void* out);
172
173    /// Get JSON-RPC message (ie one of JSONRPC prefixed classes)
174    /// If there is a message and there is a failure, will send an error response
175    template<typename T>
176    SlangResult getRPCOrSendError(T* out)
177    {
178        return getRPCOrSendError(GetRttiInfo<T>::get(), (void*)out);
179    }
180    SlangResult getRPCOrSendError(const RttiInfo* rttiInfo, void* out);
181
182    /// Get message (has to be part of JSONRPCResultResponse)
183    template<typename T>
184    SlangResult getMessage(T* out)
185    {
186        return getMessage(GetRttiInfo<T>::get(), (void*)out);
187    }
188    SlangResult getMessage(const RttiInfo* rttiInfo, void* out);
189
190    /// If there is a message and there is a failure, will send an error response
191    template<typename T>
192    SlangResult getMessageOrSendError(T* out)
193    {
194        return getMessageOrSendError(GetRttiInfo<T>::get(), (void*)out);
195    }
196    SlangResult getMessageOrSendError(const RttiInfo* rttiInfo, void* out);
197
198    /// Clears all the internal buffers (for JSON/Source/etc).
199    /// Happens automatically on tryReadMessage/readMessage
200    void clearBuffers();
201
202    /// True if this connection is active
203    bool isActive();
204
205    /// Get the id of the current message
206    JSONValue getCurrentMessageId();
207
208    /// Get the diagnostic sink. Can queue up errors before sending an error
209    DiagnosticSink* getSink() { return &m_diagnosticSink; }
210
211    /// Get the container
212    JSONContainer* getContainer() { return &m_container; }
213
214    /// Turn a value into a persistant value. This will also remove any sourceLoc under the
215    /// assumption that it's highly likely it will become invalid in most usage scenarios.
216    PersistentJSONValue getPersistentValue(const JSONValue& value)
217    {
218        return PersistentJSONValue(value, &m_container, SourceLoc());
219    }
220
221    HTTPPacketConnection* getUnderlyingConnection() { return m_connection.Ptr(); }
222
223    /// Dtor
224    ~JSONRPCConnection() { disconnect(); }
225
226    /// Ctor
227    JSONRPCConnection();
228
229protected:
230    CallStyle _getCallStyle(CallStyle callStyle) const
231    {
232        return (callStyle == CallStyle::Default) ? m_defaultCallStyle : callStyle;
233    }
234
235    RefPtr<Process> m_process;                 ///< Backing process (optional)
236    RefPtr<HTTPPacketConnection> m_connection; ///< The underlying 'transport' connection, whilst
237                                               ///< HTTP currently doesn't have to be
238
239    DiagnosticSink m_diagnosticSink; ///< Holds any diagnostics typically generated by parsing JSON,
240                                     ///< producing JSON from native types
241
242    SourceManager
243        m_sourceManager; ///< Holds the JSON text for current message/output. Is cleared regularly.
244    JSONContainer m_container; ///< Holds the backing memory for jsonMemory, and used when
245                               ///< converting input into output JSON
246
247    JSONValue m_jsonRoot; ///< The root JSON value for the currently read message.
248
249    CallStyle m_defaultCallStyle = CallStyle::Array; ///< The default calling style
250
251    RttiTypeFuncsMap m_typeMap;
252
253    Int m_terminationTimeOutInMs =
254        1 * 1000; ///< Time to wait for termination response. Default is 1 second
255};
256
257// ---------------------------------------------------------------------------
258template<typename T>
259SlangResult JSONRPCConnection::toValidNativeOrSendError(
260    const JSONValue& value,
261    T* data,
262    const JSONValue& id)
263{
264    const RttiInfo* rttiInfo = GetRttiInfo<T>::get();
265
266    SLANG_RETURN_ON_FAIL(toNativeOrSendError(value, rttiInfo, (void*)data, id));
267    if (!data->isValid())
268    {
269        // If it has a name add validation info
270        if (rttiInfo->isNamed())
271        {
272            const NamedRttiInfo* namedRttiInfo = static_cast<const NamedRttiInfo*>(rttiInfo);
273            m_diagnosticSink.diagnose(
274                SourceLoc(),
275                JSONDiagnostics::argsAreInvalid,
276                namedRttiInfo->m_name);
277        }
278
279        return sendError(JSONRPC::ErrorCode::InvalidRequest, id);
280    }
281    return SLANG_OK;
282}
283
284} // namespace Slang
285
286#endif // SLANG_COMPILER_CORE_JSON_RPC_CONNECTION_H