167 lines
6.3 KiB
C#
167 lines
6.3 KiB
C#
using Cysharp.Threading.Tasks;
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using System.Threading;
|
|
using UVC.Network;
|
|
|
|
namespace AssetsUVC.Network
|
|
{
|
|
/// <summary>
|
|
/// HTTP 요청을 디바운스(debounce) 처리하기 위한 유틸리티 클래스
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 이 클래스는 짧은 시간 내에 반복적으로 발생하는 HTTP 요청을 제어하여
|
|
/// 마지막 요청만 실행되도록 합니다. 사용자 입력에 따른 API 호출이나
|
|
/// 실시간 검색과 같이 연속된 요청을 최적화할 때 유용합니다.
|
|
///
|
|
/// 기본 사용법:
|
|
/// <code>
|
|
/// // DebounceRequester 인스턴스 생성
|
|
/// var requester = new DebounceRequester();
|
|
///
|
|
/// // 연속된 검색 요청 예제
|
|
/// void OnSearchTextChanged(string searchText)
|
|
/// {
|
|
/// requester.Request<SearchResult>(
|
|
/// 300, // 300ms 디바운스
|
|
/// "/api/search",
|
|
/// "get",
|
|
/// $"{{\"query\": \"{searchText}\"}}",
|
|
/// null,
|
|
/// false,
|
|
/// result => {
|
|
/// // 검색 결과 처리
|
|
/// DisplaySearchResults(result);
|
|
/// }
|
|
/// );
|
|
/// }
|
|
/// </code>
|
|
/// </remarks>
|
|
public class DebounceRequester
|
|
{
|
|
/// <summary>
|
|
/// 취소 토큰 소스. 이전 요청을 취소하는 데 사용됩니다.
|
|
/// </summary>
|
|
private CancellationTokenSource cts = new CancellationTokenSource();
|
|
|
|
/// <summary>
|
|
/// 취소 토큰을 재설정하여 이전 요청을 취소합니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 이 메소드는 새로운 요청이 시작될 때마다 호출되어 이전에 예약된 요청을 취소합니다.
|
|
/// </remarks>
|
|
private void resetCancellationToken()
|
|
{
|
|
cts.Cancel();
|
|
cts = new CancellationTokenSource();
|
|
}
|
|
|
|
/// <summary>
|
|
/// DebounceRequester가 사용한 리소스를 해제합니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 이 클래스의 사용이 끝나면 항상 Dispose를 호출하여 리소스 누수를 방지해야 합니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 리소스 해제 예제
|
|
/// public class SearchManager : IDisposable
|
|
/// {
|
|
/// private DebounceRequester requester = new DebounceRequester();
|
|
///
|
|
/// public void Dispose()
|
|
/// {
|
|
/// requester.Dispose();
|
|
/// }
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
public void Dispose()
|
|
{
|
|
cts.Cancel();
|
|
cts.Dispose();
|
|
}
|
|
|
|
|
|
/// <summary>
|
|
/// 지정된 시간(밀리초) 동안 디바운스된 HTTP 요청을 수행합니다.
|
|
/// </summary>
|
|
/// <typeparam name="T">응답 데이터를 변환할 타입</typeparam>
|
|
/// <param name="milliseconds">디바운스 시간(밀리초)</param>
|
|
/// <param name="url">요청할 URL (http가 포함되지 않은 경우 Domain과 결합)</param>
|
|
/// <param name="method">HTTP 메소드 (get, post 등)</param>
|
|
/// <param name="body">요청 본문으로 전송할 JSON 문자열 (null 가능)</param>
|
|
/// <param name="header">추가할 헤더 정보 (null 가능)</param>
|
|
/// <param name="useAuth">인증 토큰 사용 여부</param>
|
|
/// <param name="action">요청 완료 후 실행할 콜백 함수 (null 가능)</param>
|
|
/// <remarks>
|
|
/// 이 메소드는 호출된 후 지정된 밀리초 동안 대기하고, 그 시간 내에 다시 호출되면
|
|
/// 이전 요청을 취소하고 새로운 타이머를 시작합니다. 디바운스 시간이 경과한 후에만
|
|
/// 실제 HTTP 요청이 수행됩니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 실시간 타이핑 검색 예제
|
|
/// private DebounceRequester searchRequester = new DebounceRequester();
|
|
///
|
|
/// public void OnSearchInputChanged(string searchText)
|
|
/// {
|
|
/// // 사용자가 타이핑을 멈춘 후 500ms 후에 검색 요청
|
|
/// searchRequester.Request<List<ProductData>>(
|
|
/// 500,
|
|
/// "/api/products/search",
|
|
/// "get",
|
|
/// $"{{\"query\": \"{searchText}\"}}",
|
|
/// null,
|
|
/// true,
|
|
/// results => {
|
|
/// // 검색 결과 UI 업데이트
|
|
/// UpdateSearchResultsUI(results);
|
|
/// }
|
|
/// );
|
|
/// }
|
|
///
|
|
/// // 자동 저장 기능 예제
|
|
/// private DebounceRequester autoSaveRequester = new DebounceRequester();
|
|
///
|
|
/// public void OnDocumentChanged(string documentId, string content)
|
|
/// {
|
|
/// // 문서 변경 후 2초 동안 추가 변경이 없으면 저장
|
|
/// var body = $"{{\"Id\": \"{documentId}\", \"content\": \"{content}\"}}";
|
|
///
|
|
/// autoSaveRequester.Request<SaveResult>(
|
|
/// 2000,
|
|
/// "/api/documents/save",
|
|
/// "post",
|
|
/// body,
|
|
/// null,
|
|
/// true,
|
|
/// result => {
|
|
/// if (result.success) {
|
|
/// ShowSavedNotification();
|
|
/// }
|
|
/// }
|
|
/// );
|
|
/// }
|
|
/// </code>
|
|
/// </example>
|
|
public void Request<T>(int milliseconds, string url, string method, string body = null, Dictionary<string, string> header = null, bool useAuth = false, Action<T> action = null)
|
|
{
|
|
resetCancellationToken();
|
|
UniTask.Delay(TimeSpan.FromMilliseconds(milliseconds), cancellationToken: cts.Token, ignoreTimeScale: false).ContinueWith(async () =>
|
|
{
|
|
if (action != null)
|
|
{
|
|
T result = await HttpRequester.Request<T>(url, method, body, header, useAuth);
|
|
action.Invoke(result);
|
|
}
|
|
else
|
|
{
|
|
HttpRequester.Request<T>(url, method, body, header, useAuth).Forget();
|
|
}
|
|
});
|
|
}
|
|
|
|
}
|
|
}
|