Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
31 changes: 30 additions & 1 deletion src/Examples/WpfFdc3/Fdc3/DesktopAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ internal class DesktopAgent : IDesktopAgent
{
private readonly List<IChannel> _channels = new List<IChannel>();
private IChannel? _currentChannel;
private List<EventListener> _listeners = new List<EventListener>();

public DesktopAgent()
{
Expand All @@ -41,6 +42,16 @@ public Task<IListener> AddIntentListener<T>(string intent, IntentHandler<T> hand
throw new NotImplementedException();
}

public Task<IListener> AddEventListener(string? eventType, Fdc3EventHandler handler)
{
return Task.Run<IListener>(() =>
{
EventListener listener = new EventListener(eventType, handler);
_listeners.Add(listener);
return listener;
});
}

public Task Broadcast(IContext context)
{
if (_currentChannel != null)
Expand Down Expand Up @@ -125,12 +136,30 @@ public Task JoinUserChannel(string channelId)
{
throw new Exception(ChannelError.NoChannelFound);
}

// Notify listeners of AddEventListener of channel changed
_listeners.ForEach(listener => {
if (listener.EventType == Fdc3EventType.UserChannelChanged)
{
listener.Handler(new Fdc3ChannelChangedEvent(channelId));
}
});
});
}

public Task LeaveCurrentChannel()
{
return Task.Run(() => _currentChannel = null);
return Task.Run(() => {
_currentChannel = null;

// Notify listeners of AddEventListener of leaving channel
_listeners.ForEach(listener => {
if (listener.EventType == Fdc3EventType.UserChannelChanged)
{
listener.Handler(new Fdc3ChannelChangedEvent(null));
}
});
});
}

public Task<IAppIdentifier> Open(IAppIdentifier app, IContext? context = null)
Expand Down
17 changes: 17 additions & 0 deletions src/Examples/WpfFdc3/Fdc3/Listener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,23 @@

namespace WpfFdc3.Fdc3
{
internal class EventListener : IListener
{
internal EventListener(string? eventType, Fdc3EventHandler handler)
{
this.EventType = eventType;
this.Handler = handler;
}

public string? EventType { get; }
public Fdc3EventHandler Handler { get; }

public void Unsubscribe()
{
throw new System.NotImplementedException();
}
}

internal class Listener<T> : IListener where T : IContext
{
private IEventAggregator _eventAggregator;
Expand Down
124 changes: 124 additions & 0 deletions src/Fdc3/Fdc3Event.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,124 @@
/*
* Morgan Stanley makes this available to you under the Apache License,
* Version 2.0 (the "License"). You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Unless required by applicable law or agreed
* to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/

using System;

namespace Finos.Fdc3
{
/// <summary>
/// Interface representing the format of event objects that may be received via the FDC3 API's AddEventListener function.
/// </summary>
public interface IFdc3Event
{
public string Type { get; }
public object? Details { get; }
}

public delegate void Fdc3EventHandler(IFdc3Event fdc3Event);

/// <summary>
/// Type representing the format of event objects that may be received via the FDC3 API's addEventListener function
/// </summary>
public class Fdc3Event : IFdc3Event
{
public string Type { get; }
public object? Details { get; }

public Fdc3Event(string type, object? details = null)
{
this.Type = type ?? throw new ArgumentNullException(nameof(type));
this.Details = details;
}
}

/// <summary>
/// Valid type strings for DesktopAgent interface events.
/// </summary>
public static class Fdc3EventType
{
public const string UserChannelChanged = "userChannelChanged";
}

/// <summary>
/// Valid type strings for Private Channel events.
/// </summary>
public static class Fdc3PrivateChannelEventType
{
public const string AddContextListener = "addContextListener";
public const string Unsubscribe = "unsubscribe";
public const string Disconnect = "disconnect";
}

public interface IFdc3ChannelChangedEventDetails
{
string? CurrentChannelId { get; }
}

public class Fdc3ChannelChangedEventDetails : IFdc3ChannelChangedEventDetails
{
public string? CurrentChannelId { get; }

public Fdc3ChannelChangedEventDetails(string? channelId)
{
this.CurrentChannelId = channelId;
}
}

public class Fdc3ChannelChangedEvent : Fdc3Event
{
public Fdc3ChannelChangedEvent(string? channelId)
: base(Fdc3EventType.UserChannelChanged, new Fdc3ChannelChangedEventDetails(channelId))
{
}
}

public interface IFdc3PrivateChannelEventDetails
{
string? ContextType { get; }
}

public class Fdc3PrivateChannelEventDetails : IFdc3PrivateChannelEventDetails
{
public string? ContextType { get; }

public Fdc3PrivateChannelEventDetails(string? contextType)
{
this.ContextType = contextType;
}
}

public class Fdc3PrivateChannelAddContextListenerEvent : Fdc3Event
{
public Fdc3PrivateChannelAddContextListenerEvent(string? contextType)
: base(Fdc3PrivateChannelEventType.AddContextListener, new Fdc3PrivateChannelEventDetails(contextType))
{
}
}

public class Fdc3PrivateChannelUnsubscribeListenerEvent : Fdc3Event
{
public Fdc3PrivateChannelUnsubscribeListenerEvent(string? contextType)
: base(Fdc3PrivateChannelEventType.Unsubscribe, new Fdc3PrivateChannelEventDetails(contextType))
{
}
}

public class Fdc3PrivateChanneDisconnectEvent : Fdc3Event
{
public Fdc3PrivateChanneDisconnectEvent()
: base(Fdc3PrivateChannelEventType.Disconnect)
{
}
}
}
6 changes: 6 additions & 0 deletions src/Fdc3/IDesktopAgent.cs
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,12 @@ public interface IDesktopAgent
/// </summary>
Task<IListener> AddContextListener<T>(string? contextType, ContextHandler<T> handler) where T : IContext;

/// <summary>
/// Register a handler for events from the DesktopAgent. Whenever the handler function is
/// called it will be passed an event object with details related to the event.
/// </summary>
Task<IListener> AddEventListener(string? eventType, Fdc3EventHandler handler);

/// <summary>
/// Retreives a list of the User channels available for the app to join.
/// </summary>
Expand Down
11 changes: 11 additions & 0 deletions src/Fdc3/IPrivateChannel.cs
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@
*/

using System;
using System.Threading.Tasks;

namespace Finos.Fdc3
{
Expand All @@ -39,6 +40,7 @@ public interface IPrivateChannel : IChannel, IIntentResult
/// channel, including those that occurred before this handler was registered
/// (to prevent race conditions).
/// </summary>
[Obsolete("Use AddEventListener")]
IListener OnAddContextListener(Action<string?> handler);

/// <summary>
Expand All @@ -48,13 +50,15 @@ public interface IPrivateChannel : IChannel, IIntentResult
/// Desktop Agents MUST call this when Disconnect() is called by the other party, for
/// each listener that they had added.
/// </summary>
[Obsolete("Use AddEventListener")]
IListener OnUnsubscribe(Action<string?> handler);

/// <summary>
/// Adds an IListener that will be called when the remote app terminates, for example
/// when its window is closed or because disconnect was called.This is in addition
/// to calls that will be made to OnUnsubscribe listeners.
/// </summary>
[Obsolete("Use AddEventListener")]
IListener OnDisconnect(Action handler);

/// <summary>
Expand All @@ -66,5 +70,12 @@ public interface IPrivateChannel : IChannel, IIntentResult
/// before triggering any OnDisconnect handler added by the other party.
/// </summary>
void Disconnect();


/// <summary>
/// Register a handler for events from the PrivateChannel. Whenever the handler function is
/// called it will be passed an event object with details related to the event.
/// </summary>
Task<IListener> AddEventListener(string? eventType, Fdc3EventHandler handler);
}
}
92 changes: 92 additions & 0 deletions src/Tests/Finos.Fdc3.Tests/Fdc3EventTests.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
/*
* Morgan Stanley makes this available to you under the Apache License,
* Version 2.0 (the "License"). You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0.
*
* See the NOTICE file distributed with this work for additional information
* regarding copyright ownership. Unless required by applicable law or agreed
* to in writing, software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express
* or implied. See the License for the specific language governing permissions
* and limitations under the License.
*/

namespace Finos.Fdc3.Tests;

public class Fdc3EventTests
{
[Fact]
public void Fdc3Event_PropertiesMatchParams()
{
IFdc3Event fdc3Event = new Fdc3Event("type", new Fdc3ChannelChangedEventDetails("channelid"));
Assert.Same("type", fdc3Event.Type);
Assert.IsType<Fdc3ChannelChangedEventDetails>(fdc3Event.Details);
Assert.Same("channelid", ((Fdc3ChannelChangedEventDetails)fdc3Event.Details).CurrentChannelId);

fdc3Event = new Fdc3Event("type", null);
Assert.Null(fdc3Event.Details);
}

[Fact]
public void Fdc3ChannelChangedEventDetails_PropertiesMatchParams()
{
IFdc3ChannelChangedEventDetails details = new Fdc3ChannelChangedEventDetails("channelid");
Assert.Same("channelid", details.CurrentChannelId);

details = new Fdc3ChannelChangedEventDetails(null);
Assert.Null(details.CurrentChannelId);
}

[Fact]
public void Fdc3ChannelChangedEvent_PropertiesMatchParams()
{
IFdc3Event fdc3Event = new Fdc3ChannelChangedEvent("channelid");
Assert.Same(Fdc3EventType.UserChannelChanged, fdc3Event.Type);
Assert.IsType<Fdc3ChannelChangedEventDetails>(fdc3Event.Details);
Assert.Same("channelid", ((Fdc3ChannelChangedEventDetails)fdc3Event.Details).CurrentChannelId);

fdc3Event = new Fdc3ChannelChangedEvent(null);
Fdc3ChannelChangedEventDetails? details = fdc3Event.Details as Fdc3ChannelChangedEventDetails;
Assert.Null(details?.CurrentChannelId);
}

[Fact]
public void Fdc3PrivateChannelEventDetails_PropertiesMatchParams()
{
IFdc3PrivateChannelEventDetails details = new Fdc3PrivateChannelEventDetails("contexttype");
Assert.Same("contexttype", details.ContextType);

details = new Fdc3PrivateChannelEventDetails(null);
Assert.Null(details.ContextType);
}

[Fact]
public void Fdc3PrivateChannelAddContextListenerEvent_PropertiesMatchParams()
{
IFdc3Event fdc3Event = new Fdc3PrivateChannelAddContextListenerEvent("contextType");
Assert.Same(Fdc3PrivateChannelEventType.AddContextListener, fdc3Event.Type);

IFdc3PrivateChannelEventDetails? details = fdc3Event.Details as IFdc3PrivateChannelEventDetails;
Assert.Same("contextType", details?.ContextType);

}

[Fact]
public void Fdc3PrivateChannelUnsubscribeListenerEvent_PropertiesMatchParams()
{
IFdc3Event fdc3Event = new Fdc3PrivateChannelUnsubscribeListenerEvent("contextType");
Assert.Same(Fdc3PrivateChannelEventType.Unsubscribe, fdc3Event.Type);

IFdc3PrivateChannelEventDetails? details = fdc3Event.Details as IFdc3PrivateChannelEventDetails;
Assert.Same("contextType", details?.ContextType);
}

[Fact]
public void Fdc3PrivateChanneDisconnectEvent_PropertiesMatchParams()
{
IFdc3Event fdc3Event = new Fdc3PrivateChanneDisconnectEvent();
Assert.Same(Fdc3PrivateChannelEventType.Disconnect, fdc3Event.Type);
Assert.Null(fdc3Event.Details);
}
}