Browse Source

add dashboard

master
yangxiaodong 7 years ago
parent
commit
2d5bb1b0a7
8 changed files with 255 additions and 1 deletions
  1. +20
    -0
      src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs
  2. +61
    -0
      src/DotNetCore.CAP/CAP.DashboardMiddleware.cs
  3. +0
    -0
      src/DotNetCore.CAP/CAP.DashboardOptions.cs
  4. +43
    -0
      src/DotNetCore.CAP/CAP.DashboardOptionsExtensions.cs
  5. +19
    -0
      src/DotNetCore.CAP/Dashboard/DashboardContext.cs
  6. +27
    -1
      src/DotNetCore.CAP/Dashboard/DashboardRequest.cs
  7. +37
    -0
      src/DotNetCore.CAP/Dashboard/DashboardResponse.cs
  8. +48
    -0
      src/DotNetCore.CAP/Dashboard/RouteCollection.cs

+ 20
- 0
src/DotNetCore.CAP/CAP.AppBuilderExtensions.cs View File

@@ -1,5 +1,6 @@
using System;
using DotNetCore.CAP;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;

namespace Microsoft.AspNetCore.Builder
@@ -33,5 +34,24 @@ namespace Microsoft.AspNetCore.Builder
bootstrapper.BootstrapAsync();
return app;
}

public static IApplicationBuilder UseCapDashboard(
this IApplicationBuilder app,
string pathMatch = "/cap")
{
if (app == null) throw new ArgumentNullException(nameof(app));
if (pathMatch == null) throw new ArgumentNullException(nameof(pathMatch));

var marker = app.ApplicationServices.GetService<CapMarkerService>();

if (marker == null)
{
throw new InvalidOperationException("Add Cap must be called on the service collection.");
}

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

return app;
}
}
}

+ 61
- 0
src/DotNetCore.CAP/CAP.DashboardMiddleware.cs View File

@@ -0,0 +1,61 @@
using System;
using System.Collections.Generic;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using DotNetCore.CAP.Dashboard;
using Microsoft.AspNetCore.Http;

namespace DotNetCore.CAP
{
public class DashboardMiddleware
{
private readonly DashboardOptions _options;
private readonly RequestDelegate _next;
private readonly IStorage _storage;
private readonly RouteCollection _routes;

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;
}

public Task Invoke(HttpContext httpContext)
{
var context = new CapDashboardContext(_storage, _options, httpContext);
var findResult = _routes.FindDispatcher(httpContext.Request.Path.Value);

if (findResult == null)
{
return _next.Invoke(httpContext);
}

// ReSharper disable once LoopCanBeConvertedToQuery
foreach (var filter in _options.Authorization)
{
if (!filter.Authorize(context))
{
var isAuthenticated = httpContext.User?.Identity?.IsAuthenticated;

httpContext.Response.StatusCode = isAuthenticated == true
? (int)HttpStatusCode.Forbidden
: (int)HttpStatusCode.Unauthorized;

return Task.FromResult(0);
}
}

context.UriMatch = findResult.Item2;

return findResult.Item1.Dispatch(context);
}
}
}

src/DotNetCore.CAP/DashboardOptions.cs → src/DotNetCore.CAP/CAP.DashboardOptions.cs View File


+ 43
- 0
src/DotNetCore.CAP/CAP.DashboardOptionsExtensions.cs View File

@@ -0,0 +1,43 @@
using System;
using System.Collections.Generic;
using System.Text;
using Microsoft.Extensions.DependencyInjection;

namespace DotNetCore.CAP
{
internal sealed class DashboardOptionsExtension : ICapOptionsExtension
{
private readonly Action<DashboardOptions> _options;

public DashboardOptionsExtension(Action<DashboardOptions> option)
{
_options = option;
}

public void AddServices(IServiceCollection services)
{
var dashboardOptions = new DashboardOptions();
_options?.Invoke(dashboardOptions);
services.AddSingleton(dashboardOptions);
}
}


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, Action<DashboardOptions> options)
{
if (options == null) throw new ArgumentNullException(nameof(options));

capOptions.RegisterExtension(new DashboardOptionsExtension(options));

return capOptions;
}
}

}

+ 19
- 0
src/DotNetCore.CAP/Dashboard/DashboardContext.cs View File

@@ -2,6 +2,7 @@
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;
using Microsoft.AspNetCore.Http;

namespace DotNetCore.CAP.Dashboard
{
@@ -24,4 +25,22 @@ namespace DotNetCore.CAP.Dashboard
public DashboardRequest Request { get; protected set; }
public DashboardResponse Response { get; protected set; }
}

public sealed class CapDashboardContext : DashboardContext
{
public CapDashboardContext(
IStorage storage,
DashboardOptions options,
HttpContext httpContext)
: base(storage, options)
{
if (httpContext == null) throw new ArgumentNullException(nameof(httpContext));

HttpContext = httpContext;
Request = new CapDashboardRequest(httpContext);
Response = new CapDashboardResponse(httpContext);
}

public HttpContext HttpContext { get; }
}
}

+ 27
- 1
src/DotNetCore.CAP/Dashboard/DashboardRequest.cs View File

@@ -1,5 +1,7 @@
using System.Collections.Generic;
using System;
using System.Collections.Generic;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace DotNetCore.CAP.Dashboard
{
@@ -15,4 +17,28 @@ namespace DotNetCore.CAP.Dashboard
public abstract string GetQuery(string key);
public abstract Task<IList<string>> GetFormValuesAsync(string key);
}

internal sealed class CapDashboardRequest : DashboardRequest
{
private readonly HttpContext _context;

public CapDashboardRequest(HttpContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
_context = context;
}

public override string Method => _context.Request.Method;
public override string Path => _context.Request.Path.Value;
public override string PathBase => _context.Request.PathBase.Value;
public override string LocalIpAddress => _context.Connection.LocalIpAddress.ToString();
public override string RemoteIpAddress => _context.Connection.RemoteIpAddress.ToString();
public override string GetQuery(string key) => _context.Request.Query[key];

public override async Task<IList<string>> GetFormValuesAsync(string key)
{
var form = await _context.Request.ReadFormAsync();
return form[key];
}
}
}

+ 37
- 0
src/DotNetCore.CAP/Dashboard/DashboardResponse.cs View File

@@ -1,6 +1,8 @@
using System;
using System.Globalization;
using System.IO;
using System.Threading.Tasks;
using Microsoft.AspNetCore.Http;

namespace DotNetCore.CAP.Dashboard
{
@@ -14,4 +16,39 @@ namespace DotNetCore.CAP.Dashboard
public abstract void SetExpire(DateTimeOffset? value);
public abstract Task WriteAsync(string text);
}

internal sealed class CapDashboardResponse : DashboardResponse
{
private readonly HttpContext _context;

public CapDashboardResponse( HttpContext context)
{
if (context == null) throw new ArgumentNullException(nameof(context));
_context = context;
}

public override string ContentType
{
get { return _context.Response.ContentType; }
set { _context.Response.ContentType = value; }
}

public override int StatusCode
{
get { return _context.Response.StatusCode; }
set { _context.Response.StatusCode = value; }
}

public override Stream Body => _context.Response.Body;

public override Task WriteAsync(string text)
{
return _context.Response.WriteAsync(text);
}

public override void SetExpire(DateTimeOffset? value)
{
_context.Response.Headers["Expires"] = value?.ToString("r", CultureInfo.InvariantCulture);
}
}
}

+ 48
- 0
src/DotNetCore.CAP/Dashboard/RouteCollection.cs View File

@@ -0,0 +1,48 @@
using System;
using System.Collections.Generic;
using System.Text;
using System.Text.RegularExpressions;

namespace DotNetCore.CAP.Dashboard
{
public class RouteCollection
{
private readonly List<Tuple<string, IDashboardDispatcher>> _dispatchers
= new List<Tuple<string, IDashboardDispatcher>>();

public void Add(string pathTemplate, IDashboardDispatcher dispatcher)
{
if (pathTemplate == null) throw new ArgumentNullException(nameof(pathTemplate));
if (dispatcher == null) throw new ArgumentNullException(nameof(dispatcher));

_dispatchers.Add(new Tuple<string, IDashboardDispatcher>(pathTemplate, dispatcher));
}

public Tuple<IDashboardDispatcher, Match> FindDispatcher(string path)
{
if (path.Length == 0) path = "/";

foreach (var dispatcher in _dispatchers)
{
var pattern = dispatcher.Item1;

if (!pattern.StartsWith("^", StringComparison.OrdinalIgnoreCase))
pattern = "^" + pattern;
if (!pattern.EndsWith("$", StringComparison.OrdinalIgnoreCase))
pattern += "$";

var match = Regex.Match(
path,
pattern,
RegexOptions.CultureInvariant | RegexOptions.IgnoreCase | RegexOptions.Singleline);

if (match.Success)
{
return new Tuple<IDashboardDispatcher, Match>(dispatcher.Item2, match);
}
}

return null;
}
}
}

Loading…
Cancel
Save