123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260 |
- using DotNetCore.CAP;
- using Hotline.Share.Dtos.Push;
- using Hotline.Share.Dtos.SendSms;
- using Hotline.Share.Enums.Push;
- using MapsterMapper;
- using MediatR;
- using Microsoft.AspNetCore.Http;
- using Microsoft.Extensions.Logging;
- using Microsoft.Extensions.Options;
- using System.Net;
- using System.Net.Http.Json;
- using System.Text.RegularExpressions;
- using System.Xml;
- using XF.Domain.Dependency;
- using XF.Domain.Exceptions;
- using XF.Domain.Repository;
- namespace Hotline.Push.FWMessage;
- /// <summary>
- ///
- /// </summary>
- public class PushDomainService : IPushDomainService, IScopeDependency
- {
- #region 注入
- private readonly IRepository<Message> _messageRepository;
- private readonly IMapper _mapper;
- private readonly IMediator _mediator;
- private readonly IRepository<MessageTemplate> _messageTemplateRepository;
- private readonly ICapPublisher _capPublisher;
- private readonly IHttpClientFactory _httpClientFactory;
- private readonly ILogger<PushDomainService> _logger;
- private readonly IOptionsSnapshot<SendSmsConfiguration> _sendSmsConfiguration;
- /// <summary>
- ///
- /// </summary>
- /// <param name="messageRepository"></param>
- /// <param name="mapper"></param>
- /// <param name="mediator"></param>
- /// <param name="messageTemplateRepository"></param>
- /// <param name="capPublisher"></param>
- /// <param name="httpClientFactory"></param>
- /// <param name="logger"></param>
- /// <param name="sendSmsConfiguration"></param>
- public PushDomainService(IRepository<Message> messageRepository,
- IMapper mapper,
- IMediator mediator,
- IRepository<MessageTemplate> messageTemplateRepository,
- ICapPublisher capPublisher,
- IHttpClientFactory httpClientFactory,
- ILogger<PushDomainService> logger,
- IOptionsSnapshot<SendSmsConfiguration> sendSmsConfiguration
- )
- {
- _messageRepository = messageRepository;
- _mapper = mapper;
- _mediator = mediator;
- _messageTemplateRepository = messageTemplateRepository;
- _capPublisher = capPublisher;
- _httpClientFactory = httpClientFactory;
- _logger = logger;
- _sendSmsConfiguration = sendSmsConfiguration;
- }
- #endregion
- /// <summary>
- /// 短信发送
- /// </summary>
- /// <param name="messageDto"></param>
- /// <param name="cancellation"></param>
- /// <returns></returns>
- public async Task PushMsgAsync(MessageDto messageDto, CancellationToken cancellation)
- {
- if (messageDto == null)
- throw UserFriendlyException.SameMessage("消息不能为空!");
- if (string.IsNullOrEmpty(messageDto.TemplateCode) && string.IsNullOrEmpty(messageDto.Content))
- throw UserFriendlyException.SameMessage("模板和内容不能同时为空!");
- #region 替换模板内容
- //如果模板为空,参数为空则直接用短信内容
- if (!string.IsNullOrEmpty(messageDto.TemplateCode))
- {
- //查询模板信息
- var messageTemplate = await _messageTemplateRepository.GetAsync(p => p.Code == messageDto.TemplateCode, cancellation);
- if (messageTemplate == null || string.IsNullOrEmpty(messageTemplate.Content))
- throw UserFriendlyException.SameMessage("未找到模板短信!");
- string Template = messageTemplate.Content;
- if (messageDto.Params != null && messageDto.Params.Count > 0)
- {
- //正则查询模板中需要替换的内容
- Regex regex = new(@"\{[a-zA-Z0-9]{1,}\}");
- var matches = regex.Matches(Template);
- if (matches != null && matches.Count != messageDto.Params.Count)
- //参数与需要替换的字符数不匹配
- throw UserFriendlyException.SameMessage("模板需要参数与实际传递参数个数不匹配!");
- //reason = "模板需要参数与实际传递参数个数不匹配!";
- //根据正则查询出来的匹配项替换内容
- for (int i = 0; i < matches.Count; i++)
- Template = Template.Replace(matches[i].ToString(), messageDto.Params[i]);
- }
- messageDto.Content = Template;
- }
- #endregion
- var message = _mapper.Map<Message>(messageDto);
- var id = await _messageRepository.AddAsync(message, cancellation);//写入本地数据库
- PushMessageDto pushMessage = new()
- {
- ClientId = "Hotline",
- ExternalId = id,
- Content = message.Content,
- Remark = message.Remark,
- Name = message.Name,
- TelNumber = message.TelNumber
- };
- //消息队列
- await _capPublisher.PublishAsync(Hotline.Share.Mq.EventNames.SendSms, pushMessage, cancellationToken: cancellation);
- ////http请求
- //var result = await ExecuteAsync<PushMessageDto, SendSmsReponse>(_sendSmsConfiguration.Value.Url, pushMessage, cancellationToken: cancellation);
- //if (result != null && result.code == 0)
- //{
- // message.Status = EPushStatus.Success;
- // message.SendState = ESendState.Sending;
- // await _messageRepository.UpdateAsync(message, cancellation);
- //}
- }
- /// <summary>
- /// 修改短信推送状态
- /// </summary>
- /// <param name="dto"></param>
- /// <param name="cancellation"></param>
- /// <returns></returns>
- public async Task PushMsgUpdateStateAsync(PushReceiveMessageDto dto, CancellationToken cancellation)
- {
- var data = await _messageRepository.GetAsync(p => p.Id == dto.ExternalId, cancellation);
- if (data != null)
- {
- if (dto.Type == "0")
- {
- if (dto.SendState == ESendState.Sending)
- {
- data.SmsWaitSendingId = dto.SmsWaitSendingId;
- data.SendState = ESendState.Sending;
- data.Status = EPushStatus.Success;
- }
- else
- data.Status = EPushStatus.Failed;
- }
- else if (dto.Type == "1")
- {
- data.SendTime = Convert.ToDateTime(dto.SendTime);
- data.SendState = dto.SendState;
- data.MsgCount = dto.MsgCount;
- data.SmsSendingCompletedId = dto.SmsSendingCompletedId;
- }
- else if (dto.Type == "2")
- {
- data.IsSmsReply = dto.IsSmsReply;
- data.SmsReplyTime = Convert.ToDateTime(dto.SmsReplyTime);
- data.SmsReplyContent = dto.SmsReplyContent;
-
- }
- data.Reason = dto.Reason;
- await _messageRepository.UpdateAsync(data, cancellation);
- }
- }
- /// <summary>
- /// 修改短信推送状态
- /// </summary>
- /// <param name="dto"></param>
- /// <param name="cancellation"></param>
- /// <returns></returns>
- public async Task PushMsgUpdateStateNewAsync(PushReceiveMessageDto dto, CancellationToken cancellation)
- {
- var data = await _messageRepository.GetAsync(p => p.Id == dto.ExternalId, cancellation);
- if (data != null)
- {
- data.SmsWaitSendingId = dto.SmsWaitSendingId;
- data.Status = EPushStatus.Success;
- data.SendTime = Convert.ToDateTime(dto.SendTime);
- data.SendState = dto.SendState;
- data.MsgCount = dto.MsgCount;
- data.SmsSendingCompletedId = dto.SmsSendingCompletedId;
- data.IsSmsReply = dto.IsSmsReply;
- data.SmsReplyTime = Convert.ToDateTime(dto.SmsReplyTime);
- data.SmsReplyContent = dto.SmsReplyContent;
- data.Reason = dto.Reason;
- await _messageRepository.UpdateAsync(data, cancellation);
- }
- }
- /// <summary>
- ///
- /// </summary>
- /// <typeparam name="TRequest"></typeparam>
- /// <typeparam name="TResponse"></typeparam>
- /// <param name="path"></param>
- /// <param name="request"></param>
- /// <param name="clientInitialize"></param>
- /// <param name="cancellationToken"></param>
- /// <returns></returns>
- private async Task<TResponse?> ExecuteAsync<TRequest, TResponse>(string path, TRequest request,
- Action<HttpClient>? clientInitialize = null, CancellationToken cancellationToken = default)
- {
- var client = _httpClientFactory.CreateClient("sendwaitsms");
- clientInitialize?.Invoke(client);
- using var responseMessage = await client.PostAsJsonAsync(path, request, cancellationToken);
- responseMessage.EnsureSuccessStatusCode();
- var result = await responseMessage.Content.ReadFromJsonAsync<TResponse>(cancellationToken: cancellationToken);
- return result;
- }
- #region http请求
- /// <summary>
- /// 封装使用HttpClient调用WebService
- /// </summary>
- /// <param name="url">URL地址</param>
- /// <param name="content">参数</param>
- /// <returns></returns>
- private async Task<string> PostHelper(string url, HttpContent content)
- {
- _logger.LogInformation($"准备推送短信, {nameof(PostHelper)}");
- var result = string.Empty;
- try
- {
- using var client = _httpClientFactory.CreateClient();
- using (var response = await client.PostAsync(url, content))
- {
- if (response.StatusCode == HttpStatusCode.OK)
- {
- result = await response.Content.ReadAsStringAsync();
- XmlDocument doc = new XmlDocument();
- doc.LoadXml(result);
- result = doc.InnerText;
- }
- }
- }
- catch (Exception ex)
- {
- _logger.LogError(ex.InnerException?.Message);
- result = ex.Message;
- }
- _logger.LogInformation($"推送响应:{result}");
- return result;
- }
- #endregion
- }
|