forked from AcaMate/AcaMate_API
[♻️] PUSH API 리팩토링 진행 중
This commit is contained in:
parent
e8a2f3d7ee
commit
29072037a0
|
@ -15,9 +15,11 @@ public class PushController : ControllerBase
|
|||
{
|
||||
|
||||
private readonly IWebHostEnvironment _env;
|
||||
public PushController(IWebHostEnvironment env)
|
||||
private readonly Logger<PushController> _logger;
|
||||
public PushController(IWebHostEnvironment env, Logger<PushController> 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<bool,string,string, ApnsPushService> 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());
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -20,5 +20,35 @@ public class RefreshRevokeException: Exception
|
|||
{
|
||||
public RefreshRevokeException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 참조해야 하는 파일에서 오류가 발생하는 경우
|
||||
/// </summary>
|
||||
public class FileNotValidException : Exception
|
||||
{
|
||||
public FileNotValidException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 파일 내부에 값을 읽을 때 오류가 발생하는 경우
|
||||
/// </summary>
|
||||
public class FileContentNotFoundException : Exception
|
||||
{
|
||||
public FileContentNotFoundException(string message) : base(message)
|
||||
{
|
||||
}
|
||||
}
|
||||
/// <summary>
|
||||
/// 외부 서비스에 연결시 연결 실패시
|
||||
/// </summary>
|
||||
public class ServiceConnectionFailedException : Exception
|
||||
{
|
||||
public ServiceConnectionFailedException(string message) : base(message)
|
||||
{
|
||||
|
||||
}
|
||||
}
|
|
@ -38,4 +38,15 @@ public class Alert
|
|||
[Required(ErrorMessage = "필수 입력 누락 (body)")]
|
||||
public string body { get; set; } // 내용
|
||||
public string? subtitle { get; set; } // 부제목 (선택)
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 푸시 등록하기 위한 여러 데이터 목록
|
||||
/// </summary>
|
||||
public class PushFile
|
||||
{
|
||||
public string uri { get; set; }
|
||||
public string p12Path { get; set; }
|
||||
public string p12PWPath { get; set; }
|
||||
public string apnsTopic { get; set; }
|
||||
}
|
|
@ -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<APIResult> SendPushNotificationAsync(string deviceToken, Payload payload)
|
||||
public async Task<bool> 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<Dictionary<string, string>>(File.ReadAllText(_p12PWPath));
|
||||
var p12Password = keys["Password"];
|
||||
var keys =
|
||||
JsonSerializer.Deserialize<Dictionary<string, string>>(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}");
|
||||
}
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user