See More

using System; using System.Globalization; using System.Threading; using System.Threading.Tasks; using System.Reflection; using System.IO; using System.Collections.Generic; using System.Linq; using System.Text; using Newtonsoft.Json; namespace AustinHarris.JsonRpc { public static class JsonRpcProcessor { public static void Process(JsonRpcStateAsync async, object context = null, JsonSerializerSettings settings = null) { Process(Handler.DefaultSessionId(), async, context, settings); } public static void Process(string sessionId, JsonRpcStateAsync async, object context = null, JsonSerializerSettings settings = null) { Process(sessionId, async.JsonRpc, context, settings) .ContinueWith(t => { async.Result = t.Result; async.SetCompleted(); }); } public static Task Process(string jsonRpc, object context = null, JsonSerializerSettings settings = null) { return Process(Handler.DefaultSessionId(), jsonRpc, context, settings); } public static Task Process(string sessionId, string jsonRpc, object context = null, JsonSerializerSettings settings = null) { return Task.Factory.StartNew((_) => { var tuple = (Tuple)_; return ProcessSync(tuple.Item1, tuple.Item2, tuple.Item3, tuple.Item4); }, new Tuple(sessionId, jsonRpc, context, settings)); } public static string ProcessSync(string sessionId, string jsonRpc, object jsonRpcContext, JsonSerializerSettings settings = null) { var handler = Handler.GetSessionHandler(sessionId); JsonRequest[] batch = null; try { if (isSingleRpc(jsonRpc)) { var foo = JsonConvert.DeserializeObject(jsonRpc, settings); batch = new[] { foo }; } else { batch = JsonConvert.DeserializeObject(jsonRpc, settings); } } catch (Exception ex) { return Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse { Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32700, "Parse error", ex)) }, settings); } if (batch.Length == 0) { return Newtonsoft.Json.JsonConvert.SerializeObject(new JsonResponse { Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(3200, "Invalid Request", "Batch of calls was empty.")) }, settings); } var singleBatch = batch.Length == 1; StringBuilder sbResult = null; for (var i = 0; i < batch.Length; i++) { var jsonRequest = batch[i]; var jsonResponse = new JsonResponse(); if (jsonRequest == null) { jsonResponse.Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32700, "Parse error", "Invalid JSON was received by the server. An error occurred on the server while parsing the JSON text.")); } else if (jsonRequest.Method == null) { jsonResponse.Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32600, "Invalid Request", "Missing property 'method'")); } else if (!isSimpleValueType(jsonRequest.Id)) { jsonResponse.Error = handler.ProcessParseException(jsonRpc, new JsonRpcException(-32600, "Invalid Request", "Id property must be either null or string or integer.")); } else { jsonResponse.Id = jsonRequest.Id; var data = handler.Handle(jsonRequest, jsonRpcContext); if (data == null) continue; jsonResponse.JsonRpc = data.JsonRpc; jsonResponse.Error = data.Error; jsonResponse.Result = data.Result; } if (jsonResponse.Result == null && jsonResponse.Error == null) { // Per json rpc 2.0 spec // result : This member is REQUIRED on success. // This member MUST NOT exist if there was an error invoking the method. // Either the result member or error member MUST be included, but both members MUST NOT be included. jsonResponse.Result = new Newtonsoft.Json.Linq.JValue((Object)null); } // special case optimization for single Item batch if (singleBatch && (jsonResponse.Id != null || jsonResponse.Error != null)) { StringWriter sw = new StringWriter(); JsonTextWriter writer = new JsonTextWriter(sw); writer.WriteStartObject(); if (!string.IsNullOrEmpty(jsonResponse.JsonRpc)) { writer.WritePropertyName("jsonrpc"); writer.WriteValue(jsonResponse.JsonRpc); } if (jsonResponse.Error != null) { writer.WritePropertyName("error"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Error)); } else { writer.WritePropertyName("result"); writer.WriteRawValue(JsonConvert.SerializeObject(jsonResponse.Result)); } writer.WritePropertyName("id"); writer.WriteValue(jsonResponse.Id); writer.WriteEndObject(); return sw.ToString(); //return JsonConvert.SerializeObject(jsonResponse); } else if (jsonResponse.Id == null && jsonResponse.Error == null) { // do nothing sbResult = new StringBuilder(0); } else { // write out the response if (i == 0) { sbResult = new StringBuilder("["); } sbResult.Append(JsonConvert.SerializeObject(jsonResponse, settings)); if (i < batch.Length - 1) { sbResult.Append(','); } else if (i == batch.Length - 1) { sbResult.Append(']'); } } } return sbResult.ToString(); } private static bool isSingleRpc(string json) { for (int i = 0; i < json.Length; i++) { if (json[i] == '{') return true; else if (json[i] == '[') return false; } return true; } private static bool isSimpleValueType(object property) { if (property == null) return true; return property.GetType() == typeof(System.String) || property.GetType() == typeof(System.Int64) || property.GetType() == typeof(System.Int32) || property.GetType() == typeof(System.Int16); } } }