2 // CustomPeerResolverService.cs
5 // Marcos Cobena (marcoscobena@gmail.com)
6 // Atsushi Enomoto <atsushi@ximian.com>
8 // Copyright 2007 Marcos Cobena (http://www.youcannoteatbits.org/)
10 // Copyright (C) 2009 Novell, Inc (http://www.novell.com)
12 // Permission is hereby granted, free of charge, to any person obtaining
13 // a copy of this software and associated documentation files (the
14 // "Software"), to deal in the Software without restriction, including
15 // without limitation the rights to use, copy, modify, merge, publish,
16 // distribute, sublicense, and/or sell copies of the Software, and to
17 // permit persons to whom the Software is furnished to do so, subject to
18 // the following conditions:
20 // The above copyright notice and this permission notice shall be
21 // included in all copies or substantial portions of the Software.
23 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
24 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
25 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
26 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
27 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
28 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
29 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
32 using System.Collections.Generic;
35 using System.Net.Sockets;
36 using System.Transactions;
39 namespace System.ServiceModel.PeerResolvers
42 [MonoTODO ("Implement cleanup and refresh")]
43 // FIXME: TransactionTimeout must be null by-default.
44 [ServiceBehavior (AutomaticSessionShutdown = true, ConcurrencyMode = ConcurrencyMode.Multiple,
45 InstanceContextMode = InstanceContextMode.Single, ReleaseServiceInstanceOnTransactionComplete = true,
46 TransactionIsolationLevel = IsolationLevel.Unspecified, /*TransactionTimeout = null, */
47 UseSynchronizationContext = false, ValidateMustUnderstand = true)]
48 public class CustomPeerResolverService : IPeerResolverContract
52 // Maybe it's worth to change List<T> for a better distributed and faster collection.
53 List<Node> mesh = new List<Node> ();
54 object mesh_lock = new object ();
55 Timer refresh_timer, cleanup_timer;
56 DateTime last_refresh_time = DateTime.Now;
58 public CustomPeerResolverService ()
60 refresh_timer = new Timer () { AutoReset = true };
61 RefreshInterval = new TimeSpan (0, 10, 0);
62 refresh_timer.Elapsed += delegate {
65 cleanup_timer = new Timer () { AutoReset = true };
66 CleanupInterval = new TimeSpan (0, 1, 0);
67 cleanup_timer.Elapsed += delegate {
70 control_shape = false;
74 public TimeSpan CleanupInterval {
75 get { return TimeSpan.FromMilliseconds ((int) cleanup_timer.Interval); }
77 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
78 throw new ArgumentOutOfRangeException (
79 "The interval is either zero or greater than max value.");
81 throw new InvalidOperationException ("The interval must be set before it is opened");
83 cleanup_timer.Interval = value.TotalMilliseconds;
87 public bool ControlShape {
88 get { return control_shape; }
89 set { control_shape = value; }
92 public TimeSpan RefreshInterval {
93 get { return TimeSpan.FromMilliseconds ((int) refresh_timer.Interval); }
95 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
96 throw new ArgumentOutOfRangeException (
97 "The interval is either zero or greater than max value.");
99 throw new InvalidOperationException ("The interval must be set before it is opened");
101 refresh_timer.Interval = value.TotalMilliseconds;
105 [MonoTODO ("Do we have to unregister nodes here?")]
106 public virtual void Close ()
109 throw new InvalidOperationException ("The service has never been opened or it was closed by a previous call to this method.");
110 refresh_timer.Stop ();
111 cleanup_timer.Stop ();
115 public virtual ServiceSettingsResponseInfo GetServiceSettings ()
118 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
120 // return new ServiceSettingsResponseInfo ();
121 throw new NotImplementedException ();
124 public virtual void Open ()
126 if ((CleanupInterval == TimeSpan.Zero) || (RefreshInterval == TimeSpan.Zero))
127 throw new ArgumentException ("Cleanup interval or refresh interval are set to a time span interval of zero.");
130 throw new InvalidOperationException ("The service has been started by a previous call to this method.");
134 refresh_timer.Start ();
135 cleanup_timer.Start ();
139 public virtual RefreshResponseInfo Refresh (RefreshInfo refreshInfo)
141 if (refreshInfo == null)
142 throw new ArgumentException ("Refresh info cannot be null.");
145 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
147 var node = mesh.FirstOrDefault (n => n.MeshId == refreshInfo.MeshId && n.RegistrationId.Equals (refreshInfo.RegistrationId));
149 return new RefreshResponseInfo (TimeSpan.Zero, RefreshResult.RegistrationNotFound);
151 // FIXME: implement actual refresh.
152 last_refresh_time = DateTime.Now;
154 return new RefreshResponseInfo (RefreshInterval - (DateTime.Now - last_refresh_time), RefreshResult.Success);
157 public virtual RegisterResponseInfo Register (RegisterInfo registerInfo)
159 if (registerInfo == null)
160 throw new ArgumentException ("Register info cannot be null.");
163 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
165 return Register (registerInfo.ClientId, registerInfo.MeshId, registerInfo.NodeAddress);
168 public virtual RegisterResponseInfo Register (Guid clientId, string meshId, PeerNodeAddress address)
170 Node n = new Node () { RegistrationId = Guid.NewGuid (), MeshId = meshId, ClientId = clientId, NodeAddress = address };
171 RegisterResponseInfo rri = new RegisterResponseInfo ();
172 rri.RegistrationId = n.RegistrationId;
179 public virtual ResolveResponseInfo Resolve (ResolveInfo resolveInfo)
181 ResolveResponseInfo rri = new ResolveResponseInfo ();
182 if (resolveInfo == null)
183 throw new ArgumentException ("Resolve info cannot be null.");
186 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
188 foreach (var node in mesh)
189 if (node.MeshId == resolveInfo.MeshId &&
190 node.ClientId == resolveInfo.ClientId)
191 rri.Addresses.Add (node.NodeAddress);
196 public virtual void Unregister (UnregisterInfo unregisterInfo)
198 if (unregisterInfo == null)
199 throw new ArgumentException ("Unregister info cannot be null.");
202 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
205 foreach (var node in mesh)
206 if (node.MeshId == unregisterInfo.MeshId &&
207 node.RegistrationId == unregisterInfo.RegistrationId) {
214 public virtual RegisterResponseInfo Update (UpdateInfo updateInfo)
216 if (updateInfo == null)
217 throw new ArgumentException ("Update info cannot be null.");
220 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
222 // return new RegisterResponseInfo ();
223 throw new NotImplementedException ();
229 public Guid ClientId { get; set; }
230 public string MeshId { get; set; }
231 public Guid RegistrationId { get; set; }
232 public PeerNodeAddress NodeAddress { get; set; }
236 [MonoTODO ("Implement cleanup and refresh")]
237 // FIXME: TransactionTimeout must be null by-default.
238 [ServiceBehavior (AutomaticSessionShutdown = true, ConcurrencyMode = ConcurrencyMode.Multiple,
239 InstanceContextMode = InstanceContextMode.Single, ReleaseServiceInstanceOnTransactionComplete = true,
240 TransactionIsolationLevel = IsolationLevel.Unspecified, /*TransactionTimeout = null, */
241 UseSynchronizationContext = false, ValidateMustUnderstand = true)]
242 public class CustomPeerResolverService : IPeerResolverContract
244 static ServiceHost localhost;
246 static void SetupCustomPeerResolverServiceHost ()
248 // launch peer resolver service locally only when it does not seem to be running ...
249 var t = new TcpListener (8931);
256 Console.WriteLine ("WARNING: it is running peer resolver service locally. This means, the node registration is valid only within this application domain...");
257 var host = new ServiceHost (new LocalPeerResolverService (TextWriter.Null));
258 host.Description.Behaviors.Find<ServiceBehaviorAttribute> ().InstanceContextMode = InstanceContextMode.Single;
259 host.AddServiceEndpoint (typeof (ICustomPeerResolverContract), new BasicHttpBinding (), "http://localhost:8931");
264 ICustomPeerResolverClient client;
265 bool control_shape, opened;
266 TimeSpan refresh_interval, cleanup_interval;
268 public CustomPeerResolverService ()
270 client = ChannelFactory<ICustomPeerResolverClient>.CreateChannel (new BasicHttpBinding (), new EndpointAddress ("http://localhost:8931"));
272 refresh_interval = new TimeSpan (0, 10, 0);
273 cleanup_interval = new TimeSpan (0, 1, 0);
276 public TimeSpan CleanupInterval {
277 get { return cleanup_interval; }
279 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
280 throw new ArgumentOutOfRangeException (
281 "The interval is either zero or greater than max value.");
283 throw new InvalidOperationException ("The interval must be set before it is opened");
285 cleanup_interval = value;
289 public bool ControlShape {
290 get { return control_shape; }
293 throw new InvalidOperationException ("The interval must be set before it is opened");
294 control_shape = value;
298 public TimeSpan RefreshInterval {
299 get { return refresh_interval; }
301 if ((value < TimeSpan.Zero) || (value > TimeSpan.MaxValue))
302 throw new ArgumentOutOfRangeException (
303 "The interval is either zero or greater than max value.");
305 throw new InvalidOperationException ("The interval must be set before it is opened");
307 refresh_interval = value;
311 [MonoTODO ("Do we have to unregister nodes here?")]
312 public virtual void Close ()
315 throw new InvalidOperationException ("The service has never been opened or it was closed by a previous call to this method.");
319 if (localhost != null) {
325 public virtual ServiceSettingsResponseInfo GetServiceSettings ()
328 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
330 return client.GetServiceSettings ();
333 public virtual void Open ()
335 if (localhost == null)
336 SetupCustomPeerResolverServiceHost ();
338 if ((CleanupInterval == TimeSpan.Zero) || (RefreshInterval == TimeSpan.Zero))
339 throw new ArgumentException ("Cleanup interval or refresh interval are set to a time span interval of zero.");
342 throw new InvalidOperationException ("The service has been started by a previous call to this method.");
347 client.SetCustomServiceSettings (new PeerServiceSettingsInfo () { ControlMeshShape = control_shape, RefreshInterval = refresh_interval, CleanupInterval = cleanup_interval });
350 public virtual RefreshResponseInfo Refresh (RefreshInfo refreshInfo)
352 if (refreshInfo == null)
353 throw new ArgumentException ("Refresh info cannot be null.");
356 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
358 return client.Refresh (refreshInfo);
361 public virtual RegisterResponseInfo Register (RegisterInfo registerInfo)
363 if (registerInfo == null)
364 throw new ArgumentException ("Register info cannot be null.");
367 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
369 return client.Register (registerInfo);
372 public virtual RegisterResponseInfo Register (Guid clientId, string meshId, PeerNodeAddress address)
374 return Register (new RegisterInfo (clientId, meshId, address));
377 public virtual ResolveResponseInfo Resolve (ResolveInfo resolveInfo)
379 if (resolveInfo == null)
380 throw new ArgumentException ("Resolve info cannot be null.");
383 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
385 return client.Resolve (resolveInfo);
388 public virtual void Unregister (UnregisterInfo unregisterInfo)
390 if (unregisterInfo == null)
391 throw new ArgumentException ("Unregister info cannot be null.");
394 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
396 client.Unregister (unregisterInfo);
399 public virtual RegisterResponseInfo Update (UpdateInfo updateInfo)
401 if (updateInfo == null)
402 throw new ArgumentException ("Update info cannot be null.");
405 throw new InvalidOperationException ("The service has never been opened or it was closed previously.");
407 return client.Update (updateInfo);