zhaolei
9 days ago 921de2254ff5712a44ed8575ee8efe34252f6603
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
using Prow.Cache;
using Prow.Web;
using Microsoft.AspNetCore.Http;
using Microsoft.Extensions.DependencyInjection;
using System;
using System.Linq;
using System.Net;
 
namespace Microsoft.AspNetCore.Builder
{
    /// <summary>
    /// 当前用户统计中间件
    /// </summary>
    public static class OnlineUsersMiddlewareExtensions
    {
        /// <summary>
        /// 添加 当前用户中间件
        /// </summary>
        /// <param name="builder">IApplicationBuilder 实例</param>
        /// <param name="filter">请求地址过滤器,返回真时进入在线用户中间件</param>
        /// <param name="callback">在线用户回调方法,用于调用方扩展</param>
        /// <returns></returns>
        public static IApplicationBuilder UseOnlineUsers(this IApplicationBuilder builder, Func<HttpContext, bool>? filter = null, Action<HttpContext, OnlineUser>? callback = null) => builder.UseWhen(context => filter == null ? context.Filter() : filter.Invoke(context), app => app.Use(async (context, next) =>
        {
            await System.Threading.Tasks.Task.Run(() =>
            {
                var onlineUserSvr = context.RequestServices.GetRequiredService<IOnlineUsers>();
                var locator = context.RequestServices.GetRequiredService<IIPLocatorProvider>();
                var proxy = new Func<AutoExpireCacheEntry<OnlineUser>, Action?, AutoExpireCacheEntry<OnlineUser>>((c, action) =>
                {
                    var v = c.Value;
                    v.LastAccessTime = DateTime.Now;
                    v.Method = context.Request.Method;
                    v.RequestUrl = context.Request.Path;
                    v.AddRequestUrl(context.Request.Path);
                    action?.Invoke();
                    callback?.Invoke(context, v);
                    return c;
                });
                onlineUserSvr.AddOrUpdate(context.Connection.Id ?? "", key =>
                {
                    var agent = context.Request.Headers["User-Agent"];
                    var userAgent = string.IsNullOrEmpty(agent) ? null : new UserAgent(agent);
                    var v = new OnlineUser
                    {
                        UserAgent = agent,
                        ConnectionId = key,
                        Ip = context.Connection.RemoteIpAddress.ToIPv4String(),
                        Browser = userAgent == null ? "Unknown" : $"{userAgent.Browser?.Name} {userAgent.Browser?.Version}",
                        OS = userAgent == null ? "Unknown" : $"{userAgent.OS?.Name} {userAgent.OS?.Version}",
                        FirstAccessTime = DateTime.Now,
                        Referer = context.Request.Headers["Referer"]
                    };
                    v.Location = locator?.Locate(v.Ip) ?? "";
                    return proxy(new AutoExpireCacheEntry<OnlineUser>(v, 1000 * 60, __ => onlineUserSvr.TryRemove(key, out _)), null);
                }, (key, v) => proxy(v, () => v.Reset()));
            });
            await next();
        }));
 
        private static bool Filter(this HttpContext context)
        {
            var url = context.Request.Path;
            return !new string[] { "/api", "/NotiHub", "/swagger" }.Any(r => url.StartsWithSegments(r, StringComparison.OrdinalIgnoreCase));
        }
    }
}