增加IHttpHost,解除HttpSession对HttpServer的依赖; IHttpContext增加ISocketRemote,解除其对INetSession的依赖; 优化WebSocketCodec,便于配合标准编码器使用
智能大石头 编写于 2024-05-09 00:15:22 石头 提交于 2024-06-08 07:19:30
X
using System.ComponentModel;
using NewLife.Net;

namespace NewLife.Http;

/// <summary>Http服务器</summary>
[DisplayName("Http服务器")]
public class HttpServer : NetServer, IHttpHost
{
    #region 属性
    /// <summary>Http响应头Server名称</summary>
    public String ServerName { get; set; }

    /// <summary>路由映射</summary>
    public IDictionary<String, IHttpHandler> Routes { get; set; } = new Dictionary<String, IHttpHandler>(StringComparer.OrdinalIgnoreCase);
    #endregion

    /// <summary>实例化</summary>
    public HttpServer()
    {
        Name = "Http";
        Port = 80;
        ProtocolType = NetType.Http;

        var ver = GetType().Assembly.GetName().Version;
        ServerName = $"NewLife-HttpServer/{ver.Major}.{ver.Minor}";
    }

    ///// <summary>创建会话</summary>
    ///// <param name="session"></param>
    ///// <returns></returns>
    //protected override INetSession CreateSession(ISocketSession session) => new HttpSession();

    /// <summary>为会话创建网络数据处理器。可作为业务处理实现,也可以作为前置协议解析</summary>
    /// <param name="session"></param> 
    /// <returns></returns>
    public override INetHandler? CreateHandler(INetSession session) => new HttpSession();

    #region 方法
    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map(String path, IHttpHandler handler) => Routes[path] = handler;

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map(String path, HttpProcessDelegate handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<TResult>(String path, Func<TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<TModel, TResult>(String path, Func<TModel, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, TResult>(String path, Func<T1, T2, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, T3, TResult>(String path, Func<T1, T2, T3, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射路由处理器</summary>
    /// <param name="path"></param>
    /// <param name="handler"></param>
    public void Map<T1, T2, T3, T4, TResult>(String path, Func<T1, T2, T3, T4, TResult> handler) => Routes[path] = new DelegateHandler { Callback = handler };

    /// <summary>映射控制器</summary>
    /// <typeparam name="TController"></typeparam>
    /// <param name="path"></param>
    public void MapController<TController>(String path = null) => MapController(typeof(TController), path);

    /// <summary>映射控制器</summary>
    /// <param name="controllerType"></param>
    /// <param name="path"></param>
    public void MapController(Type controllerType, String path = null)
    {
        if (path.IsNullOrEmpty()) path = "/" + controllerType.Name.TrimEnd("Controller");

        var path2 = path.EnsureEnd("/*");
        Routes[path2] = new ControllerHandler { ControllerType = controllerType };
    }

    /// <summary>映射静态文件</summary>
    /// <param name="path">映射路径,如 /js</param>
    /// <param name="contentPath">内容目录,如 /wwwroot/js</param>
    public void MapStaticFiles(String path, String contentPath)
    {
        path = path.EnsureEnd("/");
        var path2 = path.EnsureEnd("*");
        Routes[path2] = new StaticFilesHandler { Path = path, ContentPath = contentPath };
    }

    private readonly IDictionary<String, String> _maps = new Dictionary<String, String>(StringComparer.OrdinalIgnoreCase);
    /// <summary>匹配处理器</summary>
    /// <param name="path"></param>
    /// <param name="request"></param>
    /// <returns></returns>
    public IHttpHandler? MatchHandler(String path, HttpRequest? request)
    {
        if (Routes.TryGetValue(path, out var handler)) return handler;

        // 判断缓存
        if (_maps.TryGetValue(path, out var p) &&
            Routes.TryGetValue(p, out handler)) return handler;

        // 模糊匹配
        foreach (var item in Routes)
        {
            if (item.Key.Contains("*") && item.Key.IsMatch(path))
            {
                if (Routes.TryGetValue(item.Key, out handler))
                {
                    // 大于3段的路径不做缓存,避免动态Url引起缓存膨胀
                    if (handler is StaticFilesHandler || path.Split('/').Length <= 3) _maps[path] = item.Key;

                    return handler;
                }
            }
        }

        return null;
    }
    #endregion
}