Skip to content

Commit

Permalink
fix(userchannelset) - Seperated user channel set reader, fixed exampl…
Browse files Browse the repository at this point in the history
…e projects to act upon the fdc3Ready event
  • Loading branch information
lilla28 committed Sep 6, 2024
1 parent 49a2167 commit 22b0240
Show file tree
Hide file tree
Showing 15 changed files with 241 additions and 128 deletions.
7 changes: 3 additions & 4 deletions examples/fdc3-chart-and-grid/js-chart/chart.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,14 +12,11 @@ let currentChannel;

NoDataToDisplay(Highcharts);

window.addEventListener('load', function() {
window.addEventListener('fdc3Ready', async() => {
chart = Highcharts.chart('container', {

chart: {
type: 'column',
events: {
load: requestData
}
},
title: {
text: 'Monthly Sales Data'
Expand All @@ -43,6 +40,8 @@ window.addEventListener('load', function() {
data: []
}]
});

await requestData();
});

window.addEventListener('close', async function(){
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,12 +20,15 @@ export class MockDataService{

constructor(){
this.market = new Market();
this.connecting = new Promise(async(resolve, reject) => {
try{
resolve(await this.checkFdc3Connection());
} catch(err) {
reject(err);
};

window.addEventListener('fdc3Ready', () => {
this.connecting = new Promise(async(resolve, reject) => {
try{
resolve(await this.checkFdc3Connection());
} catch(err) {
reject(err);
};
});
});

interval(1000).subscribe(() => {
Expand Down
2 changes: 1 addition & 1 deletion examples/fdc3-pricing-and-chat/js-chat/chat.js
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ window.app = function () {
}
}();

window.addEventListener('load', async function () {
window.addEventListener('fdc3Ready', async function () {
intentListener = await window.fdc3.addIntentListener("StartChat", window.app.handleChatIntent);

await window.fdc3.joinUserChannel("fdc3.channel.1");
Expand Down
2 changes: 1 addition & 1 deletion examples/fdc3-pricing-and-chat/js-pricing/pricing.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@

import "bootstrap/dist/css/bootstrap.css";

window.addEventListener('load', async function () {
window.addEventListener('fdc3Ready', async function () {
const pricingForm = document.querySelector("#pricing");
await this.window.fdc3.joinUserChannel("fdc3.channel.1");
pricingForm.addEventListener('submit', app.submitPrice);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,7 @@
*/

using MorganStanley.ComposeUI.Fdc3.DesktopAgent;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.DependencyInjection;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Infrastructure.Internal;
using MorganStanley.ComposeUI.Messaging;
using MorganStanley.ComposeUI.Messaging.Abstractions;
using MorganStanley.ComposeUI.ModuleLoader;
using MorganStanley.ComposeUI.Shell.Fdc3;

Expand All @@ -35,6 +32,8 @@ public static IServiceCollection AddFdc3DesktopAgent(
builderAction(builder);
}


serviceCollection.AddSingleton<IUserChannelSetReader, UserChannelSetReader>();
serviceCollection.AddSingleton<IFdc3DesktopAgentBridge, Fdc3DesktopAgent>();
serviceCollection.AddTransient<IStartupAction, Fdc3StartupAction>();

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,24 +35,17 @@
using Screenshot = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol.Screenshot;
using AppChannel = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Channels.AppChannel;
using MorganStanley.ComposeUI.Messaging;
using System.Text.Json;
using System.IO.Abstractions;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Converters;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol;
using System.Text.Json.Serialization;
using DisplayMetadata = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol.DisplayMetadata;
using ImplementationMetadata = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Protocol.ImplementationMetadata;
using Constants = MorganStanley.ComposeUI.Fdc3.DesktopAgent.Infrastructure.Internal.Constants;
using FileSystem = System.IO.Abstractions.FileSystem;
using System.Reflection;
using System;

namespace MorganStanley.ComposeUI.Fdc3.DesktopAgent;

internal class Fdc3DesktopAgent : IFdc3DesktopAgentBridge
{
private readonly ILogger<Fdc3DesktopAgent> _logger;
private readonly IResolverUICommunicator _resolverUI;
private readonly IUserChannelSetReader _userChannelSetReader;
private readonly ConcurrentDictionary<string, UserChannel> _userChannels = new();
private readonly ConcurrentDictionary<string, PrivateChannel> _privateChannels = new();
private readonly ConcurrentDictionary<string, AppChannel> _appChannels = new();
Expand All @@ -64,35 +57,30 @@ internal class Fdc3DesktopAgent : IFdc3DesktopAgentBridge
private readonly ConcurrentDictionary<Guid, RaisedIntentRequestHandler> _raisedIntentResolutions = new();
private readonly ConcurrentDictionary<StartRequest, TaskCompletionSource<IModuleInstance>> _pendingStartRequests = new();
private IAsyncDisposable? _subscription;
private readonly IFileSystem _fileSystem;
private readonly HttpClient _httpClient = new();
private ConcurrentDictionary<string, ChannelItem>? _userChannelSet;
private readonly JsonSerializerOptions _jsonSerializerOptions = new(JsonSerializerDefaults.Web)
{
Converters = { new DisplayMetadataJsonConverter(), new JsonStringEnumConverter() }
};

public Fdc3DesktopAgent(
IAppDirectory appDirectory,
IModuleLoader moduleLoader,
IOptions<Fdc3DesktopAgentOptions> options,
IResolverUICommunicator resolverUI,
IFileSystem? fileSystem = null,
IUserChannelSetReader userChannelSetReader,
ILoggerFactory? loggerFactory = null)
{
_appDirectory = appDirectory;
_moduleLoader = moduleLoader;
_options = options.Value;
_resolverUI = resolverUI;
_fileSystem = fileSystem ?? new FileSystem();
_userChannelSetReader = userChannelSetReader;
_loggerFactory = loggerFactory ?? NullLoggerFactory.Instance;
_logger = _loggerFactory.CreateLogger<Fdc3DesktopAgent>() ?? NullLogger<Fdc3DesktopAgent>.Instance;
}

public async ValueTask<UserChannel?> AddUserChannel(Func<string, UserChannel> addUserChannelFactory, string channelId)
{
ChannelItem? channelItem = null;
if (_userChannelSet != null && !_userChannelSet.TryGetValue(channelId, out channelItem) || channelItem == null)
var userChannelSet = await _userChannelSetReader.GetUserChannelSet();

if (!userChannelSet.TryGetValue(channelId, out channelItem) || channelItem == null)
{
return null;
}
Expand Down Expand Up @@ -217,7 +205,6 @@ public async Task StartAsync(CancellationToken cancellationToken)
});

_subscription = subscription;
_userChannelSet = await ReadUserChannelSet(cancellationToken);
}

public async Task StopAsync(CancellationToken cancellationToken)
Expand Down Expand Up @@ -245,7 +232,6 @@ public async Task StopAsync(CancellationToken cancellationToken)
_userChannels.Clear();
_privateChannels.Clear();
_appChannels.Clear();
_httpClient.Dispose();
}

public bool FindChannel(string channelId, ChannelType channelType)
Expand Down Expand Up @@ -506,30 +492,30 @@ public async ValueTask<RaiseIntentResult<IntentListenerResponse>> AddIntentListe
};
}

public ValueTask<GetUserChannelsResponse> GetUserChannels(GetUserChannelsRequest? request)
public async ValueTask<GetUserChannelsResponse> GetUserChannels(GetUserChannelsRequest? request)
{
if (request == null)
{
return ValueTask.FromResult(GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.PayloadNull));
return GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.PayloadNull);
}

if (!Guid.TryParse(request.InstanceId, out var instanceId))
{
return ValueTask.FromResult(GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.MissingId));
return GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.MissingId);
}

if (!_runningModules.TryGetValue(instanceId, out _))
{
return ValueTask.FromResult(GetUserChannelsResponse.Failure(ChannelError.AccessDenied));
return GetUserChannelsResponse.Failure(ChannelError.AccessDenied);
}

var result = _userChannelSet?.Values;
var result = (await _userChannelSetReader.GetUserChannelSet()).Values;
if (result == null)
{
return ValueTask.FromResult(GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.NoUserChannelSetFound));
return GetUserChannelsResponse.Failure(Fdc3DesktopAgentErrors.NoUserChannelSetFound);

Check warning on line 515 in src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs

View check run for this annotation

Codecov / codecov/patch

src/fdc3/dotnet/DesktopAgent/src/MorganStanley.ComposeUI.DesktopAgent/Fdc3DesktopAgent.cs#L515

Added line #L515 was not covered by tests
}

return ValueTask.FromResult(GetUserChannelsResponse.Success(result));
return GetUserChannelsResponse.Success(result);
}

public async ValueTask<JoinUserChannelResponse?> JoinUserChannel(Func<string, UserChannel> addUserChannelFactory, JoinUserChannelRequest request)
Expand All @@ -539,8 +525,9 @@ public ValueTask<GetUserChannelsResponse> GetUserChannels(GetUserChannelsRequest
return JoinUserChannelResponse.Failed(Fdc3DesktopAgentErrors.MissingId);
}

var userChannelSet = await _userChannelSetReader.GetUserChannelSet();
ChannelItem? channelItem = null;
if (_userChannelSet != null && !_userChannelSet.TryGetValue(request.ChannelId, out channelItem))
if (!userChannelSet.TryGetValue(request.ChannelId, out channelItem))
{
return JoinUserChannelResponse.Failed(ChannelError.NoChannelFound);
}
Expand Down Expand Up @@ -1224,55 +1211,6 @@ private AppMetadata GetAppMetadata(Fdc3App app, string? instanceId, IntentMetada
};
}

private async Task<ConcurrentDictionary<string, ChannelItem>?> ReadUserChannelSet(CancellationToken cancellationToken = default)
{
var uri = _options.UserChannelConfigFile;
IEnumerable<ChannelItem>? userChannelSet = null;

if (uri == null && _options.UserChannelConfig == null)
{
var assembly = Assembly.GetExecutingAssembly();
using var stream = assembly.GetManifestResourceStream(ResourceNames.DefaultUserChannelSet);
if (stream == null)
{
return null;
}

using var streamReader = new StreamReader(stream);

var result = streamReader.ReadToEnd();
userChannelSet = JsonSerializer.Deserialize<ChannelItem[]>(result, _jsonSerializerOptions);
}
else if (_options.UserChannelConfig != null)
{
userChannelSet = _options.UserChannelConfig;
}
else if (uri != null)
{
if (uri.IsFile)
{
var path = uri.IsAbsoluteUri ? uri.AbsolutePath : Path.GetFullPath(uri.ToString());

if (!_fileSystem.File.Exists(path))
{
_logger.LogError($"{Fdc3DesktopAgentErrors.NoUserChannelSetFound}, no user channel set was configured.");
return null;
}

await using var stream = _fileSystem.File.OpenRead(path);
userChannelSet = JsonSerializer.Deserialize<ChannelItem[]>(stream, _jsonSerializerOptions);
}
else if (uri.Scheme == Uri.UriSchemeHttp || uri.Scheme == Uri.UriSchemeHttps)
{
var response = await _httpClient.GetAsync(uri, cancellationToken);
await using var stream = await response.Content.ReadAsStreamAsync(cancellationToken);
userChannelSet = JsonSerializer.Deserialize<ChannelItem[]>(stream, _jsonSerializerOptions);
}
}

return new((userChannelSet ?? Array.Empty<ChannelItem>()).ToDictionary(x => x.Id, y => y));
}

private Task RemoveModuleAsync(IModuleInstance instance)
{
if (!IsFdc3StartedModule(instance, out var fdc3InstanceId))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -18,21 +18,25 @@
using ResourceReader = MorganStanley.ComposeUI.Utilities.ResourceReader;
using Microsoft.Extensions.Options;
using MorganStanley.ComposeUI.Fdc3.DesktopAgent.DependencyInjection;
using System.Text;

namespace MorganStanley.ComposeUI.Shell.Fdc3;

internal sealed class Fdc3StartupAction : IStartupAction
{
private readonly IAppDirectory _appDirectory;
private readonly IUserChannelSetReader _userChannelSetReader;
private readonly Fdc3DesktopAgentOptions _options;
private readonly ILogger<Fdc3StartupAction> _logger;

public Fdc3StartupAction(
IAppDirectory appDirectory,
IUserChannelSetReader userChannelSetReader,
IOptions<Fdc3DesktopAgentOptions> options,
ILogger<Fdc3StartupAction>? logger = null)
{
_appDirectory = appDirectory;
_userChannelSetReader = userChannelSetReader;
_options = options.Value;
_logger = logger ?? NullLogger<Fdc3StartupAction>.Instance;
}
Expand All @@ -45,29 +49,60 @@ public async Task InvokeAsync(StartupContext startupContext, Func<Task> next)
try
{
var appId = (await _appDirectory.GetApp(startupContext.StartRequest.ModuleId)).AppId;
var userChannelSet = await _userChannelSetReader.GetUserChannelSet();
var fdc3InstanceId = startupContext.StartRequest.Parameters.FirstOrDefault(parameter => parameter.Key == Fdc3StartupParameters.Fdc3InstanceId).Value ?? Guid.NewGuid().ToString();
var channelId = _options.ChannelId ?? "fdc3.channel.1";

//TODO: decide if we want to join to a channel automatically on startup of an fdc3 module
var channelId = _options.ChannelId ?? userChannelSet.FirstOrDefault().Key;

var fdc3StartupProperties = new Fdc3StartupProperties() { InstanceId = fdc3InstanceId, ChannelId = channelId };
fdc3InstanceId = startupContext.GetOrAddProperty<Fdc3StartupProperties>(_ => fdc3StartupProperties).InstanceId;

var webProperties = startupContext.GetOrAddProperty<WebStartupProperties>();

webProperties
.ScriptProviders.Add(_ =>
new ValueTask<string>(
$$"""
window.composeui.fdc3 = {
...window.composeui.fdc3,
config: {
appId: "{{appId}}",
instanceId: "{{fdc3InstanceId}}"
},
channelId: "{{channelId}}"
};
"""));
var stringBuilder = new StringBuilder();
stringBuilder.Append($$"""
window.composeui.fdc3 = {
...window.composeui.fdc3,
config: {
appId: "{{appId}}",
instanceId: "{{fdc3InstanceId}}"
}
""");

webProperties
.ScriptProviders.Add(_ => new ValueTask<string>(ResourceReader.ReadResource(ResourceNames.Fdc3Bundle)));
if (channelId != null)
{
stringBuilder.Append($$"""
,
channelId: "{{channelId}}"
""");
}

stringBuilder.Append($$"""
};
""");

stringBuilder.AppendLine();
stringBuilder.Append(ResourceReader.ReadResource(ResourceNames.Fdc3Bundle));

webProperties.ScriptProviders.Add(_ => new ValueTask<string>(stringBuilder.ToString()));

//webProperties
// .ScriptProviders.Add(_ =>
// new ValueTask<string>(
// $$"""
// window.composeui.fdc3 = {
// ...window.composeui.fdc3,
// config: {
// appId: "{{appId}}",
// instanceId: "{{fdc3InstanceId}}"
// },
// channelId: "{{channelId}}"
// };
// """));

//webProperties
// .ScriptProviders.Add(_ => new ValueTask<string>(ResourceReader.ReadResource(ResourceNames.Fdc3Bundle)));
}
catch (AppNotFoundException exception)
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,5 +24,5 @@ internal class Fdc3StartupProperties
/// <summary>
/// Id of the channel the opened app should join
/// </summary>
public string ChannelId { get; init; }
public string? ChannelId { get; init; }
}
Loading

0 comments on commit 22b0240

Please sign in to comment.