From a1118a8f4634d56431aa07b1e842b58c1b9c59e2 Mon Sep 17 00:00:00 2001 From: Fady Salama Date: Thu, 8 Feb 2024 13:27:44 +0100 Subject: [PATCH] add documentation of implementation --- WoT/Errors.cs | 22 +++--- WoT/SimpleHTTPConsumer.cs | 64 +++++++++++++---- WoT/WoT.cs | 144 +++++++++++++++++++++++++++++++++++++- 3 files changed, 204 insertions(+), 26 deletions(-) diff --git a/WoT/Errors.cs b/WoT/Errors.cs index 7e2e0bd..5e4ced9 100644 --- a/WoT/Errors.cs +++ b/WoT/Errors.cs @@ -4,7 +4,7 @@ namespace WoT.Errors { - class EvalError : Exception + public class EvalError : Exception { public EvalError() : base() { } public EvalError(string messsage) : base(messsage) { } @@ -15,7 +15,7 @@ public EvalError(string messsage, Exception inner) : base(messsage, inner) { } } } - class RangeError : Exception + public class RangeError : Exception { public RangeError() : base() { } public RangeError(string messsage) : base(messsage) { } @@ -26,7 +26,7 @@ public RangeError(string messsage, Exception inner) : base(messsage, inner) { } } } - class ReferenceError : Exception + public class ReferenceError : Exception { public ReferenceError() : base() { } public ReferenceError(string messsage) : base(messsage) { } @@ -37,7 +37,7 @@ public ReferenceError(string messsage, Exception inner) : base(messsage, inner) } } - class TypeError : Exception + public class TypeError : Exception { public TypeError() : base() { } public TypeError(string messsage) : base(messsage) { } @@ -47,7 +47,7 @@ public TypeError(string messsage, Exception inner) : base(messsage, inner) { } return $"TypeError: {this.Message}"; } } - class URIError : Exception + public class URIError : Exception { public URIError() : base() { } public URIError(string messsage) : base(messsage) { } @@ -58,7 +58,7 @@ public URIError(string messsage, Exception inner) : base(messsage, inner) { } } } - class NotFoundError : Exception + public class NotFoundError : Exception { public NotFoundError() : base() { } public NotFoundError(string messsage) : base(messsage) { } @@ -69,7 +69,7 @@ public NotFoundError(string messsage, Exception inner) : base(messsage, inner) { } } - class NotSupportedError : Exception + public class NotSupportedError : Exception { public NotSupportedError() : base() { } public NotSupportedError(string messsage) : base(messsage) { } @@ -80,7 +80,7 @@ public NotSupportedError(string messsage, Exception inner) : base(messsage, inne } } - class SyntaxErrpr : Exception + public class SyntaxErrpr : Exception { public SyntaxErrpr() : base() { } public SyntaxErrpr(string messsage) : base(messsage) { } @@ -91,7 +91,7 @@ public SyntaxErrpr(string messsage, Exception inner) : base(messsage, inner) { } } } - class NotReadableError: Exception + public class NotReadableError: Exception { public NotReadableError() : base() { } public NotReadableError(string messsage) : base(messsage) { } @@ -102,7 +102,7 @@ public NotReadableError(string messsage, Exception inner) : base(messsage, inner } } - class OperationError : Exception + public class OperationError : Exception { public OperationError() : base() { } public OperationError(string messsage) : base(messsage) { } @@ -113,7 +113,7 @@ public OperationError(string messsage, Exception inner) : base(messsage, inner) } } - class NotAllowedError : Exception + public class NotAllowedError : Exception { public NotAllowedError() : base() { } public NotAllowedError(string messsage) : base(messsage) { } diff --git a/WoT/SimpleHTTPConsumer.cs b/WoT/SimpleHTTPConsumer.cs index 8dfa7ed..b0bccdf 100644 --- a/WoT/SimpleHTTPConsumer.cs +++ b/WoT/SimpleHTTPConsumer.cs @@ -14,17 +14,22 @@ namespace WoT.Implementation { - public class SimpleHTTPConsumer : IConsumer, IDiscovery + /// + /// A simple WoT Consumer that is capable of requesting TDs only from HTTP resources und consumes them to generate + /// + public class SimpleHTTPConsumer : IConsumer, IRequester { private readonly JsonSerializer _serializer; public readonly HttpClient httpClient; + /// public SimpleHTTPConsumer() { httpClient = new HttpClient(); _serializer = new JsonSerializer(); } + public async Task Consume(ThingDescription td) { Task task = Task.Run(() => @@ -68,6 +73,12 @@ public async Task RequestThingDescription(Uri tdUrl) } } + /// + /// A representation of a consumed Thing that is capable of interacting only with HTTP resources. + /// + /// + /// This simple Consumed Thing class can only handle HTTP request and responses, "application/json" content type, and "observeproperty" and "subscribeevent" using long polling + /// public class SimpleConsumedThing : IConsumedThing { @@ -81,7 +92,6 @@ public SimpleConsumedThing(ThingDescription td, SimpleHTTPConsumer consumer) _consumer = consumer; _activeSubscriptions = new Dictionary(); _activeObservations = new Dictionary(); - } /****************************************************** Action Operations ******************************************************/ @@ -192,7 +202,7 @@ public async Task> InvokeAction(string actionName, U } /****************************************************** Property Operations ******************************************************/ - + public async Task> ReadProperty(string propertyName, InteractionOptions? options = null) { var properties = this._td.Properties; @@ -201,17 +211,17 @@ public async Task> ReadProperty(string propertyName, In if (!properties.TryGetValue(propertyName, out var propertyAffordance)) { // 4. If interaction is undefined, reject promise with a NotFoundError and stop. - throw new Exception($"Property {propertyName} not found in TD with ID {_td.Id}"); + throw new NotFoundError($"Property {propertyName} not found in TD with ID {_td.Id}"); } else { - if (propertyAffordance.WriteOnly == true) throw new Exception($"Cannot read writeOnly property {propertyName}"); + if (propertyAffordance.WriteOnly == true) throw new NotAllowedError($"Cannot read writeOnly property {propertyName}"); // find suitable form form = FindSuitableForm(propertyAffordance.Forms, "readproperty", "http", options); // Handle UriVariables if (options.HasValue && options.Value.uriVariables != null) form = HandleUriVariables(form, options.Value.uriVariables); - if (form == null) throw new Exception($"Could not find a form that allows reading property {propertyName}"); + if (form == null) throw new NotFoundError($"Could not find a form that allows reading property {propertyName}"); HttpResponseMessage interactionResponse = await _consumer.httpClient.GetAsync(form.Href); interactionResponse.EnsureSuccessStatusCode(); Stream responseStream = await interactionResponse.Content.ReadAsStreamAsync(); @@ -593,19 +603,34 @@ public async Task SubscribeEvent(string eventName, Action 0 || _activeSubscriptions.Count > 0; - } + /// + /// Indicates if there are active subscriptions for observations or events + /// + /// + /// wether there are active subscriptions + /// + public bool HasActiveListeners { get => _activeObservations.Count > 0 || _activeSubscriptions.Count > 0; } + + /// + /// Add credentials for a Thing with given ID + /// + /// Thing ID + /// + /// public void AddCredentials(string id, string password) { - + throw new NotImplementedException(); } + /// + /// Removes credentials for a Thing with given ID + /// + /// Thing ID + /// public void RemoveCredentials(string id) { - + throw new NotImplementedException (); } protected Form HandleUriVariables(Form form, Dictionary uriVariavles) @@ -667,7 +692,7 @@ public InteractionOutput(Form form) } public Stream Data => null; - public bool DataUsed => true; + public bool DataUsed => false; public Form Form => _form; @@ -682,6 +707,11 @@ public Task Value() return null; } } + + /// + /// An implementation of + /// + /// output data type public class InteractionOutput : IInteractionOutput { private readonly Form _form; @@ -798,6 +828,10 @@ public async Task Value() return await task; } } + + /// + /// An implementation of + /// public class Subscription : ISubscription { private readonly SubscriptionType _type; @@ -811,6 +845,10 @@ public class Subscription : ISubscription public event EventHandler StopEvent; public event EventHandler StopObservation; + + /// + /// Subscription Types + /// public enum SubscriptionType { Event, diff --git a/WoT/WoT.cs b/WoT/WoT.cs index afe14d1..a4bd9ee 100644 --- a/WoT/WoT.cs +++ b/WoT/WoT.cs @@ -3,6 +3,7 @@ using System.IO; using System.Threading.Tasks; using WoT.Definitions; +using WoT.Errors; namespace WoT { @@ -67,14 +68,53 @@ public interface IServient: IConsumer, IProducer, IDiscovery /// /// An interface for InteractionOutputs with no output data /// + /// + /// As this InteractionOutput interface represents and output with no data, all properties of this interface will be set to null + /// public interface IInteractionOutput { - + /// + /// Represents the raw payload in WoT Interactions as a + /// + /// + /// null + /// Stream Data { get; } + + /// + /// Tells whether the data stream has been disturbed + /// + /// + /// false + /// bool DataUsed { get; } + + /// + /// Represents the selected from the for this WoT + /// + /// + /// selected form + /// Form Form { get; } + + /// + /// Represents the of the payload. + /// + /// + /// null + /// IDataSchema Schema { get; } + + /// + /// Returns data stream as array of bytes + /// + /// that resolves with empty array Task ArrayBuffer(); + + /// + /// Parses the data returned by the WoT and returns a value with the type described by the interaction if that exists, or by the of the interaction . + /// + /// with no output Task Value(); } @@ -85,13 +125,47 @@ public interface IInteractionOutput public interface IInteractionOutput { /// - /// + /// Represents the raw payload in WoT Interactions as a /// + /// + /// output data stream + /// Stream Data { get; } + + /// + /// Tells whether the data stream has been disturbed + /// + /// + /// data stream distribution status + /// bool DataUsed { get; } + + /// + /// Represents the selected from the for this WoT + /// + /// + /// selected + /// Form Form { get; } + + /// + /// Represents the of the payload. + /// + /// + /// schema of payload used for validation + /// IDataSchema Schema { get; } + + /// + /// Returns data stream as array of bytes + /// + /// that resolves with data represented as byte[] Task ArrayBuffer(); + + /// + /// Parses the data returned by the WoT and returns a value with the type described by the interaction if that exists, or by the of the interaction . + /// + /// that resolves to data of type Task Value(); } @@ -104,6 +178,12 @@ public interface IInteractionOutput /// public interface ISubscription { + /// + /// Describes if the current Subscription is active or not + /// + /// + /// current state of Subscription + /// bool Active { get; } /// @@ -175,15 +255,60 @@ public interface IConsumedThing /// additional options for performing the interaction /// that resolves with representing value of response payload Task> InvokeAction(string actionName, U parameters, InteractionOptions? options = null); + + /// + /// Makes a request for Property value change notifications. + /// + /// type of Property value + /// name of Property to be observed + /// a callback function that is executed once a Property value change was notified; takes as input representing received data + /// additional options for performing the interaction + /// that resolves with representing the active subscription + /// Task ObserveProperty(string propertyName, Action> listener, InteractionOptions? options = null); + + /// + /// a callback function that executed if the request fails; takes as input Task ObserveProperty(string propertyName, Action> listener, Action onerror, InteractionOptions? options = null); + + /// + /// Makes a request for subscribing to Event notifications that do not provide data. + /// + /// name of Event + /// a callback function that is executed once notified. Does not take any parameters + /// additional options for performing the interaction + /// that resolves with representing the active subscription Task SubscribeEvent(string eventName, Action listener, InteractionOptions? options = null); + + /// + /// a callback function that executed if the request fails; takes as input Task SubscribeEvent(string eventName, Action listener, Action onerror, InteractionOptions? options = null); + + /// + /// Makes a request for subscribing to Event notifications that provide data. + /// + /// type of received payload data + /// name of Event + /// a callback function that is executed once notified. Takes as input representing received data + /// additional options for performing the interaction + /// that resolves with representing the active subscription Task SubscribeEvent(string eventName, Action> listener, InteractionOptions? options = null); + + /// + /// a callback function that executed if the request fails; takes as input Task SubscribeEvent(string eventName, Action> listener, Action onerror, InteractionOptions? options = null); + /// + /// Returns the of the object that represents the Thing Description of the . Applications may consult the Thing metadata stored in in order to introspect its capabilities before interacting with it. + /// + /// TD of Consumed Thing + ThingDescription GetThingDescription(); + } + /// + /// + /// public interface IExposedThing { IExposedThing SetPropertyReadHandler(string name, Action propertyReadHandler); @@ -201,10 +326,25 @@ public interface IExposedThing ThingDescription GetThingDescription(); } + + /// + /// Holds the interaction options that need to be exposed for application scripts. + /// public struct InteractionOptions { + /// + /// Represents an application hint for which Form definition, identified by this index, of the TD to use for the given WoT interaction. + /// public uint? formIndex; + + /// + /// Represents the URI template variables to be used with the WoT Interaction + /// public Dictionary uriVariables; + + /// + /// Represents additional opaque data that needs to be passed to the interaction. + /// public object data; }