492 lines
18 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

using Assets.Scenes.Ride.Scripts.Model;
using Assets.Scenes.Ride.Scripts.Network;
using Assets.Scripts;
using Assets.Scripts.Apis;
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.IO.Compression;
using System.Linq;
using System.Text;
using System.Threading;
using System.Threading.Tasks;
namespace Assets.Scenes.Ride.Scripts
{
public class MapUDPService
{
private static IService _udpService;
//private static UdpClient udpClient;
//private static IPEndPoint iPEndPoint;
private static bool isExit = false;
//private static Task task = null;
//private static CancellationTokenSource cts { get; set; }
private static CancellationToken ct { get; set; }
//private static List<OnlineUser> onlineUsers { get; set; } = new List<OnlineUser>();
private static System.Timers.Timer heartbeat { get; set; }
public static bool Pause { get; set; } = false;
private static OnlineUserHelper _onlineUserHelper;
private static OnlineUserHelper onlineUserHelper
{
get
{
if (_onlineUserHelper == null)
{
_onlineUserHelper = new OnlineUserHelper();
}
return _onlineUserHelper;
}
}
private static DateTime LastActiveTime = DateTime.Now;
private static List<ReceiveMsgModel> msgs = new List<ReceiveMsgModel>();
/// <summary>
/// 初始化如果UDP服务未启动则会已没5秒一次不断尝试直到连接上为止,前端不需要考虑任何UDP连接的事情
/// </summary>
public static void Init(int competitionid = 0, bool isWatch = false)
{
try
{
Competitionid = competitionid;
IsWatch = isWatch;
//var ddd = new MapWorkoutService().GetRealOnlineUserInfo(new List<int> { 6 });
isExit = false;
Pause = false;
if (_udpService == null)
{
_udpService = new TcpService1();
_udpService.Start(list =>
{
LastActiveTime = DateTime.Now;
//onlineUserHelper.RemoveExceptionData(list);
msgs = list;
onlineUserHelper.SetOnlineUser(msgs);
});
heartbeat = new System.Timers.Timer();
heartbeat.Interval = 1000;
heartbeat.AutoReset = true;
heartbeat.Enabled = true;
heartbeat.Elapsed += Heartbeat_Elapsed;
}
}
catch (Exception e)
{
Trace.WriteLine("UDP:" + e.Message);
}
finally
{
//发送一条心跳包
//SendHeartbeat();
//告诉tcp服务器gzip
}
}
private static void Heartbeat_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
var now = DateTime.Now;
//超过一秒没有收到消息
if ((now - LastActiveTime).TotalSeconds > 1)
{
onlineUserHelper.SetOnlineUser(new List<ReceiveMsgModel>());
}
if (now.Second % 20 == 0)
{
//LastActiveTime = now;
SendHeartbeat();
}
}
public static byte[] Compress(string text)
{
var bytes = Encoding.Unicode.GetBytes(text);
using (var mso = new MemoryStream())
{
using (var gs = new GZipStream(mso, CompressionMode.Compress))
{
gs.Write(bytes, 0, bytes.Length);
}
return mso.ToArray();
}
}
public static string Decompress(byte[] data)
{
// Read the last 4 bytes to get the length
byte[] lengthBuffer = new byte[4];
Array.Copy(data, data.Length - 4, lengthBuffer, 0, 4);
int uncompressedSize = BitConverter.ToInt32(lengthBuffer, 0);
var buffer = new byte[uncompressedSize];
using (var ms = new MemoryStream(data))
{
using (var gzip = new GZipStream(ms, CompressionMode.Decompress))
{
gzip.Read(buffer, 0, uncompressedSize);
}
}
return Encoding.Unicode.GetString(buffer);
}
/// <summary>
/// 发送心跳包
/// </summary>
private static void SendHeartbeat()
{
try
{
var model = new
{
CommandType = 0,
};
var sendBytes = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(model));
_udpService.Send(sendBytes, sendBytes.Length);
}
catch (Exception e)
{
Console.WriteLine("发送心跳失败:" + e);
}
}
public static int Competitionid { get; set; }
public static bool IsWatch { get; set; }
/// <summary>
/// 告诉TCP服务器给我Gzip的格式
/// </summary>
public static void SendGizpModel()
{
var client = App.AppVersion;
#if UNITY_ANDROID
client = "Unity-Android" + App.AppVersion;
#elif UNITY_IOS
client = "Unity-ios" + App.AppVersion;
#else
client = "Unity" + App.AppVersion;
#endif
try
{
var model = new GzipMsgModel
{
CommandType = 2,
V = 2,
Encoding = "gzip",
Client = client,
MemberId = App.CurrentUser.Id,
Competitionid = Competitionid,
IsWatch = IsWatch
};
var sendBytes = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(model));
_udpService.Send(sendBytes, sendBytes.Length);
}
catch (Exception e)
{
Console.WriteLine("发送失败:" + e);
}
}
/// <summary>
/// 发送数据
/// </summary>
/// <param name="RouteId">路书Id</param>
/// <param name="MemberId">用户id</param>
/// <param name="Point">当前点位</param>
/// <param name="prop">属性</param>
/// <param name="IsCompleted">是否完成</param>
/// <param name="exit">是否退出</param>
public static void Send(int RouteId, int MemberId, double[] Point, bool IsCompleted = false, bool exit = false,
double endDistance = 0, bool showVirtual = false, byte commandType = 1, double speed = 0, bool isVirtual = false, double preDistance = 0,
double weightKg = 0, int competitionId = 0, bool saved = false,double? heartRate = 0, double power = 0, double? cadence = 0,int totalTicks = 0)
{
try
{
Point[0] = Math.Round(Point[0], 6, MidpointRounding.AwayFromZero);
Point[1] = Math.Round(Point[1], 6, MidpointRounding.AwayFromZero);
var model = new MsgModel
{
RouteId = RouteId,
MemberId = MemberId,
Point = Point,
IsCompleted = IsCompleted,
//exit = exit,
EndDistance = endDistance,
//ShowVirtual = showVirtual,
CommandType = commandType,
Speed = speed,
Power = power,
HeartRate = heartRate,
Cadence = cadence,
TotalTicks = totalTicks,
//IsVirtual = isVirtual,
PreDistance = preDistance,
WeightKg = weightKg,
Competitionid = competitionId,
Saved = saved,
//V = 1
};
var sendBytes = Encoding.UTF8.GetBytes(Newtonsoft.Json.JsonConvert.SerializeObject(model));
_udpService.Send(sendBytes, sendBytes.Length);
}
catch (Exception e)
{
Console.WriteLine("发送失败:" + e);
}
}
public static void Dispose()
{
try
{
isExit = true;
if (MapUDPService._udpService == null) return;
for (int i = 0; i < 3; i++)
{
Send(0, App.CurrentUser.Id, new double[] { 1, 1 }, true, isExit);
}
_udpService.Close();
//task.Dispose();
_udpService = null;
_onlineUserHelper = null;
}
catch (Exception)
{
}
finally
{
//停止计时
if (heartbeat != null)
{
heartbeat.Stop();
heartbeat.Close();
}
}
}
public static OnlineUser GetOnlineUserLastDataById(int userId)
{
//return _onlineUserHelper.GetOnlineUserLastDataById(userId);
//var msg = msgs.Where(m => m.MemberId == userId);
//if (msg == null) return null;
return onlineUserHelper.OnlineUsers.FirstOrDefault(u => u.Id == userId);
}
/// <summary>
/// 根据路书获取在线用户(非比赛用户不能看到比赛中的用户)
/// </summary>
/// <param name="routeId"></param>
/// <returns></returns>
public static List<OnlineUser> GetOnlineUsers(params int[] routeId)
{
var result = onlineUserHelper.OnlineUsers.Where(u => routeId.Contains(u.RouteId) && u.CompetitionId == 0).ToList();
return result;
}
//比赛中的人只能看到当前比赛的人
public static List<OnlineUser> GetCompetitionOnlineUsers(int competitionId)
{
var result = onlineUserHelper.OnlineUsers.Where(u => u.CompetitionId == competitionId && !u.IsWatcher).ToList();
//var result = onlineUserHelper.OnlineUsers.Where(u =>!u.IsWatcher).ToList();
return result;
}
//当前比赛观察者
public static List<OnlineUser> GetCompetitionWatchers(int competitionId,int size = 5)
{
//var result = onlineUserHelper.OnlineUsers.Where(u => u.CompetitionId == competitionId && u.IsWatcher).Take(size).ToList();
var result = onlineUserHelper.OnlineUsers.Where(u =>u.IsWatcher).Take(size).ToList();
return result;
}
public static int GetNearRiderCount()
{
return onlineUserHelper.OnlineUsers.Count();
}
/// <summary>
/// 获取附近的人(当前在线的所有人)
/// </summary>
/// <returns></returns>
public static IList<NearRiderModel> GetNearRiderData(int pageIndex, int pageSize = 5, double[] point = null)
{
if (point == null) return null;
var dict = new List<System.Tuple<double, OnlineUser>>();
var allOnlineUsers = onlineUserHelper.OnlineUsers.Where(c=>c.CompetitionId == 0);
foreach (var item in allOnlineUsers)
{
if (item.Id == App.CurrentUser.Id)
{
dict.Add(new Tuple<double, OnlineUser>(0, item));
continue;
}
if (item.Point[0] != 0 && item.Point[1] != 0)
{
var distance = Math.Round(TurfHelper.GetDistances(point, item.Point) / 1000, 2);
dict.Add(new Tuple<double, OnlineUser>(distance, item));
}
}
var allList = dict.OrderBy(d => d.Item1);//.Select(d=>d.Item2);
var list = allList.Skip((pageIndex - 1) * pageSize).Take(pageSize).ToList();
var nearData = list.Select(n => new NearRiderModel()
{
Headimage = n.Item2.HeadImage,
Name = n.Item2.Name,
Near = n.Item1, //Math.Round(TurfHelper.GetDistances(point, n.Point) / 1000, 2),
KGWeight = n.Item2.WeightKg.ToString(),
Speed = Math.Round(n.Item2.Speed, 1),
CountryImg = App.Host + $"User/GetCountryImg?userid={n.Item2.Id}",
IsSelf = n.Item2.IsSelf,
Id = n.Item2.Id,
Country = n.Item2.Country,
}).ToList();
return nearData;
//return new
//{
// NearData = nearData,
// PageCount = (int)Math.Ceiling((double)allList.Count() / pageSize)
//};
}
private class OnlineUserHelper
{
//public static List<OnlineUser> users { get; private set; }
private static readonly object locker = new object();
private readonly List<OnlineUser> onlineUsers = new List<OnlineUser>();
public List<OnlineUser> OnlineUsers
{
get
{
//if((DateTime.Now - LastActiveTime).TotalSeconds > 1)
//{
// SetOnlineUser(new List<ReceiveMsgModel>());
//}
return onlineUsers.ToList();
}
}
/// <summary>
/// 设置在线的人员
/// </summary>
public void SetOnlineUser(List<ReceiveMsgModel> mes)
{
try
{
var msgs = RemoveExceptionData(mes);
//LastActiveTime = DateTime.Now;
var ids = msgs.Where(m => onlineUsers.All(u => u.Id != m.MemberId)).Select(m => m.MemberId);
if (ids.Any())
{
MapApi api = new MapApi();
var rangeUser = api.GetOnlineUserInfo(ids).data;
onlineUsers.AddRange(rangeUser);
}
foreach (var user in onlineUsers)
{
var item = msgs.FirstOrDefault(u => u.MemberId == user.Id);
if (item != null)
{
user.LastActiveTime = DateTime.Now;
user.RouteId = item.RouteId;
user.Point = item.Point;
user.IsCompleted = item.IsCompleted;
//user.exit = item.exit;
user.EndDistance = item.EndDistance;
user.IsVirtual = item.MemberId < 0;
user.Speed = item.Speed;
user.WeightKg = item.WeightKg;
user.PreDistance = item.PreDistance;
user.CompetitionId = item.Competitionid;
user.Saved = item.Saved;
user.Power = item.Power;
user.HeartRate = item.HeartRate;
user.Cadence = item.Cadence;
user.TotalTicks = item.TotoalTicks;
user.WatcherList = new List<int>();
foreach (var o in item.WatchIdList.Split('|'))
{
if (!string.IsNullOrEmpty(o))
{
user.WatcherList.Add(Convert.ToInt32(o));
}
}
user.IsWatcher = user.WatcherList.Contains(item.MemberId);
user.CreateTime = DateTime.MaxValue;
}
else
{
user.PreDistance = user.EndDistance;
}
}
onlineUsers.RemoveAll(u => u.IsLost);
}
catch (Exception)
{
#if DEBUG
throw;
#endif
//return new List<OnlineUser>();
}
}
/// <summary>
/// 去除重复数据去除坐标为0的数据
/// </summary>
/// <param name="mes"></param>
private List<ReceiveMsgModel> RemoveExceptionData(List<ReceiveMsgModel> mes)
{
var list = mes.ToList();
//去除自己的数据和命令包
//mes.RemoveAll(item => item.MemberId == App.CurrentUser.Id || item.Point[0] == 0);
list.RemoveAll(item => item.Point[0] == 0 && item.Point[1] == 0);
//去除重复数据
list = list.Distinct(new OlineUserComparer()).ToList();
return list;
}
public class NearUserComparer : IEqualityComparer<NearRiderModel>
{
public bool Equals(NearRiderModel x, NearRiderModel y)
{
if (x == null)
return y == null;
return x.Name == y.Name;
}
public int GetHashCode(NearRiderModel obj)
{
if (obj == null)
return 0;
return obj.Name.GetHashCode();
}
}
public class OlineUserComparer : IEqualityComparer<ReceiveMsgModel>
{
public bool Equals(ReceiveMsgModel x, ReceiveMsgModel y)
{
if (x == null)
return y == null;
return x.MemberId == y.MemberId;
}
public int GetHashCode(ReceiveMsgModel obj)
{
if (obj == null)
return 0;
return obj.MemberId.GetHashCode();
}
}
}
}
}