StarWeb上传文件,自动广播扩散到StarServer,测试通过智能大石头 authored at 2025-12-15 20:39:40
diff --git a/Samples/TestA/TestA.csproj b/Samples/TestA/TestA.csproj
index a8d8dfc..62ec45e 100644
--- a/Samples/TestA/TestA.csproj
+++ b/Samples/TestA/TestA.csproj
@@ -18,7 +18,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta0602" />
+ <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta1139" />
</ItemGroup>
</Project>
diff --git a/Samples/TestB/TestB.csproj b/Samples/TestB/TestB.csproj
index 8e75182..92e8983 100644
--- a/Samples/TestB/TestB.csproj
+++ b/Samples/TestB/TestB.csproj
@@ -18,7 +18,7 @@
</PropertyGroup>
<ItemGroup>
- <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta0602" />
+ <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta1139" />
</ItemGroup>
</Project>
diff --git a/Stardust.Server/Services/FileStorageService.cs b/Stardust.Server/Services/FileStorageService.cs
index 7cc7ea2..8d63b37 100644
--- a/Stardust.Server/Services/FileStorageService.cs
+++ b/Stardust.Server/Services/FileStorageService.cs
@@ -1,6 +1,7 @@
using System.Diagnostics;
using NewLife;
using NewLife.Caching;
+using NewLife.Log;
using Stardust.Data.Deployment;
using Stardust.Storages;
@@ -30,10 +31,9 @@ public static class FileStorageExtensions
public class CubeFileStorage : DefaultFileStorage
{
- public CubeFileStorage(ICacheProvider cacheProvider)
+ public CubeFileStorage(ICacheProvider cacheProvider, ITracer tracer, ILog log)
{
- var cache = cacheProvider.Cache as Cache;
- if (cache != null)
+ if (cacheProvider.Cache is Cache cache)
{
var clientId = $"{NetHelper.MyIP()}@{Process.GetCurrentProcess().Id}";
NewFileBus = cache.GetEventBus<NewFileInfo>("NewFile", clientId);
@@ -43,6 +43,9 @@ public class CubeFileStorage : DefaultFileStorage
NodeName = Environment.MachineName;
RootPath = "../Uploads";
DownloadUri = "/cube/file?id={Id}";
+
+ Tracer = tracer;
+ Log = log;
}
/// <summary>获取本地文件的元数据</summary>
diff --git a/Stardust/Stardust.csproj b/Stardust/Stardust.csproj
index e3bdc63..147cd1a 100644
--- a/Stardust/Stardust.csproj
+++ b/Stardust/Stardust.csproj
@@ -125,7 +125,7 @@
<PackageReference Include="NewLife.Remoting" Version="3.6.2025.1214-beta1229" />
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta0602" />
+ <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta1139" />
</ItemGroup>
</Project>
diff --git a/Stardust/Storages/DefaultFileStorage.cs b/Stardust/Storages/DefaultFileStorage.cs
index 9cadd44..5ef54a7 100644
--- a/Stardust/Storages/DefaultFileStorage.cs
+++ b/Stardust/Storages/DefaultFileStorage.cs
@@ -7,7 +7,7 @@ using NewLife.Serialization;
namespace Stardust.Storages;
/// <summary>分布式文件存储默认基类,用于编排文件同步流程。具体应用应继承并实现与存储相关的操作。</summary>
-public abstract class DefaultFileStorage : DisposeBase, IFileStorage
+public abstract class DefaultFileStorage : DisposeBase, IFileStorage, ILogFeature, ITracerFeature
{
#region 属性
/// <summary>用于广播新文件消息的事件总线。</summary>
@@ -46,6 +46,8 @@ public abstract class DefaultFileStorage : DisposeBase, IFileStorage
{
if (Interlocked.Exchange(ref _initialized, 1) == 1) return;
+ WriteLog("初始化分布式文件存储,节点:{0}", NodeName);
+
// 仅订阅,处理逻辑使用独立方法,避免捕获初始化的取消令牌
NewFileBus?.Subscribe(OnNewFileInfoAsync);
FileRequestBus?.Subscribe(OnFileRequestAsync);
@@ -98,16 +100,26 @@ public abstract class DefaultFileStorage : DisposeBase, IFileStorage
/// <summary>处理新文件消息。</summary>
protected virtual async Task OnNewFileInfoAsync(NewFileInfo info, IEventContext<NewFileInfo> context, CancellationToken cancellationToken)
{
- XTrace.WriteLine("新文件通知:{0}", info.ToJson());
+ var msg = info.ToJson();
+ using var span = Tracer?.NewSpan(nameof(OnNewFileInfoAsync), msg);
+ span?.Detach(info.TraceId);
+ WriteLog("新文件通知:{0}", msg);
- // 默认忽略本节点自己发布的消息(除非需要自愈)
- if (info.SourceNode.EqualIgnoreCase(NodeName)) return;
+ //// 默认忽略本节点自己发布的消息(除非需要自愈)
+ //if (info.SourceNode.EqualIgnoreCase(NodeName)) return;
// 检查本地是否已有文件且哈希正确
if (CheckLocalFile(info.Path, info.Hash)) return;
- // 从源节点拉取文件数据
- await FetchFileAsync(info, info.SourceNode, cancellationToken).ConfigureAwait(false);
+ try
+ {
+ // 从源节点拉取文件数据
+ await FetchFileAsync(info, info.SourceNode, cancellationToken).ConfigureAwait(false);
+ }
+ catch (Exception ex)
+ {
+ span?.SetError(ex, null);
+ }
}
/// <summary>通过应用自定义的传输方式(如HTTP接口)从指定源节点拉取文件数据。</summary>
@@ -116,17 +128,31 @@ public abstract class DefaultFileStorage : DisposeBase, IFileStorage
if (file == null || file.Path.IsNullOrEmpty()) throw new ArgumentNullException(nameof(file));
var url = DownloadUri;
+ if (file is NewFileInfo fi) url = fi.NodeAddress + url;
url = url.Replace("{Id}", file.Id + "");
url = url.Replace("{Name}", file.Name);
- var fileName = RootPath.CombinePath(file.Path).GetFullPath();
+ var span = DefaultSpan.Current;
+ WriteLog("下载文件:{0},来源:{1}", file.Name, url);
+ try
+ {
+ var fileName = RootPath.CombinePath(file.Path).GetFullPath();
+
+ //todo: 获取源节点基地址,通过HTTP等方式拉取文件数据
+ var client = new HttpClient();
+ client.SetUserAgent();
+ if (file is NewFileInfo fileInfo && !fileInfo.NodeAddress.IsNullOrEmpty())
+ client.BaseAddress = new Uri(fileInfo.NodeAddress.Split(";")[0]);
- //todo: 获取源节点基地址,通过HTTP等方式拉取文件数据
- var client = new HttpClient();
- if (file is NewFileInfo fileInfo && !fileInfo.NodeAddress.IsNullOrEmpty())
- client.BaseAddress = new Uri(fileInfo.NodeAddress.Split(";")[0]);
+ await client.DownloadFileAsync(url, fileName, file.Hash, cancellationToken).ConfigureAwait(false);
- await client.DownloadFileAsync(url, fileName, file.Hash, cancellationToken).ConfigureAwait(false);
+ WriteLog("下载文件:{0},成功:{1}", file.Name, url);
+ }
+ catch (Exception ex)
+ {
+ span?.SetError(ex);
+ WriteLog("下载文件:{0},异常:{1}", file.Name, ex.Message);
+ }
}
#endregion
@@ -214,4 +240,15 @@ public abstract class DefaultFileStorage : DisposeBase, IFileStorage
};
}
#endregion
+
+ #region 日志
+ /// <summary>追踪器</summary>
+ public ITracer? Tracer { get; set; }
+
+ /// <summary>日志</summary>
+ public ILog Log { get; set; } = Logger.Null;
+
+ /// <summary>写日志</summary>
+ public void WriteLog(String format, params Object?[] args) => Log?.Info(format, args);
+ #endregion
}
diff --git a/Stardust/Storages/NewFileInfo.cs b/Stardust/Storages/NewFileInfo.cs
index a94cb59..f2ea8a2 100644
--- a/Stardust/Storages/NewFileInfo.cs
+++ b/Stardust/Storages/NewFileInfo.cs
@@ -1,9 +1,11 @@
-namespace Stardust.Storages;
+using NewLife.Log;
+
+namespace Stardust.Storages;
/// <summary>
/// 新文件消息:宣告指定附件在某个节点可用。
/// </summary>
-public class NewFileInfo : IFileInfo
+public class NewFileInfo : IFileInfo, ITraceMessage
{
/// <summary>公共数据库中的附件ID。</summary>
public Int64 Id { get; set; }
@@ -25,4 +27,7 @@ public class NewFileInfo : IFileInfo
/// <summary>节点地址</summary>
public String? NodeAddress { get; set; }
+
+ /// <summary>追踪标识</summary>
+ public String? TraceId { get; set; }
}
diff --git a/Test/Test.csproj b/Test/Test.csproj
index 9aea200..23c730a 100644
--- a/Test/Test.csproj
+++ b/Test/Test.csproj
@@ -33,7 +33,7 @@
</ItemGroup>
<ItemGroup>
- <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta0602" />
+ <PackageReference Include="NewLife.Core" Version="11.9.2025.1215-beta1139" />
</ItemGroup>
<ItemGroup>