|
@@ -5,14 +5,20 @@ using Microsoft.Extensions.Primitives;
|
|
|
using TEAMModelOS.SDK.DI;
|
|
|
using TEAMModelOS.SDK.Extension;
|
|
|
using TEAMModelOS.SDK;
|
|
|
+using System.Web;
|
|
|
+using System.Text;
|
|
|
+
|
|
|
+using StackExchange.Redis;
|
|
|
namespace HTEX.Complex.Services
|
|
|
{
|
|
|
public class SignalRScreenServerHub : Hub<IClient>
|
|
|
{
|
|
|
- private readonly AzureRedisFactory _azureRedis;
|
|
|
|
|
|
- public SignalRScreenServerHub(AzureRedisFactory azureRedis)
|
|
|
+ private readonly ILogger<SignalRScreenServerHub> _logger;
|
|
|
+ private readonly AzureRedisFactory _azureRedis;
|
|
|
+ public SignalRScreenServerHub(AzureRedisFactory azureRedis, ILogger<SignalRScreenServerHub> logger)
|
|
|
{
|
|
|
+ _logger = logger;
|
|
|
_azureRedis = azureRedis;
|
|
|
}
|
|
|
|
|
@@ -21,7 +27,6 @@ namespace HTEX.Complex.Services
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
public override async Task OnConnectedAsync()
|
|
|
-
|
|
|
{
|
|
|
var connid = Context.ConnectionId;
|
|
|
var httpContext = Context.GetHttpContext();
|
|
@@ -31,7 +36,8 @@ namespace HTEX.Complex.Services
|
|
|
//wss://www.winteach.cn/signalr/notify?grant_type=bookjs_api&clientid={clientid}&id=客户端自动生成的
|
|
|
httpContext.Request.Query.TryGetValue("grant_type", out StringValues grant_type);
|
|
|
httpContext.Request.Query.TryGetValue("clientid", out StringValues clientid);
|
|
|
- var ip = GetIP(httpContext);
|
|
|
+ httpContext.Request.Query.TryGetValue("device", out StringValues _device);
|
|
|
+
|
|
|
await Groups.AddToGroupAsync(connid, grant_type!);
|
|
|
if (!clientid.Equals(StringValues.Empty) && !grant_type.Equals(StringValues.Empty)) {
|
|
|
|
|
@@ -43,55 +49,66 @@ namespace HTEX.Complex.Services
|
|
|
grant_type = grant_type,
|
|
|
clientid= clientid
|
|
|
};
|
|
|
- await _azureRedis.GetRedisClient(8).StringSetAsync($"SignalRClient:connects:{connid}", client.ToJsonString());
|
|
|
+ await _azureRedis.GetRedisClient(8).HashSetAsync($"SignalRClient:connects", connid, client.ToJsonString());
|
|
|
+ ClientDevice device = HttpUtility.UrlDecode(_device, Encoding.Unicode).ToObject<ClientDevice>();
|
|
|
switch (true)
|
|
|
{
|
|
|
case bool when grant_type.Equals(ScreenConstant.grant_type):
|
|
|
- ScreenClient screenClient = null;
|
|
|
+ ScreenClient screenClient ;
|
|
|
var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
|
|
|
if (value!=default && value.HasValue)
|
|
|
{
|
|
|
screenClient = value.ToString().ToObject<ScreenClient>();
|
|
|
- // 这里不强制设置free ,因为如果是重连,可能正在执行命令,需要等待执行完成
|
|
|
+
|
|
|
+ // 这里不强制设置free ,因为如果是重连,可能正在执行任务,需要等待执行完成
|
|
|
//screenClient.status="free";
|
|
|
- screenClient.connid=connid;
|
|
|
+
|
|
|
+ //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
|
|
|
+ if (!screenClient.status!.Equals(ScreenConstant.free) && screenClient.last_time + screenClient.timeout+ screenClient.delay + ScreenConstant.time_excess < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds())
|
|
|
+ {
|
|
|
+ screenClient.status = ScreenConstant.free;
|
|
|
+ }
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- screenClient= new ScreenClient
|
|
|
+ screenClient = new ScreenClient
|
|
|
{
|
|
|
- status=ScreenConstant.free,
|
|
|
- connid=connid,
|
|
|
- grant_type=grant_type,
|
|
|
- clientid= clientid,
|
|
|
- desc="",
|
|
|
- domain="",
|
|
|
- ip=ip,
|
|
|
- time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds(),
|
|
|
- weight= 0,
|
|
|
- duration=0,
|
|
|
+ status = ScreenConstant.free,
|
|
|
};
|
|
|
}
|
|
|
+ screenClient.connid=connid;
|
|
|
+ screenClient.grant_type = grant_type;
|
|
|
+ screenClient.clientid = clientid;
|
|
|
+ screenClient.os = device.os;
|
|
|
+ screenClient.port = device.port;
|
|
|
+ screenClient.name = device.name;
|
|
|
+ screenClient.region = device.region;
|
|
|
+ screenClient.remote = device.remote;
|
|
|
+ screenClient.networks = device.networks;
|
|
|
+ screenClient.screenUrl = device.screenUrl;
|
|
|
+ screenClient.delay = device.delay;
|
|
|
+ screenClient.timeout = device.timeout;
|
|
|
+ screenClient.last_time= DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
|
//连接成功,发送消息给客户端。
|
|
|
await SendConnection(connid, new ConnectionMessageContent
|
|
|
{
|
|
|
+ connid=connid,
|
|
|
clientid = clientid,
|
|
|
- status = ScreenConstant.free,
|
|
|
+ status = screenClient.status,
|
|
|
grant_type = grant_type,
|
|
|
+ message_type= MessageType.conn_success,
|
|
|
content = $"连接成功"
|
|
|
});
|
|
|
- //先检查状态是否是在忙碌,在时间戳范围里,如果不在时间戳范围,强制free。
|
|
|
- if (!screenClient.status!.Equals(ScreenConstant.free) &&screenClient.time + screenClient.duration < DateTimeOffset.UtcNow.ToUnixTimeMilliseconds()) {
|
|
|
- screenClient.status = ScreenConstant.free;
|
|
|
- }
|
|
|
+ _logger.LogInformation($"客户端连接成功=>{screenClient.name},{clientid}:\n{screenClient.ToJsonString()}");
|
|
|
if (screenClient.status!.Equals(ScreenConstant.free)) {
|
|
|
+ _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},分发任务......");
|
|
|
//连接成功,马上分发任务。
|
|
|
//从尾部弹出元素,队列先进先出
|
|
|
var queueValue = await _azureRedis.GetRedisClient(8).ListRightPopAsync("PDFGen:Queue");
|
|
|
if (queueValue!=default && queueValue.HasValue)
|
|
|
{
|
|
|
PDFGenQueue genQueue = queueValue.ToString().ToObject<PDFGenQueue>();
|
|
|
- await SendConnection(connid, new ScreenProcessMessageContent
|
|
|
+ await SendMessage(connid, new ScreenProcessMessageContent
|
|
|
{
|
|
|
clientid = clientid,
|
|
|
status = ScreenConstant.busy,
|
|
@@ -99,9 +116,11 @@ namespace HTEX.Complex.Services
|
|
|
content =$"{queueValue.ToString()}",//从Redis中获取任务信息
|
|
|
});
|
|
|
screenClient.status = ScreenConstant.busy;
|
|
|
- screenClient.time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
|
- //预计占用时长,并冗余5秒
|
|
|
- screenClient.duration= genQueue.timeout+genQueue.delay+ScreenConstant.time_excess;
|
|
|
+ screenClient.last_time = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
|
+ }
|
|
|
+ else {
|
|
|
+ _logger.LogInformation($"客户端当前空闲=>{screenClient.name},{clientid},暂无任务可领取的任务......");
|
|
|
+
|
|
|
}
|
|
|
}
|
|
|
await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
|
|
@@ -115,6 +134,7 @@ namespace HTEX.Complex.Services
|
|
|
clientid = string.Empty,
|
|
|
status =ScreenConstant.error,
|
|
|
grant_type = grant_type,
|
|
|
+ message_type= MessageType.conn_error,
|
|
|
content = "客户端配置错误",
|
|
|
connid = connid,
|
|
|
});
|
|
@@ -125,44 +145,44 @@ namespace HTEX.Complex.Services
|
|
|
public async override Task OnDisconnectedAsync(Exception? exception)
|
|
|
{
|
|
|
var connid = Context.ConnectionId;
|
|
|
- var redisData = await _azureRedis.GetRedisClient(8).StringGetAsync($"SignalRClient:connects:{connid}");
|
|
|
+ var redisData = await _azureRedis.GetRedisClient(8).HashGetAsync($"SignalRClient:connects", connid);
|
|
|
+ _logger.LogInformation($"客户端断开连接=>{connid} ");
|
|
|
+ ///连接配置,并且使用钉钉 离线通知。
|
|
|
if (!redisData.IsNullOrEmpty)
|
|
|
{
|
|
|
- await _azureRedis.GetRedisClient(8).KeyDeleteAsync($"SignalRClient:connects:{connid}");
|
|
|
var client = redisData.ToString().ToObject<SignalRClient>();
|
|
|
+ await _azureRedis.GetRedisClient(8).HashDeleteAsync($"SignalRClient:connects", connid);
|
|
|
if (client != null)
|
|
|
{
|
|
|
+ await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
|
|
|
var value = await _azureRedis.GetRedisClient(8).HashGetAsync($"ScreenApi:clients", client.clientid);
|
|
|
if (value!=default && value.HasValue)
|
|
|
{
|
|
|
ScreenClient screenClient = value.ToString().ToObject<ScreenClient>() ;
|
|
|
- screenClient.status=ScreenConstant.down;
|
|
|
- screenClient.connid= string.Empty;
|
|
|
- await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
|
|
|
+ _logger.LogInformation($"客户端断开连接=>{connid},{screenClient.name},{screenClient.clientid} ");
|
|
|
+ long now = DateTimeOffset.UtcNow.ToUnixTimeMilliseconds();
|
|
|
+ // 判断是否过期
|
|
|
+ if (screenClient.status!.Equals(ScreenConstant.busy ) && screenClient.last_time+screenClient.timeout+screenClient.delay+ ScreenConstant.time_excess <=now)
|
|
|
+ {
|
|
|
+ screenClient.status=ScreenConstant.down;
|
|
|
+ screenClient.connid= string.Empty;
|
|
|
+ await _azureRedis.GetRedisClient(8).HashSetAsync($"ScreenApi:clients", client.clientid, screenClient.ToJsonString());
|
|
|
+ }
|
|
|
}
|
|
|
- await Groups.RemoveFromGroupAsync(connid, client.grant_type!);
|
|
|
- ///连接配置,并且使用钉钉 离线通知。
|
|
|
}
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
public async Task SendConnection(string connectionId, MessageBody msg)
|
|
|
{
|
|
|
await Clients.Client(connectionId).ReceiveConnection(msg);
|
|
|
}
|
|
|
- public string GetIP(HttpContext httpContext)
|
|
|
+ public async Task SendMessage(string connectionId, MessageBody msg)
|
|
|
{
|
|
|
- var IpPort = httpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
|
|
|
- if (string.IsNullOrEmpty(IpPort))
|
|
|
- {
|
|
|
- IpPort = $"{httpContext.Connection.RemoteIpAddress}";
|
|
|
- }
|
|
|
- if (IpPort.Contains("::"))
|
|
|
- {
|
|
|
- IpPort = "127.0.0.1";
|
|
|
- }
|
|
|
- return IpPort;
|
|
|
+ await Clients.Client(connectionId).ReceiveMessage(msg);
|
|
|
+ }
|
|
|
+ public async Task SendDisConnection(string connectionId, MessageBody msg)
|
|
|
+ {
|
|
|
+ await Clients.Client(connectionId).ReceiveDisConnection(msg);
|
|
|
}
|
|
|
}
|
|
|
-
|
|
|
}
|