powerfun-new-net/ViewModels/MainWindowViewModel.cs
andy 0e931a3ac9 一些功能调整
增加tcp协议支持;
增加模拟多用户的功能;
2021-01-18 20:24:19 +08:00

269 lines
9.6 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 Prism.Mvvm;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Text;
using OnlineUserPool.Hander;
using OnlineUserPool.Model;
using OnlineUserPool.Unility;
using Serilog;
using System.Linq;
using System.Net;
using System.Net.Sockets;
using System.Threading.Tasks;
using System.Windows.Threading;
using System.Diagnostics;
using OnlineUserPool.Services;
using Newtonsoft.Json;
using System.Collections.Concurrent;
namespace OnlineUserPool.ViewModels
{
public class MainWindowViewModel : BindableBase
{
public ObservableCollection<HostModel> Clients { get; private set; } = new ObservableCollection<HostModel>();
private static ConcurrentBag<MsgModel> receiveMes = new ConcurrentBag<MsgModel>();
private static object locker = new object();
public static System.Timers.Timer timer;
private static IHandle mapRecordRankingHander;
private Dispatcher dispatcher;
public ObservableCollection<MsgModel> Customers { get; private set; } =
new ObservableCollection<MsgModel>();
private string _Title = "";
public string Title
{
get { return _Title; }
set
{
SetProperty(ref _Title, value);
}
}
private string _SendDataSize = "";
public string SendDataSize
{
get { return _SendDataSize; }
set
{
SetProperty(ref _SendDataSize, value);
}
}
//private IService _udpService;
public MainWindowViewModel()
{
Title = $"{ IPAddress.Any }:{ ConfigHelp.Port }";
dispatcher = Dispatcher.CurrentDispatcher;
//Customers.Add("suntao");
WriteLine(DateTime.Now.ToShortDateString());
LogHelper.Init();
mapRecordRankingHander = new MapRecordRankingHander();
Log.Information($"初始化连接,当前地址:{ IPAddress.Any }:{ConfigHelp.Port}");
new TcpService1().RunServer(ReceivedData);
//var tet = new System.Collections.Concurrent.ConcurrentBag<object>();
var _udpService = new UdpService();
_udpService.RunServer(ReceivedData);
Log.Information("服务启动成功");
timer = new System.Timers.Timer(1000);
timer.Elapsed += Timer_Elapsed;
timer.AutoReset = true;
timer.Start();
Log.Information("等待连接");
//Console.ReadKey();
}
private void ReceivedData(IPEndPoint remoteIpEndPoint, MsgModel msg, IService service)
{
dispatcher.Invoke(() =>
{
if (!Clients.Any(c => c.Equals(remoteIpEndPoint)))
{
Clients.Add(new HostModel
{
IPEndPoint = remoteIpEndPoint,
LastActiveTime = DateTime.Now,
RouteId = msg.RouteId,
MemberId = msg.MemberId,
//ShowVirtual = msg.ShowVirtual
V = msg.V,
Service = service
});
}
if (msg.CommandType == 0)
{
var client = Clients.FirstOrDefault(n => n.Equals(remoteIpEndPoint));
client.LastActiveTime = DateTime.Now;
//client.ShowVirtual = msg.ShowVirtual;
}
else if (msg.CommandType == 1)
{
receiveMes.Add(msg);
}
});
}
private void Timer_Elapsed(object sender, System.Timers.ElapsedEventArgs e)
{
NotifyClient();
}
private void NotifyClient()
{
try
{
lock (locker)
{
var list = CloneJson(receiveMes).ToList();
receiveMes.Clear();
//加入虚拟人物消息
var virtualData = mapRecordRankingHander.GetVirtualUserData();
WriteLine(DateTime.Now.ToString("yyyy-MM-dd HH:mm:ss") + "-当前在线人数:" + Clients.Count + "-当前虚拟人数:" + virtualData.Count);
#if DEBUG
WriteLine($"在线人:{Newtonsoft.Json.JsonConvert.SerializeObject(list)}");
//\r\n虚拟人{Newtonsoft.Json.JsonConvert.SerializeObject(virtualData)}
#endif
list.AddRange(virtualData);
SendMessage(Clients, list);
dispatcher.Invoke(() =>
{
Customers.Clear();
foreach (var item in list)
{
if (Customers.Any(c => c.MemberId == item.MemberId))
{
continue;
}
Customers.Add(item);
}
//移除下线的客户端
for (int i = 0; i < list.Count; i++)
{
if (list[i].exit && list[i].MemberId >0)//客户端退出,并且不是虚拟的人物
{
//这个地方有严重的逻辑错误(虚拟的人物不能和真实的人用同一个名字)
var info = Clients.FirstOrDefault(n => n.MemberId == list[i].MemberId);
if (info != null)
{
Clients.Remove(info);
}
}
}
//删除已经发送的数据
//receiveMes.Clear();
//移除5钟内连接不上的客户端
Clients.ToList().ForEach(item =>
{
if (item.Expire)
{
Clients.Remove(item);
}
});
});
}
//更新虚拟人物信息
mapRecordRankingHander.RemoveEndAndAddNewVirtualUser(Customers.Count);
}
catch (Exception e)
{
Log.Error($"NotifyClient:{ e.Message }\r\n{ e.StackTrace }");
}
}
private void SendMessage(Collection<HostModel> clients, List<MsgModel> msgModels)
{
var clients1 = clients.ToList();
var list = CloneJson<List<MsgModel>>(msgModels);
foreach (var item in list)
{
item.PreDistance = Math.Round(item.PreDistance, 5);
item.EndDistance = Math.Round(item.EndDistance, 5);
item.WeightKg = Math.Round(item.WeightKg, 2);
}
string jsonString = Newtonsoft.Json.JsonConvert.SerializeObject(list.Select(m=> new {
m.RouteId,
m.MemberId,
m.Point,
m.IsCompleted,
m.exit,
m.Speed,
m.PreDistance,
m.EndDistance,
//m.IsVirtual,//后面要把这个字段过滤掉
m.WeightKg,
m.Competitionid,
m.Saved,
}));
var data = Encoding.ASCII.GetBytes(jsonString);
SendDataSize = (data.Length/1000D).ToString() +"KB";
var strV1 = string.Join("|", list.Select(m => m.ToString(1)));
WriteLine(strV1);
WriteLine(strV1.Length.ToString());
var dataV1 = Encoding.ASCII.GetBytes(strV1);
SendDataSize += $"\tV1{ (strV1.Length/1000D) }KB";
foreach (var item in clients1)
{
try
{
if(item == null)
{
continue;
}
if (item.V == 1)
{
item.Service.Send(dataV1, dataV1.Length, item.IPEndPoint);
}
else
{
item.Service.Send(data, data.Length, item.IPEndPoint);
}
}
catch (Exception e)
{
Debug.WriteLine(e.Message);
Log.Error($"{ item.IPEndPoint.ToString() }:{ e.Message }\r\n{ e.StackTrace }");
}
}
}
void WriteLine(string str)
{
//Debug.WriteLine(str);
}
T CloneJson<T>(T source)
{
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
// initialize inner objects individually
// for example in default constructor some list property initialized with some values,
// but in 'source' these items are cleaned -
// without ObjectCreationHandling.Replace default constructor values will be added to result
var deserializeSettings = new JsonSerializerSettings { ObjectCreationHandling = ObjectCreationHandling.Replace };
return JsonConvert.DeserializeObject<T>(JsonConvert.SerializeObject(source), deserializeSettings);
}
}
}