using System;
using System.Diagnostics;
using System.Threading;
using System.Threading.Tasks;
using Newtonsoft.Json;
using Newtonsoft.Json.Linq;
namespace io.github.hatayama.uLoopMCP
{
///
/// Current client context for JSON-RPC processing
///
public class ClientExecutionContext
{
public string Endpoint { get; }
public ClientExecutionContext(string endpoint)
{
Endpoint = endpoint;
}
}
///
/// Class specialized in handling JSON-RPC 2.0 processing
///
/// Design document reference: Packages/src/Editor/ARCHITECTURE.md
///
/// Related classes:
/// - UnityApiHandler: Executes Unity commands based on JSON-RPC requests
/// - McpBridgeServer: TCP server that receives JSON-RPC messages from TypeScript
/// - MainThreadSwitcher: Ensures Unity API calls run on the main thread
/// - JsonRpcRequest: Request model for JSON-RPC 2.0 protocol
/// - ClientExecutionContext: Thread-local context for tracking current client
///
/// Processing flow:
/// 1. Receives JSON message from McpBridgeServer
/// 2. Parses and validates JSON-RPC 2.0 format
/// 3. Sets client context for the current thread
/// 4. Delegates to UnityApiHandler for command execution
/// 5. Formats response according to JSON-RPC 2.0 specification
/// 6. Returns JSON response to be sent back to client
///
public static class JsonRpcProcessor
{
///
/// Current client context for async operations
///
private static readonly AsyncLocal _currentClientContext = new();
///
/// Get current client context (ProcessID and Endpoint)
///
public static ClientExecutionContext CurrentClientContext => _currentClientContext.Value;
///
/// Process JSON-RPC request and generate response with client context
///
public static async Task ProcessRequest(string jsonRequest, string clientEndpoint)
{
var context = new ClientExecutionContext(clientEndpoint);
_currentClientContext.Value = context;
try
{
return await ProcessRequest(jsonRequest);
}
finally
{
_currentClientContext.Value = null;
}
}
///
/// Process JSON-RPC request and generate response
///
public static async Task ProcessRequest(string jsonRequest)
{
try
{
JsonRpcRequest request = ParseRequest(jsonRequest);
if (request.IsNotification)
{
ProcessNotification(request);
return null;
}
return await ProcessRpcRequest(request, jsonRequest);
}
catch (JsonReaderException ex)
{
return CreateErrorResponse(null, ex);
}
catch (Exception ex)
{
return CreateErrorResponse(null, ex);
}
}
///
/// Parse JSON-RPC request string into structured object
///
private static JsonRpcRequest ParseRequest(string jsonRequest)
{
JObject request = JObject.Parse(jsonRequest);
return new JsonRpcRequest
{
Method = request["method"]?.ToString(),
Params = request["params"],
Id = request["id"]?.ToObject