A:定义基础API
This commit is contained in:
1 parent
34cd3db09a
commit
1d30e4fe77
5 files changed
+997
-57
No files matched your search
@@ -139,25 +139,57 @@ public class NetworkRepository : INetworkRepository
|
||||
{
|
||||
var startTime = DateTimeOffset.UtcNow.AddHours(-hours).ToUnixTimeSeconds();
|
||||
|
||||
const string sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
ORDER BY Timestep DESC";
|
||||
string sql;
|
||||
object parameters;
|
||||
|
||||
if (string.IsNullOrEmpty(networkCardGuid))
|
||||
{
|
||||
// 获取所有网卡数据
|
||||
sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE Timestep >= @StartTime
|
||||
ORDER BY Timestep DESC";
|
||||
parameters = new { StartTime = startTime };
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取指定网卡数据
|
||||
sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
ORDER BY Timestep DESC";
|
||||
parameters = new { NetworkCardGuid = networkCardGuid, StartTime = startTime };
|
||||
}
|
||||
|
||||
return await _context.Connection.QueryAsync<GlobalNetwork>(sql,
|
||||
new { NetworkCardGuid = networkCardGuid, StartTime = startTime });
|
||||
return await _context.Connection.QueryAsync<GlobalNetwork>(sql, parameters);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GlobalNetwork>> GetGlobalNetworkByTimeRangeAsync(string networkCardGuid,
|
||||
long startTime, long endTime)
|
||||
{
|
||||
const string sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime AND Timestep <= @EndTime
|
||||
ORDER BY Timestep DESC";
|
||||
string sql;
|
||||
object parameters;
|
||||
|
||||
if (string.IsNullOrEmpty(networkCardGuid))
|
||||
{
|
||||
// 获取所有网卡数据
|
||||
sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE Timestep >= @StartTime AND Timestep <= @EndTime
|
||||
ORDER BY Timestep DESC";
|
||||
parameters = new { StartTime = startTime, EndTime = endTime };
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取指定网卡数据
|
||||
sql = @"
|
||||
SELECT * FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime AND Timestep <= @EndTime
|
||||
ORDER BY Timestep DESC";
|
||||
parameters = new { NetworkCardGuid = networkCardGuid, StartTime = startTime, EndTime = endTime };
|
||||
}
|
||||
|
||||
return await _context.Connection.QueryAsync<GlobalNetwork>(sql,
|
||||
new { NetworkCardGuid = networkCardGuid, StartTime = startTime, EndTime = endTime });
|
||||
return await _context.Connection.QueryAsync<GlobalNetwork>(sql, parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
@@ -305,22 +337,47 @@ public class NetworkRepository : INetworkRepository
|
||||
{
|
||||
var startTime = DateTimeOffset.UtcNow.AddHours(-hours).ToUnixTimeSeconds();
|
||||
|
||||
const string sql = @"
|
||||
SELECT
|
||||
(Timestep / 3600) * 3600 as HourTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 3600)
|
||||
ORDER BY HourTimestamp DESC";
|
||||
string sql;
|
||||
object parameters;
|
||||
|
||||
if (string.IsNullOrEmpty(networkCardGuid))
|
||||
{
|
||||
// 获取所有网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 3600) * 3600 as HourTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 3600)
|
||||
ORDER BY HourTimestamp DESC";
|
||||
parameters = new { StartTime = startTime };
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取指定网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 3600) * 3600 as HourTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 3600)
|
||||
ORDER BY HourTimestamp DESC";
|
||||
parameters = new { NetworkCardGuid = networkCardGuid, StartTime = startTime };
|
||||
}
|
||||
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql,
|
||||
new { NetworkCardGuid = networkCardGuid, StartTime = startTime });
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql, parameters);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GlobalNetworkSummary>> GetGlobalNetworkByDayAsync(string networkCardGuid,
|
||||
@@ -328,22 +385,47 @@ public class NetworkRepository : INetworkRepository
|
||||
{
|
||||
var startTime = DateTimeOffset.UtcNow.AddDays(-days).ToUnixTimeSeconds();
|
||||
|
||||
const string sql = @"
|
||||
SELECT
|
||||
(Timestep / 86400) * 86400 as DayTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 86400)
|
||||
ORDER BY DayTimestamp DESC";
|
||||
string sql;
|
||||
object parameters;
|
||||
|
||||
if (string.IsNullOrEmpty(networkCardGuid))
|
||||
{
|
||||
// 获取所有网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 86400) * 86400 as DayTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 86400)
|
||||
ORDER BY DayTimestamp DESC";
|
||||
parameters = new { StartTime = startTime };
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取指定网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 86400) * 86400 as DayTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 86400)
|
||||
ORDER BY DayTimestamp DESC";
|
||||
parameters = new { NetworkCardGuid = networkCardGuid, StartTime = startTime };
|
||||
}
|
||||
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql,
|
||||
new { NetworkCardGuid = networkCardGuid, StartTime = startTime });
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql, parameters);
|
||||
}
|
||||
|
||||
public async Task<IEnumerable<GlobalNetworkSummary>> GetGlobalNetworkByMonthAsync(string networkCardGuid,
|
||||
@@ -351,22 +433,47 @@ public class NetworkRepository : INetworkRepository
|
||||
{
|
||||
var startTime = DateTimeOffset.UtcNow.AddMonths(-months).ToUnixTimeSeconds();
|
||||
|
||||
const string sql = @"
|
||||
SELECT
|
||||
(Timestep / 2592000) * 2592000 as MonthTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 2592000)
|
||||
ORDER BY MonthTimestamp DESC";
|
||||
string sql;
|
||||
object parameters;
|
||||
|
||||
if (string.IsNullOrEmpty(networkCardGuid))
|
||||
{
|
||||
// 获取所有网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 2592000) * 2592000 as MonthTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 2592000)
|
||||
ORDER BY MonthTimestamp DESC";
|
||||
parameters = new { StartTime = startTime };
|
||||
}
|
||||
else
|
||||
{
|
||||
// 获取指定网卡数据
|
||||
sql = @"
|
||||
SELECT
|
||||
(Timestep / 2592000) * 2592000 as MonthTimestamp,
|
||||
SUM(Upload) as TotalUpload,
|
||||
SUM(Download) as TotalDownload,
|
||||
AVG(Upload) as AvgUpload,
|
||||
AVG(Download) as AvgDownload,
|
||||
MAX(Upload) as MaxUpload,
|
||||
MAX(Download) as MaxDownload
|
||||
FROM GlobalNetwork
|
||||
WHERE NetworkCardGuid = @NetworkCardGuid AND Timestep >= @StartTime
|
||||
GROUP BY (Timestep / 2592000)
|
||||
ORDER BY MonthTimestamp DESC";
|
||||
parameters = new { NetworkCardGuid = networkCardGuid, StartTime = startTime };
|
||||
}
|
||||
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql,
|
||||
new { NetworkCardGuid = networkCardGuid, StartTime = startTime });
|
||||
return await _context.Connection.QueryAsync<GlobalNetworkSummary>(sql, parameters);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
@@ -57,6 +57,7 @@
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATcpIpSendTraceData_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F28_003Fce7c9cfa_003FTcpIpSendTraceData_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimer_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F211e6f3b24fa438a92f1815153647ce2c8f908_003Fa8_003F04476824_003FTimer_002Ecs_002Fz_003A2_002D1/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimer_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003Ffe2ae574758f4da99bb3bfcba69a0a40b6928_003F7f_003Fb5cb1e21_003FTimer_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimeSpan_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F174cdfd56bcd471abff8d95d61867f0ec90938_003F35_003F09c97216_003FTimeSpan_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATimeSpan_002Ecs_002Fl_003AC_0021_003FUsers_003Fyllyo_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FSourcesCache_003F4045ad381dc69b9a8c076afe4c122961b5a86158d8dd0c76c117243ce72b_003FTimeSpan_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEventLevel_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F3e_003F5dae014e_003FTraceEventLevel_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
<s:String x:Key="/Default/CodeInspection/ExcludedFiles/FilesAndFoldersToSkip2/=7020124F_002D9FFC_002D4AC3_002D8F3D_002DAAB8E0240759_002Ff_003ATraceEventNativeMethods_002Ecs_002Fl_003AC_0021_003FUsers_003Fcharlatans_003FAppData_003FRoaming_003FJetBrains_003FRider2025_002E1_003Fresharper_002Dhost_003FDecompilerCache_003Fdecompiler_003F25b12134b1124ffbab73641db2e54e5b310830_003F03_003Fcb4b3163_003FTraceEventNativeMethods_002Ecs/@EntryIndexedValue">ForceIncluded</s:String>
|
||||
|
||||
@@ -11,9 +11,13 @@ using Common.Net.Models;
|
||||
using Common.Net.WebSocketConn;
|
||||
using Common.Utils;
|
||||
using Data;
|
||||
using Data.Models;
|
||||
using Data.Core;
|
||||
using Data.Repositories;
|
||||
using Shell.Views;
|
||||
using Utils.ETW.Etw;
|
||||
using Utils.Firewall;
|
||||
using Dapper;
|
||||
using MessageBox = System.Windows.Forms.MessageBox;
|
||||
|
||||
namespace Shell;
|
||||
@@ -209,6 +213,11 @@ public partial class App : System.Windows.Application
|
||||
_networkManager.StartMonitoring();
|
||||
}
|
||||
|
||||
// 网络接口缓存
|
||||
private static readonly Dictionary<string, object> _networkInterfaceCache = new Dictionary<string, object>();
|
||||
private static DateTime _cacheLastUpdateTime = DateTime.MinValue;
|
||||
private static readonly TimeSpan _cacheExpireTime = TimeSpan.FromMinutes(5); // 缓存5分钟
|
||||
|
||||
private static async Task StartHttpServer()
|
||||
{
|
||||
// 开启 http 服务
|
||||
@@ -827,6 +836,497 @@ public partial class App : System.Windows.Application
|
||||
|
||||
#endregion
|
||||
|
||||
#region 网络统计API
|
||||
|
||||
// 获取网络接口列表
|
||||
server.Get("/api/statistics/interfaces", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeRange = context.QueryParams["timeRange"] ?? "hour";
|
||||
|
||||
// 检查缓存是否有效
|
||||
var cacheKey = $"interfaces_{timeRange}";
|
||||
var now = DateTime.Now;
|
||||
|
||||
if (_networkInterfaceCache.ContainsKey(cacheKey) &&
|
||||
(now - _cacheLastUpdateTime) < _cacheExpireTime)
|
||||
{
|
||||
// 使用缓存数据
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = _networkInterfaceCache[cacheKey],
|
||||
Message = "获取网络接口列表成功(缓存)"
|
||||
});
|
||||
return;
|
||||
}
|
||||
|
||||
// 缓存已过期或不存在,重新获取数据
|
||||
var networkCardGuids = new HashSet<string>();
|
||||
|
||||
// 根据时间范围从不同数据表获取网卡ID
|
||||
switch (timeRange.ToLower())
|
||||
{
|
||||
case "hour":
|
||||
// 从 GlobalNetwork 表获取最近1小时的数据
|
||||
var hourData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync("",
|
||||
DateTimeOffset.UtcNow.AddHours(-1).ToUnixTimeSeconds(),
|
||||
DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||
foreach (var item in hourData)
|
||||
networkCardGuids.Add(item.NetworkCardGuid);
|
||||
break;
|
||||
case "day":
|
||||
// 从 GlobalNetwork 表获取最近1天的数据
|
||||
var dayData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync("",
|
||||
DateTimeOffset.UtcNow.AddDays(-1).ToUnixTimeSeconds(),
|
||||
DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||
foreach (var item in dayData)
|
||||
networkCardGuids.Add(item.NetworkCardGuid);
|
||||
break;
|
||||
case "week":
|
||||
// 从 GlobalNetwork 表获取最近7天的数据
|
||||
var weekData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync("",
|
||||
DateTimeOffset.UtcNow.AddDays(-7).ToUnixTimeSeconds(),
|
||||
DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||
foreach (var item in weekData)
|
||||
networkCardGuids.Add(item.NetworkCardGuid);
|
||||
break;
|
||||
case "month":
|
||||
// 从 GlobalNetwork 表获取最近30天的数据
|
||||
var monthData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync("",
|
||||
DateTimeOffset.UtcNow.AddDays(-30).ToUnixTimeSeconds(),
|
||||
DateTimeOffset.UtcNow.ToUnixTimeSeconds());
|
||||
foreach (var item in monthData)
|
||||
networkCardGuids.Add(item.NetworkCardGuid);
|
||||
break;
|
||||
}
|
||||
|
||||
// 如果没有找到任何网卡数据,使用当前连接的网卡
|
||||
if (!networkCardGuids.Any())
|
||||
{
|
||||
var connectedInterfaces = BasicNetworkMonitor.GetConnectedNetworkInterfaces();
|
||||
foreach (var iface in connectedInterfaces)
|
||||
{
|
||||
networkCardGuids.Add(iface.Id);
|
||||
}
|
||||
}
|
||||
|
||||
// 获取每个网卡的详细信息
|
||||
var interfaces = new List<object>();
|
||||
foreach (var guid in networkCardGuids)
|
||||
{
|
||||
var networkInfo = NetworkAdapterHelper.GetNetworkInfoByGuid(guid);
|
||||
if (networkInfo != null)
|
||||
{
|
||||
interfaces.Add(new
|
||||
{
|
||||
id = guid,
|
||||
name = networkInfo.NetConnectionID ?? networkInfo.Name,
|
||||
displayName = networkInfo.Description ?? networkInfo.Name,
|
||||
isActive = networkInfo.Status == "OK",
|
||||
macAddress = networkInfo.MACAddress
|
||||
});
|
||||
}
|
||||
else
|
||||
{
|
||||
// 如果无法获取网卡信息,使用基本信息
|
||||
interfaces.Add(new
|
||||
{
|
||||
id = guid,
|
||||
name = $"Network Interface {guid.Substring(0, 8)}",
|
||||
displayName = $"Network Adapter {guid.Substring(0, 8)}",
|
||||
isActive = true,
|
||||
macAddress = ""
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
// 更新缓存
|
||||
_networkInterfaceCache[cacheKey] = interfaces;
|
||||
_cacheLastUpdateTime = now;
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = interfaces,
|
||||
Message = "获取网络接口列表成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"获取网络接口列表失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取可用时间范围
|
||||
server.Get("/api/statistics/available-ranges", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var availableRanges = new List<object>();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
// 检查是否有小时数据 (GlobalNetworkHourly)
|
||||
var hasHourlyData = await HasNetworkDataInTimeRangeAsync("hourly", now.AddHours(-1).ToUnixTimeSeconds());
|
||||
if (hasHourlyData)
|
||||
{
|
||||
availableRanges.Add(new
|
||||
{
|
||||
type = "hour",
|
||||
name = "1小时",
|
||||
available = true,
|
||||
startTime = now.AddHours(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否有天数据 (GlobalNetworkDaily)
|
||||
var hasDailyData = await HasNetworkDataInTimeRangeAsync("daily", now.AddDays(-1).ToUnixTimeSeconds());
|
||||
if (hasDailyData)
|
||||
{
|
||||
availableRanges.Add(new
|
||||
{
|
||||
type = "day",
|
||||
name = "1天",
|
||||
available = true,
|
||||
startTime = now.AddDays(-1).ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否有周数据
|
||||
var hasWeeklyData = await HasNetworkDataInTimeRangeAsync("daily", now.AddDays(-7).ToUnixTimeSeconds());
|
||||
if (hasWeeklyData)
|
||||
{
|
||||
availableRanges.Add(new
|
||||
{
|
||||
type = "week",
|
||||
name = "1周",
|
||||
available = true,
|
||||
startTime = now.AddDays(-7).ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
});
|
||||
}
|
||||
|
||||
// 检查是否有月数据
|
||||
var hasMonthlyData = await HasNetworkDataInTimeRangeAsync("daily", now.AddDays(-30).ToUnixTimeSeconds());
|
||||
if (hasMonthlyData)
|
||||
{
|
||||
availableRanges.Add(new
|
||||
{
|
||||
type = "month",
|
||||
name = "1个月",
|
||||
available = true,
|
||||
startTime = now.AddDays(-30).ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
});
|
||||
}
|
||||
|
||||
// 如果没有任何数据,至少返回hour(用户刚安装)
|
||||
if (!availableRanges.Any())
|
||||
{
|
||||
availableRanges.Add(new
|
||||
{
|
||||
type = "hour",
|
||||
name = "1小时",
|
||||
available = true,
|
||||
startTime = now.ToString("yyyy-MM-ddTHH:mm:ssZ")
|
||||
});
|
||||
}
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = availableRanges.First(),
|
||||
Message = "获取可用时间范围成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"获取可用时间范围失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 清理网络接口缓存
|
||||
server.Post("/api/statistics/clear-cache", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
_networkInterfaceCache.Clear();
|
||||
_cacheLastUpdateTime = DateTime.MinValue;
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<string>
|
||||
{
|
||||
Success = true,
|
||||
Data = "缓存已清理",
|
||||
Message = "网络接口缓存清理成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"清理缓存失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region 流量数据API
|
||||
|
||||
// 获取流量趋势数据
|
||||
server.Get("/api/traffic/trends", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeRange = context.QueryParams["timeRange"] ?? "1hour";
|
||||
var interfaceId = context.QueryParams["interfaceId"] ?? "all";
|
||||
|
||||
var points = new List<object>();
|
||||
var now = DateTimeOffset.UtcNow;
|
||||
|
||||
switch (timeRange)
|
||||
{
|
||||
case "1hour":
|
||||
// 从 GlobalNetwork 表获取最近1小时数据,按5秒间隔
|
||||
var hourData = await GetTrafficTrendsAsync("hour", interfaceId, now.AddHours(-1).ToUnixTimeSeconds(), now.ToUnixTimeSeconds());
|
||||
points = hourData;
|
||||
break;
|
||||
case "1day":
|
||||
// 从 GlobalNetworkHourly 表获取最近1天数据,按小时间隔
|
||||
var dayData = await GetTrafficTrendsAsync("day", interfaceId, now.AddDays(-1).ToUnixTimeSeconds(), now.ToUnixTimeSeconds());
|
||||
points = dayData;
|
||||
break;
|
||||
case "7days":
|
||||
// 从 GlobalNetworkDaily 表获取最近7天数据,按天间隔
|
||||
var weekData = await GetTrafficTrendsAsync("week", interfaceId, now.AddDays(-7).ToUnixTimeSeconds(), now.ToUnixTimeSeconds());
|
||||
points = weekData;
|
||||
break;
|
||||
case "30days":
|
||||
// 从 GlobalNetworkDaily 表获取最近30天数据,按天间隔
|
||||
var monthData = await GetTrafficTrendsAsync("month", interfaceId, now.AddDays(-30).ToUnixTimeSeconds(), now.ToUnixTimeSeconds());
|
||||
points = monthData;
|
||||
break;
|
||||
}
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = new
|
||||
{
|
||||
@interface = interfaceId,
|
||||
timeRange = timeRange,
|
||||
points = points
|
||||
},
|
||||
Message = "获取流量趋势数据成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"获取流量趋势数据失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
// 获取Top应用流量数据
|
||||
server.Get("/api/traffic/top-apps", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeRange = context.QueryParams["timeRange"] ?? "1hour";
|
||||
var limit = int.Parse(context.QueryParams["limit"] ?? "10");
|
||||
|
||||
// 根据时间范围计算天数,对于1hour特殊处理
|
||||
IEnumerable<AppNetworkTopInfo> topApps;
|
||||
|
||||
if (timeRange == "1hour")
|
||||
{
|
||||
// 对于1小时数据,我们需要特殊处理,因为GetTopAppsByTrafficAsync不支持小时查询
|
||||
// 使用1天的数据作为替代,实际应用中可能需要创建专门的小时查询方法
|
||||
topApps = await DatabaseManager.Instance.Networks.GetTopAppsByTrafficAsync(limit, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int days = timeRange switch
|
||||
{
|
||||
"1day" => 1,
|
||||
"7days" => 7,
|
||||
"30days" => 30,
|
||||
_ => 1
|
||||
};
|
||||
topApps = await DatabaseManager.Instance.Networks.GetTopAppsByTrafficAsync(limit, days);
|
||||
}
|
||||
var result = new List<object>();
|
||||
|
||||
foreach (var app in topApps)
|
||||
{
|
||||
// GetTopAppsByTrafficAsync 已经通过 LEFT JOIN 获取了应用信息
|
||||
// 只有当JOIN没有获取到信息时才额外查询AppInfo表
|
||||
string processName = System.IO.Path.GetFileName(app.AppPath ?? "");
|
||||
string displayName = app.AppName ?? "";
|
||||
string iconBase64 = "";
|
||||
|
||||
if (string.IsNullOrEmpty(displayName) && !string.IsNullOrEmpty(app.AppId))
|
||||
{
|
||||
// 如果JOIN没有获取到应用名称,尝试单独查询
|
||||
var appInfo = await DatabaseManager.Instance.AppInfos.GetAppByAppIdAsync(app.AppId);
|
||||
if (appInfo != null)
|
||||
{
|
||||
displayName = appInfo.Name ?? "";
|
||||
iconBase64 = appInfo.Base64Icon ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = processName.Replace(".exe", "") ?? "Unknown";
|
||||
}
|
||||
|
||||
result.Add(new
|
||||
{
|
||||
processName = processName,
|
||||
displayName = displayName,
|
||||
icon = iconBase64,
|
||||
totalBytes = app.TotalTraffic
|
||||
});
|
||||
}
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = result,
|
||||
Message = "获取Top应用流量数据成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"获取Top应用流量数据失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region 软件排行榜API
|
||||
|
||||
// 获取软件流量TOP100排行
|
||||
server.Get("/api/apps/top-traffic", async (context) =>
|
||||
{
|
||||
try
|
||||
{
|
||||
var timeRange = context.QueryParams["timeRange"] ?? "1hour";
|
||||
var page = int.Parse(context.QueryParams["page"] ?? "1");
|
||||
var pageSize = int.Parse(context.QueryParams["pageSize"] ?? "100");
|
||||
|
||||
// 根据时间范围计算天数,对于1hour特殊处理
|
||||
IEnumerable<AppNetworkTopInfo> allApps;
|
||||
|
||||
if (timeRange == "1hour")
|
||||
{
|
||||
// 对于1小时数据,我们需要特殊处理,因为GetTopAppsByTrafficAsync不支持小时查询
|
||||
// 使用1天的数据作为替代,实际应用中可能需要创建专门的小时查询方法
|
||||
allApps = await DatabaseManager.Instance.Networks.GetTopAppsByTrafficAsync(pageSize * page, 1);
|
||||
}
|
||||
else
|
||||
{
|
||||
int days = timeRange switch
|
||||
{
|
||||
"1day" => 1,
|
||||
"7days" => 7,
|
||||
"30days" => 30,
|
||||
_ => 1
|
||||
};
|
||||
// 获取总数据(限制较大数量用于分页)
|
||||
allApps = await DatabaseManager.Instance.Networks.GetTopAppsByTrafficAsync(pageSize * page, days);
|
||||
}
|
||||
var totalCount = allApps.Count();
|
||||
|
||||
// 分页处理
|
||||
var pagedApps = allApps.Skip((page - 1) * pageSize).Take(pageSize).ToList();
|
||||
var items = new List<object>();
|
||||
int rank = (page - 1) * pageSize + 1;
|
||||
|
||||
foreach (var app in pagedApps)
|
||||
{
|
||||
// GetTopAppsByTrafficAsync 已经通过 LEFT JOIN 获取了应用信息
|
||||
// 只有当JOIN没有获取到信息时才额外查询AppInfo表
|
||||
string processName = System.IO.Path.GetFileName(app.AppPath ?? "");
|
||||
string displayName = app.AppName ?? "";
|
||||
string iconBase64 = "";
|
||||
|
||||
if (string.IsNullOrEmpty(displayName) && !string.IsNullOrEmpty(app.AppId))
|
||||
{
|
||||
// 如果JOIN没有获取到应用名称,尝试单独查询
|
||||
var appInfo = await DatabaseManager.Instance.AppInfos.GetAppByAppIdAsync(app.AppId);
|
||||
if (appInfo != null)
|
||||
{
|
||||
displayName = appInfo.Name ?? "";
|
||||
iconBase64 = appInfo.Base64Icon ?? "";
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(displayName))
|
||||
{
|
||||
displayName = processName.Replace(".exe", "") ?? "Unknown";
|
||||
}
|
||||
|
||||
items.Add(new
|
||||
{
|
||||
rank = rank++,
|
||||
processName = processName,
|
||||
displayName = displayName,
|
||||
processPath = app.AppPath ?? "",
|
||||
icon = iconBase64,
|
||||
totalBytes = app.TotalTraffic,
|
||||
uploadBytes = app.TotalUpload,
|
||||
connectionCount = app.ConnectionCount
|
||||
});
|
||||
}
|
||||
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = true,
|
||||
Data = new
|
||||
{
|
||||
total = totalCount,
|
||||
page = page,
|
||||
pageSize = pageSize,
|
||||
items = items
|
||||
},
|
||||
Message = "获取软件流量排行成功"
|
||||
});
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
context.Response.StatusCode = 500;
|
||||
await context.Response.WriteJsonAsync(new ResponseModel<object>
|
||||
{
|
||||
Success = false,
|
||||
Message = $"获取软件流量排行失败: {ex.Message}"
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
#endregion
|
||||
|
||||
#region 取消订阅
|
||||
|
||||
server.Post("/api/unsubscribe", async (context) =>
|
||||
@@ -1074,6 +1574,178 @@ public partial class App : System.Windows.Application
|
||||
Console.WriteLine($"Server error: {ex.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:获取所有网卡的小时数据
|
||||
private static async Task<List<GlobalNetworkAggregatedBase>> GetAllNetworkCardsHourlyDataAsync(int hours)
|
||||
{
|
||||
var result = new List<GlobalNetworkAggregatedBase>();
|
||||
var startTime = DateTimeOffset.UtcNow.AddHours(-hours).ToUnixTimeSeconds();
|
||||
|
||||
// 使用现有的方法来获取所有网卡的小时数据
|
||||
// 先获取所有存在的网卡GUID
|
||||
try
|
||||
{
|
||||
var allHourlyData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByHourAsync("", hours);
|
||||
var networkGuids = allHourlyData.Select(x => "").Distinct(); // 这里需要从实际数据中提取
|
||||
|
||||
foreach (var guid in networkGuids)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(guid))
|
||||
result.Add(new GlobalNetworkHourly { NetworkCardGuid = guid });
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果出错,返回空列表
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 辅助方法:获取所有网卡的日数据
|
||||
private static async Task<List<GlobalNetworkAggregatedBase>> GetAllNetworkCardsDailyDataAsync(int days)
|
||||
{
|
||||
var result = new List<GlobalNetworkAggregatedBase>();
|
||||
|
||||
try
|
||||
{
|
||||
var allDailyData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByDayAsync("", days);
|
||||
var networkGuids = allDailyData.Select(x => "").Distinct(); // 这里需要从实际数据中提取
|
||||
|
||||
foreach (var guid in networkGuids)
|
||||
{
|
||||
if (!string.IsNullOrEmpty(guid))
|
||||
result.Add(new GlobalNetworkDaily { NetworkCardGuid = guid });
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果出错,返回空列表
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
// 辅助方法:检查指定时间范围内是否有网络数据
|
||||
private static async Task<bool> HasNetworkDataInTimeRangeAsync(string dataType, long startTime)
|
||||
{
|
||||
try
|
||||
{
|
||||
// 使用现有方法检查数据
|
||||
switch (dataType)
|
||||
{
|
||||
case "hourly":
|
||||
var hourlyData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByHourAsync("", 1);
|
||||
return hourlyData.Any();
|
||||
case "daily":
|
||||
var dailyData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByDayAsync("", 1);
|
||||
return dailyData.Any();
|
||||
default:
|
||||
var networkData = await DatabaseManager.Instance.Networks.GetGlobalNetworkHistoryAsync("", 1);
|
||||
return networkData.Any();
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// 辅助方法:获取流量趋势数据
|
||||
private static async Task<List<object>> GetTrafficTrendsAsync(string timeRange, string interfaceId, long startTime, long endTime)
|
||||
{
|
||||
var points = new List<object>();
|
||||
|
||||
try
|
||||
{
|
||||
if (timeRange == "hour")
|
||||
{
|
||||
// 从 GlobalNetwork 表查询
|
||||
if (interfaceId == "all")
|
||||
{
|
||||
// 获取所有网卡数据并聚合
|
||||
var allData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync("", startTime, endTime);
|
||||
var groupedData = allData.GroupBy(d => d.Timestep).Select(g => new
|
||||
{
|
||||
timestamp = g.Key.ToString(),
|
||||
uploadSpeed = g.Sum(x => x.Upload),
|
||||
downloadSpeed = g.Sum(x => x.Download)
|
||||
});
|
||||
|
||||
points.AddRange(groupedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = await DatabaseManager.Instance.Networks.GetGlobalNetworkByTimeRangeAsync(interfaceId, startTime, endTime);
|
||||
points.AddRange(data.Select(d => new
|
||||
{
|
||||
timestamp = d.Timestep.ToString(),
|
||||
uploadSpeed = d.Upload,
|
||||
downloadSpeed = d.Download
|
||||
}));
|
||||
}
|
||||
}
|
||||
else if (timeRange == "day")
|
||||
{
|
||||
// 从小时数据聚合
|
||||
if (interfaceId == "all")
|
||||
{
|
||||
var allData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByHourAsync("", 24);
|
||||
var groupedData = allData.GroupBy(d => d.HourTimestamp).Select(g => new
|
||||
{
|
||||
timestamp = g.Key.ToString(),
|
||||
uploadSpeed = g.Sum(x => x.AvgUpload),
|
||||
downloadSpeed = g.Sum(x => x.AvgDownload)
|
||||
});
|
||||
|
||||
points.AddRange(groupedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = await DatabaseManager.Instance.Networks.GetGlobalNetworkByHourAsync(interfaceId, 24);
|
||||
points.AddRange(data.Select(d => new
|
||||
{
|
||||
timestamp = d.HourTimestamp.ToString(),
|
||||
uploadSpeed = d.AvgUpload,
|
||||
downloadSpeed = d.AvgDownload
|
||||
}));
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// 从日数据聚合
|
||||
int days = timeRange == "week" ? 7 : 30;
|
||||
if (interfaceId == "all")
|
||||
{
|
||||
var allData = await DatabaseManager.Instance.Networks.GetGlobalNetworkByDayAsync("", days);
|
||||
var groupedData = allData.GroupBy(d => d.DayTimestamp).Select(g => new
|
||||
{
|
||||
timestamp = g.Key.ToString(),
|
||||
uploadSpeed = g.Sum(x => x.AvgUpload),
|
||||
downloadSpeed = g.Sum(x => x.AvgDownload)
|
||||
});
|
||||
|
||||
points.AddRange(groupedData);
|
||||
}
|
||||
else
|
||||
{
|
||||
var data = await DatabaseManager.Instance.Networks.GetGlobalNetworkByDayAsync(interfaceId, days);
|
||||
points.AddRange(data.Select(d => new
|
||||
{
|
||||
timestamp = d.DayTimestamp.ToString(),
|
||||
uploadSpeed = d.AvgUpload,
|
||||
downloadSpeed = d.AvgDownload
|
||||
}));
|
||||
}
|
||||
}
|
||||
}
|
||||
catch
|
||||
{
|
||||
// 如果出错,返回空数据
|
||||
}
|
||||
|
||||
return points;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
||||
@@ -0,0 +1,160 @@
|
||||
# NetVizor Frontend - API 定义文档
|
||||
|
||||
## 1. 网络接口API
|
||||
|
||||
### 1.1 获取网络接口列表(在全局网速数据表中,把存在的网卡都展示出来,其中需要传递timeRange,以表示拿哪里的数据,day指的是1天的数据,你应该去 GlobalNetworkHourly 中寻找,因为其内部最小单位为小时。如果是 week 则应该去 GlobalNetworkDaily 因为这个表的时间为天,mouth 也对应的是GlobalNetworkDaily,如果是 hour 则应该去 GlobalNetwork 找,他内部的时间是 5 秒。这个值一共4中可能,hour,day,week,mouth,默认 hour
|
||||
目前数据库存储的有对应的 网卡ID,需要查询到所有的网卡ID再单独获取对应的网卡信息并返回 Common\Utils\NetworkAdapterHelper.cs 提供了网卡信息的获取方法
|
||||
```
|
||||
GET /api/statistics/interfaces?timeRange=day
|
||||
```
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"id": "eth0",
|
||||
"name": "以太网",
|
||||
"displayName": "Realtek PCIe GbE Family Controller",
|
||||
"isActive": true,
|
||||
"macAddress": "00:11:22:33:44:55"
|
||||
},
|
||||
{
|
||||
"id": "wifi0",
|
||||
"name": "WiFi",
|
||||
"displayName": "Intel Wi-Fi 6 AX200",
|
||||
"isActive": false,
|
||||
"macAddress": "66:77:88:99:AA:BB"
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
### 1.2 获取可用时间范围(这里的逻辑是是否有对应的数据,因为我们的数据库会定时的收集和整理信息,如果用户刚安装软件,肯定不会有月数据,也不会有周数据,所以需要据此来确定用户能展示的数据范围,同样分为 hour,day,week,mouth 返回这四个等级就行,hour只要用户安装超过10秒就有数据了,所以最低返回 hour 就行
|
||||
```
|
||||
GET /api/statistics/available-ranges
|
||||
```
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"type": "hour",
|
||||
"name": "1小时",
|
||||
"available": true,
|
||||
"startTime": "2025-01-08T15:00:00Z"
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
## 2. 流量数据API
|
||||
|
||||
### 2.1 获取流量趋势数据
|
||||
```
|
||||
GET /api/traffic/trends
|
||||
```
|
||||
**参数:**
|
||||
- `timeRange`: 时间范围 (1hour|1day|7days|30days)
|
||||
- `interfaceId`: 网卡ID,可选,默认为"all"表示所有网卡
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"interface": "all",
|
||||
"timeRange": "1hour",
|
||||
"points": [
|
||||
{
|
||||
"timestamp": "1754565364",
|
||||
"uploadSpeed": 1024000,
|
||||
"downloadSpeed": 5120000
|
||||
},{
|
||||
"timestamp": "1754565364",
|
||||
"uploadSpeed": 1024000,
|
||||
"downloadSpeed": 5120000
|
||||
},{
|
||||
"timestamp": "1754565364",
|
||||
"uploadSpeed": 1024000,
|
||||
"downloadSpeed": 5120000
|
||||
},{
|
||||
"timestamp": "1754565364",
|
||||
"uploadSpeed": 1024000,
|
||||
"downloadSpeed": 5120000
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
### 2.2 获取Top应用流量数据
|
||||
```
|
||||
GET /api/traffic/top-apps
|
||||
```
|
||||
**参数:**
|
||||
- `timeRange`: 时间范围
|
||||
- `limit`: 返回数量,默认10
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"data": [
|
||||
{
|
||||
"processName": "chrome.exe",
|
||||
"displayName": "Google Chrome",
|
||||
"icon": "+Uj0Iu09gH8tBUABUAB2HeA3IEEdYdHLY0EAAAAASUVORK5CYII=",
|
||||
"totalBytes": 1073741824
|
||||
},{
|
||||
"processName": "chrome.exe",
|
||||
"displayName": "Google Chrome",
|
||||
"icon": "+Uj0Iu09gH8tBUABUAB2HeA3IEEdYdHLY0EAAAAASUVORK5CYII=",
|
||||
"totalBytes": 1073741824
|
||||
},{
|
||||
"processName": "chrome.exe",
|
||||
"displayName": "Google Chrome",
|
||||
"icon": "+Uj0Iu09gH8tBUABUAB2HeA3IEEdYdHLY0EAAAAASUVORK5CYII=",
|
||||
"totalBytes": 1073741824
|
||||
}
|
||||
]
|
||||
}
|
||||
```
|
||||
|
||||
## 3. 软件排行榜API
|
||||
|
||||
### 3.1 获取软件流量TOP100排行
|
||||
```
|
||||
GET /api/apps/top-traffic
|
||||
```
|
||||
**参数:**
|
||||
- `timeRange`: 时间范围 (1hour|1day|7days|30days)
|
||||
- `page`: 页码,默认1
|
||||
- `pageSize`: 每页数量,默认100
|
||||
|
||||
**返回:**
|
||||
```json
|
||||
{
|
||||
"data": {
|
||||
"total": 156,
|
||||
"page": 1,
|
||||
"pageSize": 100,
|
||||
"items": [
|
||||
{
|
||||
"rank": 1,
|
||||
"processName": "chrome.exe",
|
||||
"displayName": "Google Chrome",
|
||||
"processPath": "C:\\Program Files\\Google\\Chrome\\chrome.exe",
|
||||
"icon": "H8tBUABUAB2HeA3IEEdYdHLY0EAAAAASUVORK5CYII",
|
||||
"totalBytes": 1073741824,
|
||||
"uploadBytes": 104857600,
|
||||
"connectionCount": 23
|
||||
},{
|
||||
"rank": 2,
|
||||
"processName": "chrome.exe1",
|
||||
"displayName": "Google Chrome1",
|
||||
"processPath": "C:\\Program Files\\Google\\Chrome\\chrome.exe",
|
||||
"icon": "H8tBUABUAB2HeA3IEEdYdHLY0EAAAAASUVORK5CYII",
|
||||
"totalBytes": 1073741824,
|
||||
"uploadBytes": 104857600,
|
||||
"connectionCount": 32
|
||||
}
|
||||
]
|
||||
}
|
||||
}
|
||||
```
|
||||
Whitespace-only changes.
Reference in new issue
Block a user