This commit is contained in:
zpc 2025-03-29 00:23:54 +08:00
parent 9b7bd2318c
commit 63a0438406
5 changed files with 114 additions and 55 deletions

View File

@ -17,8 +17,8 @@ public class SignalRService : ISignalRService
private readonly SemaphoreSlim _semaphore = new(1, 1);
private string? _clientId;
private bool _isInitialConnection = true;
private const int MAX_RETRY_COUNT = 10;
private const int RETRY_INTERVAL_MS = 1000;
private const int MAX_RETRY_COUNT = 15;
private const int RETRY_INTERVAL_MS = 200;
private const int HEARTBEAT_INTERVAL_MS = 3000; // 3秒发送一次心跳
private Timer? _heartbeatTimer;
private DateTime _lastHeartbeatTime = DateTime.MinValue;
@ -78,7 +78,7 @@ public class SignalRService : ISignalRService
_hubConnection = new HubConnectionBuilder()
.WithUrl(hubUrl)
.WithAutomaticReconnect([TimeSpan.FromSeconds(1), TimeSpan.FromSeconds(2), TimeSpan.FromSeconds(3)])
.WithAutomaticReconnect()
.Build();
// 启动心跳定时器

View File

@ -1,5 +1,5 @@
{
"SignalRHubUrl": "http://115.159.44.16/audiohub",
"SignalRHubUrl": "http://localhost:81/audiohub",
"ConfigBackupPath": "config.json",
"AutoConnectToServer": true,
"AllowOfflineStart": false

Binary file not shown.

View File

@ -874,44 +874,101 @@ namespace ShengShengBuXi.Hubs
/// </summary>
private void InitializeDisplayTextTimer()
{
// 注意:不再需要实际启动定时器,因为已改为客户端主动请求模式
// 但保留此方法以保持代码结构兼容性
if (!_isDisplayTimerInitialized)
{
lock (_displayTimerLock)
{
if (!_isDisplayTimerInitialized)
{
_displayTextTimer = new Timer(SendNextDisplayText, null, 0, Timeout.Infinite);
// 不再需要实际启动定时器
// _displayTextTimer = new Timer(SendNextDisplayText, null, 0, Timeout.Infinite);
_isDisplayTimerInitialized = true;
_logger.LogInformation("显示文本定时器已初始化");
_logger.LogInformation("显示文本系统已初始化(客户端主动获取模式)");
}
}
}
}
// 注意:以下方法不再使用,由客户端主动获取替代,保留代码仅作参考
/// <summary>
/// 发送下一条显示文本
/// 发送下一条显示文本(不再使用,由客户端主动获取替代)
/// </summary>
/// <param name="state">状态对象</param>
private async void SendNextDisplayText(object state)
{
// 这个方法不再使用,由客户端主动获取替代
// 保留原有逻辑仅作参考
try
{
// 获取随机等待时间(5-10秒)
// 获取随机等待时间(10-30秒)
int nextInterval = new Random().Next(10000, 30000);
// 设置下一次触发时间
_displayTextTimer.Change(nextInterval, Timeout.Infinite);
// 设置下一次触发时间,此处设置为较长时间,避免频繁触发未使用的方法
_displayTextTimer?.Change(nextInterval, Timeout.Infinite);
_logger.LogWarning("使用了已废弃的发送显示文本方法,应改为客户端主动获取模式");
}
catch (Exception ex)
{
_logger.LogError($"发送显示文本失败: {ex.Message}");
}
}
/// <summary>
/// 开始接收显示文本兼容旧客户端新客户端应使用GetNextDisplayText
/// </summary>
public async Task StartReceivingDisplayText()
{
// 兼容旧版客户端的方法
_logger.LogWarning($"客户端 {Context.ConnectionId} 使用了已废弃的StartReceivingDisplayText方法应改为GetNextDisplayText");
// 转发到新方法
await GetNextDisplayText();
}
/// <summary>
/// 获取下一条要显示的文本(由客户端主动请求)
/// </summary>
/// <returns>处理任务</returns>
public async Task GetNextDisplayText()
{
try
{
// 检查客户端是否已注册
if (!_clients.TryGetValue(Context.ConnectionId, out var clientInfo))
{
_logger.LogWarning($"未注册的客户端尝试获取显示文本: {Context.ConnectionId}");
await Clients.Caller.SendAsync("Error", "请先注册客户端");
return;
}
// 检查客户端是否为Display类型
if (clientInfo.ClientType != ClientType.Display)
{
_logger.LogWarning($"非显示端客户端尝试获取显示文本: {Context.ConnectionId}, 类型: {clientInfo.ClientType}");
await Clients.Caller.SendAsync("Error", "只有显示端客户端可以获取显示文本");
return;
}
_logger.LogInformation($"显示端请求获取下一条显示文本: {Context.ConnectionId}");
// 检查队列是否为空
if (_displayTextQueue.IsEmpty)
{
// 检查是否需要添加预设文本(如果30秒内没有真实用户说话)
// 检查是否需要添加预设文本
if (DateTime.Now.Subtract(_lastRealUserSpeakTime).TotalSeconds > 30)
{
AddFakeTextToQueue();
}
return;
else
{
_logger.LogInformation("显示文本队列为空,且不需要添加预设文本");
// 如果队列为空且不需要添加预设文本,返回空
return;
}
}
// 从队列中选择最高优先级的消息
@ -921,29 +978,28 @@ namespace ShengShengBuXi.Hubs
// 检查是否获取到有效的消息
if (highestPriority.Key == Guid.Empty || highestPriority.Value == null)
return;
// 获取大屏显示客户端数量
int displayClientsCount = _clients.Values.Count(c => c.ClientType == ClientType.Display);
if (displayClientsCount > 0)
{
// 从队列中移除该消息
if (_displayTextQueue.TryRemove(highestPriority.Key, out _))
{
// 发送给所有Display客户端
await _hubContext.Clients.Group("displays").SendAsync("ReceiveDisplayText", highestPriority.Value.Text);
_logger.LogInformation($"已发送显示文本到大屏: {highestPriority.Value.Text} (来源: {(highestPriority.Value.IsRealUser ? "" : "")})");
}
_logger.LogWarning("无法从队列中获取有效的显示文本");
return;
}
// 从队列中移除该消息
if (_displayTextQueue.TryRemove(highestPriority.Key, out var textToDisplay))
{
// 只发送给请求的客户端
await Clients.Caller.SendAsync("ReceiveDisplayText", textToDisplay.Text);
_logger.LogInformation($"已发送显示文本到客户端: {textToDisplay.Text} (来源: {(textToDisplay.IsRealUser ? "" : "")})");
}
else
{
_logger.LogWarning($"无法从队列中移除显示文本: {highestPriority.Key}");
}
}
catch (Exception ex)
{
_logger.LogError($"发送显示文本失败: {ex.Message}");
_logger.LogError($"获取显示文本失败: {ex.Message}");
}
}
private static int _presetSentencesIndex = -1;
/// <summary>
/// 添加预设文本到队列
@ -964,14 +1020,6 @@ namespace ShengShengBuXi.Hubs
_presetSentences.Add("时光匆匆流逝,思念却越来越深。");
}
}
//if (_presetSentencesIndex == -1)
//{
// _presetSentencesIndex = new Random().Next(_presetSentences.Count);
//}
//if (_presetSentencesIndex >= _presetSentences.Count)
//{
// _presetSentencesIndex = new Random().Next(_presetSentences.Count); ;
//}
_presetSentences.OrderBy(it => Guid.NewGuid()).ToList().ForEach(item =>
{
var displayText = new DisplayText
@ -982,16 +1030,8 @@ namespace ShengShengBuXi.Hubs
IsRealUser = false,
RecognitionId = ""
};
//AddRecognizedTextToDisplay(item, false);
_displayTextQueue.TryAdd(displayText.Id, displayText);
//_logger.LogInformation($"添加预设文本到显示队列: {text}");
});
// 从未最近显示过的句子中随机选择一条
//string randomText = _presetSentences[_presetSentencesIndex];
//_presetSentencesIndex += new Random().Next(3);
}
catch (Exception ex)
{

View File

@ -218,6 +218,12 @@
} else {
isAnimating = false;
if (callback) callback();
// 打字效果完成后等待随机4-7秒然后请求下一条文本
const delay = Math.floor(Math.random() * 3000) + 4000; // 4000-7000毫秒
console.log(`文本显示完成,将在${delay/1000}秒后请求下一条文本`);
setTimeout(requestNextText, delay);
}
}
typeWriter();
@ -377,11 +383,8 @@
console.error("解析显示配置失败:", error);
}
}
// 开始接收显示文本
return hubConnection.invoke("StartReceivingDisplayText");
})
.then(function() {
console.log("开始接收显示文本");
// 开始请求第一条显示文本
requestNextText();
})
.catch(function(err) {
console.error("客户端操作失败:", err);
@ -507,12 +510,9 @@
$('#magazine').turn('previous');
else if (e.keyCode == 39)
$('#magazine').turn('next');
// 空格键不再触发说话,改为请求下一条文本
else if (e.keyCode == 32 && hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) {
hubConnection.invoke("StartReceivingDisplayText")
.catch(function(err) {
console.error("请求下一条文本失败:", err);
});
// 空格键请求下一条文本
else if (e.keyCode == 32) {
requestNextText();
}
});
@ -625,6 +625,25 @@
}
}
});
/**
* 请求下一条文本
*/
function requestNextText() {
if (hubConnection && hubConnection.state === signalR.HubConnectionState.Connected) {
console.log("正在向服务器请求下一条文本...");
hubConnection.invoke("GetNextDisplayText")
.catch(function(err) {
console.error("请求下一条文本失败:", err);
// 如果请求失败,稍后重试
setTimeout(requestNextText, 5000);
});
} else {
console.warn("SignalR连接未就绪无法请求下一条文本");
// 如果连接未就绪,稍后重试
setTimeout(requestNextText, 3000);
}
}
</script>
</body>