Skip to content

Commit

Permalink
Merge pull request #38 from lillo42/master
Browse files Browse the repository at this point in the history
New release
  • Loading branch information
lillo42 authored Mar 28, 2020
2 parents fcc8011 + 2438f6e commit 563a5d6
Show file tree
Hide file tree
Showing 254 changed files with 17,932 additions and 12,019 deletions.
40 changes: 20 additions & 20 deletions Mozzila.IoT.WebThing.sln
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,16 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Itens", "Solution
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SampleThing", "sample\SampleThing\SampleThing.csproj", "{6FB673AA-FD52-4509-97C8-28572549F609}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mozilla.IoT.WebThing.AcceptanceTest", "test\Mozilla.IoT.WebThing.AcceptanceTest\Mozilla.IoT.WebThing.AcceptanceTest.csproj", "{0D709627-98FA-4A39-8631-90C982ADED44}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MultiThing", "sample\MultiThing\MultiThing.csproj", "{3CDFC9FB-F240-419A-800D-79C506CBDAE2}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Github", "Github", "{425538CC-334D-4DB3-B529-48EA7CD778BF}"
ProjectSection(SolutionItems) = preProject
.github\workflows\pull-request.yml = .github\workflows\pull-request.yml
.github\workflows\build-master.yml = .github\workflows\build-master.yml
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
ProjectSection(SolutionItems) = preProject
.github\workflows\pull-request.yml = .github\workflows\pull-request.yml
.github\workflows\build-master.yml = .github\workflows\build-master.yml
.github\workflows\release.yml = .github\workflows\release.yml
EndProjectSection
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Mozilla.IoT.WebThing.Intregration.Test", "test\Mozilla.IoT.WebThing.Intregration.Test\Mozilla.IoT.WebThing.Intregration.Test.csproj", "{2BC55368-0F49-4D1A-999D-A236616EC80A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Expand Down Expand Up @@ -82,18 +82,6 @@ Global
{6FB673AA-FD52-4509-97C8-28572549F609}.Release|x64.Build.0 = Release|Any CPU
{6FB673AA-FD52-4509-97C8-28572549F609}.Release|x86.ActiveCfg = Release|Any CPU
{6FB673AA-FD52-4509-97C8-28572549F609}.Release|x86.Build.0 = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|Any CPU.Build.0 = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|x64.ActiveCfg = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|x64.Build.0 = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|x86.ActiveCfg = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Debug|x86.Build.0 = Debug|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|Any CPU.ActiveCfg = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|Any CPU.Build.0 = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|x64.ActiveCfg = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|x64.Build.0 = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|x86.ActiveCfg = Release|Any CPU
{0D709627-98FA-4A39-8631-90C982ADED44}.Release|x86.Build.0 = Release|Any CPU
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Debug|x64.ActiveCfg = Debug|Any CPU
Expand All @@ -106,13 +94,25 @@ Global
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Release|x64.Build.0 = Release|Any CPU
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Release|x86.ActiveCfg = Release|Any CPU
{3CDFC9FB-F240-419A-800D-79C506CBDAE2}.Release|x86.Build.0 = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|x64.ActiveCfg = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|x64.Build.0 = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|x86.ActiveCfg = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Debug|x86.Build.0 = Debug|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|Any CPU.Build.0 = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|x64.ActiveCfg = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|x64.Build.0 = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|x86.ActiveCfg = Release|Any CPU
{2BC55368-0F49-4D1A-999D-A236616EC80A}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(NestedProjects) = preSolution
{4999C9EF-BCC2-4252-A404-0161E655AAD9} = {F6436C38-AB0A-4D3F-8BA7-E2C0FA30D052}
{63874B3F-6000-418D-BD19-C56A4D86B612} = {65C51E32-2901-4983-A238-0F931D9EB651}
{6FB673AA-FD52-4509-97C8-28572549F609} = {370B1F76-EFE0-44D4-A395-59F5EF266112}
{0D709627-98FA-4A39-8631-90C982ADED44} = {65C51E32-2901-4983-A238-0F931D9EB651}
{3CDFC9FB-F240-419A-800D-79C506CBDAE2} = {370B1F76-EFE0-44D4-A395-59F5EF266112}
{425538CC-334D-4DB3-B529-48EA7CD778BF} = {E90FFA85-A210-450A-AA08-528D7F8962C2}
{2BC55368-0F49-4D1A-999D-A236616EC80A} = {65C51E32-2901-4983-A238-0F931D9EB651}
EndGlobalSection
EndGlobal
56 changes: 0 additions & 56 deletions src/Mozilla.IoT.WebThing/ActionCollection.cs

This file was deleted.

15 changes: 0 additions & 15 deletions src/Mozilla.IoT.WebThing/ActionContext.cs

This file was deleted.

110 changes: 110 additions & 0 deletions src/Mozilla.IoT.WebThing/Actions/ActionCollection.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
using System;
using System.Collections;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Text.Json;

namespace Mozilla.IoT.WebThing.Actions
{
/// <summary>
/// Collection of <see cref="ActionInfo"/>
/// </summary>
public class ActionCollection : IEnumerable<ActionInfo>
{
private readonly ConcurrentDictionary<Guid, ActionInfo> _actions;
private readonly DictionaryInputConvert _inputConvert;
private readonly IActionInfoFactory _actionInfoFactory;

/// <summary>
/// Event to when Status of <see cref="ActionInfo"/> changed.
/// </summary>
public event EventHandler<ActionInfo>? Change;

/// <summary>
/// Initialize a new instance of <see cref="ActionCollection"/>.
/// </summary>
/// <param name="inputConvert">The <see cref="DictionaryInputConvert"/>.</param>
/// <param name="actionInfoFactory">The <see cref="IActionInfoFactory"/>.</param>
public ActionCollection(DictionaryInputConvert inputConvert, IActionInfoFactory actionInfoFactory)
{
_actionInfoFactory = actionInfoFactory ?? throw new ArgumentNullException(nameof(actionInfoFactory));
_inputConvert = inputConvert;
_actions = new ConcurrentDictionary<Guid, ActionInfo>();
}

/// <summary>
/// Try to add Action to collection.
/// </summary>
/// <param name="element">The <see cref="JsonElement"/> to be convert to <see cref="ActionInfo"/>.</param>
/// <param name="info">The <see cref="ActionInfo"/> created.</param>
/// <returns>Return true if could convert and added on collection, otherwise return false.</returns>
public bool TryAdd(JsonElement element, [NotNullWhen(true)]out ActionInfo? info)
{
info = null;
Dictionary<string, object>? inputValues = null;
if (element.TryGetProperty("input", out var inputProperty))
{
if (inputProperty.ValueKind == JsonValueKind.Object
&& !_inputConvert.TryConvert(inputProperty, out inputValues!))
{
return false;
}
}

inputValues ??= new Dictionary<string, object>();

info = _actionInfoFactory.CreateActionInfo(inputValues!);
if (info == null)
{
return false;
}

info.StatusChanged += OnStatusChange;

return _actions.TryAdd(info.GetId(), info);
}

/// <summary>
/// Try to get <see cref="ActionInfo"/> by Id.
/// </summary>
/// <param name="id">The id of <see cref="ActionInfo"/>.</param>
/// <param name="action">The <see cref="ActionInfo"/>.</param>
/// <returns>Return true if could get <see cref="ActionInfo"/> by Id, otherwise return false.</returns>
public bool TryGetValue(Guid id, [NotNullWhen(true)]out ActionInfo? action)
=> _actions.TryGetValue(id, out action);

/// <summary>
/// Try to remove <see cref="ActionInfo"/> by Id.
/// </summary>
/// <param name="id">The id of <see cref="ActionInfo"/>.</param>
/// <param name="action">The <see cref="ActionInfo"/>.</param>
/// <returns>Return true if could remove <see cref="ActionInfo"/> by Id, otherwise return false.</returns>
public bool TryRemove(Guid id, [NotNullWhen(true)]out ActionInfo? action)
{
var result =_actions.TryRemove(id, out action);
if (result && action != null)
{
action.StatusChanged -= OnStatusChange;
}

return result;
}

private void OnStatusChange(object? sender, EventArgs args)
{
var change = Change;
change?.Invoke(this, (ActionInfo)sender!);
}

/// <summary>
///
/// </summary>
/// <returns></returns>
public IEnumerator<ActionInfo> GetEnumerator()
=> _actions.Values.GetEnumerator();

IEnumerator IEnumerable.GetEnumerator()
=> GetEnumerator();
}
}
101 changes: 75 additions & 26 deletions src/Mozilla.IoT.WebThing/Actions/ActionInfo.cs
Original file line number Diff line number Diff line change
@@ -1,64 +1,113 @@
using System;
using System;
using System.Threading;
using System.Threading.Tasks;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

namespace Mozilla.IoT.WebThing.Actions
{
/// <summary>
/// Action information to return in Web Socket and Web API.
/// </summary>
public abstract class ActionInfo
{
private readonly Guid _id = Guid.NewGuid();
/// <summary>
/// The <see cref="CancellationTokenSource"/> to cancel action when ask by <see cref="CancellationToken"/>.
/// </summary>
protected CancellationTokenSource Source { get; } = new CancellationTokenSource();

internal Guid Id { get; } = Guid.NewGuid();
internal Thing Thing { get; set; } = default!;
protected abstract string ActionName { get; }

public string Href { get; internal set; }

internal Thing? Thing { get; set; }

/// <summary>
/// The href of action.
/// </summary>
public string Href { get; set; } = string.Empty;

/// <summary>
/// The time when action was requested.
/// </summary>
public DateTime TimeRequested { get; } = DateTime.UtcNow;

/// <summary>
/// The time when action was completed
/// </summary>
public DateTime? TimeCompleted { get; private set; } = null;
public string Status { get; private set; } = "pending";


private ActionStatus _status = ActionStatus.Pending;

public abstract bool IsValid();
/// <summary>
/// The <see cref="Status"/> of action.
/// </summary>
public ActionStatus Status
{
get => _status;
private set
{
_status = value;
StatusChanged?.Invoke(this, EventArgs.Empty);
}
}

/// <summary>
/// To performance action executing.
/// </summary>
/// <param name="thing">The <see cref="Thing"/> associated with action to be executed.</param>
/// <param name="provider">The <see cref="IServiceProvider"/> of scope to execute action.</param>
/// <returns>The action executed or executing.</returns>
protected abstract ValueTask InternalExecuteAsync(Thing thing, IServiceProvider provider);

/// <summary>
/// To Execute action.
/// </summary>
/// <param name="thing">The <see cref="Thing"/> associated with action to be executed.</param>
/// <param name="provider">The <see cref="IServiceProvider"/> of scope to execute action.</param>
/// <returns>Execute task async.</returns>
public async Task ExecuteAsync(Thing thing, IServiceProvider provider)
{
Status = ActionStatus.Pending;
var logger = provider.GetRequiredService<ILogger<ActionInfo>>();
logger.LogInformation("Going to execute {actionName}", ActionName);
logger.LogInformation("Going to execute {actionName}. [Thing: {thingName}]", GetActionName(), thing.Name);
Status = ActionStatus.Executing;

var status = StatusChanged;

Status = "executing";

status?.Invoke(this, EventArgs.Empty);

try
{
await InternalExecuteAsync(thing, provider)
.ConfigureAwait(false);

logger.LogInformation("{actionName} to executed", ActionName);
logger.LogInformation("{actionName} to executed. [Thing: {thingName}", GetActionName(), thing.Name);
}
catch (Exception e)
{
logger.LogError(e,"Error to execute {actionName}", ActionName);
logger.LogError(e,"Error to execute {actionName}. [Thing: {thingName}", GetActionName(), thing.Name);
}

TimeCompleted = DateTime.UtcNow;

Status = "completed";

status?.Invoke(this, EventArgs.Empty);

Status = ActionStatus.Completed;
}

/// <summary>
/// The action name.
/// </summary>
/// <returns></returns>
public abstract string GetActionName();

internal string GetActionName() => ActionName;

/// <summary>
/// The action Id.
/// </summary>
/// <returns></returns>
public Guid GetId()
=> _id;

/// <summary>
/// To cancel action executing.
/// </summary>
public void Cancel()
=> Source.Cancel();

/// <summary>
/// The Status changed event.
/// </summary>
public event EventHandler? StatusChanged;
}
}
Loading

0 comments on commit 563a5d6

Please sign in to comment.