using System;
using System.Collections.Generic;
using System.Configuration;
using System.Linq;
using System.Threading;
using Microsoft.AspNet.SignalR;
using Microsoft.AspNet.SignalR.Transports;
using MY.BllModel;
using Newtonsoft.Json;
using Task = System.Threading.Tasks.Task;
using MY.Logging;
using MY.Utility;
namespace SignalR.Persistent
{
/// <summary>
/// 持久连接
/// </summary>
public partial class CharPersistent : PersistentConnection
{
//log类声明为局部静态是为性能考虑
private static readonly LogHelper LogHelper = new LogHelper("SignalR.Persistent.CharPersistent");
protected static SyncList<DeviceOnlineModel> UserModelList = new SyncList<DeviceOnlineModel>();
/// <summary>
/// 真实链接数量
/// </summary>
protected static int ConnectionsCount = 0;
/// <summary>
/// 接受到消息
/// </summary>
protected override async Task OnReceived(IRequest request, string connectionId, string data)
{
try
{
if (string.IsNullOrEmpty(data))
{
throw new Exception("请求参数不能为空");
}
var json = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
if (!json.ContainsKey("type") || !json.ContainsKey("text"))
{
throw new Exception("参数{type,text}不能为空");
}
switch (json["type"].ToString().ToLower())
{
case "online": //设备、web上线
await Online(request, connectionId, json["text"].ToString());
break;
case "ng": //设备、web指令接收
await MsgForwarding(connectionId, data);
if (json["text"].ToString().ToLower() == "getall")
{
LogHelper.DebugAsync("设备返回getall时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
}
break;
case "onlineline": //获得在线列表
Connection.SendToWeb(connectionId,
new {count = ConnectionsCount, list = UserModelList}.ToJson());
break;
case "sendmsg": //中转服务器发送消息
ServiceSendMsg(json["userid"].ToString(), json["text"].ToString());
break;
case "appexceptionlog": //应用异常日志
AddException(json["text"].ToString());
break;
case "recovered": //找回设备
case "notice": //通知回复
case "getbluetooth": //取的蓝牙数据
case "getappblacklist": //取的应用黑名单数据
case "getphonebook": //取的电话簿
case "removeapp": //删除app
if (json["result"].ToString() == "1")
{
HandlePushEnd(json["text"].ToString());
LogHelper.DebugAsync(string.Format("特殊推送收到成功回复,回复类型:{0},json:{1}",
json["type"].ToString().ToLower(), data));
}
else
{
LogHelper.DebugAsync(string.Format("特殊推送收到失败回复,回复类型:{0},json:{1}",
json["type"].ToString().ToLower(), data));
}
break;
default:
LogHelper.DebugAsync(string.Format("服务器接收到消息【{0}】,消息内容为{1}", connectionId, data));
break;
}
}
catch (Exception ex)
{
LogHelper.ErrorAsync("接收消息异常:" + (ex.InnerException != null ? ex.InnerException.Message : ex.Message));
//错误指令返回
Connection.SendErrMsg(connectionId, ex.Message);
}
}
/// <summary>
/// 用户发送消息转发处理
/// </summary>
/// <param name="userid"></param>
/// <param name="msg"></param>
private void ServiceSendMsg(string userid, string msg)
{
if (string.IsNullOrEmpty(userid))
{
return;
}
userid = Uri.EscapeDataString(userid);
var entity = UserModelList.FirstOrDefaultV(q => q.UserId == userid && q.UserType == (int) UserType.AppUser);
if (entity != null)
{
//指定用户发送消息
Connection.Send(entity.UserConnerctionId, msg);
}
LogHelper.DebugAsync(string.Format("服务推送消息给设备用户【{0}】,消息内容为{1}", userid, msg));
}
/// <summary>
/// 上线
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <param name="text"></param>
private async Task Online(IRequest request, string connectionId, string text = "")
{
try
{
//获得用户信息
if (string.IsNullOrEmpty(text))
{
text = request.QueryString["userid"];
if (string.IsNullOrEmpty(text))
{
return;
}
}
if (string.IsNullOrEmpty(text))
{
throw new Exception("参数{text}不能为空");
}
var texts = text.Split('|');
if (texts.Length < 2)
{
throw new Exception("参数{text}异常:{\"type\":\"online\",\"text\":\"imei|usertype|sign|timestamp\"}");
}
var userid = texts[0]; //用户
var usertype = 0;
if (!int.TryParse(texts[1], out usertype))
{
throw new Exception(
"参数{text}异常:{\"type\":\"online\",\"text\":\"imei|usertype|sign|timestamp\"},usertype参数异常");
}
//存储用户
var model = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == connectionId);
if (model == null)
{
userid = Uri.EscapeDataString(userid);
UserModelList.Add(new DeviceOnlineModel()
{UserConnerctionId = connectionId, UserId = userid, UserType = usertype});
}
//web上线
if (usertype == (int) UserType.SysWebUser)
{
//验证请求地址是否合法
var hosts = ConfigurationManager.AppSettings["SignalRClientWebHost"];
if (!string.IsNullOrEmpty(hosts))
{
var arrHost = hosts.Split(',');
var origin = request.Headers["Origin"];
//非法地址直接断开
if (!arrHost.Contains(origin))
{
LogHelper.ErrorAsync("非法连接,请求来源:" + request.Headers.ToJson() + ",连接数据:" + text);
await ServiceDisconnect(connectionId);
return;
}
}
//获得要发送的链接id列表
var sendEntity = GetRrelatedSendList(connectionId).FirstOrDefault();
if (sendEntity != null)
{
//记录日志
LogHelper.DebugAsync("WEB用户getall时间:" + DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss fff"));
//推送获取设备信息指令
await Task.Run(() => Connection.SendToDevice(sendEntity.UserConnerctionId,
JsonConvert.SerializeObject(new {type = "ng", text = "getall",})));
//告知web该设备在线
//await Task.Run(() => Connection.SendToWeb(connectionId, "Online"));
}
else
{
//告知web该设备不在线
await Task.Run(() => Connection.SendToWeb(connectionId, "NoOnline"));
}
//记录日志
LogHelper.DebugAsync("WEB用户【" + Uri.UnescapeDataString(userid) + "】上线了");
}
//设备上线
else
{
//验证请求是否合法
if (texts.Length != 4)
{
throw new Exception(
"参数{text}异常:{\"type\":\"online\",\"text\":\"imei|usertype|sign|timestamp\"}");
}
//检测是否合法
var signalRKey = ConfigurationManager.AppSettings["SignalRKey"];
if (signalRKey != "")
{
var sign = texts[2];
var timestamp = texts[3];
var sign2 = MY.Utility.Encryption.EncryptMd5($"{userid}|{usertype}|{timestamp}|{signalRKey}");
if (!sign.Equals(sign2, StringComparison.OrdinalIgnoreCase))
{
LogHelper.ErrorAsync("非法连接 ,连接数据:" + text);
await ServiceDisconnect(connectionId);
return;
}
}
//存在网站用户登陆
bool onlineCnt =
UserModelList.AnyV(o => o.UserId == userid && o.UserType == (int) UserType.SysWebUser);
if (onlineCnt)
{
//推送获取设备信息指令
await Task.Run(() => Connection.SendToDevice(connectionId,
JsonConvert.SerializeObject(new {type = "ng", text = "getall",})));
}
//记录日志
LogHelper.DebugAsync("设备用户【" + Uri.UnescapeDataString(text) + "】上线了");
//同步设备在线情况
SyncDeviceOnlineSituation();
//写入设备上线记录
AddDeviceConnectLog(userid, connectionId, 1, "设备上线");
}
}
catch (Exception e)
{
LogHelper.ErrorAsync("连接上线异常【" + text + "】:" +
(e.InnerException != null ? e.InnerException.Message : e.Message));
LogHelper.ErrorAsync("异常堆栈:" + e.ToJson());
//错误指令返回
Connection.SendErrMsg(connectionId, e.Message);
ServiceDisconnect(connectionId, false);
}
}
/// <summary>
/// 连接断开
/// </summary>
protected override async Task OnDisconnected(IRequest request, string connectionId, bool stopCalled)
{
Interlocked.Decrement(ref ConnectionsCount);
try
{
DeviceOnlineModel model = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == connectionId);
if (model != null)
{
//设备离线
if (model.UserType == (int) UserType.AppUser)
{
var sendEntitys = GetRrelatedSendList(connectionId);
if (sendEntitys != null)
{
foreach (var sendEntity in sendEntitys)
{
List<DeviceOnlineModel> onlineList = UserModelList.WhereV(o =>
o.UserId == model.UserId && o.UserType == (int) UserType.AppUser).ToList();
if (onlineList.Count() == 1)
{
//推送设备离线
await Task.Run(() =>
Connection.SendToWeb(sendEntity.UserConnerctionId, "NoOnline"));
}
}
}
LogHelper.DebugAsync("设备用户【" + Uri.UnescapeDataString(model.UserId + "|" + model.UserType) +
"】下线了");
#pragma warning disable 4014
//同步设备在线情况
SyncDeviceOnlineSituation();
//写入设备下线记录
AddDeviceConnectLog(model.UserId, connectionId, 2, "设备下线");
#pragma warning restore 4014
}
else
{
LogHelper.DebugAsync("WEB用户【" + Uri.UnescapeDataString(model.UserId + "|" + model.UserType) +
"】下线了");
}
UserModelList.Remove(model);
}
}
catch (Exception e)
{
LogHelper.ErrorAsync("连接断开异常【" + connectionId + "】:" +
(e.InnerException != null ? e.InnerException.Message : e.Message));
LogHelper.ErrorAsync("异常堆栈:" + e.ToJson());
}
//默认调用
await base.OnDisconnected(request, connectionId, stopCalled);
}
/// <summary>
/// 连接创建
/// </summary>
protected override async Task OnConnected(IRequest request, string connectionId)
{
Interlocked.Increment(ref ConnectionsCount);await Online(request, connectionId);
await base.OnConnected(request, connectionId);
}
/// <summary>
/// 重新连接
/// </summary>
/// <param name="request"></param>
/// <param name="connectionId"></param>
/// <returns></returns>
protected override async Task OnReconnected(IRequest request, string connectionId)
{
//ConnectionsCount++;
await Online(request, connectionId);
await base.OnReconnected(request, connectionId);
}
/// <summary>
/// 消息转发,通过当前消息用户链接id找到对应的用户链接id
/// </summary>
/// <param name="userConnerctionId"></param>
/// <param name="data"></param>
private async Task MsgForwarding(string userConnerctionId, string data)
{
if (string.IsNullOrEmpty(userConnerctionId))
{
return;
}
//获得要发送的链接id列表
var sendEntitys = GetRrelatedSendList(userConnerctionId);
if (sendEntitys != null)
{
foreach (var model in sendEntitys)
{
if (model != null)
{
//指定用户发送消息
await Connection.Send(model.UserConnerctionId, data);
LogHelper.DebugAsync($"服务器转发消息给用户:{model.UserId}|{model.UserType},内容为:{data}");
}
}
}
//记录用户记录
DeviceOnlineModel entity = UserModelList.FirstOrDefaultV(o => o.UserConnerctionId == userConnerctionId);
if (entity != null)
{
//指令发送成功后回复发送端发送成功
if (entity.UserType == (int) UserType.SysWebUser)
{
var dic = JsonConvert.DeserializeObject<Dictionary<string, object>>(data);
if (dic["text"].Equals("restart")
|| dic["text"].Equals("shutdown")
|| dic["text"].Equals("resumedefault"))
{
await Connection.Send(entity.UserConnerctionId, "MainSendOK");
}
}
LogHelper.DebugAsync("服务器接收到【" + (entity.UserType == (int) UserType.SysWebUser ? "WEB" : "设备") +
"】用户【" + entity.UserId + "】,消息内容为:" + data);
}
}
/// <summary>
/// 获得发送连接id列表
/// </summary>
/// <param name="userConnerctionId"></param>
/// <returns></returns>
public List<DeviceOnlineModel> GetRrelatedSendList(string userConnerctionId)
{
//发送消息的用户
var entity = UserModelList.FirstOrDefaultV(q => q.UserConnerctionId == userConnerctionId);
if (entity != null)
{
var usertype = entity.UserType == (int) UserType.AppUser
? (int) UserType.SysWebUser
: (int) UserType.AppUser;
//要推送消息的用户
var sendEntitys = UserModelList.WhereV(q => q.UserId == entity.UserId && q.UserType == usertype)
.ToList();
return sendEntitys;
}
return null;
}
/// <summary>
/// 服务器强制断开连接
/// </summary>
/// <param name="connectionId"></param>
/// <param name="isSendErrMsg"></param>
private async Task ServiceDisconnect(string connectionId, bool isSendErrMsg = true)
{
await GlobalHost.DependencyResolver.Resolve<ITransportHeartbeat>().GetConnections()
.First(o => o.ConnectionId == connectionId).Disconnect();
if (isSendErrMsg)
{
//错误指令返回
Connection.SendErrMsg(connectionId, "非法连接,强制断开");
}
}
}
}