331 lines
11 KiB
C#
331 lines
11 KiB
C#
using Newtonsoft.Json.Linq;
|
|
using Studio.Core;
|
|
using Studio.Setting.Connect;
|
|
using Studio.Util;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using System.Threading.Tasks;
|
|
using UnityEngine;
|
|
|
|
namespace Studio
|
|
{
|
|
public class StudioServiceIdEventArgs : EventArgs
|
|
{
|
|
public readonly string Type;
|
|
public Dictionary<string, string> Entity;
|
|
|
|
public StudioServiceIdEventArgs(string type, Dictionary<string, string> entity)
|
|
{
|
|
Type = type;
|
|
Entity = entity;
|
|
}
|
|
}
|
|
|
|
public class StudioServiceTypeEventArgs : EventArgs
|
|
{
|
|
public readonly string Type;
|
|
public Dictionary<string, Dictionary<string, string>> Entitis;
|
|
|
|
public StudioServiceTypeEventArgs(string type, Dictionary<string, Dictionary<string, string>> entitis)
|
|
{
|
|
Type = type;
|
|
Entitis = entitis;
|
|
}
|
|
}
|
|
|
|
public class StudioService : UnitySingleton<StudioService>
|
|
{
|
|
private Dictionary<string, Dictionary<string, EventHandler<StudioServiceIdEventArgs>>> listenerIdMap = new();
|
|
private Dictionary<string, EventHandler<StudioServiceTypeEventArgs>> listenerTypeMap = new();
|
|
|
|
private StudioRepoistory repository;
|
|
private Dictionary<string, float> updateTime = new();
|
|
public bool isConnected
|
|
{
|
|
get
|
|
{
|
|
return repository.isConnected;
|
|
}
|
|
}
|
|
|
|
#region 패킷계산
|
|
private int totalRequestPacket;
|
|
private int totalResponsePacket;
|
|
private long maxElapsedTime;
|
|
private long totalElapsedTime;
|
|
private int maxReponesSize;
|
|
private int maxReuqestSize;
|
|
private string maxReuqestApi;
|
|
private string maxResponseApi;
|
|
private string maxResponseTimeApi;
|
|
#endregion
|
|
|
|
public Dictionary<string, StudioEntityWithState<List<Dictionary<string, string>>>> apiData = new();
|
|
public Dictionary<string, (Dictionary<string, Dictionary<string, string>>, TimeSpan)> mqttData = new();
|
|
|
|
private Dictionary<string, DateTime> lastUpdateTime = new();
|
|
|
|
public event Action<string, StudioEntityWithState<object>> onAPIDataLoaded;
|
|
public event Action<string, Dictionary<string, Dictionary<string, string>>, TimeSpan> onMQTTDataLoaded;
|
|
|
|
private Dictionary<string, List<Topic>> topicTable = new();
|
|
public Dictionary<string, List<Topic>> TopciTable { get { return topicTable; } }
|
|
|
|
public void ConnectMQTT(string domain, string port, List<Util.Topic> topics)
|
|
{
|
|
this.repository = new StudioRepoistory();
|
|
repository.OnTopicList += OnTopicList;
|
|
|
|
var conntedInfo = $"MQTT Domain : {domain} , MQTTPORT :{port}";
|
|
if (!topicTable.ContainsKey(conntedInfo))
|
|
topicTable.Add(conntedInfo, new());
|
|
topicTable[conntedInfo] = topics;
|
|
|
|
repository.MQTTCreateConnect(domain, port);
|
|
|
|
repository.MQTTConnect(conntedInfo);
|
|
}
|
|
|
|
private void OnTopicList(string type, Dictionary<string, Dictionary<string, string>> entities)
|
|
{
|
|
DateTime now = DateTime.Now;
|
|
TimeSpan elapsedTime;
|
|
|
|
// elapsed 계산
|
|
if (lastUpdateTime.ContainsKey(type))
|
|
{
|
|
DateTime last = lastUpdateTime[type];
|
|
elapsedTime = now - last;
|
|
}
|
|
else
|
|
{
|
|
elapsedTime = TimeSpan.Zero;
|
|
}
|
|
|
|
lastUpdateTime[type] = now;
|
|
|
|
foreach (var idKey in entities)
|
|
{
|
|
UpdateTopicData(type, idKey.Key, idKey.Value);
|
|
}
|
|
|
|
if (!mqttData.ContainsKey(type))
|
|
{
|
|
mqttData.Add(type, (entities, elapsedTime));
|
|
}
|
|
else
|
|
{
|
|
mqttData[type] = (entities, elapsedTime);
|
|
}
|
|
}
|
|
|
|
private void UpdateTopicData(string type, string id, Dictionary<string, string> entity)
|
|
{
|
|
if (!updateTime.ContainsKey(type))
|
|
updateTime.Add(type, 0.5f);
|
|
var time = updateTime[type];
|
|
var task = Task.Factory.StartNew(async () =>
|
|
{
|
|
int delayTime = (int)(time * 1000);
|
|
await Task.Delay(delayTime);
|
|
|
|
DispatchMachineEvent(type, id, entity);
|
|
}, CancellationToken.None, TaskCreationOptions.None, TaskScheduler.FromCurrentSynchronizationContext());
|
|
|
|
}
|
|
|
|
private Dictionary<string, Dictionary<string, Dictionary<string, string>>> timelineEntity = new();
|
|
public bool TryGetRecentTimelineEntity(string type, string id, out Dictionary<string, string> result)
|
|
{
|
|
result = null;
|
|
if (!timelineEntity.ContainsKey(type))
|
|
{
|
|
timelineEntity[type] = new Dictionary<string, Dictionary<string, string>>();
|
|
return false;
|
|
}
|
|
if (!timelineEntity[type].ContainsKey(id))
|
|
{
|
|
timelineEntity[type][id] = new();
|
|
return false;
|
|
}
|
|
result = timelineEntity[type][id];
|
|
return result != null;
|
|
}
|
|
|
|
public void AddTypeIdListener(string type, string id = null, EventHandler<StudioServiceIdEventArgs> listener = null)
|
|
{
|
|
if (!listenerIdMap.ContainsKey(type))
|
|
{
|
|
listenerIdMap.Add(type, new());
|
|
}
|
|
|
|
if (id == null)
|
|
return;
|
|
|
|
if (!listenerIdMap[type].ContainsKey(id))
|
|
{
|
|
listenerIdMap[type][id] = listener;
|
|
}
|
|
else
|
|
{
|
|
listenerIdMap[type][id] += listener;
|
|
}
|
|
}
|
|
public void AddTypeListener(string type, EventHandler<StudioServiceTypeEventArgs> listener = null)
|
|
{
|
|
listenerTypeMap[type] = listener;
|
|
}
|
|
public void RemoveTypeListener(string type)
|
|
{
|
|
if (!listenerTypeMap.ContainsKey(type))
|
|
return;
|
|
listenerTypeMap.Remove(type);
|
|
}
|
|
public void RemoveTypeIdListener(string type, string id)
|
|
{
|
|
if (!listenerIdMap.ContainsKey(type))
|
|
return;
|
|
if (!listenerIdMap[type].ContainsKey(id))
|
|
return;
|
|
|
|
listenerIdMap[type].Remove(id);
|
|
}
|
|
|
|
public async Task LoadBaseData(string url)
|
|
{
|
|
DateTime startTime = DateTime.Now;
|
|
System.Diagnostics.Stopwatch sw = new System.Diagnostics.Stopwatch();
|
|
sw.Start();
|
|
StudioEntityWithState<object> data = await repository.BaseInfo(url);
|
|
sw.Stop();
|
|
DateTime endTime = DateTime.Now;
|
|
|
|
var t = sw.ElapsedMilliseconds;
|
|
|
|
if (data.State.Equals(APIState.Loaded))
|
|
{
|
|
if (!apiData.ContainsKey(url))
|
|
apiData.Add(url, new());
|
|
|
|
data.lastRequestTime = startTime;
|
|
data.lastResponseTime = endTime;
|
|
data.elapsedTime = sw.Elapsed;
|
|
CheckAPIBoarder(data.Entity.ToString(), data.ReqSize, url, t);
|
|
var entity = UpdateEntity(url, data.Entity.ToString());
|
|
StudioEntityWithState<List<Dictionary<string, string>>> convertData = new(data.State, entity, data.ReqSize, data.Message);
|
|
apiData[url] = convertData;
|
|
}
|
|
else if (data.State == APIState.Error)
|
|
{
|
|
//TODO 에러메세지
|
|
Debug.Log($"APIState : Error , Message :{data.Message}");
|
|
}
|
|
|
|
onAPIDataLoaded?.Invoke(url, data); // 나중에 클래스 밖으로 이동 필요
|
|
}
|
|
|
|
private void CheckAPIBoarder(string data, int reqSize, string url, long time)
|
|
{
|
|
var byteSize = System.Text.Encoding.Default.GetBytes(data).Length;
|
|
if (maxElapsedTime < time)
|
|
{
|
|
maxElapsedTime = time;
|
|
maxResponseTimeApi = url;
|
|
}
|
|
|
|
if (maxReponesSize < byteSize)
|
|
{
|
|
maxReponesSize = byteSize;
|
|
maxResponseApi = url;
|
|
}
|
|
if (maxReuqestSize < reqSize)
|
|
{
|
|
maxReuqestSize = reqSize;
|
|
maxReuqestApi = url;
|
|
}
|
|
totalRequestPacket += reqSize;
|
|
totalResponsePacket += byteSize;
|
|
totalElapsedTime += time;
|
|
}
|
|
|
|
public APITotalBoardEntity GetAPIStatusBoarder()
|
|
{
|
|
var boardEntity = new APITotalBoardEntity();
|
|
boardEntity.TotalRequestPacketSize = totalRequestPacket;
|
|
boardEntity.AverageRequestPacketSize = totalRequestPacket / apiData.Count;
|
|
boardEntity.TotalResponsePacketSize = totalResponsePacket;
|
|
boardEntity.AverageResponsePacketSize = totalResponsePacket / apiData.Count;
|
|
boardEntity.MaximumResponseTime = maxElapsedTime;
|
|
boardEntity.AverageResponseTime = totalElapsedTime / apiData.Count;
|
|
boardEntity.MaximumRequestPacketAPI = maxReuqestApi;
|
|
boardEntity.MaximumResponsePacketAPI = maxResponseApi;
|
|
boardEntity.MaximumResponseTimeAPI = maxResponseTimeApi;
|
|
return boardEntity;
|
|
}
|
|
|
|
public List<Dictionary<string, string>> UpdateEntity(string type, string data)
|
|
{
|
|
//Dcitionary 형으로 바꿈
|
|
JObject json = JObject.Parse(data);
|
|
foreach (JProperty prop in json.Children())
|
|
{
|
|
string key = prop.Name.ToString();
|
|
string value = prop.Value.ToString();
|
|
Debug.Log($"kEY : {key}, Value:{value}");
|
|
}
|
|
|
|
var datas = json["rows"].ToString();
|
|
var list = new List<Dictionary<string, string>>();
|
|
JArray jarray = JArray.Parse(datas);
|
|
foreach (JObject obj in jarray.Children())
|
|
{
|
|
Dictionary<string, string> keyvalue = new();
|
|
string id = string.Empty;
|
|
foreach (JProperty prop in obj.Children())
|
|
{
|
|
string key = prop.Name.ToString();
|
|
string value = prop.Value.ToString();
|
|
keyvalue.Add(key, value);
|
|
}
|
|
list.Add(keyvalue);
|
|
}
|
|
|
|
return list;
|
|
}
|
|
|
|
private void DispatchMachineEvent(string type, string id, Dictionary<string, string> entity)
|
|
{
|
|
if (!listenerIdMap.ContainsKey(type))
|
|
{
|
|
Debug.Log($"Key Value is missing!!!! -Key:{type}-");
|
|
}
|
|
if (listenerIdMap[type].ContainsKey(id))
|
|
{
|
|
listenerIdMap[type][id].Invoke(this, new StudioServiceIdEventArgs(type, entity));
|
|
}
|
|
else
|
|
{
|
|
if (!listenerTypeMap.ContainsKey(type))
|
|
return;
|
|
var data = new Dictionary<string, Dictionary<string, string>>();
|
|
data.Add(id, entity);
|
|
|
|
if (entity == null)
|
|
return;
|
|
DispatchTypeMachineEvent(type, data);
|
|
}
|
|
}
|
|
|
|
private void DispatchTypeMachineEvent(string type, Dictionary<string, Dictionary<string, string>> entities)
|
|
{
|
|
|
|
|
|
if (listenerTypeMap.ContainsKey(type))
|
|
{
|
|
listenerTypeMap[type].Invoke(this, new(type, entities));
|
|
}
|
|
}
|
|
|
|
}
|
|
} |