/// <summary> /// Add a procedure to the service /// </summary> void AddProcedure(ProcedureSignature signature) { if (Procedures.ContainsKey(signature.Name)) { throw new ServiceException("Service " + Name + " contains duplicate procedures " + signature.Name); } Procedures [signature.Name] = signature; }
public RPCException(ProcedureSignature procedure, Exception exception) { if (VerboseErrors) { message = "'" + procedure.FullyQualifiedName + "' threw an exception."; message += " " + exception.GetType () + ": " + exception.Message; } else { message = exception.Message; } }
public RPCException (ProcedureSignature procedure, string message) { if (VerboseErrors) { description = "'" + procedure.FullyQualifiedName + "' threw an exception.\n"; description += GetType () + ": " + message; } else { description = message; } }
public RPCException(ProcedureSignature procedure, string message) { if (VerboseErrors) { this.message = "'" + procedure.FullyQualifiedName + "' threw an exception."; this.message += " " + GetType () + ": " + message; } else { this.message = message; } }
public RPCException (ProcedureSignature procedure, Exception innerException) { var innerMessage = innerException.Message; if (VerboseErrors) { description = "'" + procedure.FullyQualifiedName + "' threw an exception.\n"; description += innerException.GetType () + ": " + innerMessage + "\n" + innerException.StackTrace; } else { description = innerMessage; } }
/// <summary> /// Executes the given request and returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response.Builder HandleRequest(ProcedureSignature procedure, Request request) { object[] arguments = DecodeArguments (procedure, request.ArgumentsList); object returnValue; try { returnValue = procedure.Handler.Invoke (arguments); } catch (TargetInvocationException e) { if (e.InnerException.GetType () == typeof(YieldException)) throw e.InnerException; throw new RPCException ("Procedure '" + procedure.FullyQualifiedName + "' threw an exception. " + e.InnerException.GetType () + ": " + e.InnerException.Message + "\n" + e.InnerException.StackTrace); } var responseBuilder = Response.CreateBuilder (); if (procedure.HasReturnType) responseBuilder.ReturnValue = EncodeReturnValue (procedure, returnValue); return responseBuilder; }
public Response HandleRequest (ProcedureSignature procedure, object[] arguments) { if ((CallContext.GameScene & procedure.GameScene) == 0) throw new RPCException (procedure, "Procedure not available in game scene '" + CallContext.GameScene + "'"); object returnValue; try { returnValue = procedure.Handler.Invoke (arguments); } catch (TargetInvocationException e) { if (e.InnerException is YieldException) throw e.InnerException; throw new RPCException (procedure, e.InnerException); } var response = new Response (); if (procedure.HasReturnType) { CheckReturnValue (procedure, returnValue); response.ReturnValue = returnValue; } return response; }
/// <summary> /// Decode a serialized collection /// </summary> object DecodeCollection(ProcedureSignature procedure, int i, Type type, ByteString value) { if (TypeUtils.IsAListCollectionType (type)) { var builder = Schema.KRPC.List.CreateBuilder (); var encodedList = builder.MergeFrom (value).Build (); var list = (System.Collections.IList)(typeof(System.Collections.Generic.List<>) .MakeGenericType (type.GetGenericArguments ().Single ()) .GetConstructor (Type.EmptyTypes) .Invoke (null)); foreach (var item in encodedList.ItemsList) list.Add (Decode (procedure, i, type.GetGenericArguments ().Single (), item)); return list; } else if (TypeUtils.IsADictionaryCollectionType (type)) { var builder = Schema.KRPC.Dictionary.CreateBuilder (); var encodedDictionary = builder.MergeFrom (value).Build (); var dictionary = (System.Collections.IDictionary)(typeof(System.Collections.Generic.Dictionary<,>) .MakeGenericType (type.GetGenericArguments () [0], type.GetGenericArguments () [1]) .GetConstructor (Type.EmptyTypes) .Invoke (null)); foreach (var entry in encodedDictionary.EntriesList) { var k = Decode (procedure, i, type.GetGenericArguments () [0], entry.Key); var v = Decode (procedure, i, type.GetGenericArguments () [1], entry.Value); dictionary [k] = v; } return dictionary; } else if (TypeUtils.IsASetCollectionType (type)) { var builder = Schema.KRPC.Set.CreateBuilder (); var encodedSet = builder.MergeFrom (value).Build (); var set = (System.Collections.IEnumerable)(typeof(System.Collections.Generic.HashSet<>) .MakeGenericType (type.GetGenericArguments ().Single ()) .GetConstructor (Type.EmptyTypes) .Invoke (null)); MethodInfo methodInfo = type.GetMethod ("Add"); foreach (var item in encodedSet.ItemsList) { var decodedItem = Decode (procedure, i, type.GetGenericArguments ().Single (), item); methodInfo.Invoke (set, new [] { decodedItem }); } return set; } else { // a tuple // TODO: this is ugly var builder = Schema.KRPC.Tuple.CreateBuilder (); var encodedTuple = builder.MergeFrom (value).Build (); var valueTypes = type.GetGenericArguments ().ToArray (); var genericType = Type.GetType ("KRPC.Utils.Tuple`" + valueTypes.Length); Object[] values = new Object[valueTypes.Length]; for (int j = 0; j < valueTypes.Length; j++) { var item = encodedTuple.ItemsList [j]; values [j] = Decode (procedure, i, valueTypes [j], item); } var tuple = genericType .MakeGenericType (valueTypes) .GetConstructor (valueTypes) .Invoke (values); return tuple; } }
public object[] GetArguments (ProcedureSignature procedure, IList<Argument> arguments) { // Get list of supplied argument values and whether they were set var numParameters = procedure.Parameters.Count; var argumentValues = new object [numParameters]; var argumentSet = new BitVector32 (0); foreach (var argument in arguments) { argumentValues [argument.Position] = argument.Value; argumentSet [1 << (int)argument.Position] = true; } var mask = BitVector32.CreateMask (); for (int i = 0; i < numParameters; i++) { var value = argumentValues [i]; var parameter = procedure.Parameters [i]; var type = parameter.Type; if (!argumentSet [mask]) { // If the argument is not set, set it to the default value if (!parameter.HasDefaultValue) throw new RPCException (procedure, "Argument not specified for parameter " + parameter.Name + " in " + procedure.FullyQualifiedName + ". "); argumentValues [i] = parameter.DefaultValue; } else if (value != null && !type.IsInstanceOfType (value)) { // Check the type of the non-null argument value throw new RPCException ( procedure, "Incorrect argument type for parameter " + parameter.Name + " in " + procedure.FullyQualifiedName + ". " + "Expected an argument of type " + type + ", got " + value.GetType ()); } else if (value == null && !TypeUtils.IsAClassType (type)) { // Check the type of the null argument value throw new RPCException ( procedure, "Incorrect argument type for parameter " + parameter.Name + " in " + procedure.FullyQualifiedName + ". " + "Expected an argument of type " + type + ", got null"); } mask = BitVector32.CreateMask (mask); } return argumentValues; }
/// <summary> /// Check the value returned by a procedure handler. /// </summary> static void CheckReturnValue (ProcedureSignature procedure, object returnValue) { // Check if the type of the return value is valid if (returnValue != null && !procedure.ReturnType.IsInstanceOfType (returnValue)) { throw new RPCException ( procedure, "Incorrect value returned by " + procedure.FullyQualifiedName + ". " + "Expected a value of type " + procedure.ReturnType + ", got " + returnValue.GetType ()); } else if (returnValue == null && !TypeUtils.IsAClassType (procedure.ReturnType)) { throw new RPCException ( procedure, "Incorrect value returned by " + procedure.FullyQualifiedName + ". " + "Expected a value of type " + procedure.ReturnType + ", got null"); } }
/// <summary> /// Add a procedure to the service /// </summary> void AddProcedure(ProcedureSignature signature) { if (Procedures.ContainsKey (signature.Name)) throw new ServiceException ("Service " + Name + " contains duplicate procedures " + signature.Name); Procedures [signature.Name] = signature; }
/// <summary> /// Executes the given request and returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response HandleRequest (ProcedureSignature procedure, Request request) { return HandleRequest (procedure, GetArguments (procedure, request.Arguments)); }
/// <summary> /// Executes a request (from an array of decoded arguments) and returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response.Builder HandleRequest(ProcedureSignature procedure, object[] arguments) { if ((KRPCServer.Context.GameScene & procedure.GameScene) == 0) throw new RPCException (procedure, "Procedure not available in game scene '" + KRPCServer.Context.GameScene + "'"); object returnValue; try { returnValue = procedure.Handler.Invoke (arguments); } catch (TargetInvocationException e) { if (e.InnerException.GetType () == typeof(YieldException)) throw e.InnerException; throw new RPCException (procedure, e.InnerException); } var responseBuilder = Response.CreateBuilder (); if (procedure.HasReturnType) responseBuilder.ReturnValue = EncodeReturnValue (procedure, returnValue); return responseBuilder; }
/// <summary> /// Decode the arguments for a request /// </summary> public object[] DecodeArguments(ProcedureSignature procedure, Request request) { return DecodeArguments (procedure, request.ArgumentsList); }
/// <summary> /// Executes the given request and returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response.Builder HandleRequest(ProcedureSignature procedure, Request request) { return HandleRequest (procedure, DecodeArguments (procedure, request.ArgumentsList)); }
/// <summary> /// Executes the request, continuing using the give continuation. Returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response.Builder HandleRequest(ProcedureSignature procedure, IContinuation continuation) { object returnValue; try { returnValue = continuation.RunUntyped (); } catch (YieldException) { throw; } catch (Exception e) { throw new RPCException ("Procedure '" + procedure.FullyQualifiedName + "' threw an exception. " + e.GetType () + ": " + e.Message); } var responseBuilder = Response.CreateBuilder (); if (procedure.HasReturnType) responseBuilder.ReturnValue = EncodeReturnValue (procedure, returnValue); return responseBuilder; }
/// <summary> /// Encodes the value returned by a procedure handler into a ByteString /// </summary> ByteString EncodeReturnValue(ProcedureSignature procedure, object returnValue) { // Check the return value is missing if (returnValue == null && !TypeUtils.IsAClassType (procedure.ReturnType)) { throw new RPCException ( procedure, procedure.FullyQualifiedName + " returned null. " + "Expected an object of type " + procedure.ReturnType); } // Check if the return value is of a valid type if (!TypeUtils.IsAValidType (procedure.ReturnType)) { throw new RPCException ( procedure, procedure.FullyQualifiedName + " returned an object of an invalid type. " + "Expected " + procedure.ReturnType + "; got " + returnValue.GetType ()); } // Encode it as a ByteString return Encode (procedure.ReturnType, returnValue); }
/// <summary> /// Decode the arguments for a procedure from a serialized request /// </summary> object[] DecodeArguments(ProcedureSignature procedure, IList<Schema.KRPC.Argument> arguments) { // Rearrange argument values var argumentValues = new ByteString [procedure.Parameters.Count]; foreach (var argument in arguments) argumentValues [argument.Position] = argument.Value; var decodedArgumentValues = new object[procedure.Parameters.Count]; for (int i = 0; i < procedure.Parameters.Count; i++) { var type = procedure.Parameters [i].Type; var value = argumentValues [i]; if (value == null) { // Handle default arguments if (!procedure.Parameters [i].HasDefaultArgument) throw new RPCException (procedure, "Argument not specified for parameter " + procedure.Parameters [i].Name + " in " + procedure.FullyQualifiedName + ". "); decodedArgumentValues [i] = Type.Missing; } else { // Decode argument try { decodedArgumentValues [i] = Decode (procedure, i, type, value); } catch (Exception e) { throw new RPCException ( procedure, "Failed to decode argument for parameter " + procedure.Parameters [i].Name + " in " + procedure.FullyQualifiedName + ". " + "Expected an argument of type " + TypeUtils.GetTypeName (type) + ". " + e.GetType ().Name + ": " + e.Message); } } } return decodedArgumentValues; }
/// <summary> /// Decode a serialized value /// </summary> object Decode(ProcedureSignature procedure, int i, Type type, ByteString value) { if (TypeUtils.IsAClassType (type)) { return ObjectStore.Instance.GetInstance ((ulong)ProtocolBuffers.ReadValue (value, typeof(ulong))); } else if (TypeUtils.IsACollectionType (type)) { return DecodeCollection (procedure, i, type, value); } else if (ProtocolBuffers.IsAMessageType (type)) { var builder = procedure.ParameterBuilders [i]; builder.WeakMergeFrom (value); var built = builder.WeakBuild (); builder.WeakClear (); return built; } else if (ProtocolBuffers.IsAnEnumType (type) || TypeUtils.IsAnEnumType (type)) { // TODO: Assumes it's underlying type is int var enumValue = ProtocolBuffers.ReadValue (value, typeof(int)); if (!Enum.IsDefined (type, enumValue)) throw new RPCException (procedure, "Failed to convert value " + enumValue + " to enumeration type " + type); return Enum.ToObject (type, enumValue); } else { return ProtocolBuffers.ReadValue (value, type); } }
/// <summary> /// Executes the request, continuing using the given continuation. Returns a response builder with the relevant /// fields populated. Throws YieldException, containing a continuation, if the request yields. /// Throws RPCException if processing the request fails. /// </summary> public Response.Builder HandleRequest(ProcedureSignature procedure, IContinuation continuation) { object returnValue; try { returnValue = continuation.RunUntyped (); } catch (YieldException) { throw; } catch (Exception e) { throw new RPCException (procedure, e); } var responseBuilder = Response.CreateBuilder (); if (procedure.HasReturnType) responseBuilder.ReturnValue = EncodeReturnValue (procedure, returnValue); return responseBuilder; }
void CheckDocumentation (ProcedureSignature proc) { CheckDocumentation (proc.FullyQualifiedName, proc.Documentation); }
public Response HandleRequest (ProcedureSignature procedure, IContinuation continuation) { object returnValue; try { returnValue = continuation.RunUntyped (); } catch (YieldException) { throw; } catch (Exception e) { throw new RPCException (procedure, e); } var response = new Response (); if (procedure.HasReturnType) { CheckReturnValue (procedure, returnValue); response.ReturnValue = returnValue; } return response; }