#nullable enable using Best.HTTP; using Cysharp.Threading.Tasks; using System; using System.Collections.Generic; using System.IO; using System.Threading.Tasks; using UnityEngine; using UVC.Data.Core; using UVC.Data.Http; using UVC.Factory.Playback.UI; using UVC.Util; namespace UVC.Factory.Playback { public class PlaybackService { #region Singleton private static readonly PlaybackService instance = new PlaybackService(new PlaybackRepository()); public static PlaybackService Instance => instance; static PlaybackService() { } #endregion public static readonly string PlaybackFolderPath = Path.Combine(Application.persistentDataPath, "playback");//streamingAssetsPath, "playback"); appData 폴더로 변경 private readonly PlaybackRepository repository; private string date; private string time; private string fileName; public Action OnExitPlayback; private float timeScale = 1.0f; public float TimeScale { get => timeScale; internal set { if (value < 1f) value = 1f; if (timeScale != value) { timeScale = value; //Time.timeScale = timeScale; OnChangeTimeScale?.Invoke(timeScale); } } } public Action OnChangeTimeScale; public PlaybackService(PlaybackRepository repository) { this.repository = repository; } public async UniTask>?> RequestDataAsync() { Dictionary>? data = await repository.RequestPlaybackDateList(); return data; } public async UniTask DispatchBaseInfoData(string date, string time, string fileName, string minute = "00", string second = "00") { await UniTask.RunOnThreadPool(async () => { //헝가리 시간임 this.date = date; this.time = time; this.fileName = fileName; DateTime dateTime = DateTimeUtil.UtcParse($"{date}T{int.Parse(time).ToString("00")}:{minute}:{second}.000Z"); string formatTime = DateTimeUtil.FormatTime(dateTime); //baseInfo 가져오기 List list = await repository.SelectBySecondBaseInfo(date, fileName, formatTime); if (list.Count > 0) { HttpRequestConfig httpRequestConfig = new HttpRequestConfig(""); httpRequestConfig.SetUpdatedDataOnly(true); httpRequestConfig.SetSplitResponseByKey(true); httpRequestConfig.AddSplitConfig("AGV", DataMapperValidator.Get("AGV")); httpRequestConfig.AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM")); foreach (var item in list) { HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data); } } }); } /// /// /// /// 0 ~ 3600 public async UniTask DispatchRealTimeData(int second, int speed) { await UniTask.RunOnThreadPool(async () => { int newSecond = second; if (newSecond > 36000) newSecond = 36000; //utc 시간으로 변환 DateTime dateTime = DateTimeUtil.UtcParse($"{date}T{int.Parse(time).ToString("00")}:00:00.000Z").AddSeconds(newSecond);//.Add(-DateTimeUtil.UtcKoreaGap); string formatTime = DateTimeUtil.FormatTime(dateTime); List list = await repository.SelectBySecondAsync(date, fileName, formatTime, 1); //Debug.Log($"DispatchRealTimeData {date} {time} {formatTime} {newSecond} {list.Count}"); if (list.Count > 0) { HttpRequestConfig httpRequestConfig = new HttpRequestConfig(""); httpRequestConfig.SetUpdatedDataOnly(true); httpRequestConfig.SetSplitResponseByKey(true); httpRequestConfig.AddSplitConfig("AGV", DataMapperValidator.Get("AGV")); httpRequestConfig.AddSplitConfig("ALARM", DataMapperValidator.Get("ALARM")); foreach (var item in list) { HttpDataProcessor.ProcessSplitResponse(httpRequestConfig, item.data); } } }); } public async Task StartAsync(UIPlaybackListItemData data) { timeScale = 1.0f; //기본 시간 스케일 설정 UIPlayback.Instance.Show(); await UIPlayback.Instance.SetData(data.date, data.time, data.sqlFileName); } public void Exit() { OnExitPlayback?.Invoke(); } public HTTPRequest? ReadyData(string date, string time, string fileName, Action OnProgress, Action OnComplete) { //date : "2024-12-05" //fileName : "2024-12-05_0.sqlite.7z" string playbackPath = PlaybackService.PlaybackFolderPath; string tempPath = Path.Combine(playbackPath, "temp");//한국 시간으로 변경하기 때문에 임시 폴더 만들어서 압축 해제 후 이동 string datePath = Path.Combine(playbackPath, date); var fileNameArr = fileName.Split("."); string zipFilePath = Path.Combine(datePath, fileName); string sqlFilePath = Path.Combine(datePath, fileNameArr[0] + ".sqlite"); DateTime utcDateTime = DateTimeUtil.Parse(fileNameArr[0], "yyyy-MM-dd_H");//.Add(-DateTimeUtil.UtcKoreaGap); string utcDatePath = Path.Combine(playbackPath, utcDateTime.ToString("yyyy-MM-dd")); string utcFileName = utcDateTime.ToString("yyyy-MM-dd_H") + "." + fileNameArr[1] + "." + fileNameArr[2]; var utcFileNameArr = utcFileName.Split("."); string utcZipFilePath = Path.Combine(tempPath, utcFileName); string utcSqlFilePath = Path.Combine(tempPath, utcFileNameArr[0] + ".sqlite"); if (!Directory.Exists(playbackPath)) Directory.CreateDirectory(playbackPath); if (!Directory.Exists(datePath)) Directory.CreateDirectory(datePath); if (!Directory.Exists(utcDatePath)) Directory.CreateDirectory(utcDatePath); if (!Directory.Exists(tempPath)) Directory.CreateDirectory(tempPath); if (File.Exists(sqlFilePath)) { Debug.Log($"ONREADY SQP FILE"); if (OnProgress != null) OnProgress.Invoke(100, 100, 1.0f); if (OnComplete != null) OnComplete.Invoke(null); return null; } else { long downloadTotal = 0; return repository.DownloadPlaybackData(utcFileName, utcZipFilePath, (long progress, long length) => { float percent = (float)progress / (float)length; Debug.Log($"DownloadPlaybackData OnProgress:{percent}"); if (OnProgress != null) OnProgress.Invoke(progress, length, percent / 2); downloadTotal = length; }, async () => { await UniTask.Delay(500); Debug.Log($"DownloadPlaybackData OnComplete"); if (File.Exists(utcZipFilePath)) { if (OnProgress != null) OnProgress.Invoke(50, 100, 0.5f); //압축해제 후 var zipper = new Zipper(); string errorMessage = await zipper.Decompress(utcZipFilePath, tempPath, (long read, long total, float percent) => { if (OnProgress != null) { bool isComplte = false; float percentRate = 0.5f + percent / 2; if (percentRate > 0.99) { percentRate = 0.99f; isComplte = true; } OnProgress.Invoke(downloadTotal + read, downloadTotal + total, 0.5f + percent / 2); if (isComplte) { Debug.Log($" DownloadReadData :{downloadTotal + read} , DownloadTotalData :{downloadTotal + total} ,DownloadPlaybackData OnProgress:{percent}"); } } }); Debug.Log($"zipper1 errorMessage:{errorMessage} utcSqlFilePath:{utcSqlFilePath} sqlFilePath:{sqlFilePath} utcZipFilePath:{utcZipFilePath}"); ////파일 접근 문제면 2회 0.5초 후에 다시 실행. //if (errorMessage == "Could not open input(7z) file") //{ // await UniTask.Delay(500); // errorMessage = await zipper.Decompress(utcZipFilePath, tempPath, (long read, long total, float percent) => // { // if (OnProgress != null) OnProgress.Invoke(downloadTotal + read, downloadTotal + total, 0.5f + percent / 2); // }); // Debug.Log($"zipper2 errorMessage:{errorMessage} utcSqlFilePath:{utcSqlFilePath} sqlFilePath:{sqlFilePath} utcZipFilePath:{utcZipFilePath}"); //} //if (errorMessage == "Could not open input(7z) file") //{ // await UniTask.Delay(500); // errorMessage = await zipper.Decompress(utcZipFilePath, tempPath, (long read, long total, float percent) => // { // if (OnProgress != null) OnProgress.Invoke(downloadTotal + read, downloadTotal + total, 0.5f + percent / 2); // }); // Debug.Log($"zipper3 errorMessage:{errorMessage} utcSqlFilePath:{utcSqlFilePath} sqlFilePath:{sqlFilePath} utcZipFilePath:{utcZipFilePath}"); //} await UniTask.RunOnThreadPool(() => { //압축해제 한 파일 이동 if (File.Exists(utcSqlFilePath)) { //동일한 파일명이 있을경우 제거후 다시 File.Copy(utcSqlFilePath, sqlFilePath); File.Delete(utcSqlFilePath); } //zip 파일 삭제 File.Delete(utcZipFilePath); }); if (OnComplete != null) OnComplete.Invoke(errorMessage); } }, (string? error) => { Debug.Log($"DownloadPlaybackData OnError:{error}"); if (OnComplete != null) OnComplete.Invoke(error); }); } } } }