diff --git a/Program/V1/Controllers/PushController.cs b/Program/V1/Controllers/PushController.cs index a6c7afe..5eaa6b5 100644 --- a/Program/V1/Controllers/PushController.cs +++ b/Program/V1/Controllers/PushController.cs @@ -15,9 +15,11 @@ public class PushController : ControllerBase { private readonly IWebHostEnvironment _env; - public PushController(IWebHostEnvironment env) + private readonly Logger _logger; + public PushController(IWebHostEnvironment env, Logger logger) { _env = env; + _logger = logger; } [HttpGet()] @@ -47,68 +49,43 @@ public class PushController : ControllerBase if (string.IsNullOrWhiteSpace(deviceToken) || payload == null) return BadRequest(APIResponse.InvalidInputError()); + + var isDev = _env.IsDevelopment(); - // string uri = ""; - // string p12Path = ""; - // - // string p12PWPath = "/src/private/appleKeys.json"; - // - // // 앱 번들 ID 입력 부분 - // string apnsTopic = "me.myds.ipstein.acamate.AcaMate"; - - Func pushService = (isDevelopment,pw,topic) => + var pushFile = new PushFile() { - if (isDevelopment) + uri = isDev ? "https://api.sandbox.push.apple.com/" : "https://api.push.apple.com/", + p12Path = isDev ? "/src/private/AM_Push_Sandbox.p12" : "/src/private/AM_Push.p12", + p12PWPath = "/src/private/appleKeys.json", + apnsTopic = "me.myds.ipstein.acamate.AcaMate" + }; + + try + { + if (await new ApnsPushService().SendPushNotificationAsync(deviceToken, pushFile, payload)) { - return new ApnsPushService( - "https://api.sandbox.push.apple.com/", - "/src/private/AM_Push_Sandbox.p12", - pw, topic - ); + return Ok(APIResponse.Send("000", "정상", Empty)); } else { - return new ApnsPushService( - "https://api.push.apple.com/", - "/src/private/AM_Push.p12", - pw, topic - ); + return StatusCode(500, APIResponse.UnknownError()); } - }; - // - // if (_env.IsDevelopment()) - // { - // uri = "https://api.sandbox.push.apple.com/"; - // p12Path = "/src/private/AM_Push_Sandbox.p12"; - // } - // else - // { - // uri = "https://api.push.apple.com/"; - // p12Path = "/src/private/AM_Push.p12"; - // } - // - // ApnsPushService 인스턴스 생성 - // var pushService = new ApnsPushService(uri, p12Path, p12PWPath, apnsTopic); - // - - // 푸시 알림 전송 - // var result = await pushService.SendPushNotificationAsync(deviceToken, payload); - - var result = await pushService( - _env.IsDevelopment(), - "/src/private/appleKeys.json", - "me.myds.ipstein.acamate.AcaMate" - ).SendPushNotificationAsync(deviceToken, payload); - - if (result.Success) - { - return Ok(APIResponse.Success()); } - else + catch (ServiceConnectionFailedException failEx) { - return BadRequest(APIResponse.InternalSeverError()); + _logger.LogError($"[푸시][에러] : {failEx}"); + return StatusCode(300, APIResponse.InternalSeverError()); + } + catch (HttpRequestException httpEx) + { + _logger.LogError($"[푸시][에러] : {httpEx}"); + return StatusCode(300, APIResponse.InternalSeverError()); + } + catch (Exception ex) + { + _logger.LogError($"[푸시][에러] : {ex}"); + return StatusCode(500, APIResponse.UnknownError()); } - } } \ No newline at end of file diff --git a/Program/V1/Models/AcaException.cs b/Program/V1/Models/AcaException.cs index 42fac10..2fac8b1 100644 --- a/Program/V1/Models/AcaException.cs +++ b/Program/V1/Models/AcaException.cs @@ -20,5 +20,35 @@ public class RefreshRevokeException: Exception { public RefreshRevokeException(string message) : base(message) { + } +} + +/// +/// 참조해야 하는 파일에서 오류가 발생하는 경우 +/// +public class FileNotValidException : Exception +{ + public FileNotValidException(string message) : base(message) + { + } +} + +/// +/// 파일 내부에 값을 읽을 때 오류가 발생하는 경우 +/// +public class FileContentNotFoundException : Exception +{ + public FileContentNotFoundException(string message) : base(message) + { + } +} +/// +/// 외부 서비스에 연결시 연결 실패시 +/// +public class ServiceConnectionFailedException : Exception +{ + public ServiceConnectionFailedException(string message) : base(message) + { + } } \ No newline at end of file diff --git a/Program/V1/Models/PushPayload.cs b/Program/V1/Models/PushPayload.cs index fd7eae8..3cee7de 100644 --- a/Program/V1/Models/PushPayload.cs +++ b/Program/V1/Models/PushPayload.cs @@ -38,4 +38,15 @@ public class Alert [Required(ErrorMessage = "필수 입력 누락 (body)")] public string body { get; set; } // 내용 public string? subtitle { get; set; } // 부제목 (선택) +} + +/// +/// 푸시 등록하기 위한 여러 데이터 목록 +/// +public class PushFile +{ + public string uri { get; set; } + public string p12Path { get; set; } + public string p12PWPath { get; set; } + public string apnsTopic { get; set; } } \ No newline at end of file diff --git a/Program/V1/Services/PushService.cs b/Program/V1/Services/PushService.cs index 0e2fab0..6b467b1 100644 --- a/Program/V1/Services/PushService.cs +++ b/Program/V1/Services/PushService.cs @@ -1,65 +1,53 @@ using System; +using System.Diagnostics; using System.Net.Http; using System.Security.Cryptography; using System.Security.Cryptography.X509Certificates; using System.Text; using System.Text.Json; using System.Threading.Tasks; + +using Microsoft.AspNetCore.Mvc; + using AcaMate.V1.Models; using Version = System.Version; +namespace AcaMate.V1.Services; public class ApnsPushService { - private readonly string _uri; - private readonly string _p12Path; - private readonly string _p12PWPath; - private readonly string _apnsTopic; - - - public ApnsPushService(string uri,string p12Path, string p12PWPath, string apnsTopic) + public ApnsPushService() { - _uri = uri ?? throw new ArgumentNullException(nameof(uri)); - _p12Path = p12Path ?? throw new ArgumentNullException(nameof(p12Path)); - _p12PWPath = p12PWPath ?? throw new ArgumentNullException(nameof(p12PWPath)); - _apnsTopic = apnsTopic ?? throw new ArgumentNullException(nameof(apnsTopic)); + } - public async Task SendPushNotificationAsync(string deviceToken, Payload payload) + public async Task SendPushNotificationAsync(string deviceToken, PushFile pushFile, Payload payload) { // 존재 안하면 예외 던져 버리는거 - if (!File.Exists(_p12PWPath)) - { - Console.WriteLine($"File not found: {_p12PWPath}"); - return new APIResult - { - Success = false , - Code = "003", - Message = "서버 오류 : p12 PW 파일 확인 필요" - }; - } + if (!File.Exists(pushFile.p12Path) || !File.Exists(pushFile.p12PWPath)) + throw new FileNotFoundException("[푸시] : p12 관련 파일 확인 필요"); var jsonPayload = JsonSerializer.Serialize(payload); - - var keys = JsonSerializer.Deserialize>(File.ReadAllText(_p12PWPath)); - var p12Password = keys["Password"]; + var keys = + JsonSerializer.Deserialize>(await File.ReadAllTextAsync(pushFile.p12PWPath)) + ?? throw new FileContentNotFoundException("[푸시] : 파일 내부의 값을 읽어오지 못함"); try { - var certificate = new X509Certificate2(_p12Path, p12Password); - Console.WriteLine($"Certificate Subject: {certificate.Subject}"); - Console.WriteLine($"Certificate Issuer: {certificate.Issuer}"); + // var certificate = new X509Certificate2(pushFile.p12Path, keys["Password"]); var handler = new HttpClientHandler(); - handler.ClientCertificates.Add(certificate); + handler.ClientCertificates + .Add(new X509Certificate2(pushFile.p12Path, keys["Password"])); handler.SslProtocols = System.Security.Authentication.SslProtocols.Tls12; + using var client = new HttpClient(handler) { - BaseAddress = new Uri(_uri), + BaseAddress = new Uri(pushFile.uri), Timeout = TimeSpan.FromSeconds(60) }; - + var request = new HttpRequestMessage(HttpMethod.Post, $"/3/device/{deviceToken}") { Content = new StringContent(jsonPayload, Encoding.UTF8, "application/json"), @@ -67,60 +55,22 @@ public class ApnsPushService }; // 필수 헤더 추가 - request.Headers.Add("apns-topic", _apnsTopic); + request.Headers.Add("apns-topic", pushFile.apnsTopic); request.Headers.Add("apns-push-type", "alert"); - - Console.WriteLine($"Send -> Payload: {jsonPayload}"); var response = await client.SendAsync(request); - if (response.IsSuccessStatusCode) - { - return new APIResult - { - Success = true - }; - } + if (response.IsSuccessStatusCode) return true; else { var errorContent = await response.Content.ReadAsStringAsync(); - return new APIResult - { - Success = false, - Code = "003", - Message = $"APN 통신 실패 = {response.StatusCode} : {errorContent}" - }; + throw new ServiceConnectionFailedException($"[푸시] : APNS 통신 실패 - {errorContent}"); } } catch (HttpRequestException httpEx) { Console.WriteLine($"HttpRequestException: {httpEx.Message}"); - return new APIResult - { - Success = false, - Code = "003", - Message = $"통신 실패 : {httpEx.Message}" - }; - } - - catch (CryptographicException ex) - { - return new APIResult - { - Success = false, - Code = "999", - Message = $"오류 발생 : {ex.Message}" - }; - } - - catch (Exception ex) - { - return new APIResult - { - Success = false, - Code = "999", - Message = $"오류 발생 : {ex.Message}" - }; + throw new ServiceConnectionFailedException($"[푸시] : APNS 통신 실패 - {httpEx.Message}"); } } } \ No newline at end of file