2025-07-28 19:59:35 +09:00
#nullable enable
2025-07-22 19:58:14 +09:00
using Best.HTTP ;
using Cysharp.Threading.Tasks ;
using System ;
using System.Collections.Generic ;
using System.IO ;
2025-07-28 19:59:35 +09:00
using System.Threading.Tasks ;
2025-07-22 19:58:14 +09:00
using UnityEngine ;
using UVC.Data.Core ;
using UVC.Data.Http ;
2025-07-28 19:59:35 +09:00
using UVC.Factory.Playback.UI ;
2025-07-22 19:58:14 +09:00
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
2025-07-28 19:59:35 +09:00
public static readonly string PlaybackFolderPath = Path . Combine ( Application . persistentDataPath , "playback" ) ; //streamingAssetsPath, "playback"); appData 폴더로 변경
2025-07-22 19:58:14 +09:00
private readonly PlaybackRepository repository ;
private string date ;
private string time ;
private string fileName ;
2025-07-28 19:59:35 +09:00
public Action OnExitPlayback ;
2025-07-22 19:58:14 +09:00
2025-07-28 19:59:35 +09:00
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 < float > OnChangeTimeScale ;
2025-07-22 19:58:14 +09:00
public PlaybackService ( PlaybackRepository repository )
{
this . repository = repository ;
}
public async UniTask < Dictionary < string , Dictionary < string , string > > ? > RequestDataAsync ( )
{
Dictionary < string , Dictionary < string , string > > ? data = await repository . RequestPlaybackDateList ( ) ;
return data ;
}
public async UniTask DispatchBaseInfoData ( string date , string time , string fileName , string minute = "00" , string second = "00" )
{
2025-07-28 19:59:35 +09:00
await UniTask . RunOnThreadPool ( async ( ) = >
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
//헝가리 시간임
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 < PlaybackSQLiteDataEntity > list = await repository . SelectBySecondBaseInfo ( date , fileName , formatTime ) ;
if ( list . Count > 0 )
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
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 ) ;
}
2025-07-22 19:58:14 +09:00
}
2025-07-28 19:59:35 +09:00
} ) ;
2025-07-22 19:58:14 +09:00
}
/// <summary>
///
/// </summary>
/// <param name="second">0 ~ 3600</param>
public async UniTask DispatchRealTimeData ( int second , int speed )
{
2025-07-28 19:59:35 +09:00
await UniTask . RunOnThreadPool ( async ( ) = >
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
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 < PlaybackSQLiteDataEntity > list = await repository . SelectBySecondAsync ( date , fileName , formatTime , 1 ) ;
//Debug.Log($"DispatchRealTimeData {date} {time} {formatTime} {newSecond} {list.Count}");
if ( list . Count > 0 )
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
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 ) ;
}
2025-07-22 19:58:14 +09:00
}
2025-07-28 19:59:35 +09:00
} ) ;
2025-07-22 19:58:14 +09:00
}
2025-07-28 19:59:35 +09:00
public async Task StartAsync ( UIPlaybackListItemData data )
{
timeScale = 1.0f ; //기본 시간 스케일 설정
UIPlayback . Instance . Show ( ) ;
await UIPlayback . Instance . SetData ( data . date , data . time , data . sqlFileName ) ;
}
2025-07-22 19:58:14 +09:00
2025-07-28 19:59:35 +09:00
public void Exit ( )
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
OnExitPlayback ? . Invoke ( ) ;
2025-07-22 19:58:14 +09:00
}
2025-07-28 19:59:35 +09:00
2025-07-22 19:58:14 +09:00
public HTTPRequest ? ReadyData ( string date , string time , string fileName , Action < long , long , float > OnProgress , Action < string > OnComplete )
{
//date : "2024-12-05"
//fileName : "2024-12-05_0.sqlite.7z"
2025-07-28 19:59:35 +09:00
string playbackPath = PlaybackService . PlaybackFolderPath ;
2025-07-22 19:58:14 +09:00
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" ) ;
2025-07-28 19:59:35 +09:00
DateTime utcDateTime = DateTimeUtil . Parse ( fileNameArr [ 0 ] , "yyyy-MM-dd_H" ) ; //.Add(-DateTimeUtil.UtcKoreaGap);
2025-07-22 19:58:14 +09:00
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 ) ;
2025-07-28 19:59:35 +09:00
//압축해제 후
2025-07-22 19:58:14 +09:00
var zipper = new Zipper ( ) ;
string errorMessage = await zipper . Decompress ( utcZipFilePath , tempPath , ( long read , long total , float percent ) = >
{
if ( OnProgress ! = null )
{
2025-07-28 19:59:35 +09:00
bool isComplte = false ;
float percentRate = 0.5f + percent / 2 ;
if ( percentRate > 0.99 )
{
percentRate = 0.99f ;
isComplte = true ;
}
2025-07-22 19:58:14 +09:00
OnProgress . Invoke ( downloadTotal + read , downloadTotal + total , 0.5f + percent / 2 ) ;
2025-07-28 19:59:35 +09:00
if ( isComplte )
2025-07-22 19:58:14 +09:00
{
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}");
//}
2025-07-28 19:59:35 +09:00
await UniTask . RunOnThreadPool ( ( ) = >
2025-07-22 19:58:14 +09:00
{
2025-07-28 19:59:35 +09:00
//압축해제 한 파일 이동
if ( File . Exists ( utcSqlFilePath ) )
{
//동일한 파일명이 있을경우 제거후 다시
File . Copy ( utcSqlFilePath , sqlFilePath ) ;
File . Delete ( utcSqlFilePath ) ;
}
//zip 파일 삭제
File . Delete ( utcZipFilePath ) ;
} ) ;
2025-07-22 19:58:14 +09:00
if ( OnComplete ! = null ) OnComplete . Invoke ( errorMessage ) ;
}
} ,
( string? error ) = >
{
Debug . Log ( $"DownloadPlaybackData OnError:{error}" ) ;
if ( OnComplete ! = null ) OnComplete . Invoke ( error ) ;
} ) ;
}
}
}
}