Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Session Agent Trigger #503

Open
wants to merge 4 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
11 changes: 11 additions & 0 deletions Bot.Builder.Community.sln
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapt
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Adapters.Facebook.Tests", "tests\Bot.Builder.Community.Adapters.Facebook.Tests\Bot.Builder.Community.Adapters.Facebook.Tests.csproj", "{8201DC48-763A-4534-9E51-466E15DF01D8}"
EndProject
Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "Bot.Builder.Community.Components.Trigger.SessionAgent", "libraries\Bot.Builder.Community.Components.Trigger.SessionAgent\Bot.Builder.Community.Components.Trigger.SessionAgent.csproj", "{EA37FC80-A1FC-4B7F-B091-33128C55242E}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug - NuGet Packages|Any CPU = Debug - NuGet Packages|Any CPU
Expand Down Expand Up @@ -805,6 +807,14 @@ Global
{8201DC48-763A-4534-9E51-466E15DF01D8}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.ActiveCfg = Release|Any CPU
{8201DC48-763A-4534-9E51-466E15DF01D8}.Release|Any CPU.Build.0 = Release|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Debug - NuGet Packages|Any CPU.ActiveCfg = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Debug - NuGet Packages|Any CPU.Build.0 = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Debug|Any CPU.Build.0 = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Documentation|Any CPU.ActiveCfg = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Documentation|Any CPU.Build.0 = Debug|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Release|Any CPU.ActiveCfg = Release|Any CPU
{EA37FC80-A1FC-4B7F-B091-33128C55242E}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
Expand Down Expand Up @@ -893,6 +903,7 @@ Global
{428AD1B4-DF58-4D21-9C19-AB4AB6001A90} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
{3348B9A5-E3CE-4AF8-B059-8B4D7971C25A} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
{8201DC48-763A-4534-9E51-466E15DF01D8} = {840D4038-9AB8-4750-9FFE-365386CE47E2}
{EA37FC80-A1FC-4B7F-B091-33128C55242E} = {1F7F4CAF-CF22-491F-840D-A63835726C12}
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9FE3B75E-BA2B-45BC-BBF0-DDA8BA10C4F0}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
using System;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Helper;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Middleware;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Service;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Trigger;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Dialogs.Declarative;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;

namespace Bot.Builder.Community.Components.Trigger.SessionAgent
{
public class SessionAgentBotComponent : BotComponent
{
public override void ConfigureServices(IServiceCollection services, IConfiguration configuration)
{
if (services == null)
throw new ArgumentNullException(nameof(services));

if (configuration == null)
throw new ArgumentNullException(nameof(configuration));

ActivityHelper.IsEnable = string.IsNullOrEmpty(configuration["IsEnabled"])
|| Convert.ToBoolean(configuration["IsEnabled"]);

if (!ActivityHelper.IsEnable) return;

ActivityHelper.SleepInMilliseconds = string.IsNullOrEmpty(configuration["SleepTime"]) ? 1000 : Convert.ToInt32(configuration["SleepTime"]);

if (ActivityHelper.SleepInMilliseconds <= 100)
ActivityHelper.SleepInMilliseconds = 1000;

services.AddSingleton<IServiceAgentAnnouncer,ServiceAgentAnnouncer>();

services.AddHostedService<AgentBackgroundService>();

services.AddSingleton<IMiddleware, ConversationAgentMiddleware>();

services.AddSingleton<DeclarativeType>(sp =>
new DeclarativeType<OnSessionExpireConversation>(OnSessionExpireConversation.Kind));

services.AddSingleton<DeclarativeType>(sp =>
new DeclarativeType<OnReminderConversation>(OnReminderConversation.Kind));
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer
{
public enum AgentJob
{
Update,
Track
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
using System;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;

namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer
{
public interface IServiceAgentAnnouncer : IObservable<AgentJob>
{
void SendAnnouncement();
void UserLastAccessTime(string userId);

void RegisterUser(ITurnContext turnContext);

void SetController(IBot bot, IBotFrameworkHttpAdapter botHttpAdapter);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
using System;
using System.Collections.Concurrent;
using System.Threading.Tasks;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Receiver;
using Bot.Builder.Community.Components.Trigger.SessionAgent.UserInformation;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Builder.Integration.AspNet.Core;

namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer
{
public partial class ServiceAgentAnnouncer : IServiceAgentAnnouncer
{
private readonly ConcurrentDictionary<string, IObserver<AgentJob>> _usersDictionary =
new ConcurrentDictionary<string, IObserver<AgentJob>>();

private IBot _bot;
private IBotFrameworkHttpAdapter _botAdapter;

private IDisposable Subscribe(string userId, IObserver<AgentJob> observer)
{
if (!_usersDictionary.ContainsKey(userId))
{
_usersDictionary.TryAdd(userId, observer);
}

return new Unsubscribe(_usersDictionary, userId);
}

public IDisposable Subscribe(IObserver<AgentJob> observer)
{
throw new NotImplementedException("Subscribe function handle by internally");
}

public void SendAnnouncement()
{
if (!_usersDictionary.IsEmpty)
{
Parallel.ForEach(_usersDictionary, number =>
{
number.Value.OnNext(AgentJob.Track);
});
}
}

public void UserLastAccessTime(string userId)
{
if (_usersDictionary.TryGetValue(userId, out var subscribeTime))
{
subscribeTime.OnNext(AgentJob.Update);
}
}

public void RegisterUser(ITurnContext turnContext)
{
if (_bot != null && _botAdapter != null)
{
IUser user = new User(_bot, _botAdapter, turnContext);

var watcher = new ServiceAgentReceiver(user);

watcher.Disposable = Subscribe(user.UserId, watcher);
}
}

public void SetController(IBot bot, IBotFrameworkHttpAdapter botHttpAdapter)
{
_bot = bot ?? throw new ArgumentNullException(nameof(bot));
_botAdapter = botHttpAdapter ?? throw new ArgumentNullException(nameof(botHttpAdapter));
}

}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
using System;
using System.Collections.Concurrent;

namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer
{
public partial class ServiceAgentAnnouncer
{
private class Unsubscribe : IDisposable
{
private readonly ConcurrentDictionary<string, IObserver<AgentJob>> _observers;
private readonly string _userId;

public Unsubscribe()
{
_observers = null;
_userId = string.Empty;
}

public Unsubscribe(ConcurrentDictionary<string, IObserver<AgentJob>> observers, string userId)
{
_observers = observers;
_userId = userId;
}

public void Dispose()
{
_observers?.TryRemove(_userId, out _);
}
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
<Project Sdk="Microsoft.NET.Sdk">
<Import Project="$([MSBuild]::GetDirectoryNameOfFileAbove('$(MSBuildThisFileDirectory)../', 'Bot.Builder.Community.sln'))\CommonTargets\library.shared.targets" />

<PropertyGroup>
<TargetFramework>netstandard2.0</TargetFramework>
<Description>Action is performed when Automatically conversation has expired.</Description>
<Authors>Bot Builder Community</Authors>
<Company>Bot Builder Community</Company>
<PackageLicenseUrl>https://github.com/BotBuilderCommunity/botbuilder-community-dotnet/blob/master/LICENSE</PackageLicenseUrl>
<PackageProjectUrl>https://github.com/BotBuilderCommunity/botbuilder-community-dotnet/tree/master/libraries/Bot.Builder.Community.Components.Trigger.AutomaticallyExpireConversation</PackageProjectUrl>
<FileVersion>1.0.0</FileVersion>
<AssemblyVersion>1.0.0</AssemblyVersion>
<PackageIcon>package-icon.png</PackageIcon>
<PackageIconUrl />
<PackageTags>bots;botframework;botbuilder;msbot-component;msbot-middleware;msbot-trigger;</PackageTags>
<RepositoryUrl>http://www.github.com/botbuildercommunity/botbuildercommunity-dotnet
</RepositoryUrl>
<PackageLicenseUrl />
<PackageLicenseFile>LICENSE</PackageLicenseFile>
<Description>Action is performed when Automatically conversation has expired.</Description>
<PackageProjectUrl>https://github.com/BotBuilderCommunity/botbuilder-community-dotnet/tree/develop/libraries/Bot.Builder.Community.Components.Trigger.AutomaticallyExpireConversation</PackageProjectUrl>
<GeneratePackageOnBuild>true</GeneratePackageOnBuild>
<Version>1.0.10</Version>
<Authors>BotBuilderCommunity</Authors>
<PackageId>$(AssemblyName)</PackageId>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Microsoft.Bot.Builder.Integration.AspNet.Core" Version="$(Bot_Builder_Version)" />
<PackageReference Include="Microsoft.Bot.Builder" Version="$(Bot_Builder_Version)" />
<PackageReference Include="Microsoft.SourceLink.GitHub" Version="1.0.0" PrivateAssets="All" />
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive" Version="$(Bot_Builder_Version)" />
<PackageReference Include="Microsoft.Bot.Builder.Dialogs.Adaptive.Runtime" Version="$(Bot_Builder_Version)" />
</ItemGroup>


<ItemGroup>
<Content Include="**/*.schema" />
<Content Include="**/*.uischema" />
</ItemGroup>


<ItemGroup>
<None Include="..\..\LICENSE">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
<None Include="..\..\package-icon.png">
<Pack>True</Pack>
<PackagePath></PackagePath>
</None>
</ItemGroup>


</Project>
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Helper
{
public static class ActivityHelper
{
public static double ExpireAfterSeconds { get; set; } = 0;

public static int SleepInMilliseconds { get; set; } = 0;

public static double ReminderSeconds { get; set; } = 0;

public static string SessionExpireTrigger = "SessionExpireConversation";

public static string ReminderTrigger = "ReminderConversation";

public static bool IsEnable;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
using System.Threading;
using System.Threading.Tasks;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Announcer;
using Bot.Builder.Community.Components.Trigger.SessionAgent.Helper;
using Microsoft.Bot.Builder;
using Microsoft.Bot.Schema;

namespace Bot.Builder.Community.Components.Trigger.SessionAgent.Middleware
{
public class ConversationAgentMiddleware : IMiddleware
{
private readonly IServiceAgentAnnouncer _serviceAgentAnnouncer;

public ConversationAgentMiddleware(IServiceAgentAnnouncer serviceAgentAnnouncer)
{
_serviceAgentAnnouncer = serviceAgentAnnouncer;
}

public async Task OnTurnAsync(ITurnContext turnContext, NextDelegate next,
CancellationToken cancellationToken = new CancellationToken())
{
if (ActivityHelper.IsEnable)
{
if (turnContext.Activity.Type == ActivityTypes.ConversationUpdate &&
turnContext.Activity.MembersAdded != null)
{
_serviceAgentAnnouncer.RegisterUser(turnContext);
}
else
{
var conversationReference = turnContext.Activity.GetConversationReference();
_serviceAgentAnnouncer.UserLastAccessTime(conversationReference.User.Id);
}
}

await next(cancellationToken);

}
}
}