386 lines
18 KiB
C#
386 lines
18 KiB
C#
#nullable enable
|
|
|
|
using System;
|
|
using System.Collections.Generic;
|
|
using UVC.Data.Core;
|
|
|
|
namespace UVC.Data.Http
|
|
{
|
|
/// <summary>
|
|
/// HTTP 요청 파이프라인 정보를 관리하는 클래스입니다.
|
|
/// 요청 URL, 메서드, 헤더, 본문과 같은 HTTP 요청 정보 및
|
|
/// 반복 실행, 재시도, 데이터 매핑 등 파이프라인 동작을 구성합니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 이 클래스는 파이프라인 빌더 패턴을 사용하여 HTTP 요청 설정을 구성할 수 있도록 합니다.
|
|
/// 각 설정 메서드는 체이닝을 통해 유연하게 요청을 정의할 수 있습니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// var config = new HttpRequestConfig("https://api.example.com/data", "GET")
|
|
/// .SetDataMapper(new DataMapper(dataMask))
|
|
/// .SetSuccessHandler(data => Console.WriteLine(data)) // 성공 핸들러 예시
|
|
/// .SetFailHandler(errorData => Console.Error.WriteLine(errorData)) // 실패 핸들러 예시
|
|
/// .SetRetry(5, 2000)
|
|
/// .SetRepeat(true, 10, 5000);
|
|
///
|
|
/// // 응답을 키별로 분할하는 설정
|
|
/// // 응답이 {"AGV": [...], "ALARM": [...]} 형태일 때 사용
|
|
/// var splitConfig = new HttpRequestConfig("https://api.example.com/alldata")
|
|
/// .SetSplitResponseByKey(true) // 이 옵션을 활성화
|
|
/// .AddSplitConfig("AGV", new DataMapper(agvMask), agvValidator)
|
|
/// .AddSplitConfig("ALARM", new DataMapper(alarmMask))
|
|
/// .SetSuccessHandler(splitData => {
|
|
/// // HttpDataFetcher 구현에 따라, 분할된 각 데이터가 처리된 후 이 핸들러가 호출될 수 있습니다.
|
|
/// // 이 경우 핸들러의 IDataObject는 null일 수 있습니다.
|
|
/// Console.WriteLine("Split data processing completed.");
|
|
/// });
|
|
/// </code>
|
|
/// </example>
|
|
public class HttpRequestConfig
|
|
{
|
|
private string _url;
|
|
private string _method;
|
|
private Dictionary<string, string>? _headers = null;
|
|
private string? _body = null;
|
|
private Action<IDataObject?>? _successhandler = null; //요청 성공 시 호출될 내부 핸들러입니다.
|
|
private Action<string>? _failhandler = null; //요청 실패 시 호출될 내부 핸들러입니다.
|
|
private bool _repeat = false; // 반복 실행 여부
|
|
private int _repeatCount = 0; // 반복 횟수, 0은 무한 반복
|
|
private int _repeatInterval = 1000; // 반복 간격 (ms)
|
|
private DataMapper? _dataMapper = null; // 데이터 매퍼
|
|
private Dictionary<string, DataMapperValidator>? _splitConfigs = null; // 분할 응답에 대한 구성
|
|
private HttpResponseMask _responseMask = new HttpResponseMask(); // response 데이터 성공 여부와 데이터를 구분하는 마스크
|
|
private int _maxRetryCount = 3;
|
|
private int _retryDelay = 1000; // 밀리초
|
|
private bool _updatedDataOnly = false; // 업데이트된 데이터만 받을 여부
|
|
private bool _splitResponseByKey = false; // 응답을 키별로 분할할지 여부
|
|
|
|
/// <summary>
|
|
/// HTTP 응답 데이터의 유효성을 검사하는 데 사용되는 검사기입니다.
|
|
/// 이 검사기를 통해 특정 조건을 만족하는 데이터만 처리하도록 필터링할 수 있습니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// 데이터 유효성 검사는 HTTP 응답이 성공적으로 수신되고 JSON으로 파싱된 후,
|
|
/// 성공 핸들러에 전달되기 전에 수행됩니다.
|
|
/// 검사기가 null이 아닌 경우에만 유효성 검사가 실행됩니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // DataValidator 생성 및 규칙 추가
|
|
/// var validator = new DataValidator();
|
|
///
|
|
/// // "status" 필드가 "active"인 데이터만 유효하도록 설정
|
|
/// validator.AddValidator("status", value =>
|
|
/// value is string status && status.Equals("active", StringComparison.OrdinalIgnoreCase));
|
|
///
|
|
/// // "temperature" 필드가 유효한 범위 내에 있는지 확인
|
|
/// validator.AddValidator("temperature", value => {
|
|
/// if (value is double temp)
|
|
/// return temp >= -50 && temp <= 100;
|
|
/// return false;
|
|
/// });
|
|
///
|
|
/// // 파이프라인에 validator 설정
|
|
/// var config = new HttpRequestConfig("https://api.weather.com/current")
|
|
/// .setValidator(validator)
|
|
/// .setSuccessHandler(data => {
|
|
/// // 여기에 전달되는 데이터는 이미 유효성 검사를 통과한 데이터만 포함됩니다.
|
|
/// Console.WriteLine($"유효한 온도: {data["temperature"]}°C");
|
|
/// });
|
|
/// </code>
|
|
/// </example>
|
|
private DataValidator? _validator;
|
|
|
|
/// <summary>
|
|
/// 요청을 보낼 URL 주소
|
|
/// </summary>
|
|
public string Url => _url;
|
|
|
|
/// <summary>
|
|
/// HTTP 요청 메서드 (GET, POST 등)
|
|
/// </summary>
|
|
public string Method => _method;
|
|
|
|
/// <summary>
|
|
/// HTTP 요청 헤더
|
|
/// </summary>
|
|
public Dictionary<string, string>? Headers => _headers;
|
|
|
|
/// <summary>
|
|
/// HTTP 요청 본문
|
|
/// </summary>
|
|
public string? Body => _body;
|
|
|
|
/// <summary>
|
|
/// 요청 성공 시 호출될 핸들러
|
|
/// </summary>
|
|
public Action<IDataObject?>? SuccessHandler => _successhandler;
|
|
|
|
/// <summary>
|
|
/// 요청 실패 시 호출될 핸들러
|
|
/// </summary>
|
|
public Action<string>? FailHandler => _failhandler;
|
|
|
|
/// <summary>
|
|
/// 반복 실행 여부
|
|
/// </summary>
|
|
public bool Repeat => _repeat;
|
|
|
|
/// <summary>
|
|
/// 반복 횟수, 0은 무한 반복
|
|
/// </summary>
|
|
public int RepeatCount => _repeatCount;
|
|
|
|
/// <summary>
|
|
/// 반복 간격 (ms)
|
|
/// </summary>
|
|
public int RepeatInterval => _repeatInterval;
|
|
|
|
/// <summary>
|
|
/// 데이터 매퍼 객체
|
|
/// </summary>
|
|
public DataMapper? DataMapper => _dataMapper;
|
|
|
|
/// <summary>
|
|
/// HTTP 응답 데이터의 유효성을 검사하는 검사기입니다.
|
|
/// 이 속성을 통해 설정된 규칙에 따라 HTTP 응답 데이터를 필터링할 수 있습니다.
|
|
/// </summary>
|
|
/// <remarks>
|
|
/// null이 아닌 경우, HTTP 응답이 파싱된 후 데이터가 핸들러에 전달되기 전에
|
|
/// 데이터가 검사기의 모든 규칙을 통과하는지 확인합니다.
|
|
/// </remarks>
|
|
public DataValidator? Validator => _validator;
|
|
|
|
/// <summary>
|
|
/// 분할된 응답의 각 키에 대한 구성을 포함합니다.
|
|
/// </summary>
|
|
public IReadOnlyDictionary<string, DataMapperValidator>? SplitConfigs => _splitConfigs;
|
|
|
|
/// <summary>
|
|
/// HTTP 응답의 성공 여부를 확인하고, 성공 시 실제 데이터 페이로드를 추출하는 데 사용되는 <see cref="Data.HttpResponseMask"/>입니다.
|
|
/// 이 객체에 정의된 규칙에 따라 원시 응답 문자열이 처리됩니다.
|
|
/// </summary>
|
|
public HttpResponseMask ResponseMask => _responseMask;
|
|
|
|
/// <summary>
|
|
/// 최대 재시도 횟수
|
|
/// </summary>
|
|
public int MaxRetryCount => _maxRetryCount;
|
|
|
|
/// <summary>
|
|
/// 재시도 간격 (ms)
|
|
/// </summary>
|
|
public int RetryDelay => _retryDelay;
|
|
|
|
/// <summary>
|
|
/// 업데이트된 데이터만 받을 여부 (true로 설정하면, 데이터가 변경된 경우에만 핸들러가 호출됩니다)
|
|
/// </summary>
|
|
public bool UpdatedDataOnly => _updatedDataOnly;
|
|
|
|
/// <summary>
|
|
/// 응답 JSON을 최상위 키를 기준으로 분할하여 각각 DataRepository에 저장할지 여부를 나타냅니다.
|
|
/// </summary>
|
|
public bool SplitResponseByKey => _splitResponseByKey;
|
|
|
|
/// <summary>
|
|
/// HttpRequestConfig 클래스의 새 인스턴스를 초기화합니다.
|
|
/// </summary>
|
|
/// <param name="url">HTTP 요청을 보낼 URL</param>
|
|
/// <param name="method">HTTP 요청 메서드 (기본값: "post")</param>
|
|
/// <param name="headers">HTTP 요청 헤더 (선택사항)</param>
|
|
/// <param name="body">HTTP 요청 본문 (선택사항)</param>
|
|
public HttpRequestConfig(string url, string method = "post", Dictionary<string, string>? headers = null, string? body = null)
|
|
{
|
|
_url = url;
|
|
_method = method;
|
|
_headers = headers;
|
|
_body = body;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 요청 응답을 처리할 데이터 매퍼를 설정합니다.
|
|
/// 데이터 매퍼는 HTTP 응답을 IDataObject로 변환하는 역할을 합니다.
|
|
/// </summary>
|
|
/// <param name="dataMapper">사용할 데이터 매퍼 객체</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig SetDataMapper(DataMapper dataMapper)
|
|
{
|
|
_dataMapper = dataMapper;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 응답 데이터의 유효성을 검사하는 검사기를 설정합니다.
|
|
/// </summary>
|
|
/// <param name="validator">HTTP 응답 데이터의 유효성 검사에 사용할 DataValidator 객체</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
/// <remarks>
|
|
/// 이 메서드로 설정된 검사기는 HTTP 응답이 성공적으로 파싱된 후,
|
|
/// 성공 핸들러에 전달되기 전에 데이터의 유효성을 검사합니다.
|
|
/// 데이터가 모든 유효성 검사 규칙을 통과하지 못하면 성공 핸들러가 호출되지 않습니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 1. DataValidator 생성 및 규칙 추가
|
|
/// var validator = new DataValidator();
|
|
///
|
|
/// // 2. 유효성 검사 규칙 정의
|
|
/// // 사용자 데이터에 이메일이 포함되어 있는지 확인
|
|
/// validator.AddValidator("email", value => {
|
|
/// if (value is string email)
|
|
/// return email.Contains("@") && email.Contains(".");
|
|
/// return false;
|
|
/// });
|
|
///
|
|
/// // 사용자 나이가 18세 이상인지 확인
|
|
/// validator.AddValidator("age", value => {
|
|
/// if (value is long age)
|
|
/// return age >= 18;
|
|
/// return false;
|
|
/// });
|
|
///
|
|
/// // 3. 검사기를 HTTP 파이프라인에 설정
|
|
/// var pipelineInfo = new HttpRequestConfig("https://api.example.com/users", "get")
|
|
/// .SetDataMapper(userDataMapper)
|
|
/// .SetValidator(validator)
|
|
/// .SetSuccessHandler(userData => {
|
|
/// // 여기에 도달하는 사용자 데이터는 모두 이메일이 유효하고 18세 이상입니다.
|
|
/// Console.WriteLine($"유효한 사용자: {userData["name"]}, {userData["email"]}");
|
|
/// })
|
|
/// .SetFailHandler(errorMsg => {
|
|
/// Console.WriteLine($"요청 실패: {errorMsg}");
|
|
/// });
|
|
/// </code>
|
|
/// </example>
|
|
public HttpRequestConfig SetValidator(DataValidator validator)
|
|
{
|
|
this._validator = validator;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 분할된 응답의 특정 키에 대한 구성을 추가합니다.
|
|
/// </summary>
|
|
/// <param name="key">구성할 응답의 키입니다.</param>
|
|
/// <param name="dataMapper">이 키에 사용할 데이터 매퍼입니다.</param>
|
|
/// <param name="validator">이 키에 사용할 데이터 유효성 검사기입니다.</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig AddSplitConfig(string key, DataMapperValidator? dataMapperValidator = null)
|
|
{
|
|
if (_splitConfigs == null)
|
|
{
|
|
_splitConfigs = new Dictionary<string, DataMapperValidator>();
|
|
}
|
|
if(dataMapperValidator != null)_splitConfigs[key] = dataMapperValidator;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 파이프라인에 적용할 ResponseMask를 설정하고 업데이트된 파이프라인 구성을 반환합니다.
|
|
/// </summary>
|
|
/// <param name="responseMask">HTTP response에 적용할 <see cref="HttpResponseMask"/>입니다.</param>
|
|
/// <returns>지정된 response 마스크가 적용된 업데이트된 <see cref="HttpRequestConfig"/> 인스턴스입니다.</returns>
|
|
public HttpRequestConfig SetResponseMask(HttpResponseMask responseMask)
|
|
{
|
|
_responseMask = responseMask;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 요청이 완료된 후 호출될 핸들러를 설정합니다.
|
|
/// 변경 된 데이터는 IDataObject로 전달됩니다.
|
|
/// UpdatedDataOnly=true일 경우 변경 된 데이터가 없으면 호출 되지 않습니다.
|
|
/// </summary>
|
|
/// <param name="handler">응답 데이터를 처리할 콜백 함수</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig SetSuccessHandler(Action<IDataObject?>? handler)
|
|
{
|
|
_successhandler = handler;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 요청이 실패했을 때 호출될 핸들러를 설정합니다.
|
|
/// 실패 정보 또는 관련 데이터가 string 형태로 전달될 수 있습니다.
|
|
/// </summary>
|
|
/// <param name="handler">실패 정보를 처리할 콜백 함수입니다. 실패 시 관련 데이터를 인자로 받습니다.</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig SetFailHandler(Action<string>? handler)
|
|
{
|
|
_failhandler = handler;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 요청 실패 시 재시도 정책을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="maxRetryCount">최대 재시도 횟수 (기본값: 3)</param>
|
|
/// <param name="retryDelay">재시도 간 대기 시간(밀리초) (기본값: 1000)</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig SetRetry(int maxRetryCount = 3, int retryDelay = 1000)
|
|
{
|
|
_maxRetryCount = maxRetryCount;
|
|
_retryDelay = retryDelay;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// HTTP 요청의 반복 실행 설정을 구성합니다.
|
|
/// </summary>
|
|
/// <param name="repeat">반복 실행 여부</param>
|
|
/// <param name="count">반복 횟수 (0은 무한 반복) (기본값: 0)</param>
|
|
/// <param name="interval">반복 실행 간 대기 시간(밀리초) (기본값: 1000)</param>
|
|
/// <param name="updatedDataOnly">변경된 데이터만 처리할지 여부 (기본값: true)</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
/// <remarks>
|
|
/// 반복 요청 시 updatedDataOnly가 true인 경우, 서버 응답에서 데이터가 변경된 경우에만 핸들러가 호출됩니다.
|
|
/// 이는 불필요한 데이터 처리를 방지하고 성능을 향상시키는 데 도움이 됩니다.
|
|
/// </remarks>
|
|
/// <example>
|
|
/// <code>
|
|
/// // 5초마다 10번 반복 요청, 변경된 데이터만 처리
|
|
/// var pipelineInfo = new HttpRequestConfig("https://api.example.com/data", "GET")
|
|
/// .SetHandler(data => ProcessData(data))
|
|
/// .SetRepeat(true, 10, 5000, true);
|
|
///
|
|
/// // 3초마다 무한 반복, 모든 응답 데이터 처리
|
|
/// var pipelineInfo = new HttpRequestConfig("https://api.example.com/status", "GET")
|
|
/// .SetHandler(data => UpdateStatus(data))
|
|
/// .SetRepeat(true, 0, 3000, false);
|
|
/// </code>
|
|
/// </example>
|
|
public HttpRequestConfig SetRepeat(bool repeat, int count = 0, int interval = 1000, bool updatedDataOnly = true)
|
|
{
|
|
_repeat = repeat;
|
|
_repeatCount = count;
|
|
_repeatInterval = interval;
|
|
_updatedDataOnly = updatedDataOnly; // true로 설정하면, 데이터가 변경된 경우에만 핸들러가 호출됩니다.
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 응답 JSON을 최상위 키를 기준으로 분할하여 처리할지 여부를 설정합니다.
|
|
/// true로 설정하면, 응답이 {"key1": [...], "key2": [...]} 형태일 때,
|
|
/// key1과 key2를 각각의 키로 사용하여 DataRepository에 데이터를 추가/업데이트합니다.
|
|
/// </summary>
|
|
/// <param name="split">분할 처리 여부</param>
|
|
/// <returns>현재 HttpRequestConfig 인스턴스 (메서드 체이닝용)</returns>
|
|
public HttpRequestConfig SetSplitResponseByKey(bool split)
|
|
{
|
|
_splitResponseByKey = split;
|
|
return this;
|
|
}
|
|
|
|
/// <summary>
|
|
/// 업데이트된 데이터만 처리할지 여부를 나타내는 값을 설정합니다.
|
|
/// </summary>
|
|
/// <param name="v">부울 값. <see langword="true"/>는 업데이트된 데이터만 처리하도록 지정합니다. 그렇지 않으면
|
|
/// <see langword="false"/>입니다.</param>
|
|
public void SetUpdatedDataOnly(bool v)
|
|
{
|
|
_updatedDataOnly = v;
|
|
}
|
|
}
|
|
}
|