Merge branch 'main' of http://git.ts.e57.cn/chfei/29WxOrder
This commit is contained in:
commit
0b94c43fab
13 files changed
+600
-573
No files matched your search
@@ -106,10 +106,10 @@ namespace _29WxOrderWpf
|
||||
pddBuyerOrderReadCtrl.Visibility = Visibility.Visible;
|
||||
tbBuyerOrderReadCtrl.Visibility = Visibility.Visible;
|
||||
pddBuyerSelectCtrl.Visibility = Visibility.Visible;
|
||||
Task.Run(() =>
|
||||
Task.Run(async () =>
|
||||
{
|
||||
GetServerShop();
|
||||
StartTicketRealtimeMonitor();//启动工单监控
|
||||
GetServerShop();
|
||||
await StartTicketRealtimeMonitor();//启动工单监控
|
||||
GetShopSupplier(GlobalConfig.ShopLoginList.ToList());
|
||||
});
|
||||
Task.Run(() =>
|
||||
@@ -609,12 +609,12 @@ namespace _29WxOrderWpf
|
||||
_ticketMonitor.MarkAllRead();
|
||||
}
|
||||
|
||||
private void StartTicketRealtimeMonitor()
|
||||
private async Task StartTicketRealtimeMonitor()
|
||||
{
|
||||
try
|
||||
{
|
||||
var options = GetTicketOptions().Clone();
|
||||
_ticketMonitor.Start(options);
|
||||
await _ticketMonitor.Start(options);
|
||||
UpdateOrderSupportBadge();
|
||||
_ = LoadHistoricalTicketUnreadAsync(options);
|
||||
}
|
||||
@@ -637,7 +637,7 @@ namespace _29WxOrderWpf
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
LogSave.Add("TicketUnreadLoadError:" + ex);
|
||||
NLogger.Instance.Error("TicketUnreadLoadError:" + ex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -652,9 +652,6 @@ namespace _29WxOrderWpf
|
||||
AppIds = GlobalConfig.ShopLoginList.Select(a => a.ShopId).ToList(),
|
||||
Orders = []
|
||||
};
|
||||
|
||||
|
||||
|
||||
//OrderSupportTicketView
|
||||
// .CreateDefaultOptions(BaseClass.UserName)
|
||||
// .Clone();
|
||||
|
||||
@@ -37,7 +37,7 @@ namespace AllBase
|
||||
/// 版本ID
|
||||
/// </summary>
|
||||
|
||||
public static int VersionCount = 337;
|
||||
public static int VersionCount = 339;
|
||||
|
||||
public static string ServerUrl { get; set; } = "http://1.13.195.131:9000";
|
||||
public static string DebugUrl { get; set; } = "http://localhost:9000";
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using WxOrder.Framework.Helpers;
|
||||
|
||||
namespace LaunchDarkly.EventSource
|
||||
{
|
||||
@@ -114,6 +115,7 @@ namespace LaunchDarkly.EventSource
|
||||
/// This is never null; if logging is not configured, it will be <c>LaunchDarkly.Logging.Logs.None</c>.
|
||||
/// </remarks>
|
||||
/// <seealso cref="ConfigurationBuilder.Logger(Logger)"/>
|
||||
public ILogger Logger { get; }
|
||||
|
||||
/// <summary>
|
||||
/// The maximum amount of time to wait before attempting to reconnect.
|
||||
@@ -174,13 +176,14 @@ namespace LaunchDarkly.EventSource
|
||||
{
|
||||
Uri = builder._uri;
|
||||
|
||||
|
||||
var logger = builder._logger;
|
||||
|
||||
BackoffResetThreshold = builder._backoffResetThreshold;
|
||||
HttpClient = builder._httpClient;
|
||||
HttpMessageHandler = (builder._httpClient != null) ? null : builder._httpMessageHandler;
|
||||
InitialRetryDelay = builder._initialRetryDelay;
|
||||
LastEventId = builder._lastEventId;
|
||||
Logger = logger;
|
||||
MaxRetryDelay = builder._maxRetryDelay;
|
||||
Method = builder._method;
|
||||
PreferDataAsUtf8Bytes = builder._preferDataAsUtf8Bytes;
|
||||
|
||||
@@ -3,6 +3,7 @@ using System.Collections.Generic;
|
||||
using System.Net.Http;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using WxOrder.Framework.Helpers;
|
||||
|
||||
namespace LaunchDarkly.EventSource
|
||||
{
|
||||
@@ -30,6 +31,7 @@ namespace LaunchDarkly.EventSource
|
||||
internal TimeSpan _initialRetryDelay = Configuration.DefaultInitialRetryDelay;
|
||||
internal TimeSpan _backoffResetThreshold = Configuration.DefaultBackoffResetThreshold;
|
||||
internal string _lastEventId;
|
||||
internal ILogger _logger;
|
||||
internal IDictionary<string, string> _requestHeaders = new Dictionary<string, string>();
|
||||
internal HttpMessageHandler _httpMessageHandler;
|
||||
internal HttpClient _httpClient;
|
||||
@@ -230,45 +232,6 @@ namespace LaunchDarkly.EventSource
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets the logging implementation to be used for all EventSource log output.
|
||||
/// </summary>
|
||||
/// <remarks>
|
||||
/// <para>
|
||||
/// This uses the <c>ILogAdapter</c> abstraction from the <c>LaunchDarkly.Logging</c> library,
|
||||
/// which provides several basic implementations such as <c>Logs.ToConsole</c> and an integration
|
||||
/// with the .NET Core logging framework. For more about this and about adapters to other logging
|
||||
/// frameworks, see <a href="https://github.com/launchdarkly/dotnet-logging"><c>LaunchDarkly.Logging</c></a>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// <c>LaunchDarkly.Logging</c> defines logging levels of Debug, Info, Warn, and Error. If you do not
|
||||
/// want detailed Debug-level logging, use the <c>Level()</c> modifier to set a minimum level of Info
|
||||
/// or above, as shown in the code example (unless you are using an adapter to another logging
|
||||
/// framework that has its own way of doing log filtering).
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// Log messages will use <see cref="Configuration.DefaultLoggerName"/> as the logger name. If you
|
||||
/// want to specify a different logger name, use <see cref="Logger(Logging.Logger)"/>.
|
||||
/// </para>
|
||||
/// <para>
|
||||
/// If you don't specify <see cref="LogAdapter(ILogAdapter)"/> or <see cref="Logger(Logging.Logger)"/>,
|
||||
/// EventSource will not do any logging.
|
||||
/// </para>
|
||||
/// </remarks>
|
||||
/// <example>
|
||||
/// using LaunchDarkly.Logging;
|
||||
///
|
||||
/// // Send log output to the console (standard error), suppressing Debug messages
|
||||
/// var config = new ConfigurationBuilder(uri).
|
||||
/// LogAdapter(Logs.ToConsole.Level(LogLevel.Info)).
|
||||
/// Build();
|
||||
/// </example>
|
||||
/// <param name="logAdapter">a <c>LaunchDarkly.Logging.ILogAdapter</c></param>
|
||||
/// <returns>the builder</returns>
|
||||
public ConfigurationBuilder LogAdapter()
|
||||
{
|
||||
return this;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Sets a custom logger to be used for all EventSource log output.
|
||||
@@ -297,8 +260,9 @@ namespace LaunchDarkly.EventSource
|
||||
/// </example>
|
||||
/// <param name="logger">a <c>LaunchDarkly.Logging.Logger</c> instance</param>
|
||||
/// <returns>the builder</returns>
|
||||
public ConfigurationBuilder Logger()
|
||||
public ConfigurationBuilder Logger(ILogger logger)
|
||||
{
|
||||
_logger = logger;
|
||||
return this;
|
||||
}
|
||||
|
||||
|
||||
File diff suppressed because it is too large.
Load diff
@@ -7,6 +7,7 @@ using System.Net.Http.Headers;
|
||||
using System.Reflection;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using WxOrder.Framework.Helpers;
|
||||
|
||||
using static LaunchDarkly.EventSource.AsyncHelpers;
|
||||
|
||||
@@ -23,6 +24,7 @@ namespace LaunchDarkly.EventSource
|
||||
|
||||
private readonly Configuration _configuration;
|
||||
private readonly HttpClient _httpClient;
|
||||
private readonly ILogger _logger;
|
||||
|
||||
private const string UserAgentProduct = "DotNetClient";
|
||||
internal static readonly string UserAgentVersion = ((AssemblyInformationalVersionAttribute)typeof(EventSource)
|
||||
@@ -48,10 +50,11 @@ namespace LaunchDarkly.EventSource
|
||||
|
||||
#region Constructors
|
||||
|
||||
internal EventSourceService(Configuration configuration, HttpClient httpClient)
|
||||
internal EventSourceService(Configuration configuration, HttpClient httpClient, ILogger logger)
|
||||
{
|
||||
_configuration = configuration ?? throw new ArgumentNullException(nameof(configuration));
|
||||
_httpClient = httpClient ?? throw new ArgumentNullException(nameof(httpClient));
|
||||
_logger = logger ?? throw new ArgumentNullException(nameof(logger));
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -85,16 +88,20 @@ namespace LaunchDarkly.EventSource
|
||||
CancellationToken cancellationToken
|
||||
)
|
||||
{
|
||||
_logger.Debug(string.Format("Making {0} request to EventSource URI {1}",
|
||||
_configuration.Method ?? HttpMethod.Get,
|
||||
_configuration.Uri));
|
||||
|
||||
var request = CreateHttpRequestMessage(_configuration.Uri, lastEventId);
|
||||
|
||||
this._configuration.HttpRequestModifier?.Invoke(request);
|
||||
|
||||
using (var response = await _httpClient.SendAsync(request,
|
||||
using (var response = await _httpClient.SendAsync(request,
|
||||
HttpCompletionOption.ResponseHeadersRead,
|
||||
cancellationToken).ConfigureAwait(false))
|
||||
{
|
||||
ValidateResponse(response);
|
||||
_logger.Debug(string.Format("Response status: {0}", (int)response.StatusCode));
|
||||
ValidateResponse(response);
|
||||
|
||||
using (var stream = await response.Content.ReadAsStreamAsync().ConfigureAwait(false))
|
||||
{
|
||||
@@ -109,10 +116,12 @@ namespace LaunchDarkly.EventSource
|
||||
|
||||
if (_configuration.PreferDataAsUtf8Bytes)
|
||||
{
|
||||
_logger.Debug("Reading UTF-8 stream without string conversion");
|
||||
await ProcessResponseFromUtf8StreamAsync(processResponseLineUTF8, stream, cancellationToken);
|
||||
}
|
||||
else
|
||||
{
|
||||
_logger.Debug("Reading stream with string conversion");
|
||||
using (var reader = new StreamReader(stream, Encoding.UTF8,
|
||||
detectEncodingFromByteOrderMarks: true, bufferSize: ReadBufferSize))
|
||||
{
|
||||
|
||||
@@ -5,6 +5,8 @@ using OrderSupportTicket.Models;
|
||||
using OrderSupportTicket.Models.Api;
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Net;
|
||||
using System.Net.Http;
|
||||
using System.Threading.Tasks;
|
||||
using WxOrder.Framework.Helpers;
|
||||
|
||||
@@ -31,7 +33,7 @@ public sealed class EventSourceTicketRealtimeService
|
||||
/// </summary>
|
||||
public TicketRealtimeState State { get; private set; } = TicketRealtimeState.Disconnected;
|
||||
|
||||
public void Start(TicketClientOptions options)
|
||||
public async Task Start(TicketClientOptions options)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(EventSourceTicketRealtimeService));
|
||||
@@ -40,9 +42,8 @@ public sealed class EventSourceTicketRealtimeService
|
||||
|
||||
TicketApiService.ValidateOptions(options);
|
||||
StopCore();
|
||||
|
||||
var uri = BuildEventsUri(options);
|
||||
var source = new EventSource(uri);
|
||||
var config = BuildEventsUri(options);
|
||||
var source = new EventSource(config);
|
||||
source.Opened += OnOpened;
|
||||
source.Closed += OnClosed;
|
||||
source.MessageReceived += OnMessageReceived;
|
||||
@@ -55,7 +56,7 @@ public sealed class EventSourceTicketRealtimeService
|
||||
}
|
||||
|
||||
SetState(TicketRealtimeState.Connecting, "连接中…");
|
||||
_ = RunAsync(source);
|
||||
await RunAsync(source);
|
||||
}
|
||||
|
||||
public Task StopAsync()
|
||||
@@ -77,7 +78,6 @@ public sealed class EventSourceTicketRealtimeService
|
||||
{
|
||||
try
|
||||
{
|
||||
NLogger.Instance.Info("工单服务连接成");
|
||||
await source.StartAsync();
|
||||
lock (_sync)
|
||||
{
|
||||
@@ -182,22 +182,53 @@ public sealed class EventSourceTicketRealtimeService
|
||||
new TicketRealtimeStateChangedEventArgs(state, message));
|
||||
}
|
||||
|
||||
private static Uri BuildEventsUri(TicketClientOptions options)
|
||||
//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);
|
||||
//}
|
||||
|
||||
private static Configuration BuildEventsUri(TicketClientOptions options)
|
||||
{
|
||||
var appIds = options.AppIds
|
||||
.Where(a => !string.IsNullOrWhiteSpace(a))
|
||||
.Distinct(StringComparer.Ordinal)
|
||||
.Select(a => "appId=" + Uri.EscapeDataString(a.Trim()));
|
||||
.Select(a => Uri.EscapeDataString(a.Trim()));
|
||||
var query = new[]
|
||||
{
|
||||
"purchaseAccount=" + Uri.EscapeDataString(options.UserName)
|
||||
}.Concat(appIds);
|
||||
|
||||
return new Uri(
|
||||
};
|
||||
var uri = new Uri(
|
||||
TicketApiService.ServerUrl
|
||||
+ EventsPath
|
||||
+ "?"
|
||||
+ string.Join("&", query),
|
||||
UriKind.Absolute);
|
||||
ConfigurationBuilder builder = Configuration.Builder(uri);
|
||||
builder.RequestHeader("X-AppIds", $"[\"{string.Join("\",\"", appIds)}\"]");
|
||||
builder.Logger(NLogger.Instance);
|
||||
//var proxy = new WebProxy("http://127.0.0.1:8081"); //
|
||||
//var handler = new HttpClientHandler
|
||||
//{
|
||||
// Proxy = proxy,
|
||||
// UseProxy = true
|
||||
//};
|
||||
//var client = new HttpClient(handler);
|
||||
//builder.HttpClient(client);
|
||||
builder._responseStartTimeout = TimeSpan.FromSeconds(30);
|
||||
return builder.Build();
|
||||
}
|
||||
}
|
||||
@@ -372,8 +372,8 @@ public sealed class TicketApiService
|
||||
.ToList();
|
||||
if (normalized.Count == 0)
|
||||
throw new ArgumentException("appIds 至少需要一个 APPID。", nameof(appIds));
|
||||
if (normalized.Count > 500)
|
||||
throw new ArgumentException("appIds 最多支持 50 个 APPID。", nameof(appIds));
|
||||
//if (normalized.Count > 5000)
|
||||
// throw new ArgumentException("appIds 最多支持 50 个 APPID。", nameof(appIds));
|
||||
foreach (var appId in normalized)
|
||||
ValidateAppId(appId);
|
||||
return normalized;
|
||||
|
||||
@@ -91,7 +91,7 @@ public sealed class TicketRealtimeMonitor : IDisposable
|
||||
/// <summary>
|
||||
/// 启动或复用实时连接。相同账号和 APPID 重复调用不会重建连接。
|
||||
/// </summary>
|
||||
public void Start(TicketClientOptions options)
|
||||
public async Task Start(TicketClientOptions options)
|
||||
{
|
||||
if (_disposed)
|
||||
throw new ObjectDisposedException(nameof(TicketRealtimeMonitor));
|
||||
@@ -113,7 +113,7 @@ public sealed class TicketRealtimeMonitor : IDisposable
|
||||
_optionsFingerprint = fingerprint;
|
||||
}
|
||||
|
||||
RealtimeService.Start(options);
|
||||
await RealtimeService.Start(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -167,11 +167,11 @@ public sealed class TicketService : IDisposable
|
||||
/// <summary>
|
||||
/// 使用指定工单参数建立 SSE 连接。
|
||||
/// </summary>
|
||||
public void StartRealtime(TicketClientOptions options)
|
||||
public async Task StartRealtime(TicketClientOptions options)
|
||||
{
|
||||
ThrowIfDisposed();
|
||||
ValidateOptions(options);
|
||||
_realtime.Start(options);
|
||||
await _realtime.Start(options);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
@@ -191,7 +191,7 @@ public sealed class TicketService : IDisposable
|
||||
ThrowIfDisposed();
|
||||
await _realtime.StopAsync();
|
||||
ThrowIfDisposed();
|
||||
StartRealtime(options);
|
||||
await StartRealtime(options);
|
||||
}
|
||||
|
||||
public void Dispose()
|
||||
|
||||
@@ -714,7 +714,7 @@ public sealed class OrderSupportTicketViewModel : BindableBaseEx, IDialogAware,
|
||||
|| (_ticketService.OwnsRealtime && !_initialized);
|
||||
if (shouldStartRealtime)
|
||||
{
|
||||
_ticketService.StartRealtime(_options);
|
||||
await _ticketService.StartRealtime(_options);
|
||||
started = true;
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
namespace WxOrder.Framework.Helpers;
|
||||
|
||||
public interface ILogger
|
||||
{
|
||||
void Debug(string message, Exception exception = null);
|
||||
void Dispose();
|
||||
void Error(string message, Exception exception = null);
|
||||
void Fatal(string message, Exception exception = null);
|
||||
void Info(string message, Exception exception = null);
|
||||
void Log(string message, LogMessageLevel level, Exception exception = null);
|
||||
void Trace(string message, Exception exception = null);
|
||||
void Warn(string message, Exception exception = null);
|
||||
}
|
||||
@@ -32,7 +32,7 @@ namespace WxOrder.Framework.Helpers
|
||||
/// 日志文件按日期分目录存放,并在跨天时自动切换:
|
||||
/// {logDirectory}/yyyy-MM/yyyy-MM-dd.log,例如 log/2022-12/2022-12-12.log
|
||||
/// </summary>
|
||||
public sealed class NLogger : IDisposable
|
||||
public sealed class NLogger : IDisposable, ILogger
|
||||
{
|
||||
private const string DefaultName = "Default";
|
||||
|
||||
@@ -77,9 +77,9 @@ namespace WxOrder.Framework.Helpers
|
||||
/// <summary> 日志名称(写入每行日志中,用于区分来源,不再决定文件名)。 </summary>
|
||||
public string Name { get; }
|
||||
|
||||
public bool IsDebugEnabled { get; set; } = true;
|
||||
public bool IsDebugEnabled { get; set; } = false;
|
||||
|
||||
public bool IsDebugWriteLineEnabled { get; set; } = true;
|
||||
public bool IsDebugWriteLineEnabled { get; set; } = false;
|
||||
|
||||
public LogMessageLevel MinimumLevel { get; set; } = LogMessageLevel.Trace;
|
||||
|
||||
|
||||
Reference in new issue
Block a user