|
@@ -1,5 +1,8 @@
|
|
|
-using Hotline.Push.Notifies;
|
|
|
+using Hotline.Identity.Accounts;
|
|
|
+using Hotline.Orders;
|
|
|
+using Hotline.Push.Notifies;
|
|
|
using Hotline.Share.Dtos.Push;
|
|
|
+using Hotline.Share.Dtos.Push.FWMessage;
|
|
|
using Hotline.Share.Enums.Push;
|
|
|
using MapsterMapper;
|
|
|
using MediatR;
|
|
@@ -10,48 +13,52 @@ using Microsoft.Extensions.Logging;
|
|
|
using System.Net;
|
|
|
using System.Text.RegularExpressions;
|
|
|
using System.Xml;
|
|
|
+using XF.Domain.Cache;
|
|
|
using XF.Domain.Dependency;
|
|
|
using XF.Domain.Exceptions;
|
|
|
+using static System.Runtime.InteropServices.JavaScript.JSType;
|
|
|
|
|
|
-namespace Hotline.Push;
|
|
|
+namespace Hotline.Push.FWMessage;
|
|
|
|
|
|
/// <summary>
|
|
|
///
|
|
|
/// </summary>
|
|
|
public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
{
|
|
|
-
|
|
|
+ #region 注入
|
|
|
private readonly IMessageRepository _messageRepository;
|
|
|
private readonly IMapper _mapper;
|
|
|
private readonly IHttpClientFactory _httpClientFactory;
|
|
|
- private readonly ILogger<PushDomainService> _logger;
|
|
|
private readonly IConfiguration _config;
|
|
|
private readonly SmsAccountInfo accountInfo = null;
|
|
|
private readonly IMediator _mediator;
|
|
|
+ private readonly ITypedCache<CacheWaitSendId> _cacheWaitSendId;
|
|
|
|
|
|
/// <summary>
|
|
|
///
|
|
|
/// </summary>
|
|
|
/// <param name="messageRepository"></param>
|
|
|
/// <param name="httpClientFactory"></param>
|
|
|
- /// <param name="logger"></param>
|
|
|
/// <param name="mapper"></param>
|
|
|
/// <param name="config"></param>
|
|
|
/// <param name="mediator"></param>
|
|
|
- public PushDomainService(IMessageRepository messageRepository, IHttpClientFactory httpClientFactory, ILogger<PushDomainService> logger
|
|
|
- , IMapper mapper, IConfiguration config, IMediator mediator)
|
|
|
+ /// <param name="cacheWaitSendId"></param>
|
|
|
+ public PushDomainService(IMessageRepository messageRepository, IHttpClientFactory httpClientFactory
|
|
|
+ , IMapper mapper, IConfiguration config, IMediator mediator, ITypedCache<CacheWaitSendId> cacheWaitSendId)
|
|
|
{
|
|
|
_messageRepository = messageRepository;
|
|
|
_httpClientFactory = httpClientFactory;
|
|
|
- _logger = logger;
|
|
|
_mapper = mapper;
|
|
|
_config = config;
|
|
|
accountInfo = _config.GetSection("SmsAccountInfo").Get<SmsAccountInfo>();
|
|
|
_mediator = mediator;
|
|
|
+ _cacheWaitSendId = cacheWaitSendId;
|
|
|
}
|
|
|
+ #endregion
|
|
|
|
|
|
+ #region 短信发送
|
|
|
/// <summary>
|
|
|
- /// 业务处理
|
|
|
+ /// 短信发送
|
|
|
/// </summary>
|
|
|
/// <param name="messageDto"></param>
|
|
|
/// <param name="cancellation"></param>
|
|
@@ -63,31 +70,47 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
throw UserFriendlyException.SameMessage("消息不能为空!");
|
|
|
}
|
|
|
|
|
|
- #region 替换模板内容
|
|
|
- //如果模板为空,参数为空则直接用短信内容
|
|
|
- if (!string.IsNullOrEmpty(messageDto.Template) && messageDto.Params.Count > 0)
|
|
|
+ Message message = new();
|
|
|
+ int WaitSendId = 0;
|
|
|
+ var sendData = await _messageRepository.GetAsync(p => p.ExternalId == messageDto.ExternalId && p.PushBusiness == messageDto.PushBusiness && p.TelNumber == messageDto.TelNumber);
|
|
|
+ if (sendData != null)//处理重复数据
|
|
|
{
|
|
|
- string Template = messageDto.Template;
|
|
|
- //正则查询模板中需要替换的内容
|
|
|
- Regex regex = new(@"\{[a-zA-Z0-9]{1,}\}");
|
|
|
- var matches = regex.Matches(Template);
|
|
|
- if (matches != null && matches.Count != messageDto.Params.Count)
|
|
|
- //参数与需要替换的字符数不匹配
|
|
|
- //throw UserFriendlyException.SameMessage("模板需要参数与实际传递参数个数不匹配!");
|
|
|
- messageDto.Remark = "模板需要参数与实际传递参数个数不匹配!";
|
|
|
+ WaitSendId = sendData.WaitSendId;
|
|
|
+ messageDto = _mapper.Map<MessageDto>(sendData);
|
|
|
+ message = sendData;
|
|
|
+ }
|
|
|
+ else
|
|
|
+ {
|
|
|
+
|
|
|
+ #region 替换模板内容
|
|
|
+ string reason = null;
|
|
|
+ //如果模板为空,参数为空则直接用短信内容
|
|
|
+ if (!string.IsNullOrEmpty(messageDto.Template) && messageDto.Params.Count > 0)
|
|
|
+ {
|
|
|
+ string Template = messageDto.Template;
|
|
|
+ //正则查询模板中需要替换的内容
|
|
|
+ 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]);
|
|
|
+ //根据正则查询出来的匹配项替换内容
|
|
|
+ for (int i = 0; i < matches.Count; i++)
|
|
|
+ Template = Template.Replace(matches[i].ToString(), messageDto.Params[i]);
|
|
|
|
|
|
- messageDto.Content = Template;
|
|
|
+ messageDto.Content = Template;
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
+ message = _mapper.Map<Message>(messageDto);
|
|
|
+ WaitSendId = GenerateWaitSendId();
|
|
|
+ message.WaitSendId = WaitSendId;
|
|
|
+ message.Reason = reason;
|
|
|
}
|
|
|
- #endregion
|
|
|
-
|
|
|
- var message = _mapper.Map<Message>(messageDto);
|
|
|
|
|
|
//调用短信发送业务
|
|
|
- var strResult = await SmsSend(messageDto);
|
|
|
+ var strResult = await SmsSend(messageDto, WaitSendId);
|
|
|
|
|
|
//处理返回值
|
|
|
if (true == strResult.Contains("ok,")) // ok,35797257
|
|
@@ -97,17 +120,23 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
{
|
|
|
// 短信服务中心返回 IFSFWID,用于短信发送状态接收时匹配
|
|
|
message.SmsWaitSendingId = strArray[1];
|
|
|
- message.SendState = Share.Enums.Push.ESendState.Sending;
|
|
|
+ message.SendState = ESendState.Sending;
|
|
|
+ message.Status = EPushStatus.Success;
|
|
|
}
|
|
|
}
|
|
|
else
|
|
|
{
|
|
|
- message.Remark = strResult;
|
|
|
+ message.Reason = strResult;
|
|
|
+ message.Status = EPushStatus.Failed;
|
|
|
}
|
|
|
- //写入本地数据库
|
|
|
- await _messageRepository.AddAsync(message);
|
|
|
+ if (sendData != null)
|
|
|
+ await _messageRepository.UpdateAsync(message);//跟新本地数据库
|
|
|
+ else
|
|
|
+ await _messageRepository.AddAsync(message);//写入本地数据库
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
#region 查询账号短信剩余量
|
|
|
/// <summary>
|
|
|
/// 查询账号短信剩余量
|
|
@@ -141,6 +170,7 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
+ #region 短信发送状态回调接口
|
|
|
/// <summary>
|
|
|
/// 短信发送状态回调接口
|
|
|
/// </summary>
|
|
@@ -161,7 +191,6 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
strResult = "error,参数错误";
|
|
|
return strResult;
|
|
|
}
|
|
|
-
|
|
|
//修改数据
|
|
|
var data = await _messageRepository.GetAsync(p => p.SmsWaitSendingId == receiveMessageDto.msgid);
|
|
|
if (data != null)
|
|
@@ -170,17 +199,19 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
data.MsgCount = receiveMessageDto.msgcount;
|
|
|
data.SendState = (ESendState)receiveMessageDto.state;
|
|
|
data.SmsSendingCompletedId = receiveMessageDto.sfid + "";
|
|
|
- data.Remark = receiveMessageDto.errormsg;
|
|
|
+ data.Reason = receiveMessageDto.errormsg;
|
|
|
await _messageRepository.UpdateAsync(data);
|
|
|
// 成功返回值必须是ok
|
|
|
strResult = "ok";
|
|
|
}
|
|
|
else
|
|
|
strResult = "error,调用失败";
|
|
|
-
|
|
|
return strResult;
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
+ #region 短信接收
|
|
|
/// <summary>
|
|
|
/// 短信接收
|
|
|
/// </summary>
|
|
@@ -222,6 +253,8 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
|
|
|
}
|
|
|
|
|
|
+ #endregion
|
|
|
+
|
|
|
#region 私有方法
|
|
|
|
|
|
#region 短信发送
|
|
@@ -229,15 +262,15 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
/// 短信发送
|
|
|
/// </summary>
|
|
|
/// <returns></returns>
|
|
|
- private async Task<string> SmsSend(MessageDto messageDto)
|
|
|
+ private async Task<string> SmsSend(MessageDto messageDto, int WaitSendId)
|
|
|
{
|
|
|
- string strResult = "";
|
|
|
+ string strResult;
|
|
|
try
|
|
|
{
|
|
|
SendSmsModelDto tSms = new()
|
|
|
{
|
|
|
// 业务系统短信ID
|
|
|
- nWaitID = 1,
|
|
|
+ nWaitID = WaitSendId,
|
|
|
// 短信类型1:默认2:营销
|
|
|
strType = "1",
|
|
|
// 业务系统工单ID
|
|
@@ -266,7 +299,8 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
strAccountPwd = accountInfo.AccountPwd
|
|
|
};
|
|
|
// 序列化
|
|
|
- string strSendJson = Newtonsoft.Json.JsonConvert.SerializeObject(tSms);
|
|
|
+ string strSendJson = Newtonsoft.Json.JsonConvert.SerializeObject(tSms);//System.Text.Json.JsonSerializer.Serialize(tSms);//
|
|
|
+
|
|
|
// 参数加密
|
|
|
string strKey = await FwEncrypt(strSendJson);
|
|
|
// 短信发送参数
|
|
@@ -348,5 +382,32 @@ public class PushDomainService : IPushDomainService, IScopeDependency
|
|
|
}
|
|
|
#endregion
|
|
|
|
|
|
+ #region 生成待发短信ID缓存
|
|
|
+ /// <summary>
|
|
|
+ /// 生成待发短信ID缓存
|
|
|
+ /// </summary>
|
|
|
+ /// <returns></returns>
|
|
|
+ private int GenerateWaitSendId()
|
|
|
+ {
|
|
|
+ var cacheKey = "PushMessageWaitSendId";
|
|
|
+ var cacheWaitSend = _cacheWaitSendId.GetOrSet(cacheKey, f =>
|
|
|
+ {
|
|
|
+ var waitSendId = _messageRepository.Queryable(true)
|
|
|
+ .MaxAsync(p => p.WaitSendId)
|
|
|
+ .GetAwaiter()
|
|
|
+ .GetResult();
|
|
|
+ return new CacheWaitSendId { WaitSendId = waitSendId };
|
|
|
+ }, TimeSpan.FromDays(1));
|
|
|
+ cacheWaitSend!.WaitSendId += 1;
|
|
|
+
|
|
|
+ _cacheWaitSendId.Set(cacheKey, cacheWaitSend);
|
|
|
+ return cacheWaitSend.WaitSendId;
|
|
|
+ }
|
|
|
+
|
|
|
+ public class CacheWaitSendId
|
|
|
+ {
|
|
|
+ public int WaitSendId { get; set; }
|
|
|
+ }
|
|
|
+ #endregion
|
|
|
#endregion
|
|
|
}
|