233 lines
7.3 KiB
C#
233 lines
7.3 KiB
C#
using System.Reflection;
|
|
using AntJob.Data;
|
|
using AntJob.Data.Entity;
|
|
using AntJob.Models;
|
|
using AntJob.Server;
|
|
using AntJob.Server.Services;
|
|
using AntJob.Web.Models;
|
|
using Microsoft.AspNetCore.Authorization;
|
|
using Microsoft.AspNetCore.Mvc;
|
|
using Microsoft.AspNetCore.Mvc.Controllers;
|
|
using Microsoft.AspNetCore.Mvc.Filters;
|
|
using NewLife;
|
|
using NewLife.Cube;
|
|
using NewLife.Data;
|
|
using NewLife.Log;
|
|
using NewLife.Remoting;
|
|
using NewLife.Remoting.Models;
|
|
using NewLife.Serialization;
|
|
using NewLife.Web;
|
|
using ApiFilterAttribute = NewLife.Remoting.Extensions.ApiFilterAttribute;
|
|
using IActionFilter = Microsoft.AspNetCore.Mvc.Filters.IActionFilter;
|
|
|
|
namespace AntJob.Web.Controllers;
|
|
|
|
[ApiController]
|
|
[Route("[controller]")]
|
|
public class AntJobController : ControllerBase, IActionFilter
|
|
{
|
|
///// <summary>令牌</summary>
|
|
//public String Token { get; private set; }
|
|
|
|
/// <summary>用户主机</summary>
|
|
public String UserHost => HttpContext.GetUserHost();
|
|
|
|
private App _App;
|
|
private IDictionary<String, Object> _args;
|
|
private AntJobSetting _setting;
|
|
private readonly AppService _appService;
|
|
private readonly JobService _jobService;
|
|
|
|
#region 构造
|
|
public AntJobController(AppService appService, JobService jobService, AntJobSetting setting)
|
|
{
|
|
_appService = appService;
|
|
_jobService = jobService;
|
|
_setting = setting;
|
|
}
|
|
|
|
void IActionFilter.OnActionExecuting(ActionExecutingContext context)
|
|
{
|
|
_args = context.ActionArguments;
|
|
|
|
var token = ApiFilterAttribute.GetToken(context.HttpContext);
|
|
|
|
try
|
|
{
|
|
if (context.ActionDescriptor is ControllerActionDescriptor act && !act.MethodInfo.IsDefined(typeof(AllowAnonymousAttribute)))
|
|
{
|
|
var rs = !token.IsNullOrEmpty() && OnAuthorize(token);
|
|
if (!rs) throw new ApiException(403, "认证失败");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var traceId = DefaultSpan.Current?.TraceId;
|
|
context.Result = ex is ApiException aex
|
|
? new JsonResult(new { code = aex.Code, data = aex.Message, traceId })
|
|
: new JsonResult(new { code = 500, data = ex.Message, traceId });
|
|
|
|
WriteError(ex, context);
|
|
}
|
|
}
|
|
|
|
void IActionFilter.OnActionExecuted(ActionExecutedContext context)
|
|
{
|
|
if (context.Exception != null) WriteError(context.Exception, context);
|
|
}
|
|
|
|
protected Boolean OnAuthorize(String token)
|
|
{
|
|
var (app, ex) = _appService.DecodeToken(token, _setting.TokenSecret);
|
|
_App = app;
|
|
if (ex != null) throw ex;
|
|
|
|
return app != null;
|
|
}
|
|
|
|
private void WriteError(Exception ex, ActionContext context)
|
|
{
|
|
// 拦截全局异常,写日志
|
|
var action = context.HttpContext.Request.Path + "";
|
|
if (context.ActionDescriptor is ControllerActionDescriptor act) action = $"{act.ControllerName}/{act.ActionName}";
|
|
|
|
_appService.WriteHistory(_App, action, false, ex?.GetTrue() + Environment.NewLine + _args?.ToJson(true), UserHost);
|
|
}
|
|
#endregion
|
|
|
|
#region 登录
|
|
/// <summary>应用登录</summary>
|
|
/// <param name="model">模型</param>
|
|
/// <returns></returns>
|
|
[AllowAnonymous]
|
|
[HttpPost(nameof(Login))]
|
|
public LoginResponse Login(LoginModel model)
|
|
{
|
|
if (model.Code.IsNullOrEmpty()) throw new ArgumentNullException(nameof(model.Code));
|
|
|
|
var sessionId = $"{model.Code}@{UserHost}";
|
|
var (app, online, rs) = _appService.Login(model, sessionId, UserHost);
|
|
|
|
return rs;
|
|
}
|
|
|
|
[ApiFilter]
|
|
public TokenModel Token([FromBody] TokenInModel model)
|
|
{
|
|
var set = _setting;
|
|
|
|
if (model.grant_type.IsNullOrEmpty()) model.grant_type = "password";
|
|
|
|
var ip = HttpContext.GetUserHost();
|
|
var clientId = model.ClientId;
|
|
|
|
try
|
|
{
|
|
// 密码模式
|
|
if (model.grant_type == "password")
|
|
{
|
|
var sessionId = $"{model.UserName}@{ip}";
|
|
var (app, online, rs) = _appService.Login(new LoginModel { Code = model.UserName, Secret = model.Password }, sessionId, ip);
|
|
|
|
var tokenModel = _appService.IssueToken(app.Name, set);
|
|
|
|
_appService.WriteHistory(app, "Authorize", true, model.ToJson(), ip);
|
|
|
|
return tokenModel;
|
|
}
|
|
// 刷新令牌
|
|
else if (model.grant_type == "refresh_token")
|
|
{
|
|
var (app, ex) = _appService.DecodeToken(model.refresh_token, set.TokenSecret);
|
|
|
|
if (ex != null)
|
|
{
|
|
_appService.WriteHistory(app, "RefreshToken", false, ex.ToString(), ip);
|
|
throw ex;
|
|
}
|
|
|
|
var tokenModel = _appService.IssueToken(app.Name, set);
|
|
|
|
//app.WriteHistory("RefreshToken", true, model.refresh_token, olt?.Version, ip, clientId);
|
|
|
|
return tokenModel;
|
|
}
|
|
else
|
|
{
|
|
throw new NotSupportedException($"未支持 grant_type={model.grant_type}");
|
|
}
|
|
}
|
|
catch (Exception ex)
|
|
{
|
|
var app = App.FindByName(model.UserName);
|
|
_appService.WriteHistory(app, "Authorize", false, ex.ToString(), ip);
|
|
|
|
throw;
|
|
}
|
|
}
|
|
|
|
/// <summary>获取当前应用的所有在线实例</summary>
|
|
/// <returns></returns>
|
|
[HttpGet(nameof(GetPeers))]
|
|
public PeerModel[] GetPeers() => _appService.GetPeers(_App);
|
|
#endregion
|
|
|
|
#region 业务
|
|
/// <summary>获取指定名称的作业</summary>
|
|
/// <returns></returns>
|
|
[HttpGet(nameof(GetJobs))]
|
|
public IJob[] GetJobs() => _jobService.GetJobs(_App);
|
|
|
|
/// <summary>批量添加作业</summary>
|
|
/// <param name="jobs"></param>
|
|
/// <returns></returns>
|
|
[HttpPost(nameof(AddJobs))]
|
|
public String[] AddJobs(JobModel[] jobs)
|
|
{
|
|
if (jobs == null || jobs.Length == 0) return [];
|
|
|
|
return _jobService.AddJobs(_App, jobs);
|
|
}
|
|
|
|
/// <summary>申请作业任务</summary>
|
|
/// <param name="model">模型</param>
|
|
/// <returns></returns>
|
|
[HttpPost(nameof(Acquire))]
|
|
public ITask[] Acquire(AcquireModel model)
|
|
{
|
|
var job = model.Job?.Trim();
|
|
if (job.IsNullOrEmpty()) return [];
|
|
|
|
var sessionId = $"{_App.Name}@{UserHost}";
|
|
var online = _appService.GetOnline(_App, sessionId, UserHost);
|
|
|
|
return _jobService.Acquire(_App, model, online);
|
|
}
|
|
|
|
/// <summary>生产消息</summary>
|
|
/// <param name="model">模型</param>
|
|
/// <returns></returns>
|
|
[HttpPost(nameof(Produce))]
|
|
public Int32 Produce(ProduceModel model)
|
|
{
|
|
var messages = model?.Messages?.Where(e => !e.IsNullOrEmpty()).Distinct().ToArray();
|
|
if (messages == null || messages.Length == 0) return 0;
|
|
|
|
return _jobService.Produce(_App, model);
|
|
}
|
|
|
|
/// <summary>报告状态(进度、成功、错误)</summary>
|
|
/// <param name="task"></param>
|
|
/// <returns></returns>
|
|
[HttpPost(nameof(Report))]
|
|
public Boolean Report(TaskResult task)
|
|
{
|
|
if (task == null || task.ID == 0) throw new InvalidOperationException("无效操作 TaskID=" + task?.ID);
|
|
|
|
var sessionId = $"{_App.Name}@{UserHost}";
|
|
var online = _appService.GetOnline(_App, sessionId, UserHost);
|
|
return _jobService.Report(_App, task, online);
|
|
}
|
|
#endregion
|
|
}
|