工单增加连接失败日志
This commit is contained in:
1 parent
8e0cc20649
commit
1b0aa81263
1 file changed
+161
-159
@@ -1,3 +1,4 @@
|
||||
using AllBase;
|
||||
using LaunchDarkly.EventSource;
|
||||
using Newtonsoft.Json;
|
||||
using OrderSupportTicket.Models;
|
||||
@@ -14,186 +15,187 @@ namespace OrderSupportTicket.Services;
|
||||
/// </summary>
|
||||
public sealed class EventSourceTicketRealtimeService
|
||||
{
|
||||
private const string EventsPath = "/api/open/v2/customer-work-orders/events";
|
||||
private readonly object _sync = new object();
|
||||
private EventSource _eventSource;
|
||||
private bool _running;
|
||||
private bool _disposed;
|
||||
private const string EventsPath = "/api/open/v2/customer-work-orders/events";
|
||||
private readonly object _sync = new object();
|
||||
private EventSource _eventSource;
|
||||
private bool _running;
|
||||
private bool _disposed;
|
||||
|
||||
public event EventHandler<TicketRealtimeNotificationEventArgs> NotificationReceived;
|
||||
public event EventHandler<TicketRealtimeNotificationEventArgs> NotificationReceived;
|
||||
|
||||
public event EventHandler<TicketRealtimeStateChangedEventArgs> StateChanged;
|
||||
public event EventHandler<TicketRealtimeStateChangedEventArgs> StateChanged;
|
||||
|
||||
/// <summary>
|
||||
/// 当前 SSE 连接状态。
|
||||
/// </summary>
|
||||
public TicketRealtimeState State { get; private set; } = TicketRealtimeState.Disconnected;
|
||||
/// <summary>
|
||||
/// 当前 SSE 连接状态。
|
||||
/// </summary>
|
||||
public TicketRealtimeState State { get; private set; } = TicketRealtimeState.Disconnected;
|
||||
|
||||
public void Start(TicketClientOptions options)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(EventSourceTicketRealtimeService));
|
||||
if (options == null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
public void Start(TicketClientOptions options)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(EventSourceTicketRealtimeService));
|
||||
if (options == null)
|
||||
throw new ArgumentNullException(nameof(options));
|
||||
|
||||
TicketApiService.ValidateOptions(options);
|
||||
StopCore();
|
||||
TicketApiService.ValidateOptions(options);
|
||||
StopCore();
|
||||
|
||||
var uri = BuildEventsUri(options);
|
||||
var source = new EventSource(uri);
|
||||
source.Opened += OnOpened;
|
||||
source.Closed += OnClosed;
|
||||
source.MessageReceived += OnMessageReceived;
|
||||
source.Error += OnError;
|
||||
var uri = BuildEventsUri(options);
|
||||
var source = new EventSource(uri);
|
||||
source.Opened += OnOpened;
|
||||
source.Closed += OnClosed;
|
||||
source.MessageReceived += OnMessageReceived;
|
||||
source.Error += OnError;
|
||||
|
||||
lock (_sync)
|
||||
{
|
||||
_running = true;
|
||||
_eventSource = source;
|
||||
}
|
||||
lock (_sync)
|
||||
{
|
||||
_running = true;
|
||||
_eventSource = source;
|
||||
}
|
||||
|
||||
SetState(TicketRealtimeState.Connecting, "连接中…");
|
||||
_ = RunAsync(source);
|
||||
}
|
||||
SetState(TicketRealtimeState.Connecting, "连接中…");
|
||||
_ = RunAsync(source);
|
||||
}
|
||||
|
||||
public Task StopAsync()
|
||||
{
|
||||
StopCore();
|
||||
SetState(TicketRealtimeState.Disconnected, "已断开");
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
public Task StopAsync()
|
||||
{
|
||||
StopCore();
|
||||
SetState(TicketRealtimeState.Disconnected, "已断开");
|
||||
return Task.FromResult(0);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
StopCore();
|
||||
_disposed = true;
|
||||
}
|
||||
public void Dispose()
|
||||
{
|
||||
if (_disposed)
|
||||
return;
|
||||
StopCore();
|
||||
_disposed = true;
|
||||
}
|
||||
|
||||
private async Task RunAsync(EventSource source)
|
||||
{
|
||||
try
|
||||
{
|
||||
await source.StartAsync();
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, source))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接已关闭,等待重连…");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, source))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接失败:" + ex.Message);
|
||||
}
|
||||
}
|
||||
private async Task RunAsync(EventSource source)
|
||||
{
|
||||
try
|
||||
{
|
||||
await source.StartAsync();
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, source))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接已关闭,等待重连…");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSave.Add("工单服务连接失败:" + ex.Message);
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, source))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接失败:" + ex.Message);
|
||||
}
|
||||
}
|
||||
|
||||
private void OnOpened(object sender, StateChangedEventArgs args)
|
||||
{
|
||||
SetState(TicketRealtimeState.Connected, "已连接");
|
||||
}
|
||||
private void OnOpened(object sender, StateChangedEventArgs args)
|
||||
{
|
||||
SetState(TicketRealtimeState.Connected, "已连接");
|
||||
}
|
||||
|
||||
private void OnClosed(object sender, StateChangedEventArgs args)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, sender))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接断开,重连中…");
|
||||
}
|
||||
private void OnClosed(object sender, StateChangedEventArgs args)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, sender))
|
||||
return;
|
||||
}
|
||||
SetState(TicketRealtimeState.Reconnecting, "连接断开,重连中…");
|
||||
}
|
||||
|
||||
private void OnError(object sender, ExceptionEventArgs args)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, sender))
|
||||
return;
|
||||
}
|
||||
SetState(
|
||||
TicketRealtimeState.Reconnecting,
|
||||
"连接异常,重连中:" + (args.Exception?.Message ?? "未知错误"));
|
||||
}
|
||||
private void OnError(object sender, ExceptionEventArgs args)
|
||||
{
|
||||
lock (_sync)
|
||||
{
|
||||
if (!_running || !ReferenceEquals(_eventSource, sender))
|
||||
return;
|
||||
}
|
||||
SetState(
|
||||
TicketRealtimeState.Reconnecting,
|
||||
"连接异常,重连中:" + (args.Exception?.Message ?? "未知错误"));
|
||||
}
|
||||
|
||||
private void OnMessageReceived(object sender, MessageReceivedEventArgs args)
|
||||
{
|
||||
if (args == null)
|
||||
return;
|
||||
var data = args.Message.Data;
|
||||
if (string.IsNullOrWhiteSpace(data))
|
||||
return;
|
||||
private void OnMessageReceived(object sender, MessageReceivedEventArgs args)
|
||||
{
|
||||
if (args == null)
|
||||
return;
|
||||
var data = args.Message.Data;
|
||||
if (string.IsNullOrWhiteSpace(data))
|
||||
return;
|
||||
|
||||
TicketRealtimeNotification notification;
|
||||
try
|
||||
{
|
||||
notification = JsonConvert.DeserializeObject<TicketRealtimeNotification>(data, TicketApiService.JsonSettings);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
TicketRealtimeNotification notification;
|
||||
try
|
||||
{
|
||||
notification = JsonConvert.DeserializeObject<TicketRealtimeNotification>(data, TicketApiService.JsonSettings);
|
||||
}
|
||||
catch (JsonException)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (notification == null)
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(notification.EventId))
|
||||
notification.EventId = args.Message.LastEventId;
|
||||
if (string.IsNullOrWhiteSpace(notification.Type))
|
||||
notification.Type = args.EventName;
|
||||
if (notification == null)
|
||||
return;
|
||||
if (string.IsNullOrWhiteSpace(notification.EventId))
|
||||
notification.EventId = args.Message.LastEventId;
|
||||
if (string.IsNullOrWhiteSpace(notification.Type))
|
||||
notification.Type = args.EventName;
|
||||
|
||||
NotificationReceived?.Invoke(
|
||||
this,
|
||||
new TicketRealtimeNotificationEventArgs(notification));
|
||||
}
|
||||
NotificationReceived?.Invoke(
|
||||
this,
|
||||
new TicketRealtimeNotificationEventArgs(notification));
|
||||
}
|
||||
|
||||
private void StopCore()
|
||||
{
|
||||
EventSource source;
|
||||
lock (_sync)
|
||||
{
|
||||
_running = false;
|
||||
source = _eventSource;
|
||||
_eventSource = null;
|
||||
}
|
||||
private void StopCore()
|
||||
{
|
||||
EventSource source;
|
||||
lock (_sync)
|
||||
{
|
||||
_running = false;
|
||||
source = _eventSource;
|
||||
_eventSource = null;
|
||||
}
|
||||
|
||||
if (source == null)
|
||||
return;
|
||||
source.Opened -= OnOpened;
|
||||
source.Closed -= OnClosed;
|
||||
source.MessageReceived -= OnMessageReceived;
|
||||
source.Error -= OnError;
|
||||
source.Close();
|
||||
}
|
||||
if (source == null)
|
||||
return;
|
||||
source.Opened -= OnOpened;
|
||||
source.Closed -= OnClosed;
|
||||
source.MessageReceived -= OnMessageReceived;
|
||||
source.Error -= OnError;
|
||||
source.Close();
|
||||
}
|
||||
|
||||
private void SetState(TicketRealtimeState state, string message)
|
||||
{
|
||||
State = state;
|
||||
StateChanged?.Invoke(
|
||||
this,
|
||||
new TicketRealtimeStateChangedEventArgs(state, message));
|
||||
}
|
||||
private void SetState(TicketRealtimeState state, string message)
|
||||
{
|
||||
State = state;
|
||||
StateChanged?.Invoke(
|
||||
this,
|
||||
new TicketRealtimeStateChangedEventArgs(state, message));
|
||||
}
|
||||
|
||||
private static Uri BuildEventsUri(TicketClientOptions options)
|
||||
{
|
||||
var appIds = options.AppIds
|
||||
.Where(a => !string.IsNullOrWhiteSpace(a))
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.Select(a => "appId=" + Uri.EscapeDataString(a.Trim()));
|
||||
var query = new[]
|
||||
{
|
||||
"purchaseAccount=" + Uri.EscapeDataString(options.UserName)
|
||||
}.Concat(appIds);
|
||||
private static Uri BuildEventsUri(TicketClientOptions options)
|
||||
{
|
||||
var appIds = options.AppIds
|
||||
.Where(a => !string.IsNullOrWhiteSpace(a))
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.Select(a => "appId=" + Uri.EscapeDataString(a.Trim()));
|
||||
var query = new[]
|
||||
{
|
||||
"purchaseAccount=" + Uri.EscapeDataString(options.UserName)
|
||||
}.Concat(appIds);
|
||||
|
||||
return new Uri(
|
||||
TicketApiService.ServerUrl
|
||||
+ EventsPath
|
||||
+ "?"
|
||||
+ string.Join("&", query),
|
||||
UriKind.Absolute);
|
||||
}
|
||||
return new Uri(
|
||||
TicketApiService.ServerUrl
|
||||
+ EventsPath
|
||||
+ "?"
|
||||
+ string.Join("&", query),
|
||||
UriKind.Absolute);
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user