Browse Source

add dashbaord feature

master
yangxiaodong 7 years ago
parent
commit
2f4e78d641
10 changed files with 331 additions and 35 deletions
  1. +1
    -1
      src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs
  2. +4
    -12
      src/DotNetCore.CAP/CAP.DashboardMiddleware.cs
  3. +14
    -8
      src/DotNetCore.CAP/CAP.DashboardOptionsExtensions.cs
  4. +33
    -0
      src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs
  5. +195
    -0
      src/DotNetCore.CAP/Dashboard/DashboardRoutes.cs
  6. +3
    -3
      src/DotNetCore.CAP/Dashboard/JobHistoryRenderer.cs
  7. +4
    -4
      src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cshtml
  8. +3
    -3
      src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.generated.cs
  9. +72
    -0
      src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs
  10. +2
    -4
      src/DotNetCore.CAP/DotNetCore.CAP.csproj

+ 1
- 1
src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs View File

@@ -49,7 +49,7 @@ namespace Microsoft.AspNetCore.Builder
throw new InvalidOperationException("Add Cap must be called on the service collection.");
}

app.Map(new PathString(pathMatch), x => x.UseMiddleware<DashboardMiddleware>(storage, options, routes));
app.Map(new PathString(pathMatch), x => x.UseMiddleware<DashboardMiddleware>());

return app;
}


+ 4
- 12
src/DotNetCore.CAP/CAP.DashboardMiddleware.cs View File

@@ -1,7 +1,5 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using DotNetCore.CAP.Dashboard;
using Microsoft.AspNetCore.Http;
@@ -17,15 +15,10 @@ namespace DotNetCore.CAP

public DashboardMiddleware(RequestDelegate next, DashboardOptions options, IStorage storage, RouteCollection routes)
{
if (next == null) throw new ArgumentNullException(nameof(next));
if (storage == null) throw new ArgumentNullException(nameof(storage));
if (options == null) throw new ArgumentNullException(nameof(options));
if (routes == null) throw new ArgumentNullException(nameof(routes));

_next = next;
_options = options;
_storage = storage;
_routes = routes;
_next = next ?? throw new ArgumentNullException(nameof(next));
_options = options ?? throw new ArgumentNullException(nameof(options));
_storage = storage ?? throw new ArgumentNullException(nameof(storage));
_routes = routes ?? throw new ArgumentNullException(nameof(routes));
}

public Task Invoke(HttpContext httpContext)
@@ -38,7 +31,6 @@ namespace DotNetCore.CAP
return _next.Invoke(httpContext);
}

// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var filter in _options.Authorization)
{
if (!filter.Authorize(context))


+ 14
- 8
src/DotNetCore.CAP/CAP.DashboardOptionsExtensions.cs View File

@@ -1,10 +1,12 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetCore.CAP
{
using DotNetCore.CAP.Dashboard;
using Microsoft.Extensions.DependencyInjection;

internal sealed class DashboardOptionsExtension : ICapOptionsExtension
{
private readonly Action<DashboardOptions> _options;
@@ -19,17 +21,22 @@ namespace DotNetCore.CAP
var dashboardOptions = new DashboardOptions();
_options?.Invoke(dashboardOptions);
services.AddSingleton(dashboardOptions);
services.AddSingleton(DashboardRoutes.Routes);
}
}
}

namespace Microsoft.Extensions.DependencyInjection
{
using DotNetCore.CAP;

public static class CapOptionsExtensions
{
/// <summary>
/// Configuration to use kafka in CAP.
/// </summary>
/// <param name="options">Provides programmatic configuration for the kafka .</param>
/// <returns></returns>
public static CapOptions UseDashboard(this CapOptions capOptions)
{
return capOptions.UseDashboard(opt => {});
}
public static CapOptions UseDashboard(this CapOptions capOptions, Action<DashboardOptions> options)
{
if (options == null) throw new ArgumentNullException(nameof(options));
@@ -39,5 +46,4 @@ namespace DotNetCore.CAP
return capOptions;
}
}

}
}

+ 33
- 0
src/DotNetCore.CAP/Dashboard/BatchCommandDispatcher.cs View File

@@ -0,0 +1,33 @@
using System;
using System.Net;
using System.Threading.Tasks;

namespace DotNetCore.CAP.Dashboard
{
internal class BatchCommandDispatcher : IDashboardDispatcher
{
private readonly Action<DashboardContext, string> _command;

public BatchCommandDispatcher(Action<DashboardContext, string> command)
{
_command = command;
}

public async Task Dispatch(DashboardContext context)
{
var jobIds = await context.Request.GetFormValuesAsync("jobs[]");
if (jobIds.Count == 0)
{
context.Response.StatusCode = 422;
return;
}

foreach (var jobId in jobIds)
{
_command(context, jobId);
}

context.Response.StatusCode = (int)HttpStatusCode.NoContent;
}
}
}

+ 195
- 0
src/DotNetCore.CAP/Dashboard/DashboardRoutes.cs View File

@@ -0,0 +1,195 @@
using System.Reflection;
using DotNetCore.CAP.Dashboard.Pages;
using DotNetCore.CAP.Processor.States;

namespace DotNetCore.CAP.Dashboard
{
public static class DashboardRoutes
{
private static readonly string[] Javascripts =
{
"jquery-2.1.4.min.js",
"bootstrap.min.js",
"moment.min.js",
"moment-with-locales.min.js",
"d3.min.js",
"d3.layout.min.js",
"rickshaw.min.js",
"cap.js"
};

private static readonly string[] Stylesheets =
{
"bootstrap.min.css",
"rickshaw.min.css",
"cap.css"
};

static DashboardRoutes()
{
Routes = new RouteCollection();
Routes.AddRazorPage("/", x => new HomePage());
Routes.Add("/stats", new JsonStats());
#region Embedded static content

Routes.Add("/js[0-9]+", new CombinedResourceDispatcher(
"application/javascript",
GetExecutingAssembly(),
GetContentFolderNamespace("js"),
Javascripts));

Routes.Add("/css[0-9]+", new CombinedResourceDispatcher(
"text/css",
GetExecutingAssembly(),
GetContentFolderNamespace("css"),
Stylesheets));

Routes.Add("/fonts/glyphicons-halflings-regular/eot", new EmbeddedResourceDispatcher(
"application/vnd.ms-fontobject",
GetExecutingAssembly(),
GetContentResourceName("fonts", "glyphicons-halflings-regular.eot")));

Routes.Add("/fonts/glyphicons-halflings-regular/svg", new EmbeddedResourceDispatcher(
"image/svg+xml",
GetExecutingAssembly(),
GetContentResourceName("fonts", "glyphicons-halflings-regular.svg")));

Routes.Add("/fonts/glyphicons-halflings-regular/ttf", new EmbeddedResourceDispatcher(
"application/octet-stream",
GetExecutingAssembly(),
GetContentResourceName("fonts", "glyphicons-halflings-regular.ttf")));

Routes.Add("/fonts/glyphicons-halflings-regular/woff", new EmbeddedResourceDispatcher(
"font/woff",
GetExecutingAssembly(),
GetContentResourceName("fonts", "glyphicons-halflings-regular.woff")));

Routes.Add("/fonts/glyphicons-halflings-regular/woff2", new EmbeddedResourceDispatcher(
"font/woff2",
GetExecutingAssembly(),
GetContentResourceName("fonts", "glyphicons-halflings-regular.woff2")));

#endregion

#region Razor pages and commands

//Routes.AddRazorPage("/jobs/enqueued", x => new QueuesPage());
//Routes.AddRazorPage(
// "/jobs/enqueued/fetched/(?<Queue>.+)",
// x => new FetchedJobsPage(x.Groups["Queue"].Value));

//Routes.AddClientBatchCommand("/jobs/enqueued/delete", (client, jobId) => client.ChangeState(jobId, CreateDeletedState()));
//Routes.AddClientBatchCommand("/jobs/enqueued/requeue", (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState()));

//Routes.AddRazorPage(
// "/jobs/enqueued/(?<Queue>.+)",
// x => new EnqueuedJobsPage(x.Groups["Queue"].Value));

//Routes.AddRazorPage("/jobs/processing", x => new ProcessingJobsPage());
//Routes.AddClientBatchCommand(
// "/jobs/processing/delete",
// (client, jobId) => client.ChangeState(jobId, CreateDeletedState(), ProcessingState.StateName));

//Routes.AddClientBatchCommand(
// "/jobs/processing/requeue",
// (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState(), ProcessingState.StateName));

//Routes.AddRazorPage("/jobs/scheduled", x => new ScheduledJobsPage());

//Routes.AddClientBatchCommand(
// "/jobs/scheduled/enqueue",
// (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState(), ScheduledState.StateName));

//Routes.AddClientBatchCommand(
// "/jobs/scheduled/delete",
// (client, jobId) => client.ChangeState(jobId, CreateDeletedState(), ScheduledState.StateName));

//Routes.AddRazorPage("/jobs/succeeded", x => new SucceededJobs());
//Routes.AddClientBatchCommand(
// "/jobs/succeeded/requeue",
// (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState(), SucceededState.StateName));

//Routes.AddRazorPage("/jobs/failed", x => new FailedJobsPage());

//Routes.AddClientBatchCommand(
// "/jobs/failed/requeue",
// (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState(), FailedState.StateName));

//Routes.AddClientBatchCommand(
// "/jobs/failed/delete",
// (client, jobId) => client.ChangeState(jobId, CreateDeletedState(), FailedState.StateName));

//Routes.AddRazorPage("/jobs/deleted", x => new DeletedJobsPage());

//Routes.AddClientBatchCommand(
// "/jobs/deleted/requeue",
// (client, jobId) => client.ChangeState(jobId, CreateEnqueuedState(), DeletedState.StateName));

//Routes.AddRazorPage("/jobs/awaiting", x => new AwaitingJobsPage());
//Routes.AddClientBatchCommand("/jobs/awaiting/enqueue", (client, jobId) => client.ChangeState(
// jobId, CreateEnqueuedState(), AwaitingState.StateName));
//Routes.AddClientBatchCommand("/jobs/awaiting/delete", (client, jobId) => client.ChangeState(
// jobId, CreateDeletedState(), AwaitingState.StateName));

//Routes.AddCommand(
// "/jobs/actions/requeue/(?<JobId>.+)",
// context =>
// {
// var client = new BackgroundJobClient(context.Storage);
// return client.ChangeState(context.UriMatch.Groups["JobId"].Value, CreateEnqueuedState());
// });

//Routes.AddCommand(
// "/jobs/actions/delete/(?<JobId>.+)",
// context =>
// {
// var client = new BackgroundJobClient(context.Storage);
// return client.ChangeState(context.UriMatch.Groups["JobId"].Value, CreateDeletedState());
// });

//Routes.AddRazorPage("/jobs/details/(?<JobId>.+)", x => new JobDetailsPage(x.Groups["JobId"].Value));

//Routes.AddRazorPage("/recurring", x => new RecurringJobsPage());
//Routes.AddRecurringBatchCommand(
// "/recurring/remove",
// (manager, jobId) => manager.RemoveIfExists(jobId));

//Routes.AddRecurringBatchCommand(
// "/recurring/trigger",
// (manager, jobId) => manager.Trigger(jobId));

//Routes.AddRazorPage("/servers", x => new ServersPage());
//Routes.AddRazorPage("/retries", x => new RetriesPage());

#endregion
}

public static RouteCollection Routes { get; }

internal static string GetContentFolderNamespace(string contentFolder)
{
return $"{typeof (DashboardRoutes).Namespace}.Content.{contentFolder}";
}

internal static string GetContentResourceName(string contentFolder, string resourceName)
{
return $"{GetContentFolderNamespace(contentFolder)}.{resourceName}";
}

//private static DeletedState CreateDeletedState()
//{
// return new DeletedState { Reason = "Triggered via Dashboard UI" };
//}

private static EnqueuedState CreateEnqueuedState()
{
return new EnqueuedState();// { Reason = "Triggered via Dashboard UI" };
}

private static Assembly GetExecutingAssembly()
{
return typeof (DashboardRoutes).GetTypeInfo().Assembly;
}
}
}

+ 3
- 3
src/DotNetCore.CAP/Dashboard/JobHistoryRenderer.cs View File

@@ -20,7 +20,7 @@ namespace DotNetCore.CAP.Dashboard
[System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Performance", "CA1810:InitializeReferenceTypeStaticFieldsInline")]
static JobHistoryRenderer()
{
Register(SucceededState.StateName, SucceededRenderer);
Register(SuccessedState.StateName, SucceededRenderer);
Register(FailedState.StateName, FailedRenderer);
Register(ProcessingState.StateName, ProcessingRenderer);
Register(EnqueuedState.StateName, EnqueuedRenderer);
@@ -29,7 +29,7 @@ namespace DotNetCore.CAP.Dashboard
//Register(AwaitingState.StateName, AwaitingRenderer);

BackgroundStateColors.Add(EnqueuedState.StateName, "#F5F5F5");
BackgroundStateColors.Add(SucceededState.StateName, "#EDF7ED");
BackgroundStateColors.Add(SuccessedState.StateName, "#EDF7ED");
BackgroundStateColors.Add(FailedState.StateName, "#FAEBEA");
BackgroundStateColors.Add(ProcessingState.StateName, "#FCEFDC");
BackgroundStateColors.Add(ScheduledState.StateName, "#E0F3F8");
@@ -37,7 +37,7 @@ namespace DotNetCore.CAP.Dashboard
//BackgroundStateColors.Add(AwaitingState.StateName, "#F5F5F5");

ForegroundStateColors.Add(EnqueuedState.StateName, "#999");
ForegroundStateColors.Add(SucceededState.StateName, "#5cb85c");
ForegroundStateColors.Add(SuccessedState.StateName, "#5cb85c");
ForegroundStateColors.Add(FailedState.StateName, "#d9534f");
ForegroundStateColors.Add(ProcessingState.StateName, "#f0ad4e");
ForegroundStateColors.Add(ScheduledState.StateName, "#5bc0de");


+ 4
- 4
src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.cshtml View File

@@ -9,7 +9,7 @@
<!DOCTYPE html>
<html lang="@CultureInfo.CurrentUICulture.TwoLetterISOLanguageName">
<head>
<title>@Title - Hangfire</title>
<title>@Title - CAP</title>
<meta http-equiv="X-UA-Compatible" content="IE=edge">
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
@@ -29,7 +29,7 @@
<span class="icon-bar"></span>
<span class="icon-bar"></span>
</button>
<a class="navbar-brand" href="@Url.Home()">Hangfire Dashboard</a>
<a class="navbar-brand" href="@Url.Home()">CAP Dashboard</a>
</div>
<div class="collapse navbar-collapse">
@Html.RenderPartial(new Navigation())
@@ -58,7 +58,7 @@
<div class="container">
<ul class="list-inline credit">
<li>
<a href="http://hangfire.io/" target="_blank">Hangfire @($"{version.Major}.{version.Minor}.{version.Build}")
<a href="https://github.com/dotnetcore/cap/" target="_blank">Hangfire @($"{version.Major}.{version.Minor}.{version.Build}")
</a>
</li>
<li>@Storage</li>
@@ -68,7 +68,7 @@
</div>
</div>
<div id="hangfireConfig"
<div id="capConfig"
data-pollinterval="@StatsPollingInterval"
data-pollurl="@(Url.To("/stats"))">
</div>


+ 3
- 3
src/DotNetCore.CAP/Dashboard/Pages/LayoutPage.generated.cs View File

@@ -89,7 +89,7 @@ WriteLiteral("\">\r\n<head>\r\n <title>");
#line default
#line hidden
WriteLiteral(" - Hangfire</title>\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n " +
WriteLiteral(" - CAP</title>\r\n <meta http-equiv=\"X-UA-Compatible\" content=\"IE=edge\">\r\n " +
" <meta charset=\"utf-8\">\r\n <meta name=\"viewport\" content=\"width=device-width" +
", initial-scale=1.0\">\r\n");

@@ -136,7 +136,7 @@ WriteLiteral(@""">
#line default
#line hidden
WriteLiteral("\">Hangfire Dashboard</a>\r\n </div>\r\n <div cl" +
WriteLiteral("\">CAP Dashboard</a>\r\n </div>\r\n <div cl" +
"ass=\"collapse navbar-collapse\">\r\n ");


@@ -211,7 +211,7 @@ WriteLiteral(@"
<div class=""container"">
<ul class=""list-inline credit"">
<li>
<a href=""http://hangfire.io/"" target=""_blank"">Hangfire ");
<a href=""https://github.com/dotnetcore/cap/"" target=""_blank"">CAP ");




+ 72
- 0
src/DotNetCore.CAP/Dashboard/RouteCollectionExtensions.cs View File

@@ -0,0 +1,72 @@
using System;
using System.Text.RegularExpressions;

namespace DotNetCore.CAP.Dashboard
{
public static class RouteCollectionExtensions
{
public static void AddRazorPage(
this RouteCollection routes,
string pathTemplate,
Func<Match, RazorPage> pageFunc)
{
if (routes == null) throw new ArgumentNullException(nameof(routes));
if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate));
if (pageFunc == null) throw new ArgumentNullException(nameof(pageFunc));

routes.Add(pathTemplate, new RazorPageDispatcher(pageFunc));
}

public static void AddCommand(
this RouteCollection routes,
string pathTemplate,
Func<DashboardContext, bool> command)
{
if (routes == null) throw new ArgumentNullException(nameof(routes));
if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate));
if (command == null) throw new ArgumentNullException(nameof(command));

routes.Add(pathTemplate, new CommandDispatcher(command));
}

public static void AddBatchCommand(
this RouteCollection routes,
string pathTemplate,
Action<DashboardContext, string> command)
{
if (routes == null) throw new ArgumentNullException(nameof(routes));
if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate));
if (command == null) throw new ArgumentNullException(nameof(command));

routes.Add(pathTemplate, new BatchCommandDispatcher(command));
}

//public static void AddClientBatchCommand(
// this RouteCollection routes,
// string pathTemplate,
// [NotNull] Action<IBackgroundJobClient, string> command)
//{
// if (command == null) throw new ArgumentNullException(nameof(command));

// routes.AddBatchCommand(pathTemplate, (context, jobId) =>
// {
// var client = new BackgroundJobClient(context.Storage);
// command(client, jobId);
// });
//}

//public static void AddRecurringBatchCommand(
// this RouteCollection routes,
// string pathTemplate,
// Action<RecurringJobManager, string> command)
//{
// if (command == null) throw new ArgumentNullException(nameof(command));

// routes.AddBatchCommand(pathTemplate, (context, jobId) =>
// {
// var manager = new RecurringJobManager(context.Storage);
// command(manager, jobId);
// });
//}
}
}

+ 2
- 4
src/DotNetCore.CAP/DotNetCore.CAP.csproj View File

@@ -10,7 +10,6 @@
<ItemGroup>
<None Remove="Dashboard\Content\css\bootstrap.min.css" />
<None Remove="Dashboard\Content\css\hangfire.css" />
<None Remove="Dashboard\Content\css\rickshaw.min.css" />
<None Remove="Dashboard\Content\fonts\glyphicons-halflings-regular.eot" />
<None Remove="Dashboard\Content\fonts\glyphicons-halflings-regular.svg" />
@@ -20,7 +19,6 @@
<None Remove="Dashboard\Content\js\bootstrap.min.js" />
<None Remove="Dashboard\Content\js\d3.layout.min.js" />
<None Remove="Dashboard\Content\js\d3.min.js" />
<None Remove="Dashboard\Content\js\hangfire.js" />
<None Remove="Dashboard\Content\js\jquery-2.1.4.min.js" />
<None Remove="Dashboard\Content\js\moment-with-locales.min.js" />
<None Remove="Dashboard\Content\js\moment.min.js" />
@@ -29,7 +27,7 @@
<ItemGroup>
<EmbeddedResource Include="Dashboard\Content\css\bootstrap.min.css" />
<EmbeddedResource Include="Dashboard\Content\css\hangfire.css" />
<EmbeddedResource Include="Dashboard\Content\css\cap.css" />
<EmbeddedResource Include="Dashboard\Content\css\rickshaw.min.css" />
<EmbeddedResource Include="Dashboard\Content\fonts\glyphicons-halflings-regular.eot" />
<EmbeddedResource Include="Dashboard\Content\fonts\glyphicons-halflings-regular.svg" />
@@ -39,7 +37,7 @@
<EmbeddedResource Include="Dashboard\Content\js\bootstrap.min.js" />
<EmbeddedResource Include="Dashboard\Content\js\d3.layout.min.js" />
<EmbeddedResource Include="Dashboard\Content\js\d3.min.js" />
<EmbeddedResource Include="Dashboard\Content\js\hangfire.js" />
<EmbeddedResource Include="Dashboard\Content\js\cap.js" />
<EmbeddedResource Include="Dashboard\Content\js\jquery-2.1.4.min.js" />
<EmbeddedResource Include="Dashboard\Content\js\moment-with-locales.min.js" />
<EmbeddedResource Include="Dashboard\Content\js\moment.min.js" />


Loading…
Cancel
Save