Mono.Zeroconf – Blame information for rev 1
?pathlinks?
Rev | Author | Line No. | Line |
---|---|---|---|
1 | office | 1 | // Copyright 2006 Alp Toker <alp@atoker.com> |
2 | // This software is made available under the MIT License |
||
3 | // See COPYING for details |
||
4 | |||
5 | using System; |
||
6 | using System.Reflection; |
||
7 | using System.Reflection.Emit; |
||
8 | using System.Collections.Generic; |
||
9 | |||
10 | namespace NDesk.DBus |
||
11 | { |
||
12 | class BusObject |
||
13 | { |
||
14 | protected Connection conn; |
||
15 | string bus_name; |
||
16 | ObjectPath object_path; |
||
17 | |||
18 | //protected BusObject () |
||
19 | public BusObject () |
||
20 | { |
||
21 | } |
||
22 | |||
23 | public BusObject (Connection conn, string bus_name, ObjectPath object_path) |
||
24 | { |
||
25 | this.conn = conn; |
||
26 | this.bus_name = bus_name; |
||
27 | this.object_path = object_path; |
||
28 | } |
||
29 | |||
30 | public Connection Connection |
||
31 | { |
||
32 | get { |
||
33 | return conn; |
||
34 | } |
||
35 | } |
||
36 | |||
37 | public string BusName |
||
38 | { |
||
39 | get { |
||
40 | return bus_name; |
||
41 | } |
||
42 | } |
||
43 | |||
44 | public ObjectPath Path |
||
45 | { |
||
46 | get { |
||
47 | return object_path; |
||
48 | } |
||
49 | } |
||
50 | |||
51 | public void ToggleSignal (string iface, string member, Delegate dlg, bool adding) |
||
52 | { |
||
53 | MatchRule rule = new MatchRule (); |
||
54 | rule.MessageType = MessageType.Signal; |
||
55 | rule.Interface = iface; |
||
56 | rule.Member = member; |
||
57 | rule.Path = object_path; |
||
58 | |||
59 | if (adding) { |
||
60 | if (conn.Handlers.ContainsKey (rule)) |
||
61 | conn.Handlers[rule] = Delegate.Combine (conn.Handlers[rule], dlg); |
||
62 | else { |
||
63 | conn.Handlers[rule] = dlg; |
||
64 | conn.AddMatch (rule.ToString ()); |
||
65 | } |
||
66 | } else { |
||
67 | conn.Handlers[rule] = Delegate.Remove (conn.Handlers[rule], dlg); |
||
68 | if (conn.Handlers[rule] == null) { |
||
69 | conn.RemoveMatch (rule.ToString ()); |
||
70 | conn.Handlers.Remove (rule); |
||
71 | } |
||
72 | } |
||
73 | } |
||
74 | |||
75 | public void SendSignal (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception) |
||
76 | { |
||
77 | exception = null; |
||
78 | |||
79 | //TODO: don't ignore retVal, exception etc. |
||
80 | |||
81 | Signature outSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr); |
||
82 | |||
83 | Signal signal = new Signal (object_path, iface, member); |
||
84 | signal.message.Signature = outSig; |
||
85 | |||
86 | Message signalMsg = signal.message; |
||
87 | signalMsg.Body = writer.ToArray (); |
||
88 | |||
89 | conn.Send (signalMsg); |
||
90 | } |
||
91 | |||
92 | public object SendMethodCall (string iface, string member, string inSigStr, MessageWriter writer, Type retType, out Exception exception) |
||
93 | { |
||
94 | exception = null; |
||
95 | |||
96 | //TODO: don't ignore retVal, exception etc. |
||
97 | |||
98 | Signature inSig = String.IsNullOrEmpty (inSigStr) ? Signature.Empty : new Signature (inSigStr); |
||
99 | |||
100 | MethodCall method_call = new MethodCall (object_path, iface, member, bus_name, inSig); |
||
101 | |||
102 | Message callMsg = method_call.message; |
||
103 | callMsg.Body = writer.ToArray (); |
||
104 | |||
105 | //Invoke Code:: |
||
106 | |||
107 | //TODO: complete out parameter support |
||
108 | /* |
||
109 | Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); |
||
110 | Signature outParmSig = Signature.GetSig (outParmTypes); |
||
111 | |||
112 | if (outParmSig != Signature.Empty) |
||
113 | throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); |
||
114 | */ |
||
115 | |||
116 | Type[] outTypes = new Type[1]; |
||
117 | outTypes[0] = retType; |
||
118 | |||
119 | //we default to always requiring replies for now, even though unnecessary |
||
120 | //this is to make sure errors are handled synchronously |
||
121 | //TODO: don't hard code this |
||
122 | bool needsReply = true; |
||
123 | |||
124 | //if (mi.ReturnType == typeof (void)) |
||
125 | // needsReply = false; |
||
126 | |||
127 | callMsg.ReplyExpected = needsReply; |
||
128 | callMsg.Signature = inSig; |
||
129 | |||
130 | if (!needsReply) { |
||
131 | conn.Send (callMsg); |
||
132 | return null; |
||
133 | } |
||
134 | |||
135 | #if PROTO_REPLY_SIGNATURE |
||
136 | if (needsReply) { |
||
137 | Signature outSig = Signature.GetSig (outTypes); |
||
138 | callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; |
||
139 | } |
||
140 | #endif |
||
141 | |||
142 | Message retMsg = conn.SendWithReplyAndBlock (callMsg); |
||
143 | |||
144 | object retVal = null; |
||
145 | |||
146 | //handle the reply message |
||
147 | switch (retMsg.Header.MessageType) { |
||
148 | case MessageType.MethodReturn: |
||
149 | object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes); |
||
150 | if (retVals.Length != 0) |
||
151 | retVal = retVals[retVals.Length - 1]; |
||
152 | break; |
||
153 | case MessageType.Error: |
||
154 | //TODO: typed exceptions |
||
155 | Error error = new Error (retMsg); |
||
156 | string errMsg = String.Empty; |
||
157 | if (retMsg.Signature.Value.StartsWith ("s")) { |
||
158 | MessageReader reader = new MessageReader (retMsg); |
||
159 | errMsg = reader.ReadString (); |
||
160 | } |
||
161 | exception = new Exception (error.ErrorName + ": " + errMsg); |
||
162 | break; |
||
163 | default: |
||
164 | throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); |
||
165 | } |
||
166 | |||
167 | return retVal; |
||
168 | } |
||
169 | |||
170 | public void Invoke (MethodBase methodBase, string methodName, object[] inArgs, out object[] outArgs, out object retVal, out Exception exception) |
||
171 | { |
||
172 | outArgs = new object[0]; |
||
173 | retVal = null; |
||
174 | exception = null; |
||
175 | |||
176 | MethodInfo mi = methodBase as MethodInfo; |
||
177 | |||
178 | if (mi != null && mi.IsSpecialName && (methodName.StartsWith ("add_") || methodName.StartsWith ("remove_"))) { |
||
179 | string[] parts = methodName.Split (new char[]{'_'}, 2); |
||
180 | string ename = parts[1]; |
||
181 | Delegate dlg = (Delegate)inArgs[0]; |
||
182 | |||
183 | ToggleSignal (Mapper.GetInterfaceName (mi), ename, dlg, parts[0] == "add"); |
||
184 | |||
185 | return; |
||
186 | } |
||
187 | |||
188 | Type[] inTypes = Mapper.GetTypes (ArgDirection.In, mi.GetParameters ()); |
||
189 | Signature inSig = Signature.GetSig (inTypes); |
||
190 | |||
191 | MethodCall method_call; |
||
192 | Message callMsg; |
||
193 | |||
194 | //build the outbound method call message |
||
195 | { |
||
196 | //this bit is error-prone (no null checking) and will need rewriting when DProxy is replaced |
||
197 | string iface = null; |
||
198 | if (mi != null) |
||
199 | iface = Mapper.GetInterfaceName (mi); |
||
200 | |||
201 | //map property accessors |
||
202 | //TODO: this needs to be done properly, not with simple String.Replace |
||
203 | //note that IsSpecialName is also for event accessors, but we already handled those and returned |
||
204 | if (mi != null && mi.IsSpecialName) { |
||
205 | methodName = methodName.Replace ("get_", "Get"); |
||
206 | methodName = methodName.Replace ("set_", "Set"); |
||
207 | } |
||
208 | |||
209 | method_call = new MethodCall (object_path, iface, methodName, bus_name, inSig); |
||
210 | |||
211 | callMsg = method_call.message; |
||
212 | |||
213 | if (inArgs != null && inArgs.Length != 0) { |
||
214 | MessageWriter writer = new MessageWriter (Connection.NativeEndianness); |
||
215 | writer.connection = conn; |
||
216 | |||
217 | for (int i = 0 ; i != inTypes.Length ; i++) |
||
218 | writer.Write (inTypes[i], inArgs[i]); |
||
219 | |||
220 | callMsg.Body = writer.ToArray (); |
||
221 | } |
||
222 | } |
||
223 | |||
224 | //TODO: complete out parameter support |
||
225 | /* |
||
226 | Type[] outParmTypes = Mapper.GetTypes (ArgDirection.Out, mi.GetParameters ()); |
||
227 | Signature outParmSig = Signature.GetSig (outParmTypes); |
||
228 | |||
229 | if (outParmSig != Signature.Empty) |
||
230 | throw new Exception ("Out parameters not yet supported: out_signature='" + outParmSig.Value + "'"); |
||
231 | */ |
||
232 | |||
233 | Type[] outTypes = new Type[1]; |
||
234 | outTypes[0] = mi.ReturnType; |
||
235 | |||
236 | //we default to always requiring replies for now, even though unnecessary |
||
237 | //this is to make sure errors are handled synchronously |
||
238 | //TODO: don't hard code this |
||
239 | bool needsReply = true; |
||
240 | |||
241 | //if (mi.ReturnType == typeof (void)) |
||
242 | // needsReply = false; |
||
243 | |||
244 | callMsg.ReplyExpected = needsReply; |
||
245 | callMsg.Signature = inSig; |
||
246 | |||
247 | if (!needsReply) { |
||
248 | conn.Send (callMsg); |
||
249 | return; |
||
250 | } |
||
251 | |||
252 | #if PROTO_REPLY_SIGNATURE |
||
253 | if (needsReply) { |
||
254 | Signature outSig = Signature.GetSig (outTypes); |
||
255 | callMsg.Header.Fields[FieldCode.ReplySignature] = outSig; |
||
256 | } |
||
257 | #endif |
||
258 | |||
259 | Message retMsg = conn.SendWithReplyAndBlock (callMsg); |
||
260 | |||
261 | //handle the reply message |
||
262 | switch (retMsg.Header.MessageType) { |
||
263 | case MessageType.MethodReturn: |
||
264 | object[] retVals = MessageHelper.GetDynamicValues (retMsg, outTypes); |
||
265 | if (retVals.Length != 0) |
||
266 | retVal = retVals[retVals.Length - 1]; |
||
267 | break; |
||
268 | case MessageType.Error: |
||
269 | //TODO: typed exceptions |
||
270 | Error error = new Error (retMsg); |
||
271 | string errMsg = String.Empty; |
||
272 | if (retMsg.Signature.Value.StartsWith ("s")) { |
||
273 | MessageReader reader = new MessageReader (retMsg); |
||
274 | errMsg = reader.ReadString (); |
||
275 | } |
||
276 | exception = new Exception (error.ErrorName + ": " + errMsg); |
||
277 | break; |
||
278 | default: |
||
279 | throw new Exception ("Got unexpected message of type " + retMsg.Header.MessageType + " while waiting for a MethodReturn or Error"); |
||
280 | } |
||
281 | |||
282 | return; |
||
283 | } |
||
284 | |||
285 | public static object GetObject (Connection conn, string bus_name, ObjectPath object_path, Type declType) |
||
286 | { |
||
287 | Type proxyType = TypeImplementer.GetImplementation (declType); |
||
288 | |||
289 | BusObject inst = (BusObject)Activator.CreateInstance (proxyType); |
||
290 | inst.conn = conn; |
||
291 | inst.bus_name = bus_name; |
||
292 | inst.object_path = object_path; |
||
293 | |||
294 | return inst; |
||
295 | } |
||
296 | |||
297 | public Delegate GetHookupDelegate (EventInfo ei) |
||
298 | { |
||
299 | DynamicMethod hookupMethod = TypeImplementer.GetHookupMethod (ei); |
||
300 | Delegate d = hookupMethod.CreateDelegate (ei.EventHandlerType, this); |
||
301 | return d; |
||
302 | } |
||
303 | } |
||
304 | } |