Fixed #2: Improve connection status and changing servers
This commit is contained in:
parent
d6b9970d51
commit
3d229b5ea8
@ -17,5 +17,11 @@
|
||||
Username = username;
|
||||
Password = password;
|
||||
}
|
||||
|
||||
|
||||
public override string ToString()
|
||||
{
|
||||
return $"{Host}:{Port}{VirtualHost}";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
100
PettingZoo.Core/Connection/DynamicConnection.cs
Normal file
100
PettingZoo.Core/Connection/DynamicConnection.cs
Normal file
@ -0,0 +1,100 @@
|
||||
using System;
|
||||
using System.Diagnostics.CodeAnalysis;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace PettingZoo.Core.Connection
|
||||
{
|
||||
public class DynamicConnection : IConnection
|
||||
{
|
||||
public Guid ConnectionId => currentConnection?.ConnectionId ?? Guid.Empty;
|
||||
public ConnectionParams? ConnectionParams { get; private set; }
|
||||
public ConnectionStatus Status { get; private set; } = ConnectionStatus.Disconnected;
|
||||
public event EventHandler<StatusChangedEventArgs>? StatusChanged;
|
||||
|
||||
|
||||
private IConnection? currentConnection;
|
||||
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
if (currentConnection != null)
|
||||
await currentConnection.DisposeAsync();
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
CheckConnection();
|
||||
currentConnection.Connect();
|
||||
|
||||
}
|
||||
|
||||
public async ValueTask Disconnect()
|
||||
{
|
||||
if (currentConnection == null)
|
||||
return;
|
||||
|
||||
var disconnectedConnectionId = currentConnection.ConnectionId;
|
||||
await currentConnection.DisposeAsync();
|
||||
currentConnection = null;
|
||||
|
||||
ConnectionStatusChanged(this, new StatusChangedEventArgs(disconnectedConnectionId, ConnectionStatus.Disconnected));
|
||||
}
|
||||
|
||||
|
||||
public void SetConnection(IConnection connection)
|
||||
{
|
||||
if (currentConnection != null)
|
||||
{
|
||||
currentConnection.StatusChanged -= ConnectionStatusChanged;
|
||||
ConnectionStatusChanged(this, new StatusChangedEventArgs(currentConnection.ConnectionId, ConnectionStatus.Disconnected));
|
||||
}
|
||||
|
||||
currentConnection = connection;
|
||||
|
||||
// Assume we get the new connection before Connect is called, thus before the status changes
|
||||
if (currentConnection != null)
|
||||
currentConnection.StatusChanged += ConnectionStatusChanged;
|
||||
}
|
||||
|
||||
|
||||
public ISubscriber Subscribe(string exchange, string routingKey)
|
||||
{
|
||||
CheckConnection();
|
||||
return currentConnection.Subscribe(exchange, routingKey);
|
||||
}
|
||||
|
||||
|
||||
public ISubscriber Subscribe()
|
||||
{
|
||||
CheckConnection();
|
||||
return currentConnection.Subscribe();
|
||||
}
|
||||
|
||||
|
||||
public Task Publish(PublishMessageInfo messageInfo)
|
||||
{
|
||||
CheckConnection();
|
||||
return currentConnection.Publish(messageInfo);
|
||||
}
|
||||
|
||||
|
||||
private void ConnectionStatusChanged(object? sender, StatusChangedEventArgs e)
|
||||
{
|
||||
ConnectionParams = e.ConnectionParams;
|
||||
Status = e.Status;
|
||||
|
||||
StatusChanged?.Invoke(sender, e);
|
||||
}
|
||||
|
||||
|
||||
[MemberNotNull(nameof(currentConnection))]
|
||||
private void CheckConnection()
|
||||
{
|
||||
if (currentConnection == null)
|
||||
throw new InvalidOperationException("No current connection");
|
||||
}
|
||||
}
|
||||
}
|
@ -5,8 +5,15 @@ namespace PettingZoo.Core.Connection
|
||||
{
|
||||
public interface IConnection : IAsyncDisposable
|
||||
{
|
||||
Guid ConnectionId { get; }
|
||||
ConnectionParams? ConnectionParams { get; }
|
||||
ConnectionStatus Status { get; }
|
||||
|
||||
event EventHandler<StatusChangedEventArgs> StatusChanged;
|
||||
|
||||
|
||||
void Connect();
|
||||
|
||||
ISubscriber Subscribe(string exchange, string routingKey);
|
||||
ISubscriber Subscribe();
|
||||
|
||||
@ -25,14 +32,18 @@ namespace PettingZoo.Core.Connection
|
||||
|
||||
public class StatusChangedEventArgs : EventArgs
|
||||
{
|
||||
public Guid ConnectionId { get; }
|
||||
public ConnectionStatus Status { get; }
|
||||
public string? Context { get; }
|
||||
public ConnectionParams? ConnectionParams { get; }
|
||||
public Exception? Exception { get; }
|
||||
|
||||
|
||||
public StatusChangedEventArgs(ConnectionStatus status, string? context)
|
||||
public StatusChangedEventArgs(Guid connectionId, ConnectionStatus status, ConnectionParams? connectionParams = null, Exception? exception = null)
|
||||
{
|
||||
ConnectionId = connectionId;
|
||||
Status = status;
|
||||
Context = context;
|
||||
ConnectionParams = connectionParams;
|
||||
Exception = exception;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -3,51 +3,56 @@ using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using PettingZoo.Core.Connection;
|
||||
using RabbitMQ.Client;
|
||||
using IConnection = RabbitMQ.Client.IConnection;
|
||||
|
||||
namespace PettingZoo.RabbitMQ
|
||||
{
|
||||
public class RabbitMQClientConnection : Core.Connection.IConnection
|
||||
{
|
||||
public Guid ConnectionId { get; } = Guid.NewGuid();
|
||||
public ConnectionParams? ConnectionParams { get; }
|
||||
public ConnectionStatus Status { get; set; }
|
||||
public event EventHandler<StatusChangedEventArgs>? StatusChanged;
|
||||
|
||||
|
||||
private const int ConnectRetryDelay = 5000;
|
||||
|
||||
private readonly CancellationTokenSource connectionTaskToken = new();
|
||||
private readonly Task connectionTask;
|
||||
private Task? connectionTask;
|
||||
private readonly object connectionLock = new();
|
||||
private global::RabbitMQ.Client.IConnection? connection;
|
||||
private IModel? model;
|
||||
private IConnection? connection;
|
||||
|
||||
|
||||
public event EventHandler<StatusChangedEventArgs>? StatusChanged;
|
||||
|
||||
|
||||
public RabbitMQClientConnection(ConnectionParams connectionParams)
|
||||
{
|
||||
connectionTask = Task.Factory.StartNew(() => TryConnection(connectionParams, connectionTaskToken.Token), CancellationToken.None);
|
||||
ConnectionParams = connectionParams;
|
||||
}
|
||||
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
if (connectionTask == null)
|
||||
return;
|
||||
|
||||
connectionTaskToken.Cancel();
|
||||
if (!connectionTask.IsCompleted)
|
||||
await connectionTask;
|
||||
|
||||
lock (connectionLock)
|
||||
{
|
||||
if (model != null)
|
||||
{
|
||||
model.Dispose();
|
||||
model = null;
|
||||
}
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
connection.Dispose();
|
||||
connection = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
public void Connect()
|
||||
{
|
||||
connectionTask = Task.Factory.StartNew(() => TryConnection(ConnectionParams!, connectionTaskToken.Token), CancellationToken.None);
|
||||
}
|
||||
|
||||
|
||||
@ -67,6 +72,7 @@ namespace PettingZoo.RabbitMQ
|
||||
{
|
||||
lock (connectionLock)
|
||||
{
|
||||
var model = connection?.CreateModel();
|
||||
var subscriber = new RabbitMQClientSubscriber(model, exchange, routingKey);
|
||||
if (model != null)
|
||||
return subscriber;
|
||||
@ -79,10 +85,10 @@ namespace PettingZoo.RabbitMQ
|
||||
|
||||
lock (connectionLock)
|
||||
{
|
||||
if (model == null)
|
||||
if (connection == null)
|
||||
return;
|
||||
|
||||
subscriber.Connected(model);
|
||||
subscriber.Connected(connection.CreateModel());
|
||||
}
|
||||
|
||||
StatusChanged -= ConnectSubscriber;
|
||||
@ -97,12 +103,30 @@ namespace PettingZoo.RabbitMQ
|
||||
|
||||
public Task Publish(PublishMessageInfo messageInfo)
|
||||
{
|
||||
if (model == null)
|
||||
IConnection? lockedConnection;
|
||||
|
||||
lock (connectionLock)
|
||||
{
|
||||
lockedConnection = connection;
|
||||
}
|
||||
|
||||
if (lockedConnection == null)
|
||||
throw new InvalidOperationException("Not connected");
|
||||
|
||||
model.BasicPublish(messageInfo.Exchange, messageInfo.RoutingKey, false,
|
||||
RabbitMQClientPropertiesConverter.Convert(messageInfo.Properties, model.CreateBasicProperties()),
|
||||
messageInfo.Body);
|
||||
using (var model = lockedConnection.CreateModel())
|
||||
{
|
||||
try
|
||||
{
|
||||
model.BasicPublish(messageInfo.Exchange, messageInfo.RoutingKey, false,
|
||||
RabbitMQClientPropertiesConverter.Convert(messageInfo.Properties,
|
||||
model.CreateBasicProperties()),
|
||||
messageInfo.Body);
|
||||
}
|
||||
finally
|
||||
{
|
||||
model.Close();
|
||||
}
|
||||
}
|
||||
|
||||
return Task.CompletedTask;
|
||||
}
|
||||
@ -119,22 +143,22 @@ namespace PettingZoo.RabbitMQ
|
||||
Password = connectionParams.Password
|
||||
};
|
||||
|
||||
var statusContext = $"{connectionParams.Host}:{connectionParams.Port}{connectionParams.VirtualHost}";
|
||||
|
||||
while (!cancellationToken.IsCancellationRequested)
|
||||
{
|
||||
DoStatusChanged(ConnectionStatus.Connecting, statusContext);
|
||||
DoStatusChanged(ConnectionStatus.Connecting);
|
||||
try
|
||||
{
|
||||
connection = factory.CreateConnection();
|
||||
model = connection.CreateModel();
|
||||
|
||||
DoStatusChanged(ConnectionStatus.Connected, statusContext);
|
||||
lock (connectionLock)
|
||||
{
|
||||
connection = factory.CreateConnection();
|
||||
}
|
||||
|
||||
DoStatusChanged(ConnectionStatus.Connected);
|
||||
break;
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
DoStatusChanged(ConnectionStatus.Error, e.Message);
|
||||
DoStatusChanged(ConnectionStatus.Error, e);
|
||||
|
||||
try
|
||||
{
|
||||
@ -148,9 +172,10 @@ namespace PettingZoo.RabbitMQ
|
||||
}
|
||||
|
||||
|
||||
private void DoStatusChanged(ConnectionStatus status, string? context = null)
|
||||
private void DoStatusChanged(ConnectionStatus status, Exception? exception = null)
|
||||
{
|
||||
StatusChanged?.Invoke(this, new StatusChangedEventArgs(status, context));
|
||||
Status = status;
|
||||
StatusChanged?.Invoke(this, new StatusChangedEventArgs(ConnectionId, status, ConnectionParams, exception));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
2
PettingZoo/UI/Main/MainWindowStrings.Designer.cs
generated
2
PettingZoo/UI/Main/MainWindowStrings.Designer.cs
generated
@ -160,7 +160,7 @@ namespace PettingZoo.UI.Main {
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Connected.
|
||||
/// Looks up a localized string similar to Connected to {0}.
|
||||
/// </summary>
|
||||
public static string StatusConnected {
|
||||
get {
|
||||
|
@ -151,7 +151,7 @@
|
||||
<value>Importing messages...</value>
|
||||
</data>
|
||||
<data name="StatusConnected" xml:space="preserve">
|
||||
<value>Connected</value>
|
||||
<value>Connected to {0}</value>
|
||||
</data>
|
||||
<data name="StatusConnecting" xml:space="preserve">
|
||||
<value>Connecting to {0}...</value>
|
||||
|
@ -43,7 +43,7 @@ namespace PettingZoo.UI.Main
|
||||
private readonly IExportImportFormatProvider exportImportFormatProvider;
|
||||
|
||||
private SubscribeDialogParams? subscribeDialogParams;
|
||||
private IConnection? connection;
|
||||
private readonly DynamicConnection connection = new();
|
||||
private string connectionStatus;
|
||||
private ITab? activeTab;
|
||||
private readonly Dictionary<ITab, Window> undockedTabs = new();
|
||||
@ -141,15 +141,15 @@ namespace PettingZoo.UI.Main
|
||||
closeTabCommand = new DelegateCommand(CloseTabExecute, HasActiveTabCanExecute);
|
||||
undockTabCommand = new DelegateCommand(UndockTabExecute, HasActiveTabCanExecute);
|
||||
importCommand = new DelegateCommand(ImportExecute);
|
||||
|
||||
connection.StatusChanged += ConnectionStatusChanged;
|
||||
}
|
||||
|
||||
|
||||
public async ValueTask DisposeAsync()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
|
||||
if (connection != null)
|
||||
await connection.DisposeAsync();
|
||||
await connection.DisposeAsync();
|
||||
}
|
||||
|
||||
|
||||
@ -159,13 +159,9 @@ namespace PettingZoo.UI.Main
|
||||
if (connectionSettings == null)
|
||||
return;
|
||||
|
||||
if (connection != null)
|
||||
await connection.DisposeAsync();
|
||||
|
||||
connection = connectionFactory.CreateConnection(new ConnectionParams(
|
||||
connection.SetConnection(connectionFactory.CreateConnection(new ConnectionParams(
|
||||
connectionSettings.Host, connectionSettings.VirtualHost, connectionSettings.Port,
|
||||
connectionSettings.Username, connectionSettings.Password));
|
||||
connection.StatusChanged += ConnectionStatusChanged;
|
||||
connectionSettings.Username, connectionSettings.Password)));
|
||||
|
||||
if (connectionSettings.Subscribe)
|
||||
{
|
||||
@ -173,40 +169,22 @@ namespace PettingZoo.UI.Main
|
||||
tabFactory.CreateSubscriberTab(connection, subscriber);
|
||||
}
|
||||
|
||||
connection.Connect();
|
||||
ConnectionChanged();
|
||||
}
|
||||
|
||||
|
||||
private async void DisconnectExecute()
|
||||
{
|
||||
Tabs.Clear();
|
||||
|
||||
var capturedUndockedTabs = undockedTabs.ToList();
|
||||
undockedTabs.Clear();
|
||||
|
||||
foreach (var undockedTab in capturedUndockedTabs)
|
||||
undockedTab.Value.Close();
|
||||
|
||||
RaisePropertyChanged(nameof(NoTabsVisibility));
|
||||
undockTabCommand.RaiseCanExecuteChanged();
|
||||
|
||||
if (connection != null)
|
||||
{
|
||||
await connection.DisposeAsync();
|
||||
connection = null;
|
||||
}
|
||||
|
||||
ConnectionStatus = GetConnectionStatus(null);
|
||||
ConnectionStatusType = ConnectionStatusType.Error;
|
||||
ConnectionChanged();
|
||||
await connection.Disconnect();
|
||||
}
|
||||
|
||||
|
||||
private void SubscribeExecute()
|
||||
{
|
||||
if (connection == null)
|
||||
if (connection.Status != Core.Connection.ConnectionStatus.Connected)
|
||||
return;
|
||||
|
||||
|
||||
var newParams = subscribeDialog.Show(subscribeDialogParams);
|
||||
if (newParams == null)
|
||||
return;
|
||||
@ -220,16 +198,16 @@ namespace PettingZoo.UI.Main
|
||||
|
||||
private void PublishExecute()
|
||||
{
|
||||
if (connection == null)
|
||||
if (connection.Status != Core.Connection.ConnectionStatus.Connected)
|
||||
return;
|
||||
|
||||
|
||||
tabFactory.CreatePublisherTab(connection);
|
||||
}
|
||||
|
||||
|
||||
private bool IsConnectedCanExecute()
|
||||
{
|
||||
return connection != null;
|
||||
return connection.Status == Core.Connection.ConnectionStatus.Connected;
|
||||
}
|
||||
|
||||
|
||||
@ -419,6 +397,8 @@ namespace PettingZoo.UI.Main
|
||||
Core.Connection.ConnectionStatus.Connecting => ConnectionStatusType.Connecting,
|
||||
_ => ConnectionStatusType.Error
|
||||
};
|
||||
|
||||
Application.Current.Dispatcher.BeginInvoke(ConnectionChanged);
|
||||
}
|
||||
|
||||
|
||||
@ -427,9 +407,9 @@ namespace PettingZoo.UI.Main
|
||||
{
|
||||
return args?.Status switch
|
||||
{
|
||||
Core.Connection.ConnectionStatus.Connecting => string.Format(MainWindowStrings.StatusConnecting, args.Context),
|
||||
Core.Connection.ConnectionStatus.Connected => string.Format(MainWindowStrings.StatusConnected, args.Context),
|
||||
Core.Connection.ConnectionStatus.Error => string.Format(MainWindowStrings.StatusError, args.Context),
|
||||
Core.Connection.ConnectionStatus.Connecting => string.Format(MainWindowStrings.StatusConnecting, args.ConnectionParams),
|
||||
Core.Connection.ConnectionStatus.Connected => string.Format(MainWindowStrings.StatusConnected, args.ConnectionParams),
|
||||
Core.Connection.ConnectionStatus.Error => string.Format(MainWindowStrings.StatusError, args.Exception?.Message),
|
||||
Core.Connection.ConnectionStatus.Disconnected => MainWindowStrings.StatusDisconnected,
|
||||
_ => MainWindowStrings.StatusDisconnected
|
||||
};
|
||||
|
@ -4,7 +4,7 @@ namespace PettingZoo.UI.Tab
|
||||
{
|
||||
public interface ITabFactory
|
||||
{
|
||||
void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber);
|
||||
void CreateSubscriberTab(IConnection connection, ISubscriber subscriber);
|
||||
string CreateReplySubscriberTab(IConnection connection);
|
||||
void CreatePublisherTab(IConnection connection, ReceivedMessageInfo? fromReceivedMessage = null);
|
||||
}
|
||||
|
@ -8,7 +8,7 @@
|
||||
xmlns:svgc="http://sharpvectors.codeplex.com/svgc/"
|
||||
xmlns:valueConverters="clr-namespace:PettingZoo.WPF.ValueConverters;assembly=PettingZoo.WPF"
|
||||
mc:Ignorable="d"
|
||||
d:DesignHeight="450"
|
||||
d:DesignHeight="1200"
|
||||
d:DesignWidth="800"
|
||||
d:DataContext="{d:DesignInstance res:DesignTimePublisherViewModel, IsDesignTimeCreatable=True}"
|
||||
Background="White">
|
||||
@ -34,6 +34,7 @@
|
||||
<RowDefinition Height="16" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" SharedSizeGroup="Label" />
|
||||
@ -81,6 +82,7 @@
|
||||
<ContentControl Grid.Row="10" Grid.Column="0" Grid.ColumnSpan="2" Margin="0 8 0 0" Content="{Binding MessageTypeControl}" />
|
||||
|
||||
<Button Grid.Row="11" Grid.Column="1" Command="{Binding PublishCommand}" Content="{x:Static res:PublisherViewStrings.CommandPublish}" HorizontalAlignment="Left" />
|
||||
<TextBlock Grid.Row="12" Grid.Column="1" Text="{x:Static res:PublisherViewStrings.Published}" Visibility="{Binding PublishedVisibility}" />
|
||||
</controls:GridLayout>
|
||||
</ScrollViewer>
|
||||
|
||||
|
@ -8,7 +8,7 @@ using System.Threading.Tasks;
|
||||
using System.Windows;
|
||||
using System.Windows.Forms;
|
||||
using System.Windows.Input;
|
||||
using Accessibility;
|
||||
using System.Windows.Threading;
|
||||
using Newtonsoft.Json;
|
||||
using Newtonsoft.Json.Converters;
|
||||
using PettingZoo.Core.Connection;
|
||||
@ -17,11 +17,12 @@ using PettingZoo.Core.Generator;
|
||||
using PettingZoo.Core.Macros;
|
||||
using PettingZoo.Core.Settings;
|
||||
using PettingZoo.WPF.ViewModel;
|
||||
using Application = System.Windows.Application;
|
||||
using UserControl = System.Windows.Controls.UserControl;
|
||||
|
||||
namespace PettingZoo.UI.Tab.Publisher
|
||||
{
|
||||
public class PublisherViewModel : BaseViewModel, ITabToolbarCommands, ITabHostWindowNotify, IPublishDestination
|
||||
public class PublisherViewModel : BaseViewModel, IDisposable, ITabToolbarCommands, ITabHostWindowNotify, IPublishDestination
|
||||
{
|
||||
private readonly IConnection connection;
|
||||
private readonly IExampleGenerator exampleGenerator;
|
||||
@ -197,6 +198,19 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
public ICommand ImportCommand => importCommand;
|
||||
|
||||
|
||||
private readonly DispatcherTimer publishedVisibilityTimer = new()
|
||||
{
|
||||
Interval = TimeSpan.FromSeconds(1)
|
||||
};
|
||||
|
||||
private Visibility publishedVisibility = Visibility.Hidden;
|
||||
public Visibility PublishedVisibility
|
||||
{
|
||||
get => publishedVisibility;
|
||||
set => SetField(ref publishedVisibility, value);
|
||||
}
|
||||
|
||||
|
||||
public string Title => SendToQueue
|
||||
? string.IsNullOrWhiteSpace(Queue) ? PublisherViewStrings.TabTitleEmpty :
|
||||
string.Format(PublisherViewStrings.TabTitle, Queue)
|
||||
@ -244,17 +258,51 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
|
||||
|
||||
PropertyChanged += (_, _) => { saveCommand.RaiseCanExecuteChanged(); };
|
||||
|
||||
|
||||
// ReSharper disable once ConditionIsAlwaysTrueOrFalse - null in design time
|
||||
if (connection != null)
|
||||
connection.StatusChanged += ConnectionStatusChanged;
|
||||
|
||||
publishedVisibilityTimer.Tick += (_, _) =>
|
||||
{
|
||||
PublishedVisibility = Visibility.Hidden;
|
||||
publishedVisibilityTimer.Stop();
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
connection.StatusChanged -= ConnectionStatusChanged;
|
||||
GC.SuppressFinalize(this);
|
||||
}
|
||||
|
||||
|
||||
private void ConnectionStatusChanged(object? sender, StatusChangedEventArgs e)
|
||||
{
|
||||
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
publishCommand.RaiseCanExecuteChanged();
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void PublishExecute()
|
||||
{
|
||||
messageTypePublishCommand?.Execute(null);
|
||||
|
||||
PublishedVisibility = Visibility.Visible;
|
||||
publishedVisibilityTimer.Stop();
|
||||
publishedVisibilityTimer.Start();
|
||||
}
|
||||
|
||||
|
||||
private bool PublishCanExecute()
|
||||
{
|
||||
if (connection.Status != ConnectionStatus.Connected)
|
||||
return false;
|
||||
|
||||
if (SendToExchange)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(Exchange) || string.IsNullOrWhiteSpace(RoutingKey))
|
||||
@ -571,6 +619,8 @@ namespace PettingZoo.UI.Tab.Publisher
|
||||
SelectedStoredMessage = StoredMessages[0];
|
||||
ActiveStoredMessage = StoredMessages[1];
|
||||
};
|
||||
|
||||
PublishedVisibility = Visibility.Visible;
|
||||
}
|
||||
|
||||
public override Visibility ExchangeVisibility => Visibility.Visible;
|
||||
|
@ -177,6 +177,15 @@ namespace PettingZoo.UI.Tab.Publisher {
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Message published.
|
||||
/// </summary>
|
||||
public static string Published {
|
||||
get {
|
||||
return ResourceManager.GetString("Published", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Re: .
|
||||
/// </summary>
|
||||
|
@ -156,6 +156,9 @@
|
||||
<data name="PanelTitleMessages" xml:space="preserve">
|
||||
<value>Saved messages</value>
|
||||
</data>
|
||||
<data name="Published" xml:space="preserve">
|
||||
<value>Message published</value>
|
||||
</data>
|
||||
<data name="ReplyToCorrelationIdPrefix" xml:space="preserve">
|
||||
<value>Re: </value>
|
||||
</data>
|
||||
|
@ -37,8 +37,8 @@
|
||||
<ListBox.ItemsSource>
|
||||
<CompositeCollection>
|
||||
<CollectionContainer Collection="{Binding Source={StaticResource Messages}}" />
|
||||
<ListBoxItem HorizontalContentAlignment="Stretch" IsEnabled="False" IsHitTestVisible="False">
|
||||
<Grid Visibility="{Binding UnreadMessagesVisibility}">
|
||||
<ListBoxItem HorizontalContentAlignment="Stretch" IsEnabled="False" IsHitTestVisible="False" Visibility="{Binding UnreadMessagesVisibility}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition SharedSizeGroup="DateTime" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
@ -51,6 +51,17 @@
|
||||
</Grid>
|
||||
</ListBoxItem>
|
||||
<CollectionContainer Collection="{Binding Source={StaticResource UnreadMessages}}" />
|
||||
<ListBoxItem HorizontalContentAlignment="Stretch" IsEnabled="False" IsHitTestVisible="False" Visibility="{Binding StatusVisibility}">
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition SharedSizeGroup="DateTime" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="*" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="1" Text="{Binding StatusText}" HorizontalAlignment="Center" Background="{Binding Background, RelativeSource={RelativeSource AncestorType={x:Type ListBoxItem}}}" Foreground="{x:Static SystemColors.GrayTextBrush}" />
|
||||
</Grid>
|
||||
</ListBoxItem>
|
||||
</CompositeCollection>
|
||||
</ListBox.ItemsSource>
|
||||
<ListBox.ItemTemplate>
|
||||
|
@ -25,7 +25,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
{
|
||||
private readonly ILogger logger;
|
||||
private readonly ITabFactory tabFactory;
|
||||
private readonly IConnection? connection;
|
||||
private readonly IConnection connection;
|
||||
private readonly ISubscriber subscriber;
|
||||
private readonly IExportImportFormatProvider exportImportFormatProvider;
|
||||
private ReceivedMessageInfo? selectedMessage;
|
||||
@ -106,8 +106,14 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
public Visibility ReplyTabVisibility => IsReplyTab ? Visibility.Visible : Visibility.Collapsed;
|
||||
// ReSharper restore UnusedMember.Global
|
||||
|
||||
private readonly Guid subscribeConnectionId;
|
||||
private ConnectionStatus connectionStatus = ConnectionStatus.Connecting;
|
||||
|
||||
public SubscriberViewModel(ILogger logger, ITabFactory tabFactory, IConnection? connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider, bool isReplyTab)
|
||||
public Visibility StatusVisibility => connectionStatus is ConnectionStatus.Connecting or ConnectionStatus.Disconnected or ConnectionStatus.Error ? Visibility.Visible : Visibility.Collapsed;
|
||||
public string StatusText => connectionStatus == ConnectionStatus.Connecting ? SubscriberViewStrings.StatusConnecting : SubscriberViewStrings.StatusDisconnected;
|
||||
|
||||
|
||||
public SubscriberViewModel(ILogger logger, ITabFactory tabFactory, IConnection connection, ISubscriber subscriber, IExportImportFormatProvider exportImportFormatProvider, bool isReplyTab)
|
||||
{
|
||||
IsReplyTab = isReplyTab;
|
||||
|
||||
@ -133,6 +139,8 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
createPublisherCommand = new DelegateCommand(CreatePublisherExecute, CreatePublisherCanExecute);
|
||||
|
||||
subscribeConnectionId = connection.ConnectionId;
|
||||
connection.StatusChanged += ConnectionStatusChanged;
|
||||
subscriber.MessageReceived += SubscriberMessageReceived;
|
||||
subscriber.Start();
|
||||
}
|
||||
@ -141,11 +149,47 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
public void Dispose()
|
||||
{
|
||||
GC.SuppressFinalize(this);
|
||||
connection.StatusChanged -= ConnectionStatusChanged;
|
||||
newMessageTimer?.Dispose();
|
||||
subscriber.Dispose();
|
||||
}
|
||||
|
||||
|
||||
private void ConnectionStatusChanged(object? sender, StatusChangedEventArgs e)
|
||||
{
|
||||
// If another connection has been made, this does not concern us
|
||||
if (e.ConnectionId != subscribeConnectionId)
|
||||
return;
|
||||
|
||||
// The subscriber will not reconnect, so after the first disconnect it's over for us
|
||||
if (connectionStatus is ConnectionStatus.Disconnected)
|
||||
return;
|
||||
|
||||
switch (e.Status)
|
||||
{
|
||||
case ConnectionStatus.Connecting:
|
||||
case ConnectionStatus.Error:
|
||||
return;
|
||||
|
||||
case ConnectionStatus.Connected:
|
||||
connectionStatus = ConnectionStatus.Connected;
|
||||
break;
|
||||
|
||||
case ConnectionStatus.Disconnected:
|
||||
default:
|
||||
connectionStatus = ConnectionStatus.Disconnected;
|
||||
break;
|
||||
}
|
||||
|
||||
Application.Current.Dispatcher.BeginInvoke(() =>
|
||||
{
|
||||
|
||||
RaisePropertyChanged(nameof(StatusVisibility));
|
||||
RaisePropertyChanged(nameof(StatusText));
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
private void ClearExecute()
|
||||
{
|
||||
Messages.Clear();
|
||||
@ -254,7 +298,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
private void CreatePublisherExecute()
|
||||
{
|
||||
if (connection == null)
|
||||
if (connection.Status != ConnectionStatus.Connected)
|
||||
return;
|
||||
|
||||
tabFactory.CreatePublisherTab(connection, SelectedMessage);
|
||||
@ -263,7 +307,7 @@ namespace PettingZoo.UI.Tab.Subscriber
|
||||
|
||||
private bool CreatePublisherCanExecute()
|
||||
{
|
||||
return connection != null && SelectedMessage != null;
|
||||
return SelectedMessage != null;
|
||||
}
|
||||
|
||||
|
||||
|
@ -194,5 +194,23 @@ namespace PettingZoo.UI.Tab.Subscriber {
|
||||
return ResourceManager.GetString("ReplyTabTitle", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Connecting....
|
||||
/// </summary>
|
||||
public static string StatusConnecting {
|
||||
get {
|
||||
return ResourceManager.GetString("StatusConnecting", resourceCulture);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Looks up a localized string similar to Disconnected.
|
||||
/// </summary>
|
||||
public static string StatusDisconnected {
|
||||
get {
|
||||
return ResourceManager.GetString("StatusDisconnected", resourceCulture);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -162,4 +162,10 @@
|
||||
<data name="ReplyTabTitle" xml:space="preserve">
|
||||
<value>Replies</value>
|
||||
</data>
|
||||
<data name="StatusConnecting" xml:space="preserve">
|
||||
<value>Connecting...</value>
|
||||
</data>
|
||||
<data name="StatusDisconnected" xml:space="preserve">
|
||||
<value>Disconnected</value>
|
||||
</data>
|
||||
</root>
|
@ -36,7 +36,7 @@ namespace PettingZoo.UI.Tab
|
||||
}
|
||||
|
||||
|
||||
public void CreateSubscriberTab(IConnection? connection, ISubscriber subscriber)
|
||||
public void CreateSubscriberTab(IConnection connection, ISubscriber subscriber)
|
||||
{
|
||||
InternalCreateSubscriberTab(connection, subscriber, false);
|
||||
}
|
||||
@ -75,7 +75,7 @@ namespace PettingZoo.UI.Tab
|
||||
}
|
||||
|
||||
|
||||
private ITab InternalCreateSubscriberTab(IConnection? connection, ISubscriber subscriber, bool isReplyTab)
|
||||
private ITab InternalCreateSubscriberTab(IConnection connection, ISubscriber subscriber, bool isReplyTab)
|
||||
{
|
||||
var viewModel = new SubscriberViewModel(logger, this, connection, subscriber, exportImportFormatProvider, isReplyTab);
|
||||
var tab = new ViewTab<SubscriberView, SubscriberViewModel>(
|
||||
|
Loading…
Reference in New Issue
Block a user