From f102b89a21d04321733658da277bc66d338ac162 Mon Sep 17 00:00:00 2001 From: kunkliricsi Date: Sun, 8 Nov 2020 18:51:19 +0100 Subject: [PATCH] Added MQTT tester, added input service --- Birdmap.API/Controllers/DevicesController.cs | 5 +- Birdmap.API/Controllers/ServicesController.cs | 3 +- Birdmap.BLL/Helpers/IEnumerableExtensions.cs | 16 + Birdmap.BLL/Interfaces/IInputService.cs | 163 ++++++ ...ceBase.cs => DeviceAndInputServiceBase.cs} | 6 +- ...rvice.cs => DummyDeviceAndInputService.cs} | 56 +- Birdmap.BLL/Services/LiveInputService.cs | 477 ++++++++++++++++++ Birdmap.BLL/Startup.cs | 8 +- Birdmap.sln | 8 +- MQTTnet.TestApp.WinForm/Form1.Designer.cs | 394 +++++++++++++++ MQTTnet.TestApp.WinForm/Form1.cs | 476 +++++++++++++++++ MQTTnet.TestApp.WinForm/Form1.resx | 60 +++ MQTTnet.TestApp.WinForm/JsonServerStorage.cs | 83 +++ .../MQTTnet.TestApp.WinForm.csproj | 19 + MQTTnet.TestApp.WinForm/Program.cs | 32 ++ input.yml | 167 ++++++ 16 files changed, 1956 insertions(+), 17 deletions(-) create mode 100644 Birdmap.BLL/Helpers/IEnumerableExtensions.cs create mode 100644 Birdmap.BLL/Interfaces/IInputService.cs rename Birdmap.BLL/Services/{DeviceServiceBase.cs => DeviceAndInputServiceBase.cs} (87%) rename Birdmap.BLL/Services/{DummyDeviceService.cs => DummyDeviceAndInputService.cs} (66%) create mode 100644 Birdmap.BLL/Services/LiveInputService.cs create mode 100644 MQTTnet.TestApp.WinForm/Form1.Designer.cs create mode 100644 MQTTnet.TestApp.WinForm/Form1.cs create mode 100644 MQTTnet.TestApp.WinForm/Form1.resx create mode 100644 MQTTnet.TestApp.WinForm/JsonServerStorage.cs create mode 100644 MQTTnet.TestApp.WinForm/MQTTnet.TestApp.WinForm.csproj create mode 100644 MQTTnet.TestApp.WinForm/Program.cs create mode 100644 input.yml diff --git a/Birdmap.API/Controllers/DevicesController.cs b/Birdmap.API/Controllers/DevicesController.cs index 2791598..1cec346 100644 --- a/Birdmap.API/Controllers/DevicesController.cs +++ b/Birdmap.API/Controllers/DevicesController.cs @@ -10,7 +10,7 @@ using Microsoft.AspNetCore.Authorization; namespace Birdmap.API.Controllers { - [Authorize] + [Authorize(Roles = "Admin")] [ApiController] [Route("api/[controller]")] public class DevicesController : ControllerBase @@ -26,6 +26,7 @@ namespace Birdmap.API.Controllers /// Get all device info /// Array of devices + [Authorize(Roles = "User,Admin")] [HttpGet] public async Task>> Getall() { @@ -61,6 +62,7 @@ namespace Birdmap.API.Controllers /// Get all device info /// ID of device to query /// Information about a particular device + [Authorize(Roles = "User,Admin")] [HttpGet, Route("{deviceID}")] public async Task> Getdevice([BindRequired] Guid deviceID) { @@ -99,6 +101,7 @@ namespace Birdmap.API.Controllers /// ID of device to query /// ID of sensor to query /// Information about a sensor + [Authorize(Roles = "User,Admin")] [HttpGet, Route("{deviceID}/{sensorID}")] public async Task> Getsensor([BindRequired] Guid deviceID, [BindRequired] Guid sensorID) { diff --git a/Birdmap.API/Controllers/ServicesController.cs b/Birdmap.API/Controllers/ServicesController.cs index 6da1729..085b9fc 100644 --- a/Birdmap.API/Controllers/ServicesController.cs +++ b/Birdmap.API/Controllers/ServicesController.cs @@ -14,7 +14,7 @@ using System.Threading.Tasks; namespace Birdmap.API.Controllers { - [Authorize] + [Authorize(Roles = "Admin")] [ApiController] [Route("api/[controller]")] public class ServicesController : ControllerBase @@ -30,6 +30,7 @@ namespace Birdmap.API.Controllers _logger = logger; } + [Authorize(Roles = "User,Admin")] [HttpGet, ProducesResponseType(StatusCodes.Status200OK)] public async Task>> GetAsync() { diff --git a/Birdmap.BLL/Helpers/IEnumerableExtensions.cs b/Birdmap.BLL/Helpers/IEnumerableExtensions.cs new file mode 100644 index 0000000..a103ea2 --- /dev/null +++ b/Birdmap.BLL/Helpers/IEnumerableExtensions.cs @@ -0,0 +1,16 @@ +using System; +using System.Collections.Generic; +using System.Linq; + +namespace Birdmap.BLL.Helpers +{ + public static class IEnumerableExtensions + { + public static TSource RandomElementAt(this IEnumerable source, Random random = null) + { + random ??= new Random(); + + return source.ElementAt(random.Next(source.Count())); + } + } +} diff --git a/Birdmap.BLL/Interfaces/IInputService.cs b/Birdmap.BLL/Interfaces/IInputService.cs new file mode 100644 index 0000000..6584309 --- /dev/null +++ b/Birdmap.BLL/Interfaces/IInputService.cs @@ -0,0 +1,163 @@ +using System; +using System.Collections.Generic; +using System.Text; + +namespace Birdmap.BLL.Interfaces +{ + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial interface IInputService + { + /// Get input object by ID + /// ID of input object file + /// input object + /// A server side error occurred. + System.Threading.Tasks.Task GetInputAsync(System.Guid tagID); + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get input object by ID + /// ID of input object file + /// input object + /// A server side error occurred. + System.Threading.Tasks.Task GetInputAsync(System.Guid tagID, System.Threading.CancellationToken cancellationToken); + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class InputSingeResponse + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required] + public InputObject Message { get; set; } = new InputObject(); + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class InputResponse : System.Collections.ObjectModel.Collection + { + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class InputObject + { + [Newtonsoft.Json.JsonProperty("tag", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public System.Guid Tag { get; set; } + + [Newtonsoft.Json.JsonProperty("date", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] + public System.DateTimeOffset Date { get; set; } + + [Newtonsoft.Json.JsonProperty("device_id", Required = Newtonsoft.Json.Required.Always)] + public Guid Device_id { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class ApiResponse + { + [Newtonsoft.Json.JsonProperty("status", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Status { get; set; } + + [Newtonsoft.Json.JsonProperty("message", Required = Newtonsoft.Json.Required.Always)] + [System.ComponentModel.DataAnnotations.Required(AllowEmptyStrings = true)] + public string Message { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + public partial class Description + { + [Newtonsoft.Json.JsonProperty("deviceid", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + public string Deviceid { get; set; } + + [Newtonsoft.Json.JsonProperty("date", Required = Newtonsoft.Json.Required.DisallowNull, NullValueHandling = Newtonsoft.Json.NullValueHandling.Ignore)] + [Newtonsoft.Json.JsonConverter(typeof(DateFormatConverter))] + public System.DateTimeOffset Date { get; set; } + + private System.Collections.Generic.IDictionary _additionalProperties = new System.Collections.Generic.Dictionary(); + + [Newtonsoft.Json.JsonExtensionData] + public System.Collections.Generic.IDictionary AdditionalProperties + { + get { return _additionalProperties; } + set { _additionalProperties = value; } + } + + + } + + [System.CodeDom.Compiler.GeneratedCode("NJsonSchema", "10.2.1.0 (Newtonsoft.Json v12.0.0.0)")] + internal class DateFormatConverter : Newtonsoft.Json.Converters.IsoDateTimeConverter + { + public DateFormatConverter() + { + DateTimeFormat = "yyyy-MM-dd"; + } + } + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial class FileParameter + { + public FileParameter(System.IO.Stream data) + : this(data, null, null) + { + } + + public FileParameter(System.IO.Stream data, string fileName) + : this(data, fileName, null) + { + } + + public FileParameter(System.IO.Stream data, string fileName, string contentType) + { + Data = data; + FileName = fileName; + ContentType = contentType; + } + + public System.IO.Stream Data { get; private set; } + + public string FileName { get; private set; } + + public string ContentType { get; private set; } + } + +} diff --git a/Birdmap.BLL/Services/DeviceServiceBase.cs b/Birdmap.BLL/Services/DeviceAndInputServiceBase.cs similarity index 87% rename from Birdmap.BLL/Services/DeviceServiceBase.cs rename to Birdmap.BLL/Services/DeviceAndInputServiceBase.cs index aeab79d..9e421fa 100644 --- a/Birdmap.BLL/Services/DeviceServiceBase.cs +++ b/Birdmap.BLL/Services/DeviceAndInputServiceBase.cs @@ -6,8 +6,12 @@ using System.Threading.Tasks; namespace Birdmap.BLL.Services { - public abstract class DeviceServiceBase : IDeviceService + public abstract class DeviceAndInputServiceBase : IDeviceService, IInputService { + public virtual Task GetInputAsync(Guid tagID) + => GetInputAsync(tagID, CancellationToken.None); + public abstract Task GetInputAsync(Guid tagID, CancellationToken cancellationToken); + public virtual Task> GetallAsync() => GetallAsync(CancellationToken.None); public abstract Task> GetallAsync(CancellationToken cancellationToken); diff --git a/Birdmap.BLL/Services/DummyDeviceService.cs b/Birdmap.BLL/Services/DummyDeviceAndInputService.cs similarity index 66% rename from Birdmap.BLL/Services/DummyDeviceService.cs rename to Birdmap.BLL/Services/DummyDeviceAndInputService.cs index 617a83a..1728ae9 100644 --- a/Birdmap.BLL/Services/DummyDeviceService.cs +++ b/Birdmap.BLL/Services/DummyDeviceAndInputService.cs @@ -1,4 +1,5 @@ -using Birdmap.BLL.Interfaces; +using Birdmap.BLL.Helpers; +using Birdmap.BLL.Interfaces; using System; using System.Collections.Generic; using System.Linq; @@ -7,33 +8,40 @@ using System.Threading.Tasks; namespace Birdmap.BLL.Services { - public class DummyDeviceService : DeviceServiceBase + public class DummyDeviceAndInputService : DeviceAndInputServiceBase { + private const int numberOfDevices = 15; + private const double centerLong = 21.469640; private const double centerLat = 48.275939; private const double radius = 0.000200; - private readonly Lazy> _devices = new Lazy>(GenerateDevices); + private static readonly Random Rand = new Random(); + + private static readonly Lazy> Devices = new Lazy>(GenerateDevices); + + private static readonly Dictionary TagToInput = new Dictionary(); + private static readonly object InputLock = new object(); + private static ListOfDevices GenerateDevices() { var devices = new ListOfDevices(); - var rand = new Random(); T GetRandomEnum() { var values = Enum.GetValues(typeof(T)); - return (T)values.GetValue(rand.Next(values.Length)); + return (T)values.GetValue(Rand.Next(values.Length)); } double GetPlusMinus(double center, double radius) { - return center - radius + rand.NextDouble() * radius * 2; + return center - radius + Rand.NextDouble() * radius * 2; } - for (int d = 0; d < 15; d++) + for (int d = 0; d < numberOfDevices; d++) { var sensors = new ArrayofSensors(); - for (int s = 0; s < rand.Next(1, 5); s++) + for (int s = 0; s < Rand.Next(1, 6); s++) { sensors.Add(new Sensor { @@ -61,17 +69,17 @@ namespace Birdmap.BLL.Services public override Task> GetallAsync(CancellationToken cancellationToken) { - return Task.FromResult(_devices.Value); + return Task.FromResult(Devices.Value); } public override Task GetdeviceAsync(Guid deviceID, CancellationToken cancellationToken) { - return Task.FromResult(_devices.Value.SingleOrDefault(d => d.Id == deviceID)); + return Task.FromResult(Devices.Value.SingleOrDefault(d => d.Id == deviceID)); } public override Task GetsensorAsync(Guid deviceID, Guid sensorID, CancellationToken cancellationToken) { - return Task.FromResult(_devices.Value.SingleOrDefault(d => d.Id == deviceID)?.Sensors.SingleOrDefault(s => s.Id == sensorID)); + return Task.FromResult(Devices.Value.SingleOrDefault(d => d.Id == deviceID)?.Sensors.SingleOrDefault(s => s.Id == sensorID)); } public override Task OfflineallAsync(CancellationToken cancellationToken) @@ -114,7 +122,7 @@ namespace Birdmap.BLL.Services private void SetStatus(DeviceStatus deviceStatus, SensorStatus sensorStatus) { - foreach (var device in _devices.Value) + foreach (var device in Devices.Value) { device.Status = deviceStatus; foreach (var sensor in device.Sensors) @@ -135,5 +143,29 @@ namespace Birdmap.BLL.Services var sensor = GetsensorAsync(deviceId, sensorID).Result; sensor.Status = status; } + + public override Task GetInputAsync(Guid tagID, CancellationToken cancellationToken) + { + lock (InputLock) + { + if (!TagToInput.TryGetValue(tagID, out var value)) + { + value = new InputSingeResponse + { + Status = "Dummy_OK", + Message = new InputObject + { + Tag = tagID, + Date = DateTime.Now, + Device_id = Devices.Value.Where(d => d.Status == DeviceStatus.Online).RandomElementAt(Rand).Id, + } + }; + + TagToInput.TryAdd(tagID, value); + } + + return Task.FromResult(value); + } + } } } diff --git a/Birdmap.BLL/Services/LiveInputService.cs b/Birdmap.BLL/Services/LiveInputService.cs new file mode 100644 index 0000000..d231010 --- /dev/null +++ b/Birdmap.BLL/Services/LiveInputService.cs @@ -0,0 +1,477 @@ +//---------------------- +// +// Generated using the NSwag toolchain v13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0)) (http://NSwag.org) +// +//---------------------- + +#pragma warning disable 108 // Disable "CS0108 '{derivedDto}.ToJson()' hides inherited member '{dtoBase}.ToJson()'. Use the new keyword if hiding was intended." +#pragma warning disable 114 // Disable "CS0114 '{derivedDto}.RaisePropertyChanged(String)' hides inherited member 'dtoBase.RaisePropertyChanged(String)'. To make the current member override that implementation, add the override keyword. Otherwise add the new keyword." +#pragma warning disable 472 // Disable "CS0472 The result of the expression is always 'false' since a value of type 'Int32' is never equal to 'null' of type 'Int32?' +#pragma warning disable 1573 // Disable "CS1573 Parameter '...' has no matching param tag in the XML comment for ... +#pragma warning disable 1591 // Disable "CS1591 Missing XML comment for publicly visible type or member ..." + +namespace Birdmap.BLL.Services +{ + using Birdmap.BLL.Interfaces; + using System = global::System; + + [System.CodeDom.Compiler.GeneratedCode("NSwag", "13.8.2.0 (NJsonSchema v10.2.1.0 (Newtonsoft.Json v12.0.0.0))")] + public partial class LiveInputService : IInputService + { + private string _baseUrl = "https://birb.k8s.kmlabz.com"; + private System.Net.Http.HttpClient _httpClient; + private System.Lazy _settings; + + public LiveInputService(System.Net.Http.HttpClient httpClient) + { + _httpClient = httpClient; + _settings = new System.Lazy(CreateSerializerSettings); + } + + private Newtonsoft.Json.JsonSerializerSettings CreateSerializerSettings() + { + var settings = new Newtonsoft.Json.JsonSerializerSettings(); + UpdateJsonSerializerSettings(settings); + return settings; + } + + public string BaseUrl + { + get { return _baseUrl; } + set { _baseUrl = value; } + } + + protected Newtonsoft.Json.JsonSerializerSettings JsonSerializerSettings { get { return _settings.Value; } } + + partial void UpdateJsonSerializerSettings(Newtonsoft.Json.JsonSerializerSettings settings); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, string url); + partial void PrepareRequest(System.Net.Http.HttpClient client, System.Net.Http.HttpRequestMessage request, System.Text.StringBuilder urlBuilder); + partial void ProcessResponse(System.Net.Http.HttpClient client, System.Net.Http.HttpResponseMessage response); + + /// Get all stored input queries + /// Array of input objects + /// A server side error occurred. + public System.Threading.Tasks.Task> GetallAsync() + { + return GetallAsync(System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get all stored input queries + /// Array of input objects + /// A server side error occurred. + public async System.Threading.Tasks.Task> GetallAsync(System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync>(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("No object matching filter", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// uploads a sample into the system + /// successful operation + /// A server side error occurred. + public System.Threading.Tasks.Task UploadFileAsync(Description description, FileParameter file) + { + return UploadFileAsync(description, file, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// uploads a sample into the system + /// successful operation + /// A server side error occurred. + public async System.Threading.Tasks.Task UploadFileAsync(Description description, FileParameter file, System.Threading.CancellationToken cancellationToken) + { + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample"); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + var boundary_ = System.Guid.NewGuid().ToString(); + var content_ = new System.Net.Http.MultipartFormDataContent(boundary_); + content_.Headers.Remove("Content-Type"); + content_.Headers.TryAddWithoutValidation("Content-Type", "multipart/form-data; boundary=" + boundary_); + if (description == null) + throw new System.ArgumentNullException("description"); + else + { + content_.Add(new System.Net.Http.StringContent(ConvertToString(description, System.Globalization.CultureInfo.InvariantCulture)), "description"); + } + if (file == null) + throw new System.ArgumentNullException("file"); + else + { + var content_file_ = new System.Net.Http.StreamContent(file.Data); + if (!string.IsNullOrEmpty(file.ContentType)) + content_file_.Headers.ContentType = System.Net.Http.Headers.MediaTypeHeaderValue.Parse(file.ContentType); + content_.Add(content_file_, "file", file.FileName ?? "file"); + } + request_.Content = content_; + request_.Method = new System.Net.Http.HttpMethod("POST"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 400) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("JSON parse error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 415) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Media type error", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 417) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("JSON invalid schema", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 469) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("No file found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + if (status_ == 470) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Description missing", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + /// Get input object by ID + /// ID of input object file + /// input object + /// A server side error occurred. + public System.Threading.Tasks.Task GetInputAsync(System.Guid tagID) + { + return GetInputAsync(tagID, System.Threading.CancellationToken.None); + } + + /// A cancellation token that can be used by other objects or threads to receive notice of cancellation. + /// Get input object by ID + /// ID of input object file + /// input object + /// A server side error occurred. + public async System.Threading.Tasks.Task GetInputAsync(System.Guid tagID, System.Threading.CancellationToken cancellationToken) + { + if (tagID == null) + throw new System.ArgumentNullException("tagID"); + + var urlBuilder_ = new System.Text.StringBuilder(); + urlBuilder_.Append(BaseUrl != null ? BaseUrl.TrimEnd('/') : "").Append("/sample/{tagID}"); + urlBuilder_.Replace("{tagID}", System.Uri.EscapeDataString(ConvertToString(tagID, System.Globalization.CultureInfo.InvariantCulture))); + + var client_ = _httpClient; + var disposeClient_ = false; + try + { + using (var request_ = new System.Net.Http.HttpRequestMessage()) + { + request_.Method = new System.Net.Http.HttpMethod("GET"); + request_.Headers.Accept.Add(System.Net.Http.Headers.MediaTypeWithQualityHeaderValue.Parse("application/json")); + + PrepareRequest(client_, request_, urlBuilder_); + var url_ = urlBuilder_.ToString(); + request_.RequestUri = new System.Uri(url_, System.UriKind.RelativeOrAbsolute); + PrepareRequest(client_, request_, url_); + + var response_ = await client_.SendAsync(request_, System.Net.Http.HttpCompletionOption.ResponseHeadersRead, cancellationToken).ConfigureAwait(false); + var disposeResponse_ = true; + try + { + var headers_ = System.Linq.Enumerable.ToDictionary(response_.Headers, h_ => h_.Key, h_ => h_.Value); + if (response_.Content != null && response_.Content.Headers != null) + { + foreach (var item_ in response_.Content.Headers) + headers_[item_.Key] = item_.Value; + } + + ProcessResponse(client_, response_); + + var status_ = (int)response_.StatusCode; + if (status_ == 200) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + return objectResponse_.Object; + } + else + if (status_ == 404) + { + var objectResponse_ = await ReadObjectResponseAsync(response_, headers_).ConfigureAwait(false); + if (objectResponse_.Object == null) + { + throw new ApiException("Response was null which was not expected.", status_, objectResponse_.Text, headers_, null); + } + throw new ApiException("Tag not found", status_, objectResponse_.Text, headers_, objectResponse_.Object, null); + } + else + { + var responseData_ = response_.Content == null ? null : await response_.Content.ReadAsStringAsync().ConfigureAwait(false); + throw new ApiException("The HTTP status code of the response was not expected (" + status_ + ").", status_, responseData_, headers_, null); + } + } + finally + { + if (disposeResponse_) + response_.Dispose(); + } + } + } + finally + { + if (disposeClient_) + client_.Dispose(); + } + } + + protected struct ObjectResponseResult + { + public ObjectResponseResult(T responseObject, string responseText) + { + this.Object = responseObject; + this.Text = responseText; + } + + public T Object { get; } + + public string Text { get; } + } + + public bool ReadResponseAsString { get; set; } + + protected virtual async System.Threading.Tasks.Task> ReadObjectResponseAsync(System.Net.Http.HttpResponseMessage response, System.Collections.Generic.IReadOnlyDictionary> headers) + { + if (response == null || response.Content == null) + { + return new ObjectResponseResult(default(T), string.Empty); + } + + if (ReadResponseAsString) + { + var responseText = await response.Content.ReadAsStringAsync().ConfigureAwait(false); + try + { + var typedBody = Newtonsoft.Json.JsonConvert.DeserializeObject(responseText, JsonSerializerSettings); + return new ObjectResponseResult(typedBody, responseText); + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body string as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, responseText, headers, exception); + } + } + else + { + try + { + using (var responseStream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false)) + using (var streamReader = new System.IO.StreamReader(responseStream)) + using (var jsonTextReader = new Newtonsoft.Json.JsonTextReader(streamReader)) + { + var serializer = Newtonsoft.Json.JsonSerializer.Create(JsonSerializerSettings); + var typedBody = serializer.Deserialize(jsonTextReader); + return new ObjectResponseResult(typedBody, string.Empty); + } + } + catch (Newtonsoft.Json.JsonException exception) + { + var message = "Could not deserialize the response body stream as " + typeof(T).FullName + "."; + throw new ApiException(message, (int)response.StatusCode, string.Empty, headers, exception); + } + } + } + + private string ConvertToString(object value, System.Globalization.CultureInfo cultureInfo) + { + if (value == null) + { + return null; + } + + if (value is System.Enum) + { + var name = System.Enum.GetName(value.GetType(), value); + if (name != null) + { + var field = System.Reflection.IntrospectionExtensions.GetTypeInfo(value.GetType()).GetDeclaredField(name); + if (field != null) + { + var attribute = System.Reflection.CustomAttributeExtensions.GetCustomAttribute(field, typeof(System.Runtime.Serialization.EnumMemberAttribute)) + as System.Runtime.Serialization.EnumMemberAttribute; + if (attribute != null) + { + return attribute.Value != null ? attribute.Value : name; + } + } + + return System.Convert.ToString(System.Convert.ChangeType(value, System.Enum.GetUnderlyingType(value.GetType()), cultureInfo)); + } + } + else if (value is bool) + { + return System.Convert.ToString((bool)value, cultureInfo).ToLowerInvariant(); + } + else if (value is byte[]) + { + return System.Convert.ToBase64String((byte[])value); + } + else if (value.GetType().IsArray) + { + var array = System.Linq.Enumerable.OfType((System.Array)value); + return string.Join(",", System.Linq.Enumerable.Select(array, o => ConvertToString(o, cultureInfo))); + } + + var result = System.Convert.ToString(value, cultureInfo); + return (result is null) ? string.Empty : result; + } + } + +} + +#pragma warning restore 1591 +#pragma warning restore 1573 +#pragma warning restore 472 +#pragma warning restore 114 +#pragma warning restore 108 \ No newline at end of file diff --git a/Birdmap.BLL/Startup.cs b/Birdmap.BLL/Startup.cs index 698db11..9132d87 100644 --- a/Birdmap.BLL/Startup.cs +++ b/Birdmap.BLL/Startup.cs @@ -14,9 +14,15 @@ namespace Birdmap.BLL services.AddTransient(); if (configuration.GetValue("UseDummyServices")) - services.AddTransient(); + { + services.AddTransient(); + services.AddTransient(); + } else + { + services.AddTransient(); services.AddTransient(); + } return services; } diff --git a/Birdmap.sln b/Birdmap.sln index 913ed9a..05e0b6c 100644 --- a/Birdmap.sln +++ b/Birdmap.sln @@ -9,7 +9,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.BLL", "Birdmap.BLL\ EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.DAL", "Birdmap.DAL\Birdmap.DAL.csproj", "{543FAB06-B960-41A9-8865-1624A2ED2170}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Birdmap.Common", "Birdmap.Common\Birdmap.Common.csproj", "{CE96BAFA-A0FD-4010-8EF2-700451091F71}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Birdmap.Common", "Birdmap.Common\Birdmap.Common.csproj", "{CE96BAFA-A0FD-4010-8EF2-700451091F71}" +EndProject +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "MQTTnet.TestApp.WinForm", "MQTTnet.TestApp.WinForm\MQTTnet.TestApp.WinForm.csproj", "{E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution @@ -33,6 +35,10 @@ Global {CE96BAFA-A0FD-4010-8EF2-700451091F71}.Debug|Any CPU.Build.0 = Debug|Any CPU {CE96BAFA-A0FD-4010-8EF2-700451091F71}.Release|Any CPU.ActiveCfg = Release|Any CPU {CE96BAFA-A0FD-4010-8EF2-700451091F71}.Release|Any CPU.Build.0 = Release|Any CPU + {E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Release|Any CPU.ActiveCfg = Release|Any CPU + {E1707FE7-4A65-42AC-B71C-6CC1A55FC42A}.Release|Any CPU.Build.0 = Release|Any CPU EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/MQTTnet.TestApp.WinForm/Form1.Designer.cs b/MQTTnet.TestApp.WinForm/Form1.Designer.cs new file mode 100644 index 0000000..e8083e9 --- /dev/null +++ b/MQTTnet.TestApp.WinForm/Form1.Designer.cs @@ -0,0 +1,394 @@ +namespace MQTTnet.TestApp.WinForm +{ + partial class Form1 + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + this.label1 = new System.Windows.Forms.Label(); + this.TextBoxPort = new System.Windows.Forms.TextBox(); + this.ButtonServerStart = new System.Windows.Forms.Button(); + this.ButtonServerStop = new System.Windows.Forms.Button(); + this.label2 = new System.Windows.Forms.Label(); + this.maskedTextBox1 = new System.Windows.Forms.MaskedTextBox(); + this.label3 = new System.Windows.Forms.Label(); + this.TextBoxTopicPublished = new System.Windows.Forms.TextBox(); + this.label4 = new System.Windows.Forms.Label(); + this.label5 = new System.Windows.Forms.Label(); + this.ButtonPublisherStop = new System.Windows.Forms.Button(); + this.ButtonPublisherStart = new System.Windows.Forms.Button(); + this.TextBoxPublish = new System.Windows.Forms.TextBox(); + this.ButtonPublish = new System.Windows.Forms.Button(); + this.ButtonSubscriberStop = new System.Windows.Forms.Button(); + this.ButtonSubscriberStart = new System.Windows.Forms.Button(); + this.TextBoxSubscriber = new System.Windows.Forms.TextBox(); + this.ButtonGeneratePublishedMessage = new System.Windows.Forms.Button(); + this.label6 = new System.Windows.Forms.Label(); + this.TextBoxTopicSubscribed = new System.Windows.Forms.TextBox(); + this.ButtonSubscribe = new System.Windows.Forms.Button(); + this.label7 = new System.Windows.Forms.Label(); + this.trackBar1 = new System.Windows.Forms.TrackBar(); + this.ButtonAutoPublisherStop = new System.Windows.Forms.Button(); + this.ButtonAutoPublisherStart = new System.Windows.Forms.Button(); + this.label8 = new System.Windows.Forms.Label(); + this.checkBox1 = new System.Windows.Forms.CheckBox(); + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).BeginInit(); + this.SuspendLayout(); + // + // label1 + // + this.label1.AutoSize = true; + this.label1.Location = new System.Drawing.Point(119, 24); + this.label1.Name = "label1"; + this.label1.Size = new System.Drawing.Size(32, 15); + this.label1.TabIndex = 0; + this.label1.Text = "Port:"; + // + // TextBoxPort + // + this.TextBoxPort.Location = new System.Drawing.Point(172, 21); + this.TextBoxPort.Name = "TextBoxPort"; + this.TextBoxPort.Size = new System.Drawing.Size(100, 23); + this.TextBoxPort.TabIndex = 1; + this.TextBoxPort.Text = "1883"; + this.TextBoxPort.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged); + // + // ButtonServerStart + // + this.ButtonServerStart.Location = new System.Drawing.Point(433, 21); + this.ButtonServerStart.Name = "ButtonServerStart"; + this.ButtonServerStart.Size = new System.Drawing.Size(75, 23); + this.ButtonServerStart.TabIndex = 2; + this.ButtonServerStart.Text = "Start"; + this.ButtonServerStart.UseVisualStyleBackColor = true; + this.ButtonServerStart.Click += new System.EventHandler(this.ButtonServerStartClick); + // + // ButtonServerStop + // + this.ButtonServerStop.Location = new System.Drawing.Point(514, 21); + this.ButtonServerStop.Name = "ButtonServerStop"; + this.ButtonServerStop.Size = new System.Drawing.Size(75, 23); + this.ButtonServerStop.TabIndex = 3; + this.ButtonServerStop.Text = "Stop"; + this.ButtonServerStop.UseVisualStyleBackColor = true; + this.ButtonServerStop.Click += new System.EventHandler(this.ButtonServerStopClick); + // + // label2 + // + this.label2.AutoSize = true; + this.label2.Location = new System.Drawing.Point(33, 25); + this.label2.Name = "label2"; + this.label2.Size = new System.Drawing.Size(39, 15); + this.label2.TabIndex = 4; + this.label2.Text = "Server"; + // + // maskedTextBox1 + // + this.maskedTextBox1.Location = new System.Drawing.Point(0, 0); + this.maskedTextBox1.Name = "maskedTextBox1"; + this.maskedTextBox1.Size = new System.Drawing.Size(100, 23); + this.maskedTextBox1.TabIndex = 5; + this.maskedTextBox1.Text = "maskedTextBox1"; + // + // label3 + // + this.label3.AutoSize = true; + this.label3.Location = new System.Drawing.Point(33, 79); + this.label3.Name = "label3"; + this.label3.Size = new System.Drawing.Size(90, 15); + this.label3.TabIndex = 5; + this.label3.Text = "Topic Published"; + // + // TextBoxTopicPublished + // + this.TextBoxTopicPublished.Location = new System.Drawing.Point(164, 76); + this.TextBoxTopicPublished.Name = "TextBoxTopicPublished"; + this.TextBoxTopicPublished.Size = new System.Drawing.Size(425, 23); + this.TextBoxTopicPublished.TabIndex = 1; + this.TextBoxTopicPublished.Text = "devices/output"; + this.TextBoxTopicPublished.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged); + // + // label4 + // + this.label4.AutoSize = true; + this.label4.Location = new System.Drawing.Point(33, 109); + this.label4.Name = "label4"; + this.label4.Size = new System.Drawing.Size(90, 15); + this.label4.TabIndex = 5; + this.label4.Text = "Client Publisher"; + // + // label5 + // + this.label5.AutoSize = true; + this.label5.Location = new System.Drawing.Point(33, 224); + this.label5.Name = "label5"; + this.label5.Size = new System.Drawing.Size(96, 15); + this.label5.TabIndex = 5; + this.label5.Text = "Client Subscriber"; + // + // ButtonPublisherStop + // + this.ButtonPublisherStop.Location = new System.Drawing.Point(514, 105); + this.ButtonPublisherStop.Name = "ButtonPublisherStop"; + this.ButtonPublisherStop.Size = new System.Drawing.Size(75, 23); + this.ButtonPublisherStop.TabIndex = 3; + this.ButtonPublisherStop.Text = "Stop"; + this.ButtonPublisherStop.UseVisualStyleBackColor = true; + this.ButtonPublisherStop.Click += new System.EventHandler(this.ButtonPublisherStopClick); + // + // ButtonPublisherStart + // + this.ButtonPublisherStart.Location = new System.Drawing.Point(433, 105); + this.ButtonPublisherStart.Name = "ButtonPublisherStart"; + this.ButtonPublisherStart.Size = new System.Drawing.Size(75, 23); + this.ButtonPublisherStart.TabIndex = 2; + this.ButtonPublisherStart.Text = "Start"; + this.ButtonPublisherStart.UseVisualStyleBackColor = true; + this.ButtonPublisherStart.Click += new System.EventHandler(this.ButtonPublisherStartClick); + // + // TextBoxPublish + // + this.TextBoxPublish.Location = new System.Drawing.Point(33, 134); + this.TextBoxPublish.Name = "TextBoxPublish"; + this.TextBoxPublish.Size = new System.Drawing.Size(394, 23); + this.TextBoxPublish.TabIndex = 1; + this.TextBoxPublish.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged); + // + // ButtonPublish + // + this.ButtonPublish.Location = new System.Drawing.Point(514, 134); + this.ButtonPublish.Name = "ButtonPublish"; + this.ButtonPublish.Size = new System.Drawing.Size(75, 23); + this.ButtonPublish.TabIndex = 3; + this.ButtonPublish.Text = "Publish"; + this.ButtonPublish.UseVisualStyleBackColor = true; + this.ButtonPublish.Click += new System.EventHandler(this.ButtonPublishClick); + // + // ButtonSubscriberStop + // + this.ButtonSubscriberStop.Location = new System.Drawing.Point(514, 220); + this.ButtonSubscriberStop.Name = "ButtonSubscriberStop"; + this.ButtonSubscriberStop.Size = new System.Drawing.Size(75, 23); + this.ButtonSubscriberStop.TabIndex = 3; + this.ButtonSubscriberStop.Text = "Stop"; + this.ButtonSubscriberStop.UseVisualStyleBackColor = true; + this.ButtonSubscriberStop.Click += new System.EventHandler(this.ButtonSubscriberStopClick); + // + // ButtonSubscriberStart + // + this.ButtonSubscriberStart.Location = new System.Drawing.Point(433, 220); + this.ButtonSubscriberStart.Name = "ButtonSubscriberStart"; + this.ButtonSubscriberStart.Size = new System.Drawing.Size(75, 23); + this.ButtonSubscriberStart.TabIndex = 2; + this.ButtonSubscriberStart.Text = "Start"; + this.ButtonSubscriberStart.UseVisualStyleBackColor = true; + this.ButtonSubscriberStart.Click += new System.EventHandler(this.ButtonSubscriberStartClick); + // + // TextBoxSubscriber + // + this.TextBoxSubscriber.Location = new System.Drawing.Point(33, 309); + this.TextBoxSubscriber.Multiline = true; + this.TextBoxSubscriber.Name = "TextBoxSubscriber"; + this.TextBoxSubscriber.Size = new System.Drawing.Size(556, 182); + this.TextBoxSubscriber.TabIndex = 6; + // + // ButtonGeneratePublishedMessage + // + this.ButtonGeneratePublishedMessage.Location = new System.Drawing.Point(433, 133); + this.ButtonGeneratePublishedMessage.Name = "ButtonGeneratePublishedMessage"; + this.ButtonGeneratePublishedMessage.Size = new System.Drawing.Size(75, 23); + this.ButtonGeneratePublishedMessage.TabIndex = 2; + this.ButtonGeneratePublishedMessage.Text = "Random"; + this.ButtonGeneratePublishedMessage.UseVisualStyleBackColor = true; + this.ButtonGeneratePublishedMessage.Click += new System.EventHandler(this.ButtonGeneratePublishedMessageClick); + // + // label6 + // + this.label6.AutoSize = true; + this.label6.Location = new System.Drawing.Point(33, 252); + this.label6.Name = "label6"; + this.label6.Size = new System.Drawing.Size(96, 15); + this.label6.TabIndex = 5; + this.label6.Text = "Topic Subscribed"; + // + // TextBoxTopicSubscribed + // + this.TextBoxTopicSubscribed.Location = new System.Drawing.Point(164, 249); + this.TextBoxTopicSubscribed.Name = "TextBoxTopicSubscribed"; + this.TextBoxTopicSubscribed.Size = new System.Drawing.Size(344, 23); + this.TextBoxTopicSubscribed.TabIndex = 1; + this.TextBoxTopicSubscribed.Text = "devices/output"; + this.TextBoxTopicSubscribed.TextChanged += new System.EventHandler(this.TextBoxPortTextChanged); + // + // ButtonSubscribe + // + this.ButtonSubscribe.Location = new System.Drawing.Point(514, 248); + this.ButtonSubscribe.Name = "ButtonSubscribe"; + this.ButtonSubscribe.Size = new System.Drawing.Size(75, 23); + this.ButtonSubscribe.TabIndex = 3; + this.ButtonSubscribe.Text = "Subscribe"; + this.ButtonSubscribe.UseVisualStyleBackColor = true; + this.ButtonSubscribe.Click += new System.EventHandler(this.ButtonSubscribeClick); + // + // label7 + // + this.label7.AutoSize = true; + this.label7.Location = new System.Drawing.Point(33, 167); + this.label7.Name = "label7"; + this.label7.Size = new System.Drawing.Size(141, 15); + this.label7.TabIndex = 5; + this.label7.Text = "Auto (Random) Publisher"; + // + // trackBar1 + // + this.trackBar1.LargeChange = 500; + this.trackBar1.Location = new System.Drawing.Point(180, 162); + this.trackBar1.Maximum = 5050; + this.trackBar1.Minimum = 50; + this.trackBar1.Name = "trackBar1"; + this.trackBar1.Size = new System.Drawing.Size(247, 45); + this.trackBar1.SmallChange = 100; + this.trackBar1.TabIndex = 7; + this.trackBar1.TickFrequency = 500; + this.trackBar1.Value = 550; + this.trackBar1.Scroll += new System.EventHandler(this.trackBar1_Scroll); + // + // ButtonAutoPublisherStop + // + this.ButtonAutoPublisherStop.Location = new System.Drawing.Point(513, 162); + this.ButtonAutoPublisherStop.Name = "ButtonAutoPublisherStop"; + this.ButtonAutoPublisherStop.Size = new System.Drawing.Size(75, 23); + this.ButtonAutoPublisherStop.TabIndex = 8; + this.ButtonAutoPublisherStop.Text = "Stop"; + this.ButtonAutoPublisherStop.UseVisualStyleBackColor = true; + this.ButtonAutoPublisherStop.Click += new System.EventHandler(this.ButtonAutoPublisherStopClick); + // + // ButtonAutoPublisherStart + // + this.ButtonAutoPublisherStart.Location = new System.Drawing.Point(433, 162); + this.ButtonAutoPublisherStart.Name = "ButtonAutoPublisherStart"; + this.ButtonAutoPublisherStart.Size = new System.Drawing.Size(75, 23); + this.ButtonAutoPublisherStart.TabIndex = 8; + this.ButtonAutoPublisherStart.Text = "Start"; + this.ButtonAutoPublisherStart.UseVisualStyleBackColor = true; + this.ButtonAutoPublisherStart.Click += new System.EventHandler(this.ButtonAutoPublisherStartClick); + // + // label8 + // + this.label8.Anchor = System.Windows.Forms.AnchorStyles.Right; + this.label8.AutoSize = true; + this.label8.Location = new System.Drawing.Point(180, 191); + this.label8.Name = "label8"; + this.label8.RightToLeft = System.Windows.Forms.RightToLeft.No; + this.label8.Size = new System.Drawing.Size(44, 15); + this.label8.TabIndex = 9; + this.label8.Text = "550 ms"; + this.label8.TextAlign = System.Drawing.ContentAlignment.MiddleRight; + // + // checkBox1 + // + this.checkBox1.AutoSize = true; + this.checkBox1.Checked = true; + this.checkBox1.CheckState = System.Windows.Forms.CheckState.Checked; + this.checkBox1.Location = new System.Drawing.Point(433, 191); + this.checkBox1.Name = "checkBox1"; + this.checkBox1.Size = new System.Drawing.Size(82, 19); + this.checkBox1.TabIndex = 10; + this.checkBox1.Text = "randomize"; + this.checkBox1.UseVisualStyleBackColor = true; + // + // Form1 + // + this.AutoScaleDimensions = new System.Drawing.SizeF(7F, 15F); + this.AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + this.ClientSize = new System.Drawing.Size(627, 530); + this.Controls.Add(this.checkBox1); + this.Controls.Add(this.label8); + this.Controls.Add(this.ButtonAutoPublisherStart); + this.Controls.Add(this.ButtonAutoPublisherStop); + this.Controls.Add(this.trackBar1); + this.Controls.Add(this.label7); + this.Controls.Add(this.TextBoxSubscriber); + this.Controls.Add(this.label5); + this.Controls.Add(this.label4); + this.Controls.Add(this.label3); + this.Controls.Add(this.label2); + this.Controls.Add(this.ButtonServerStop); + this.Controls.Add(this.ButtonServerStart); + this.Controls.Add(this.TextBoxPort); + this.Controls.Add(this.label1); + this.Controls.Add(this.TextBoxTopicPublished); + this.Controls.Add(this.ButtonPublisherStop); + this.Controls.Add(this.ButtonPublisherStart); + this.Controls.Add(this.TextBoxPublish); + this.Controls.Add(this.ButtonPublish); + this.Controls.Add(this.ButtonSubscriberStop); + this.Controls.Add(this.ButtonSubscriberStart); + this.Controls.Add(this.ButtonGeneratePublishedMessage); + this.Controls.Add(this.label6); + this.Controls.Add(this.TextBoxTopicSubscribed); + this.Controls.Add(this.ButtonSubscribe); + this.FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle; + this.Name = "Form1"; + this.Text = "MQTT Testing"; + ((System.ComponentModel.ISupportInitialize)(this.trackBar1)).EndInit(); + this.ResumeLayout(false); + this.PerformLayout(); + + } + + #endregion + + private System.Windows.Forms.Label label1; + private System.Windows.Forms.TextBox TextBoxPort; + private System.Windows.Forms.Button ButtonServerStart; + private System.Windows.Forms.Button ButtonServerStop; + private System.Windows.Forms.Label label2; + private System.Windows.Forms.MaskedTextBox maskedTextBox1; + private System.Windows.Forms.Label label3; + private System.Windows.Forms.Label label4; + private System.Windows.Forms.Label label5; + private System.Windows.Forms.Button ButtonPublisherStop; + private System.Windows.Forms.Button ButtonPublisherStart; + private System.Windows.Forms.TextBox TextBoxPublish; + private System.Windows.Forms.Button ButtonPublish; + private System.Windows.Forms.Button ButtonSubscriberStop; + private System.Windows.Forms.Button ButtonSubscriberStart; + private System.Windows.Forms.TextBox TextBoxSubscriber; + private System.Windows.Forms.Button ButtonGeneratePublishedMessage; + private System.Windows.Forms.Label label6; + private System.Windows.Forms.TextBox TextBoxTopicPublished; + private System.Windows.Forms.Button ButtonSubscribe; + private System.Windows.Forms.TextBox TextBoxTopicSubscribed; + private System.Windows.Forms.Label label7; + private System.Windows.Forms.TrackBar trackBar1; + private System.Windows.Forms.Button ButtonAutoPublisherStop; + private System.Windows.Forms.Button ButtonAutoPublisherStart; + private System.Windows.Forms.Label label8; + private System.Windows.Forms.CheckBox checkBox1; + } +} + diff --git a/MQTTnet.TestApp.WinForm/Form1.cs b/MQTTnet.TestApp.WinForm/Form1.cs new file mode 100644 index 0000000..c798654 --- /dev/null +++ b/MQTTnet.TestApp.WinForm/Form1.cs @@ -0,0 +1,476 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 All rights reserved. +// +// +// The main form. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace MQTTnet.TestApp.WinForm +{ + using System; + using System.Text; + using System.Timers; + using System.Windows.Forms; + + using MQTTnet.Client.Connecting; + using MQTTnet.Client.Disconnecting; + using MQTTnet.Client.Options; + using MQTTnet.Client.Receiving; + using MQTTnet.Extensions.ManagedClient; + using MQTTnet.Formatter; + using MQTTnet.Protocol; + using MQTTnet.Server; + using Newtonsoft.Json; + using Timer = System.Timers.Timer; + + /// + /// The main form. + /// + public partial class Form1 : Form + { + /// + /// The managed publisher client. + /// + private IManagedMqttClient managedMqttClientPublisher; + + /// + /// The managed subscriber client. + /// + private IManagedMqttClient managedMqttClientSubscriber; + + /// + /// The MQTT server. + /// + private IMqttServer mqttServer; + + /// + /// The port. + /// + private string port = "1883"; + + private readonly Random random; + private readonly Timer randomPublisherTimer; + + /// + /// Initializes a new instance of the class. + /// + public Form1() + { + this.InitializeComponent(); + + var timer = new Timer + { + AutoReset = true, Enabled = true, Interval = 1000 + }; + + timer.Elapsed += this.TimerElapsed; + + random = new Random(); + randomPublisherTimer = new Timer + { + AutoReset = true, + Enabled = false, + }; + + randomPublisherTimer.Elapsed += (_, __) => this.BeginInvoke((MethodInvoker)delegate + { + if (checkBox1.Checked) + ButtonGeneratePublishedMessageClick(ButtonGeneratePublishedMessage, EventArgs.Empty); + + ButtonPublishClick(ButtonPublish, EventArgs.Empty); + }); + } + + /// + /// Handles the publisher connected event. + /// + /// The MQTT client connected event args. + private void OnPublisherConnected(MqttClientConnectedEventArgs x) + { + var item = "Publisher Connected"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// Handles the publisher disconnected event. + /// + /// The MQTT client disconnected event args. + private void OnPublisherDisconnected(MqttClientDisconnectedEventArgs x) + { + var item = "Publisher Disconnected"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// Handles the subscriber connected event. + /// + /// The MQTT client connected event args. + private void OnSubscriberConnected(MqttClientConnectedEventArgs x) + { + var item = "Subscriber Connected"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// Handles the subscriber disconnected event. + /// + /// The MQTT client disconnected event args. + private void OnSubscriberDisconnected(MqttClientDisconnectedEventArgs x) + { + var item = "Subscriber Disconnected"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// The method that handles the button click to generate a message. + /// + /// The sender. + /// The event args. + private void ButtonGeneratePublishedMessageClick(object sender, EventArgs e) + { + var message = new + { + tag = Guid.NewGuid(), + probability = random.NextDouble(), + }; + + var json = JsonConvert.SerializeObject(message); + this.TextBoxPublish.Text = json; + } + + /// + /// The method that handles the button click to publish a message. + /// + /// The sender. + /// The event args. + private async void ButtonPublishClick(object sender, EventArgs e) + { + ((Button)sender).Enabled = false; + + try + { + var payload = Encoding.UTF8.GetBytes(this.TextBoxPublish.Text); + var message = new MqttApplicationMessageBuilder().WithTopic(this.TextBoxTopicPublished.Text.Trim()).WithPayload(payload).WithQualityOfServiceLevel(MqttQualityOfServiceLevel.AtLeastOnce).WithRetainFlag().Build(); + + if (this.managedMqttClientPublisher != null) + { + await this.managedMqttClientPublisher.PublishAsync(message); + } + } + catch (Exception ex) + { + var item = ex.Message; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + ((Button)sender).Enabled = true; + } + + /// + /// The method that handles the button click to start the publisher. + /// + /// The sender. + /// The event args. + private async void ButtonPublisherStartClick(object sender, EventArgs e) + { + var mqttFactory = new MqttFactory(); + + var tlsOptions = new MqttClientTlsOptions + { + UseTls = false, IgnoreCertificateChainErrors = true, IgnoreCertificateRevocationErrors = true, AllowUntrustedCertificates = true + }; + + var options = new MqttClientOptions + { + ClientId = "ClientPublisher", + ProtocolVersion = MqttProtocolVersion.V311, + ChannelOptions = new MqttClientTcpOptions + { + Server = "localhost", Port = int.Parse(this.TextBoxPort.Text.Trim()), TlsOptions = tlsOptions + } + }; + + if (options.ChannelOptions == null) + { + throw new InvalidOperationException(); + } + + options.Credentials = new MqttClientCredentials + { + Username = "username", Password = Encoding.UTF8.GetBytes("password") + }; + + options.CleanSession = true; + options.KeepAlivePeriod = TimeSpan.FromSeconds(5); + this.managedMqttClientPublisher = mqttFactory.CreateManagedMqttClient(); + this.managedMqttClientPublisher.UseApplicationMessageReceivedHandler(this.HandleReceivedApplicationMessage); + this.managedMqttClientPublisher.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnPublisherConnected); + this.managedMqttClientPublisher.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnPublisherDisconnected); + + await this.managedMqttClientPublisher.StartAsync( + new ManagedMqttClientOptions + { + ClientOptions = options + }); + } + + /// + /// The method that handles the button click to stop the publisher. + /// + /// The sender. + /// The event args. + private async void ButtonPublisherStopClick(object sender, EventArgs e) + { + if (this.managedMqttClientPublisher == null) + { + return; + } + + await this.managedMqttClientPublisher.StopAsync(); + this.managedMqttClientPublisher = null; + } + + /// + /// The method that handles the button click to start the server. + /// + /// The sender. + /// The event args. + private async void ButtonServerStartClick(object sender, EventArgs e) + { + if (this.mqttServer != null) + { + return; + } + + var storage = new JsonServerStorage(); + storage.Clear(); + this.mqttServer = new MqttFactory().CreateMqttServer(); + var options = new MqttServerOptions(); + options.DefaultEndpointOptions.Port = int.Parse(this.TextBoxPort.Text); + options.Storage = storage; + options.EnablePersistentSessions = true; + options.ConnectionValidator = new MqttServerConnectionValidatorDelegate( + c => + { + if (c.ClientId.Length < 10) + { + c.ReasonCode = MqttConnectReasonCode.ClientIdentifierNotValid; + return; + } + + if (c.Username != "username") + { + c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; + return; + } + + if (c.Password != "password") + { + c.ReasonCode = MqttConnectReasonCode.BadUserNameOrPassword; + return; + } + + c.ReasonCode = MqttConnectReasonCode.Success; + }); + + try + { + await this.mqttServer.StartAsync(options); + } + catch (Exception ex) + { + var item = ex.Message; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + + await this.mqttServer.StopAsync(); + this.mqttServer = null; + } + } + + /// + /// The method that handles the button click to stop the server. + /// + /// The sender. + /// The event args. + private async void ButtonServerStopClick(object sender, EventArgs e) + { + if (this.mqttServer == null) + { + return; + } + + await this.mqttServer.StopAsync(); + this.mqttServer = null; + } + + /// + /// The method that handles the button click to subscribe to a certain topic. + /// + /// The sender. + /// The event args. + private async void ButtonSubscribeClick(object sender, EventArgs e) + { + var topicFilter = new MqttTopicFilter { Topic = this.TextBoxTopicSubscribed.Text.Trim() }; + await this.managedMqttClientSubscriber.SubscribeAsync(topicFilter); + var item = "Topic " + this.TextBoxTopicSubscribed.Text.Trim() + " is subscribed"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// The method that handles the button click to start the subscriber. + /// + /// The sender. + /// The event args. + private async void ButtonSubscriberStartClick(object sender, EventArgs e) + { + var mqttFactory = new MqttFactory(); + + var tlsOptions = new MqttClientTlsOptions + { + UseTls = false, IgnoreCertificateChainErrors = true, IgnoreCertificateRevocationErrors = true, AllowUntrustedCertificates = true + }; + + var options = new MqttClientOptions + { + ClientId = "ClientSubscriber", + ProtocolVersion = MqttProtocolVersion.V311, + ChannelOptions = new MqttClientTcpOptions + { + Server = "localhost", Port = int.Parse(this.TextBoxPort.Text.Trim()), TlsOptions = tlsOptions + } + }; + + if (options.ChannelOptions == null) + { + throw new InvalidOperationException(); + } + + options.Credentials = new MqttClientCredentials + { + Username = "username", + Password = Encoding.UTF8.GetBytes("password") + }; + + options.CleanSession = true; + options.KeepAlivePeriod = TimeSpan.FromSeconds(5); + + this.managedMqttClientSubscriber = mqttFactory.CreateManagedMqttClient(); + this.managedMqttClientSubscriber.ConnectedHandler = new MqttClientConnectedHandlerDelegate(OnSubscriberConnected); + this.managedMqttClientSubscriber.DisconnectedHandler = new MqttClientDisconnectedHandlerDelegate(OnSubscriberDisconnected); + this.managedMqttClientSubscriber.ApplicationMessageReceivedHandler = new MqttApplicationMessageReceivedHandlerDelegate(this.OnSubscriberMessageReceived); + + await this.managedMqttClientSubscriber.StartAsync( + new ManagedMqttClientOptions + { + ClientOptions = options + }); + } + + /// + /// The method that handles the button click to stop the subscriber. + /// + /// The sender. + /// The event args. + private async void ButtonSubscriberStopClick(object sender, EventArgs e) + { + if (this.managedMqttClientSubscriber == null) + { + return; + } + + await this.managedMqttClientSubscriber.StopAsync(); + this.managedMqttClientSubscriber = null; + } + + /// + /// Handles the received application message event. + /// + /// The MQTT application message received event args. + private void HandleReceivedApplicationMessage(MqttApplicationMessageReceivedEventArgs x) + { + var item = $"Timestamp: {DateTime.Now:O} | Topic: {x.ApplicationMessage.Topic} | Payload: {x.ApplicationMessage.ConvertPayloadToString()} | QoS: {x.ApplicationMessage.QualityOfServiceLevel}"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// Handles the received subscriber message event. + /// + /// The MQTT application message received event args. + private void OnSubscriberMessageReceived(MqttApplicationMessageReceivedEventArgs x) + { + var item = $"Timestamp: {DateTime.Now:O} | Topic: {x.ApplicationMessage.Topic} | Payload: {x.ApplicationMessage.ConvertPayloadToString()} | QoS: {x.ApplicationMessage.QualityOfServiceLevel}"; + this.BeginInvoke((MethodInvoker)delegate { this.TextBoxSubscriber.Text = item + Environment.NewLine + this.TextBoxSubscriber.Text; }); + } + + /// + /// The method that handles the text changes in the text box. + /// + /// The sender. + /// The event args. + private void TextBoxPortTextChanged(object sender, EventArgs e) + { + // ReSharper disable once StyleCop.SA1126 + if (int.TryParse(this.TextBoxPort.Text, out _)) + { + this.port = this.TextBoxPort.Text.Trim(); + } + else + { + this.TextBoxPort.Text = this.port; + this.TextBoxPort.SelectionStart = this.TextBoxPort.Text.Length; + this.TextBoxPort.SelectionLength = 0; + } + } + + /// + /// The method that handles the timer events. + /// + /// The sender. + /// The event args. + private void TimerElapsed(object sender, ElapsedEventArgs e) + { + this.BeginInvoke( + (MethodInvoker)delegate + { + // Server + this.TextBoxPort.Enabled = this.mqttServer == null; + this.ButtonServerStart.Enabled = this.mqttServer == null; + this.ButtonServerStop.Enabled = this.mqttServer != null; + + // Publisher + this.ButtonPublisherStart.Enabled = this.managedMqttClientPublisher == null; + this.ButtonPublisherStop.Enabled = this.managedMqttClientPublisher != null; + + // Auto Publisher + this.ButtonAutoPublisherStart.Enabled = !this.randomPublisherTimer.Enabled; + this.ButtonAutoPublisherStop.Enabled = this.randomPublisherTimer.Enabled; + + // Subscriber + this.ButtonSubscriberStart.Enabled = this.managedMqttClientSubscriber == null; + this.ButtonSubscriberStop.Enabled = this.managedMqttClientSubscriber != null; + }); + } + + private void trackBar1_Scroll(object sender, EventArgs e) + { + this.label8.Text = $"{this.trackBar1.Value:N0} ms"; + this.randomPublisherTimer.Interval = this.trackBar1.Value; + } + + private void ButtonAutoPublisherStartClick(object sender, EventArgs e) + { + ((Button)sender).Enabled = false; + this.randomPublisherTimer.Start(); + ((Button)sender).Enabled = true; + } + + private void ButtonAutoPublisherStopClick(object sender, EventArgs e) + { + ((Button)sender).Enabled = false; + this.randomPublisherTimer.Stop(); + ((Button)sender).Enabled = true; + } + } +} diff --git a/MQTTnet.TestApp.WinForm/Form1.resx b/MQTTnet.TestApp.WinForm/Form1.resx new file mode 100644 index 0000000..f298a7b --- /dev/null +++ b/MQTTnet.TestApp.WinForm/Form1.resx @@ -0,0 +1,60 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/MQTTnet.TestApp.WinForm/JsonServerStorage.cs b/MQTTnet.TestApp.WinForm/JsonServerStorage.cs new file mode 100644 index 0000000..9700314 --- /dev/null +++ b/MQTTnet.TestApp.WinForm/JsonServerStorage.cs @@ -0,0 +1,83 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 All rights reserved. +// +// +// The JSON server storage. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace MQTTnet.TestApp.WinForm +{ + using System.Collections.Generic; + using System.IO; + using System.Threading.Tasks; + + using MQTTnet.Server; + + using Newtonsoft.Json; + + /// + /// + /// The JSON server storage. + /// + /// + public class JsonServerStorage : IMqttServerStorage + { + /// + /// The file name. + /// + private readonly string filename = Path.Combine(Directory.GetCurrentDirectory(), "Retained.json"); + + /// + /// Clears the file. + /// + public void Clear() + { + if (File.Exists(this.filename)) + { + File.Delete(this.filename); + } + } + + /// + /// + /// Loads the retained messages. + /// + /// A of . + /// + public async Task> LoadRetainedMessagesAsync() + { + await Task.CompletedTask; + + if (!File.Exists(this.filename)) + { + return new List(); + } + + try + { + var json = await File.ReadAllTextAsync(this.filename); + return JsonConvert.DeserializeObject>(json); + } + catch + { + return new List(); + } + } + + /// + /// + /// Saves the retained messages to a file. + /// + /// The messages. + /// A representing any asynchronous operation. + /// + public async Task SaveRetainedMessagesAsync(IList messages) + { + await Task.CompletedTask; + var json = JsonConvert.SerializeObject(messages); + await File.WriteAllTextAsync(this.filename, json); + } + } +} diff --git a/MQTTnet.TestApp.WinForm/MQTTnet.TestApp.WinForm.csproj b/MQTTnet.TestApp.WinForm/MQTTnet.TestApp.WinForm.csproj new file mode 100644 index 0000000..07ec309 --- /dev/null +++ b/MQTTnet.TestApp.WinForm/MQTTnet.TestApp.WinForm.csproj @@ -0,0 +1,19 @@ + + + + WinExe + netcoreapp3.1 + true + + + + + all + runtime; build; native; contentfiles; analyzers; buildtransitive + + + + + + + \ No newline at end of file diff --git a/MQTTnet.TestApp.WinForm/Program.cs b/MQTTnet.TestApp.WinForm/Program.cs new file mode 100644 index 0000000..c23d801 --- /dev/null +++ b/MQTTnet.TestApp.WinForm/Program.cs @@ -0,0 +1,32 @@ +// -------------------------------------------------------------------------------------------------------------------- +// +// Copyright (c) 2020 All rights reserved. +// +// +// The main program. +// +// -------------------------------------------------------------------------------------------------------------------- + +namespace MQTTnet.TestApp.WinForm +{ + using System; + using System.Windows.Forms; + + /// + /// The main program. + /// + internal static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + private static void Main() + { + Application.SetHighDpiMode(HighDpiMode.SystemAware); + Application.EnableVisualStyles(); + Application.SetCompatibleTextRenderingDefault(false); + Application.Run(new Form1()); + } + } +} diff --git a/input.yml b/input.yml new file mode 100644 index 0000000..3867786 --- /dev/null +++ b/input.yml @@ -0,0 +1,167 @@ +openapi: 3.0.3 +info: + title: Input Service + description: This is the input interface of the Birbnetes system. + contact: + email: tormakristof@tormakristof.eu + license: + name: Apache 2.0 + url: http://www.apache.org/licenses/LICENSE-2.0.html + version: 1.1.3 +servers: +- url: https://birb.k8s.kmlabz.com +tags: +- name: input + description: Input Service interaction +paths: + /sample: + get: + tags: + - input + summary: Get all stored input queries + operationId: getall + responses: + 200: + description: Array of input objects + content: + application/json: + schema: + $ref: '#/components/schemas/InputResponse' + 404: + description: No object matching filter + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + post: + tags: + - input + summary: uploads a sample into the system + operationId: uploadFile + requestBody: + content: + multipart/form-data: + schema: + required: + - description + - file + properties: + description: + type: object + description: Metadata json + properties: + deviceid: + type: string + date: + type: string + format: date + file: + type: string + description: Wave file to upload + format: binary + required: true + responses: + 200: + description: successful operation + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + 400: + description: JSON parse error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + 415: + description: Media type error + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + 417: + description: JSON invalid schema + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + 469: + description: No file found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + 470: + description: Description missing + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' + /sample/{tagID}: + get: + tags: + - input + summary: Get input object by ID + operationId: getInput + parameters: + - name: tagID + in: path + description: ID of input object file + required: true + schema: + type: string + format: uuid + responses: + 200: + description: input object + content: + application/json: + schema: + $ref: '#/components/schemas/InputSingeResponse' + 404: + description: Tag not found + content: + application/json: + schema: + $ref: '#/components/schemas/ApiResponse' +components: + schemas: + InputSingeResponse: + required: + - message + - status + type: object + properties: + status: + type: string + message: + $ref: '#/components/schemas/InputObject' + InputResponse: + type: array + items: + $ref: '#/components/schemas/InputObject' + InputObject: + required: + - date + - device_id + - tag + type: object + properties: + tag: + type: string + format: uuid + date: + type: string + format: date + device_id: + type: integer + ApiResponse: + required: + - message + - status + type: object + properties: + status: + type: string + message: + type: string