using System.Reflection;
using JNPF.Common.Configuration;
using JNPF.Common.Const;
using JNPF.Common.Core.Manager;
using JNPF.Common.Enums;
using JNPF.Common.Extension;
using JNPF.Common.Filter;
using JNPF.Common.Manager;
using JNPF.Common.Security;
using JNPF.DataEncryption;
using JNPF.DependencyInjection;
using JNPF.DynamicApiController;
using JNPF.FriendlyException;
using JNPF.LinqBuilder;
using JNPF.Schedule;
using JNPF.Systems.Interfaces.System;
using JNPF.TaskScheduler.Entitys;
using JNPF.TaskScheduler.Entitys.Dto.TaskScheduler;
using JNPF.TaskScheduler.Entitys.Model;
using JNPF.TaskScheduler.Interfaces.TaskScheduler;
using JNPF.TimeCrontab;
using Mapster;
using Microsoft.AspNetCore.Mvc;
using SqlSugar;
namespace JNPF.TaskScheduler;
///
/// 定时任务
/// 版 本:V3.4.1
/// 版 权:拓通智联科技有限公司(http://www.tuotong-tech.com)
/// 日 期:2021-06-01.
///
[ApiDescriptionSettings(Tag = "TaskScheduler", Name = "scheduletask", Order = 220)]
[Route("api/[controller]")]
public class TimeTaskService : ITimeTaskService, IDynamicApiController, ITransient
{
private readonly ISqlSugarRepository _repository;
private readonly IDataInterfaceService _dataInterfaceService;
private readonly IUserManager _userManager;
private readonly ICacheManager _cacheManager;
//private readonly ISchedulerFactory _schedulerFactory;
private readonly IDataBaseManager _dataBaseManager;
///
/// 初始化一个类型的新实例.
///
public TimeTaskService(
ISqlSugarRepository repository,
IUserManager userManager,
IDataInterfaceService dataInterfaceService,
ICacheManager cacheManager,
//ISchedulerFactory schedulerFactory,
IDataBaseManager dataBaseManager)
{
_repository = repository;
_userManager = userManager;
_dataInterfaceService = dataInterfaceService;
_cacheManager = cacheManager;
_dataBaseManager = dataBaseManager;
//_schedulerFactory = schedulerFactory;
}
#region Get
///
/// 列表.
///
/// 请求参数
///
[HttpGet("")]
public async Task GetList([FromQuery] PageInputBase input)
{
var queryWhere = LinqExpression.And().And(x => x.DeleteMark == null);
if (!string.IsNullOrEmpty(input.keyword))
queryWhere = queryWhere.And(m => m.FullName.Contains(input.keyword) || m.EnCode.Contains(input.keyword));
var list = await _repository.AsQueryable().Where(queryWhere).OrderBy(x => x.CreatorTime, OrderByType.Desc)
.OrderByIF(!string.IsNullOrEmpty(input.keyword), t => t.LastModifyTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize);
var pageList = new SqlSugarPagedList()
{
list = list.list.Adapt>(),
pagination = list.pagination
};
return PageResult.SqlSugarPageResult(pageList);
}
///
/// 列表(执行记录).
///
/// 请求参数.
/// 任务Id.
///
[HttpGet("{id}/TaskLog")]
public async Task GetTaskLogList([FromQuery] TaskLogInput input, string id)
{
var whereLambda = LinqExpression.And().And(x => x.TaskId == id);
if (input.runResult.IsNotEmptyOrNull())
whereLambda = whereLambda.And(x => x.RunResult == input.runResult);
if (input.endTime != null && input.startTime != null)
{
var start = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 00:00:00}", input.startTime?.TimeStampToDateTime()));
var end = Convert.ToDateTime(string.Format("{0:yyyy-MM-dd 23:59:59}", input.endTime?.TimeStampToDateTime()));
whereLambda = whereLambda.And(x => SqlFunc.Between(x.RunTime, start, end));
}
var list = await _repository.AsSugarClient().Queryable().Where(whereLambda).OrderBy(x => x.RunTime, OrderByType.Desc).ToPagedListAsync(input.currentPage, input.pageSize);
var pageList = new SqlSugarPagedList()
{
list = list.list.Adapt>(),
pagination = list.pagination
};
return PageResult.SqlSugarPageResult(pageList);
}
///
/// 信息.
///
/// 主键值.
///
[HttpGet("Info/{id}")]
public async Task GetInfo_Api(string id)
{
return (await GetInfo(id)).Adapt();
}
///
/// 本地方法.
///
///
[HttpGet("TaskMethods")]
public async Task GetTaskMethodSelector()
{
return await GetTaskMethods();
}
#endregion
#region Post
///
/// 新建.
///
/// 实体对象.
///
[HttpPost("")]
public async Task Create([FromBody] TimeTaskCrInput input)
{
if (await _repository.IsAnyAsync(x => (x.EnCode == input.enCode || x.FullName == input.fullName) && x.DeleteMark == null))
throw Oops.Oh(ErrorCode.COM1004);
var comtentModel = input.executeContent.ToObject();
comtentModel.TenantId = _userManager.TenantId;
comtentModel.TenantDbName = _userManager.TenantDbName;
comtentModel.ConnectionConfig = _userManager.ConnectionConfig;
comtentModel.Token = _userManager.ToKen;
var entity = input.Adapt();
entity.ExecuteContent = comtentModel.ToJsonString();
entity.ExecuteCycleJson = comtentModel.cron;
var result = await _repository.AsInsertable(entity).IgnoreColumns(ignoreNullColumn: true).CallEntityMethod(m => m.Create()).ExecuteReturnEntityAsync();
// var job = _repository.AsTenant().GetConnection("JNPF-Job");
// var jobDetail = new JobDetail() { };
// job.Insertable()
_ = result ?? throw Oops.Oh(ErrorCode.COM1000);
// 添加到任务调度里
AddTimerJob(result);
//await AddJob(result);
}
///
/// 更新.
///
/// 主键值
/// 实体对象
///
[HttpPut("{id}")]
public async Task Update(string id, [FromBody] TimeTaskUpInput input)
{
if (await _repository.IsAnyAsync(x => x.Id != id && (x.EnCode == input.enCode || x.FullName == input.fullName) && x.DeleteMark == null))
throw Oops.Oh(ErrorCode.COM1004);
var entityOld = await GetInfo(id);
// 先从调度器里取消
SpareTime.Cancel(id);
var entityNew = input.Adapt();
entityNew.RunCount = entityOld.RunCount;
var comtentModel = input.executeContent.ToObject();
comtentModel.TenantId = _userManager.TenantId;
comtentModel.TenantDbName = _userManager.TenantDbName;
comtentModel.ConnectionConfig = _userManager.ConnectionConfig;
comtentModel.Token = _userManager.ToKen;
entityNew.ExecuteContent = comtentModel.ToJsonString();
entityNew.ExecuteCycleJson = comtentModel.cron;
var isOk = await _repository.AsUpdateable(entityNew).IgnoreColumns(ignoreAllNullColumns: true).CallEntityMethod(m => m.LastModify()).ExecuteCommandHasChangeAsync();
if (!isOk)
throw Oops.Oh(ErrorCode.COM1001);
// 再添加到任务调度里
if (entityNew.EnabledMark == 1)
{
AddTimerJob(entityNew);
}
}
///
/// 删除.
///
/// 主键值.
///
[HttpDelete("{id}")]
public async Task Delete(string id)
{
var entity = await GetInfo(id);
if (entity == null)
throw Oops.Oh(ErrorCode.COM1005);
var isOk = await _repository.AsUpdateable(entity).CallEntityMethod(m => m.Delete()).UpdateColumns(it => new { it.DeleteMark, it.DeleteTime, it.DeleteUserId }).ExecuteCommandHasChangeAsync();
if (!isOk)
throw Oops.Oh(ErrorCode.COM1002);
// 从调度器里取消
SpareTime.Cancel(entity.Id);
}
///
/// 停止.
///
/// 主键值.
///
[HttpPut("{id}/Actions/Stop")]
public async Task Stop(string id)
{
var isOk = await _repository.AsUpdateable().SetColumns(it => new TimeTaskEntity()
{
EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
LastModifyUserId = _userManager.UserId,
LastModifyTime = SqlFunc.GetDate()
}).Where(it => it.Id.Equals(id)).ExecuteCommandHasChangeAsync();
if (!isOk)
throw Oops.Oh(ErrorCode.COM1003);
SpareTime.Stop(id);
}
///
/// 启动.
///
/// 主键值.
///
[HttpPut("{id}/Actions/Enable")]
public async Task Enable(string id)
{
var entity = await GetInfo(id);
var isOk = await _repository.AsUpdateable().SetColumns(it => new TimeTaskEntity()
{
EnabledMark = SqlFunc.IIF(it.EnabledMark == 1, 0, 1),
LastModifyUserId = _userManager.UserId,
LastModifyTime = SqlFunc.GetDate()
}).Where(it => it.Id.Equals(id)).ExecuteCommandHasChangeAsync();
if (!isOk)
throw Oops.Oh(ErrorCode.COM1003);
var comtentModel = entity.ExecuteContent.ToObject();
comtentModel.Token = _userManager.ToKen;
entity.ExecuteContent = comtentModel.ToJsonString();
var timer = SpareTime.GetWorkers().ToList().Find(u => u.WorkerName == id);
if (timer == null)
{
AddTimerJob(entity);
}
else
{
// 如果 StartNow 为 flase , 执行 AddTimerJob 并不会启动任务
SpareTime.Start(entity.Id);
}
}
#endregion
#region PublicMethod
///
/// 启动自启动任务.
///
[NonAction]
public void StartTimerJob()
{
// 非多租户模式启动自启任务
if (!KeyVariable.MultiTenancy)
{
//_repository.AsQueryable().Where(x => x.DeleteMark == null && x.EnabledMark == 1).ToList().ForEach(AddTimerJob);
}
}
///
/// 根据类型执行任务.
///
/// 任务实体.
///
[NonAction]
public async Task PerformJob(TimeTaskEntity entity)
{
try
{
var model = entity.ExecuteContent.ToObject();
if (!string.IsNullOrEmpty(model.Token))
{
var claims = JWTEncryption.ReadJwtToken(model.Token.Replace("Bearer ", string.Empty).Replace("bearer ", string.Empty))?.Claims;
var connectionConfig = claims.FirstOrDefault(e => e.Type == ClaimConst.CONNECTIONCONFIG)?.Value.ToObject();
var parameters = model.parameter.ToDictionary(key => key.field, value => value.value.IsNotEmptyOrNull() ? value.value : value.defaultValue);
await _dataInterfaceService.GetResponseByType(model.interfaceId, 3, model.TenantId, null, parameters);
}
return string.Empty;
}
catch (Exception ex)
{
return ex.Message;
}
}
#endregion
#region PrivateMethod
///
/// 详情.
///
/// 主键.
///
private async Task GetInfo(string id)
{
return await _repository.GetFirstAsync(x => x.Id == id && x.DeleteMark == null);
}
///
/// 新增定时任务.
///
///
private async void AddTimerJob(TimeTaskEntity input)
{
Action? action = null;
ContentModel? comtentModel = input.ExecuteContent.ToObject();
input.ExecuteCycleJson = comtentModel.cron;
switch (input.ExecuteType)
{
case "3":
// 查询符合条件的任务方法
TaskMethodInfo? taskMethod = GetTaskMethods()?.Result.FirstOrDefault(m => m.id == comtentModel.localHostTaskId);
if (taskMethod == null) break;
// 创建任务对象
object? typeInstance = Activator.CreateInstance(taskMethod.DeclaringType);
// 创建委托
action = (Action)Delegate.CreateDelegate(typeof(Action), typeInstance, taskMethod.MethodName);
break;
default:
action = async (timer, count) =>
{
var msg = await PerformJob(input);
};
break;
}
if (action == null) return;
// SpareTime.Do(comtentModel.cron, action, input.Id, comtentModel.ConnectionConfig.ToJsonString(), true, executeType: SpareTimeExecuteTypes.Parallel);
var starTime = comtentModel.startTime?.TimeStampToDateTime();
var endTime = comtentModel.endTime?.TimeStampToDateTime();
var interval = 1;
if (DateTime.Now < starTime)
{
interval = (starTime.ParseToDateTime() - DateTime.Now).TotalMilliseconds.ParseToInt();
}
SpareTime.DoOnce(interval, action, "Once_" + input.Id);
SpareTime.Do(
() =>
{
var isRun = comtentModel.endTime.IsNullOrEmpty() ? DateTime.Now >= starTime : DateTime.Now >= starTime && DateTime.Now < endTime;
if (isRun)
{
return SpareTime.GetCronNextOccurrence(comtentModel.cron);
}
else
{
return null;
}
},
action, input.Id, comtentModel.ConnectionConfig.ToJsonString(), true, executeType: SpareTimeExecuteTypes.Parallel, cancelInNoneNextTime: false);
}
private async Task AddJob(TimeTaskEntity input)
{
//ContentModel? comtentModel = input.ExecuteContent.ToObject();
//var starTime = comtentModel.startTime?.TimeStampToDateTime();
//var endTime = comtentModel.endTime?.TimeStampToDateTime();
//var jobBuilder = JobBuilder.Create(async (context, stoppingToken) =>
//{
// Console.WriteLine(string.Format("{0}在执行任务,执行时间{1},触发时间:{1}", context.JobId, context.ExecutingTime, context.OccurrenceTime));
// if (!input.ExecuteType.Equals("3"))
// {
// var msg = await PerformJob(input);
// }
//});
//jobBuilder.SetJobId(input.Id);
//jobBuilder.SetGroupName(input.FullName);
//var triggerBuilder = TriggerBuilder.Create(input.ExecuteCycleJson, CronStringFormat.WithSeconds);
//triggerBuilder.SetStartTime(starTime);
//triggerBuilder.SetEndTime(endTime);
////triggerBuilder.SetRunOnStart(true);
//_schedulerFactory.AddJob(jobBuilder, triggerBuilder);
}
///
/// 获取所有本地任务.
///
///
private async Task> GetTaskMethods()
{
//var taskMethods = await _cacheManager.GetAsync>(CommonConst.CACHEKEYTIMERJOB);
//if (taskMethods != null) return taskMethods;
//// 获取所有本地任务方法,必须有spareTimeAttribute特性
//taskMethods = App.EffectiveTypes
// .Where(u => u.IsClass && !u.IsInterface && !u.IsAbstract && typeof(ISpareTimeWorker).IsAssignableFrom(u))
// .SelectMany(u => u.GetMethods(BindingFlags.Public | BindingFlags.Instance)
// .Where(m => m.IsDefined(typeof(SpareTimeAttribute), false) &&
// m.GetParameters().Length == 2 &&
// m.GetParameters()[0].ParameterType == typeof(SpareTimer) &&
// m.GetParameters()[1].ParameterType == typeof(long) && m.ReturnType == typeof(void))
// .Select(m =>
// {
// // 默认获取第一条任务特性
// var spareTimeAttribute = m.GetCustomAttribute();
// return new TaskMethodInfo
// {
// id = $"{m.DeclaringType.Name}/{m.Name}",
// fullName = spareTimeAttribute.WorkerName,
// RequestUrl = $"{m.DeclaringType.Name}/{m.Name}",
// cron = spareTimeAttribute.CronExpression,
// DoOnce = spareTimeAttribute.DoOnce,
// ExecuteType = spareTimeAttribute.ExecuteType,
// Interval = (int)spareTimeAttribute.Interval / 1000,
// StartNow = spareTimeAttribute.StartNow,
// RequestType = RequestTypeEnum.BuiltIn,
// Remark = spareTimeAttribute.Description,
// TimerType = string.IsNullOrEmpty(spareTimeAttribute.CronExpression) ? SpareTimeTypes.Interval : SpareTimeTypes.Cron,
// MethodName = m.Name,
// DeclaringType = m.DeclaringType
// };
// })).ToList();
//await _cacheManager.SetAsync(CommonConst.CACHEKEYTIMERJOB, taskMethods);
//return taskMethods;
return new List();
}
#endregion
}