yum-mirror/slang
Making it easier to work with shaders
git clone https://git.yummers.dev/yum-mirror/slang
5621ace93
master
1// slang-json-rpc-connection.cpp 2#include "slang-json-rpc-connection.h" 3 4#include "../core/slang-process-util.h" 5#include "../core/slang-short-list.h" 6#include "../core/slang-string-util.h" 7#include "slang-json-native.h" 8#include "slang-json-rpc.h" 9 10namespace Slang 11{ 12 13/// Ctor 14JSONRPCConnection ::JSONRPCConnection () 15 :m_container (nullptr ),m_typeMap (JSONNativeUtil ::getTypeFuncsMap ()) 16{ 17} 18 19SlangResult JSONRPCConnection ::init ( 20HTTPPacketConnection * connection , 21CallStyle defaultCallStyle , 22Process * process ) 23{ 24m_connection = connection ; 25m_process = process ; 26 27 { 28// If a call style isn't set, use the prefered style 29const CallStyle preferedCallStyle = CallStyle ::Array ; 30defaultCallStyle = 31 (defaultCallStyle == CallStyle ::Default ) ?preferedCallStyle :defaultCallStyle ; 32m_defaultCallStyle = defaultCallStyle ; 33 } 34 35 36m_sourceManager .initialize (nullptr ,nullptr ); 37m_diagnosticSink .init (& m_sourceManager ,& JSONLexer ::calcLexemeLocation ); 38m_container .setSourceManager (& m_sourceManager ); 39 40return SLANG_OK ; 41} 42 43SlangResult JSONRPCConnection ::initWithStdStreams (CallStyle defaultCallStyle ,Process * process ) 44{ 45RefPtr < Stream > stdinStream ,stdoutStream ; 46 47Process ::getStdStream (StdStreamType ::In ,stdinStream ); 48Process ::getStdStream (StdStreamType ::Out ,stdoutStream ); 49 50RefPtr < BufferedReadStream > readStream (new BufferedReadStream (stdinStream )); 51 52RefPtr < HTTPPacketConnection > connection = new HTTPPacketConnection (readStream ,stdoutStream ); 53return init (connection ,defaultCallStyle ,process ); 54} 55 56void JSONRPCConnection ::clearBuffers () 57{ 58m_sourceManager .reset (); 59m_diagnosticSink .reset (); 60m_container .reset (); 61m_jsonRoot .reset (); 62} 63 64bool JSONRPCConnection ::isActive () 65{ 66return m_connection -> isActive ()&& (m_process == nullptr || !m_process -> isTerminated ()); 67} 68 69JSONValue JSONRPCConnection ::getCurrentMessageId () 70{ 71SLANG_ASSERT (hasMessage ()); 72return JSONRPCUtil ::getId (& m_container ,m_jsonRoot ); 73} 74 75void JSONRPCConnection ::disconnect () 76{ 77if (m_process ) 78 { 79if (!m_process -> isTerminated ()) 80 { 81if (m_connection ) 82 { 83// Send. If succeeded, wait 84if (SLANG_SUCCEEDED (sendCall (UnownedStringSlice ::fromLiteral ("quit" )))) 85 { 86// Wait for termination 87m_process -> waitForTermination (m_terminationTimeOutInMs ); 88 } 89 } 90 91if (!m_process -> isTerminated ()) 92 { 93// Okay, just try terminating 94m_process -> waitForTermination (m_terminationTimeOutInMs ); 95 } 96 97// Okay just kill it then 98if (!m_process -> isTerminated ()) 99 { 100m_process -> kill (-1 ); 101 } 102 } 103m_process .setNull (); 104 } 105 106m_connection .setNull (); 107} 108 109SlangResult JSONRPCConnection ::sendRPC (const RttiInfo * rttiInfo ,const void * data ) 110{ 111auto typeMap = JSONNativeUtil ::getTypeFuncsMap (); 112 113// Convert to JSON 114NativeToJSONConverter converter (& m_container ,& typeMap ,& m_diagnosticSink ); 115JSONValue value ; 116 117SLANG_RETURN_ON_FAIL (converter .convert (rttiInfo ,data ,value )); 118 119// Convert to text 120JSONWriter writer (JSONWriter ::IndentationStyle ::Allman ); 121 122m_container .traverseRecursively (value ,& writer ); 123const StringBuilder & builder = writer .getBuilder (); 124return m_connection -> write (builder .getBuffer (),builder .getLength ()); 125} 126 127SlangResult JSONRPCConnection ::sendError (JSONRPC ::ErrorCode code ,const JSONValue & id ) 128{ 129return sendError (code ,m_diagnosticSink .outputBuffer .getUnownedSlice (),id ); 130} 131 132SlangResult JSONRPCConnection ::sendError ( 133JSONRPC ::ErrorCode errorCode , 134const UnownedStringSlice & msg , 135const JSONValue & id ) 136{ 137JSONRPCErrorResponse errorResponse ; 138errorResponse .error .code = Int (errorCode ); 139errorResponse .error .message = msg ; 140errorResponse .id = id ; 141 142return sendRPC (& errorResponse ); 143} 144 145SlangResult JSONRPCConnection ::checkArrayObjectWrap ( 146const JSONValue & srcArgs , 147const RttiInfo * dstArgsRttiInfo , 148void * dstArgs , 149const JSONValue & id ) 150{ 151if (dstArgsRttiInfo -> m_kind == RttiInfo ::Kind ::Struct && 152srcArgs .getKind ()== JSONValue ::Kind ::Array ) 153 { 154auto array = m_container .getArray (srcArgs ); 155if (array .getCount ()== 1 ) 156 { 157return toNativeOrSendError (array [0 ],dstArgsRttiInfo ,dstArgs ,id ); 158 } 159return SLANG_OK ; 160 } 161else 162 { 163return toNativeOrSendError (srcArgs ,dstArgsRttiInfo ,dstArgs ,id ); 164 } 165} 166 167SlangResult JSONRPCConnection ::toNativeArgsOrSendError ( 168const JSONValue & srcArgs , 169const RttiInfo * dstArgsRttiInfo , 170void * dstArgs , 171const JSONValue & id ) 172{ 173if (dstArgsRttiInfo -> m_kind == RttiInfo ::Kind ::Struct && 174srcArgs .getKind ()== JSONValue ::Kind ::Array ) 175 { 176JSONToNativeConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 177if (SLANG_FAILED (converter .convertArrayToStruct (srcArgs ,dstArgsRttiInfo ,dstArgs ))) 178 { 179return sendError (JSONRPC ::ErrorCode ::InvalidRequest ,id ); 180 } 181return SLANG_OK ; 182 } 183else 184 { 185return toNativeOrSendError (srcArgs ,dstArgsRttiInfo ,dstArgs ,id ); 186 } 187} 188 189SlangResult JSONRPCConnection ::toNativeOrSendError ( 190const JSONValue & value , 191const RttiInfo * info , 192void * dst , 193const JSONValue & id ) 194{ 195m_diagnosticSink .outputBuffer .clear (); 196 197JSONToNativeConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 198 199if (SLANG_FAILED (converter .convert (value ,info ,dst ))) 200 { 201return sendError (JSONRPC ::ErrorCode ::InvalidRequest ,id ); 202 } 203 204return SLANG_OK ; 205} 206 207SlangResult JSONRPCConnection ::sendCall (const UnownedStringSlice & method ,const JSONValue & id ) 208{ 209JSONRPCCall call ; 210call .id = id ; 211call .method = method ; 212 213SLANG_RETURN_ON_FAIL (sendRPC (& call )); 214return SLANG_OK ; 215} 216 217SlangResult JSONRPCConnection ::sendResult ( 218const RttiInfo * rttiInfo , 219const void * result , 220const JSONValue & id ) 221{ 222JSONResultResponse response ; 223response .id = id ; 224 225NativeToJSONConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 226SLANG_RETURN_ON_FAIL (converter .convert (rttiInfo ,result ,response .result )); 227 228// Send the RPC 229SLANG_RETURN_ON_FAIL (sendRPC (& response )); 230return SLANG_OK ; 231} 232 233SlangResult JSONRPCConnection ::sendCall ( 234const UnownedStringSlice & method , 235const RttiInfo * argsRttiInfo , 236const void * args , 237const JSONValue & id ) 238{ 239return sendCall (m_defaultCallStyle ,method ,argsRttiInfo ,args ,id ); 240} 241 242SlangResult JSONRPCConnection ::sendCall ( 243CallStyle callStyle , 244const UnownedStringSlice & method , 245const RttiInfo * argsRttiInfo , 246const void * args , 247const JSONValue & id ) 248{ 249JSONRPCCall call ; 250call .id = id ; 251call .method = method ; 252 253// Set up the converter to now convert the args. 254NativeToJSONConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 255 256// If we have a struct *and* call style is 'array', do special handling 257if (argsRttiInfo -> m_kind == RttiInfo ::Kind ::Struct && 258_getCallStyle (callStyle )== CallStyle ::Array ) 259 { 260// Convert the args/params in the 'array' style 261SLANG_RETURN_ON_FAIL (converter .convertStructToArray (argsRttiInfo ,args ,call .params )); 262 } 263else 264 { 265// Convert the args/params in the 'object' sytle 266SLANG_RETURN_ON_FAIL (converter .convert (argsRttiInfo ,args ,call .params )); 267 } 268 269// Send the RPC 270SLANG_RETURN_ON_FAIL (sendRPC (& call )); 271return SLANG_OK ; 272} 273 274SlangResult JSONRPCConnection ::waitForResult (Int timeOutInMs ) 275{ 276// Invalidate m_jsonRoot before waitForResult, because when waitForResult fail, 277// we don't want to use the result from the previous read. 278m_jsonRoot .reset (); 279 280SLANG_RETURN_ON_FAIL (m_connection -> waitForResult (timeOutInMs )); 281return tryReadMessage (); 282} 283 284SlangResult JSONRPCConnection ::tryReadMessage () 285{ 286m_jsonRoot .reset (); 287 288SLANG_RETURN_ON_FAIL (m_connection -> update ()); 289if (!m_connection -> hasContent ()) 290 { 291return SLANG_OK ; 292 } 293 294auto content = m_connection -> getContent (); 295UnownedStringSlice slice ((const char * )content .begin (),content .getCount ()); 296 297clearBuffers (); 298 299 { 300const SlangResult res = 301JSONRPCUtil ::parseJSON (slice ,& m_container ,& m_diagnosticSink ,m_jsonRoot ); 302 303// Consume that content/packet 304m_connection -> consumeContent (); 305if (SLANG_FAILED (res )) 306 { 307// if we can't parse JSON, we return with id of 'null' as per the standard 308return sendError (JSONRPC ::ErrorCode ::ParseError ,JSONValue ::makeNull ()); 309 } 310 } 311 312return SLANG_OK ; 313} 314 315JSONRPCMessageType JSONRPCConnection ::getMessageType () 316{ 317return JSONRPCUtil ::getMessageType (& m_container ,m_jsonRoot ); 318} 319 320SlangResult JSONRPCConnection ::getMessage (const RttiInfo * rttiInfo ,void * out ) 321{ 322if (!hasMessage ()) 323 { 324return SLANG_FAIL ; 325 } 326 327m_diagnosticSink .outputBuffer .clear (); 328JSONToNativeConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 329 330// Get the RPC response 331JSONResultResponse resultResponse ; 332SLANG_RETURN_ON_FAIL (converter .convert (m_jsonRoot ,& resultResponse )); 333 334// Convert the result in the response 335SLANG_RETURN_ON_FAIL (converter .convert (resultResponse .result ,rttiInfo ,out )); 336return SLANG_OK ; 337} 338 339SlangResult JSONRPCConnection ::getMessageOrSendError (const RttiInfo * rttiInfo ,void * out ) 340{ 341if (!hasMessage ()) 342 { 343return SLANG_FAIL ; 344 } 345 346const auto res = getMessage (rttiInfo ,out ); 347if (SLANG_FAILED (res )) 348 { 349return sendError (JSONRPC ::ErrorCode ::ParseError ,getCurrentMessageId ()); 350 } 351return res ; 352} 353 354SlangResult JSONRPCConnection ::getRPC (const RttiInfo * rttiInfo ,void * out ) 355{ 356if (!hasMessage ()) 357 { 358return SLANG_FAIL ; 359 } 360 361m_diagnosticSink .outputBuffer .clear (); 362JSONToNativeConverter converter (& m_container ,& m_typeMap ,& m_diagnosticSink ); 363 364// Convert the result in the response 365SLANG_RETURN_ON_FAIL (converter .convert (m_jsonRoot ,rttiInfo ,out )); 366return SLANG_OK ; 367} 368 369SlangResult JSONRPCConnection ::getRPCOrSendError (const RttiInfo * rttiInfo ,void * out ) 370{ 371if (!hasMessage ()) 372 { 373return SLANG_FAIL ; 374 } 375 376const auto res = getRPC (rttiInfo ,out ); 377if (SLANG_FAILED (res )) 378 { 379return sendError (JSONRPC ::ErrorCode ::ParseError ,getCurrentMessageId ()); 380 } 381return res ; 382} 383 384}// namespace Slang