| 1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374 |
- using System.Net.Http.Headers;
- using System.Net.Http.Json;
- using System.Text;
- using Application.Abstractions.Notification;
- using Microsoft.Extensions.Hosting;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using SharedKernel;
- namespace Infrastructure.Notification;
- /// <summary>
- /// Nextcloud Talk OCS Chat API 운영 알림 발송기.
- /// 메시지는 백그라운드로 발송(fire-and-forget) — 외부 메신저 장애가 파트너 API 응답을 지연/실패시키지 않는다.
- /// 모든 메시지에 [환경명] prefix 를 붙여 dev/prod 발신원을 구분한다.
- /// </summary>
- internal sealed class NextcloudTalkAlertService(
- IHttpClientFactory httpClientFactory,
- IOptions<AppSettings> options,
- IHostEnvironment env,
- ILogger<NextcloudTalkAlertService> logger
- ) : IAdminAlertService
- {
- public Task SendActivityAsync(string message, CancellationToken ct = default)
- {
- QueueSend(options.Value.NextcloudTalk.ActivityRoomToken, message);
- return Task.CompletedTask;
- }
- public Task SendAlertAsync(string message, CancellationToken ct = default)
- {
- QueueSend(options.Value.NextcloudTalk.AlertRoomToken, message);
- return Task.CompletedTask;
- }
- private void QueueSend(string roomToken, string message)
- {
- var cfg = options.Value.NextcloudTalk;
- if (!cfg.Enabled || string.IsNullOrWhiteSpace(cfg.BaseUrl) || string.IsNullOrWhiteSpace(cfg.Username) || string.IsNullOrWhiteSpace(cfg.AppPassword) || string.IsNullOrWhiteSpace(roomToken))
- {
- return;
- }
- // fire-and-forget — 호출자 CancellationToken 과 분리해 클라이언트 연결 종료에도 발송을 완료한다
- var label = string.IsNullOrWhiteSpace(cfg.Label) ? env.EnvironmentName : cfg.Label;
- _ = Task.Run(() => SendCoreAsync(cfg, roomToken, $"[{label}] {message}"));
- }
- private async Task SendCoreAsync(AppSettings.NextcloudTalkSection cfg, string roomToken, string message)
- {
- try
- {
- var client = httpClientFactory.CreateClient("NextcloudTalk");
- var request = new HttpRequestMessage(HttpMethod.Post, $"{cfg.BaseUrl.TrimEnd('/')}/ocs/v2.php/apps/spreed/api/v1/chat/{roomToken}");
- request.Headers.Add("OCS-APIRequest", "true");
- request.Headers.Accept.Add(new MediaTypeWithQualityHeaderValue("application/json"));
- request.Headers.Authorization = new AuthenticationHeaderValue("Basic", Convert.ToBase64String(Encoding.UTF8.GetBytes($"{cfg.Username}:{cfg.AppPassword}")));
- request.Content = JsonContent.Create(new { message });
- var response = await client.SendAsync(request);
- if (!response.IsSuccessStatusCode)
- {
- logger.LogWarning("[NextcloudTalk] 발송 실패 — HTTP {Status}, room={Room}", (int)response.StatusCode, roomToken);
- }
- }
- catch (Exception ex)
- {
- logger.LogWarning(ex, "[NextcloudTalk] 발송 오류 — room={Room}", roomToken);
- }
- }
- }
|