Neuron®
The Neuron® is the basis for the creation of open and secure federated networks for smart societies.
Loading...
Searching...
No Matches
GeoClient.cs
1using System;
2using System.Text;
3using System.Threading.Tasks;
4using System.Xml;
5using Waher.Content;
7using Waher.Events;
10
12{
19 public class GeoClient : XmppExtension
20 {
21 private readonly string componentAddress;
22
26 public const string NamespaceGeoSpatialNeuroFoundationV1 = "urn:nf:iot:geo:1.0";
27
31 public static readonly string[] NamespacesGeoSpatial = new string[]
32 {
34 };
35
41 public static bool IsNamespaceGeoSpatial(string Namespace)
42 {
43 return Array.IndexOf(NamespacesGeoSpatial, Namespace) >= 0;
44 }
45
46 #region Construction
47
57 : base(Client)
58 {
59 this.componentAddress = ComponentAddress;
60
61 #region NeuroFoundation V1
62
63 this.client.RegisterMessageHandler("added", NamespaceGeoSpatialNeuroFoundationV1, this.AddedMessageHandler, true);
64 this.client.RegisterMessageHandler("updated", NamespaceGeoSpatialNeuroFoundationV1, this.UpdatedMessageHandler, false);
65 this.client.RegisterMessageHandler("removed", NamespaceGeoSpatialNeuroFoundationV1, this.RemovedMessageHandler, false);
66
67 #endregion
68 }
69
73 public override void Dispose()
74 {
75 #region NeuroFoundation V1
76
77 this.client.UnregisterMessageHandler("added", NamespaceGeoSpatialNeuroFoundationV1, this.AddedMessageHandler, true);
78 this.client.UnregisterMessageHandler("updated", NamespaceGeoSpatialNeuroFoundationV1, this.UpdatedMessageHandler, false);
79 this.client.UnregisterMessageHandler("removed", NamespaceGeoSpatialNeuroFoundationV1, this.RemovedMessageHandler, false);
80
81 #endregion
82
83 base.Dispose();
84 }
85
89 public override string[] Extensions => new string[] { };
90
94 public string ComponentAddress => this.componentAddress;
95
96 #endregion
97
98 #region Subscribe
99
115 public Task Subscribe(GeoPosition Min, GeoPosition Max,
116 EventHandlerAsync<SubscribedEventArgs> Callback, object State)
117 {
118 return this.Subscribe(string.Empty, Min, Max, null, Callback, State);
119 }
120
138 public Task Subscribe(GeoPosition Min, GeoPosition Max, int Ttl,
139 EventHandlerAsync<SubscribedEventArgs> Callback, object State)
140 {
141 return this.Subscribe(string.Empty, Min, Max, Ttl, Callback, State);
142 }
143
162 public Task Subscribe(string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl,
163 EventHandlerAsync<SubscribedEventArgs> Callback, object State)
164 {
165 return this.Subscribe(this.componentAddress, SubscriptionId, Min, Max, Ttl, Callback, State);
166 }
167
187 public async Task Subscribe(string ComponentAddress, string SubscriptionId,
188 GeoPosition Min, GeoPosition Max, int? Ttl,
189 EventHandlerAsync<SubscribedEventArgs> Callback, object State)
190 {
191 if (Min is null)
192 throw new ArgumentNullException(nameof(Min));
193
194 if (Max is null)
195 throw new ArgumentNullException(nameof(Max));
196
197 StringBuilder Xml = new StringBuilder();
198
199 Xml.Append("<subscribe xmlns='");
201
202 if (!string.IsNullOrEmpty(SubscriptionId))
203 {
204 Xml.Append("' id='");
205 Xml.Append(XML.Encode(SubscriptionId));
206 }
207
208 Xml.Append("' minLat='");
209 Xml.Append(CommonTypes.Encode(Min.Latitude));
210
211 Xml.Append("' minLon='");
212 Xml.Append(CommonTypes.Encode(Min.Longitude));
213
214 if (Min.Altitude.HasValue)
215 {
216 Xml.Append("' minAlt='");
217 Xml.Append(CommonTypes.Encode(Min.Altitude.Value));
218 }
219
220 Xml.Append("' maxLat='");
221 Xml.Append(CommonTypes.Encode(Max.Latitude));
222
223 Xml.Append("' maxLon='");
224 Xml.Append(CommonTypes.Encode(Max.Longitude));
225
226 if (Max.Altitude.HasValue)
227 {
228 Xml.Append("' maxAlt='");
229 Xml.Append(CommonTypes.Encode(Max.Altitude.Value));
230 }
231
232 if (Ttl.HasValue)
233 {
234 Xml.Append("' ttl='");
235 Xml.Append(Ttl.Value);
236 }
237
238 Xml.Append("'/>");
239
240 await this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (sender, e) =>
241 {
242 await Callback.Raise(this, new SubscribedEventArgs(e));
243 }, State);
244 }
245
261 public Task<SubscribedEventArgs> SubscribeAsync(GeoPosition Min, GeoPosition Max)
262 {
263 return this.SubscribeAsync(string.Empty, Min, Max, null);
264 }
265
283 public Task<SubscribedEventArgs> SubscribeAsync(GeoPosition Min, GeoPosition Max, int Ttl)
284 {
285 return this.SubscribeAsync(string.Empty, Min, Max, Ttl);
286 }
287
306 public Task<SubscribedEventArgs> SubscribeAsync(string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl)
307 {
308 return this.SubscribeAsync(this.componentAddress, SubscriptionId, Min, Max, Ttl);
309 }
310
330 public async Task<SubscribedEventArgs> SubscribeAsync(string ComponentAddress, string SubscriptionId,
331 GeoPosition Min, GeoPosition Max, int? Ttl)
332 {
333 TaskCompletionSource<SubscribedEventArgs> Result = new TaskCompletionSource<SubscribedEventArgs>();
334
335 await this.Subscribe(ComponentAddress, SubscriptionId, Min, Max, Ttl, (sender, e) =>
336 {
337 if (e.Ok)
338 Result.TrySetResult(e);
339 else
340 Result.TrySetException(e.StanzaError ?? new Exception("Unable to perform subscription."));
341
342 return Task.CompletedTask;
343 }, null);
344
345 return await Result.Task;
346 }
347
348 #endregion
349
350 #region Unsubscribe
351
358 public Task Unsubscribe(string SubscriptionId,
359 EventHandlerAsync<UnsubscribedEventArgs> Callback, object State)
360 {
361 return this.Unsubscribe(this.componentAddress, SubscriptionId, Callback, State);
362 }
363
371 public async Task Unsubscribe(string ComponentAddress, string SubscriptionId,
372 EventHandlerAsync<UnsubscribedEventArgs> Callback, object State)
373 {
374 StringBuilder Xml = new StringBuilder();
375
376 Xml.Append("<unsubscribe xmlns='");
378 Xml.Append("' id='");
379 Xml.Append(XML.Encode(SubscriptionId));
380 Xml.Append("'/>");
381
382 await this.client.SendIqSet(ComponentAddress, Xml.ToString(), async (sender, e) =>
383 {
384 await Callback.Raise(this, new UnsubscribedEventArgs(e));
385 }, State);
386 }
387
394 public Task<UnsubscribedEventArgs> UnsubscribeAsync(string SubscriptionId)
395 {
396 return this.UnsubscribeAsync(this.componentAddress, SubscriptionId);
397 }
398
406 public async Task<UnsubscribedEventArgs> UnsubscribeAsync(string ComponentAddress, string SubscriptionId)
407 {
408 TaskCompletionSource<UnsubscribedEventArgs> Result = new TaskCompletionSource<UnsubscribedEventArgs>();
409
410 await this.Unsubscribe(ComponentAddress, SubscriptionId, (sender, e) =>
411 {
412 if (e.Ok)
413 Result.TrySetResult(e);
414 else
415 Result.TrySetException(e.StanzaError ?? new Exception("Unable to perform unsubscription."));
416
417 return Task.CompletedTask;
418 }, null);
419
420 return await Result.Task;
421 }
422
423 #endregion
424
425 #region Event Notifications
426
427 private async Task AddedMessageHandler(object Sender, MessageEventArgs e)
428 {
429 string SubscriptionId = XML.Attribute(e.Content, "id");
430 GeoObjectReference Ref = ParseObjectReferenceFirstChild(e.Content);
431
432 if (!(Ref is null))
433 await this.ObjectAdded.Raise(this, new GeoObjectSubscriptionEventArgs(e, SubscriptionId, Ref));
434 }
435
439 public event EventHandlerAsync<GeoObjectSubscriptionEventArgs> ObjectAdded;
440
441 private async Task UpdatedMessageHandler(object Sender, MessageEventArgs e)
442 {
443 string SubscriptionId = XML.Attribute(e.Content, "id");
444 GeoObjectReference Ref = ParseObjectReferenceFirstChild(e.Content);
445
446 if (!(Ref is null))
447 await this.ObjectUpdated.Raise(this, new GeoObjectSubscriptionEventArgs(e, SubscriptionId, Ref));
448 }
449
453 public event EventHandlerAsync<GeoObjectSubscriptionEventArgs> ObjectUpdated;
454
455 private async Task RemovedMessageHandler(object Sender, MessageEventArgs e)
456 {
457 string SubscriptionId = XML.Attribute(e.Content, "id");
458 GeoObjectReference Ref = ParseObjectReferenceFirstChild(e.Content);
459
460 if (!(Ref is null))
461 await this.ObjectRemoved.Raise(this, new GeoObjectSubscriptionEventArgs(e, SubscriptionId, Ref));
462 }
463
467 public event EventHandlerAsync<GeoObjectSubscriptionEventArgs> ObjectRemoved;
468
469 private static GeoObjectReference ParseObjectReferenceFirstChild(XmlElement ParentXml)
470 {
471 if (ParentXml is null)
472 return null;
473
474 foreach (XmlNode Node in ParentXml.ChildNodes)
475 {
476 if (Node is XmlElement E &&
477 E.LocalName == "ref" &&
478 IsNamespaceGeoSpatial(E.NamespaceURI))
479 {
480 return ParseObjectReference(E);
481 }
482 }
483
484 return null;
485 }
486
487 private static GeoObjectReference ParseObjectReference(XmlElement Xml)
488 {
490 {
491 GeoId = XML.Attribute(Xml, "id"),
492 Creator = Xml.HasAttribute("creator") ? XML.Attribute(Xml, "creator") : null,
493 Position = new GeoPosition(
494 XML.Attribute(Xml, "lat", 0.0),
495 XML.Attribute(Xml, "lon", 0.0),
496 Xml.HasAttribute("alt") ? XML.Attribute(Xml, "alt", 0.0) : (double?)null),
497 TimeToLive = Xml.HasAttribute("ttl") ? XML.Attribute(Xml, "ttl", 0) : (int?)null,
498 Created = XML.Attribute(Xml, "created", DateTime.MinValue),
499 Updated = Xml.HasAttribute("updated") ? XML.Attribute(Xml, "updated", DateTime.MinValue) : (DateTime?)null,
500 From = Xml.HasAttribute("from") ? XML.Attribute(Xml, "from", DateTime.MinValue) : (DateTime?)null,
501 To = Xml.HasAttribute("to") ? XML.Attribute(Xml, "to", DateTime.MinValue) : (DateTime?)null
502 };
503
504 foreach (XmlNode N in Xml.ChildNodes)
505 {
506 if (N is XmlElement E)
507 {
508 Result.Definition = E;
509 break;
510 }
511 }
512
513 return Result;
514 }
515
516 #endregion
517
518 #region publish
519
520 public Task Publish(string GeoId, GeoPosition Location, int? Ttl,
521 DateTime? From, DateTime? To, string CustomXml)
522 {
523 return Task.CompletedTask; // TODO
524 }
525
526 public Task PublishAsync()
527 {
528 return Task.CompletedTask; // TODO
529 }
530
531 #endregion
532
533 #region Delete
534
535 public Task Delete()
536 {
537 return Task.CompletedTask; // TODO
538 }
539
540 public Task DeleteAsync()
541 {
542 return Task.CompletedTask; // TODO
543 }
544
545 #endregion
546
547 #region Search
548
549 public Task Search()
550 {
551 return Task.CompletedTask; // TODO
552 }
553
554 public Task SearchAsync()
555 {
556 return Task.CompletedTask; // TODO
557 }
558
559 #endregion
560 }
561}
Helps with parsing of commong data types.
Definition: CommonTypes.cs:15
static string Encode(bool x)
Encodes a Boolean for use in XML and other formats.
Definition: CommonTypes.cs:596
Helps with common XML-related tasks.
Definition: XML.cs:21
static string Attribute(XmlElement E, string Name)
Gets the value of an XML attribute.
Definition: XML.cs:1062
static string Encode(string s)
Encodes a string for use in XML.
Definition: XML.cs:29
Event arguments for message events.
XmlElement Content
Content of the message. For messages that are processed by registered message handlers,...
Adds support for geo-spatial publish/subscribe communication pattern to an XMPP client.
Definition: GeoClient.cs:20
Task Unsubscribe(string SubscriptionId, EventHandlerAsync< UnsubscribedEventArgs > Callback, object State)
Unsubscribes an existing subscription.
Definition: GeoClient.cs:358
Task Subscribe(string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl, EventHandlerAsync< SubscribedEventArgs > Callback, object State)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:162
static bool IsNamespaceGeoSpatial(string Namespace)
If a namespace corresponds to a geo-spatial namespace.
Definition: GeoClient.cs:41
Task< SubscribedEventArgs > SubscribeAsync(GeoPosition Min, GeoPosition Max)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:261
Task Subscribe(GeoPosition Min, GeoPosition Max, EventHandlerAsync< SubscribedEventArgs > Callback, object State)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:115
override string[] Extensions
Implemented extensions.
Definition: GeoClient.cs:89
string ComponentAddress
Component address.
Definition: GeoClient.cs:94
async Task< SubscribedEventArgs > SubscribeAsync(string ComponentAddress, string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:330
EventHandlerAsync< GeoObjectSubscriptionEventArgs > ObjectAdded
Event raised when object hass been added.
Definition: GeoClient.cs:439
override void Dispose()
Disposes of the extension.
Definition: GeoClient.cs:73
async Task Unsubscribe(string ComponentAddress, string SubscriptionId, EventHandlerAsync< UnsubscribedEventArgs > Callback, object State)
Unsubscribes an existing subscription.
Definition: GeoClient.cs:371
Task< SubscribedEventArgs > SubscribeAsync(string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:306
EventHandlerAsync< GeoObjectSubscriptionEventArgs > ObjectUpdated
Event raised when object hass been updated.
Definition: GeoClient.cs:453
EventHandlerAsync< GeoObjectSubscriptionEventArgs > ObjectRemoved
Event raised when object hass been updated.
Definition: GeoClient.cs:467
const string NamespaceGeoSpatialNeuroFoundationV1
urn:nf:iot:geo:1.0
Definition: GeoClient.cs:26
GeoClient(XmppClient Client, string ComponentAddress)
Adds support for geo-spatial publish/subscribe communication pattern to an XMPP client.
Definition: GeoClient.cs:56
Task< UnsubscribedEventArgs > UnsubscribeAsync(string SubscriptionId)
Unsubscribes an existing subscription.
Definition: GeoClient.cs:394
async Task Subscribe(string ComponentAddress, string SubscriptionId, GeoPosition Min, GeoPosition Max, int? Ttl, EventHandlerAsync< SubscribedEventArgs > Callback, object State)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:187
Task< SubscribedEventArgs > SubscribeAsync(GeoPosition Min, GeoPosition Max, int Ttl)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:283
async Task< UnsubscribedEventArgs > UnsubscribeAsync(string ComponentAddress, string SubscriptionId)
Unsubscribes an existing subscription.
Definition: GeoClient.cs:406
Task Subscribe(GeoPosition Min, GeoPosition Max, int Ttl, EventHandlerAsync< SubscribedEventArgs > Callback, object State)
Subscribes to geo-spatial information, or updates an existing subscription.
Definition: GeoClient.cs:138
static readonly string[] NamespacesGeoSpatial
Namespaces supported for legal identities.
Definition: GeoClient.cs:31
Represents a reference to a geo-spatial object.
Event arguments for events related to Geo-spatial objects.
Event arguments for the result of a subscription request.
Event arguments for the result of an unsubscription request.
Manages an XMPP client connection. Implements XMPP, as defined in https://tools.ietf....
Definition: XmppClient.cs:58
bool UnregisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool RemoveNamespaceAsClientFeature)
Unregisters a Message handler.
Definition: XmppClient.cs:2884
void RegisterMessageHandler(string LocalName, string Namespace, EventHandlerAsync< MessageEventArgs > Handler, bool PublishNamespaceAsClientFeature)
Registers a Message handler.
Definition: XmppClient.cs:2852
Task< uint > SendIqSet(string To, string Xml, EventHandlerAsync< IqResultEventArgs > Callback, object State)
Sends an IQ Set request.
Definition: XmppClient.cs:3646
Base class for XMPP Extensions.
XmppClient client
XMPP Client used by the extension.
void Exception(Exception Exception)
Called to inform the viewer of an exception state.
XmppClient Client
XMPP Client.
Contains information about a position in a geo-spatial coordinate system.
Definition: GeoPosition.cs:17
double Longitude
Longitude in degrees.
Definition: GeoPosition.cs:85
double? Altitude
Altitude in meters. Can be null.
Definition: GeoPosition.cs:100
double Latitude
Latitude in degrees.
Definition: GeoPosition.cs:70