//this might need reworking with MulticastDelegate internal void HandleSignal(Message msg) { Signal signal = new Signal(msg); //TODO: this is a hack, not necessary when MatchRule is complete MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Interface = signal.Interface; rule.Member = signal.Member; rule.Path = signal.Path; Delegate dlg; if (Handlers.TryGetValue(rule, out dlg)) { //dlg.DynamicInvoke (GetDynamicValues (msg)); MethodInfo mi = dlg.Method; //signals have no return value dlg.DynamicInvoke(MessageHelper.GetDynamicValues(msg, mi.GetParameters())); } else { //TODO: how should we handle this condition? sending an Error may not be appropriate in this case if (Protocol.Verbose) { Console.Error.WriteLine("Warning: No signal handler for " + signal.Member); } } }
public override void HandleMethodCall(MethodCall method_call) { //object retVal = obj.GetType ().InvokeMember (method_call.Member, BindingFlags.InvokeMethod, null, obj, new object[0]); //IDynamicMetaObjectProvider idyn = obj as IDynamicMetaObjectProvider; object retVal = null; Exception raisedException = null; try { object[] args = MessageHelper.GetDynamicValues(method_call.message); retVal = ops.InvokeMember(obj, method_call.Member, args); //retVal = ops.Call (ops.GetMember (obj, method_call.Member), args); } catch (Exception e) { raisedException = e; } if (!method_call.message.ReplyExpected) { return; } Message msg = method_call.message; Message replyMsg = null; if (raisedException == null) { MethodReturn method_return = new MethodReturn(msg.Header.Serial); replyMsg = method_return.message; if (retVal != null) { if (retVal.GetType().FullName == "IronRuby.Builtins.MutableString") { retVal = retVal.ToString(); } // TODO: Invalid sig handling Signature outSig = Signature.GetSig(retVal.GetType()); MessageWriter retWriter = new MessageWriter(); retWriter.Write(retVal.GetType(), retVal); //retWriter.WriteValueType (retVal, retVal.GetType ()); replyMsg.Body = retWriter.ToArray(); replyMsg.Signature = outSig; } } else { Error error = method_call.CreateError(Mapper.GetInterfaceName(raisedException.GetType()), raisedException.Message); replyMsg = error.message; } if (method_call.Sender != null) { replyMsg.Header[FieldCode.Destination] = method_call.Sender; } conn.Send(replyMsg); }
//GetDynamicValues() should probably use yield eventually public static object[] GetDynamicValues(Message msg, ParameterInfo[] parms) { //TODO: consider out parameters Type[] types = new Type[parms.Length]; for (int i = 0; i != parms.Length; i++) { types[i] = parms[i].ParameterType; } return(MessageHelper.GetDynamicValues(msg, types)); }
public void HandleMethodCall(MethodCall method_call) { Type type = obj.GetType(); //object retObj = type.InvokeMember (msg.Member, BindingFlags.InvokeMethod, null, obj, MessageHelper.GetDynamicValues (msg)); //TODO: there is no member name mapping for properties etc. yet MethodInfo mi = Mapper.GetMethod(type, method_call); if (mi == null) { conn.MaybeSendUnknownMethodError(method_call); return; } object retObj = null; object[] parmValues = MessageHelper.GetDynamicValues(method_call.message, mi.GetParameters()); try { retObj = mi.Invoke(obj, parmValues); } catch (TargetInvocationException e) { if (!method_call.message.ReplyExpected) { return; } Exception ie = e.InnerException; //TODO: complete exception sending support Error error = new Error(Mapper.GetInterfaceName(ie.GetType()), method_call.message.Header.Serial); error.message.Signature = new Signature(DType.String); MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.connection = conn; writer.Write(ie.Message); error.message.Body = writer.ToArray(); //TODO: we should be more strict here, but this fallback was added as a quick fix for p2p if (method_call.Sender != null) { error.message.Header.Fields[FieldCode.Destination] = method_call.Sender; } conn.Send(error.message); return; } if (method_call.message.ReplyExpected) { Message reply = MessageHelper.ConstructDynamicReply(method_call, mi, retObj, parmValues); conn.Send(reply); } }
public void Invoke(MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) { outArgs = new object[0]; retVal = null; exception = null; MethodInfo mi = methodBase as MethodInfo; if (mi != null && mi.IsSpecialName && (methodName.StartsWith("add_") || methodName.StartsWith("remove_"))) { string[] parts = methodName.Split(new char[] { '_' }, 2); string ename = parts[1]; Delegate dlg = (Delegate)inArgs[0]; MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Interface = Mapper.GetInterfaceName(mi); rule.Member = ename; rule.Path = object_path; if (parts[0] == "add") { if (conn.Handlers.ContainsKey(rule)) { conn.Handlers[rule] = Delegate.Combine(conn.Handlers[rule], dlg); } else { conn.Handlers[rule] = dlg; conn.AddMatch(rule.ToString()); } } else if (parts[0] == "remove") { conn.Handlers[rule] = Delegate.Remove(conn.Handlers[rule], dlg); if (conn.Handlers[rule] == null) { conn.RemoveMatch(rule.ToString()); conn.Handlers.Remove(rule); } } return; } Type[] inTypes = Mapper.GetTypes(ArgDirection.In, mi.GetParameters()); Signature inSig = Signature.GetSig(inTypes); MethodCall method_call; Message callMsg; //build the outbound method call message { //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced string iface = null; if (mi != null) { iface = Mapper.GetInterfaceName(mi); } //map property accessors //TODO: this needs to be done properly, not with simple String.Replace //note that IsSpecialName is also for event accessors, but we already handled those and returned if (mi != null && mi.IsSpecialName) { methodName = methodName.Replace("get_", "Get"); methodName = methodName.Replace("set_", "Set"); } method_call = new MethodCall(object_path, iface, methodName, bus_name, inSig); callMsg = method_call.message; if (inArgs != null && inArgs.Length != 0) { MessageWriter writer = new MessageWriter(Connection.NativeEndianness); writer.connection = conn; for (int i = 0; i != inTypes.Length; i++) { writer.Write(inTypes[i], inArgs[i]); } callMsg.Body = writer.ToArray(); } } //TODO: complete out parameter support Type[] outParmTypes = Mapper.GetTypes(ArgDirection.Out, mi.GetParameters()); Signature outParmSig = Signature.GetSig(outParmTypes); if (outParmSig != Signature.Empty) { throw new Exception("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); } Type[] outTypes = new Type[1]; outTypes[0] = mi.ReturnType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send(callMsg); return; } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig(outTypes); callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock(callMsg); //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues(retMsg, outTypes); if (retVals.Length != 0) { retVal = retVals[retVals.Length - 1]; } break; case MessageType.Error: //TODO: typed exceptions Error error = new Error(retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(retMsg); reader.GetValue(out errMsg); } exception = new Exception(error.ErrorName + ": " + errMsg); break; default: throw new Exception("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return; }
public object SendMethodCall(string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception) { exception = null; //TODO: don't ignore retVal, exception etc. Signature inSig = String.IsNullOrEmpty(inSigStr) ? Signature.Empty : new Signature(inSigStr); MethodCall method_call = new MethodCall(object_path, iface, member, bus_name, inSig); Message callMsg = method_call.message; callMsg.Body = writer.ToArray(); //Invoke Code:: //TODO: complete out parameter support /* * Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); * Signature outParmSig = Signature.GetSig (outParmTypes); * * if (outParmSig != Signature.Empty) * throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); */ Type[] outTypes = new Type[1]; outTypes[0] = retType; //we default to always requiring replies for now, even though unnecessary //this is to make sure errors are handled synchronously //TODO: don't hard code this bool needsReply = true; //if (mi.ReturnType == typeof (void)) // needsReply = false; callMsg.ReplyExpected = needsReply; callMsg.Signature = inSig; if (!needsReply) { conn.Send(callMsg); return(null); } #if PROTO_REPLY_SIGNATURE if (needsReply) { Signature outSig = Signature.GetSig(outTypes); callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; } #endif Message retMsg = conn.SendWithReplyAndBlock(callMsg); object retVal = null; //handle the reply message switch (retMsg.Header.MessageType) { case MessageType.MethodReturn: object[] retVals = MessageHelper.GetDynamicValues(retMsg, outTypes); if (retVals.Length != 0) { retVal = retVals[retVals.Length - 1]; } break; case MessageType.Error: //TODO: typed exceptions Error error = new Error(retMsg); string errMsg = String.Empty; if (retMsg.Signature.Value.StartsWith("s")) { MessageReader reader = new MessageReader(retMsg); errMsg = reader.ReadString(); } exception = new Exception(error.ErrorName + ": " + errMsg); break; default: throw new Exception("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); } return(retVal); }
//this might need reworking with MulticastDelegate internal void HandleSignal(Message msg) { Signal signal = new Signal(msg); //TODO: this is a hack, not necessary when MatchRule is complete MatchRule rule = new MatchRule(); rule.MessageType = MessageType.Signal; rule.Fields.Add(FieldCode.Interface, new MatchTest(signal.Interface)); rule.Fields.Add(FieldCode.Member, new MatchTest(signal.Member)); rule.Fields.Add(FieldCode.Path, new MatchTest(signal.Path)); Delegate dlg; if (Handlers.TryGetValue(rule, out dlg)) { MethodInfo mi = dlg.GetType().GetMethod("Invoke"); bool compatible = false; Signature inSig, outSig; if (TypeImplementer.SigsForMethod(mi, out inSig, out outSig)) { if (outSig == Signature.Empty && inSig == msg.Signature) { compatible = true; } } if (!compatible) { if (Protocol.Verbose) { Console.Error.WriteLine("Signal argument mismatch: " + signal.Interface + '.' + signal.Member); } return; } try { //signals have no return value dlg.DynamicInvoke(MessageHelper.GetDynamicValues(msg, mi.GetParameters())); } catch (MemberAccessException) { throw; } catch (TargetInvocationException) { if (Protocol.Verbose) { Console.Error.WriteLine("Error: Signal handler threw exception " + signal.Member); } } } else { //TODO: how should we handle this condition? sending an Error may not be appropriate in this case if (Protocol.Verbose) { Console.Error.WriteLine("Warning: No signal handler for " + signal.Member); } } }