zhaolei
2020-11-20 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
using Prow.Cache;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Linq;
using System.Net.Http;
 
namespace Prow.Web
{
    /// <summary>
    /// 默认 IP 地理位置定位器
    /// </summary>
    internal class DefaultIPLocatorProvider : IIPLocatorProvider
    {
        private readonly ConcurrentDictionary<string, AutoExpireCacheEntry<string>> _ipPool = new ConcurrentDictionary<string, AutoExpireCacheEntry<string>>();
        private readonly IPLocatorOption _option = new IPLocatorOption();
 
        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="factory"></param>
        /// <param name="logger"></param>
        public DefaultIPLocatorProvider(IHttpClientFactory factory, ILogger<DefaultIPLocatorProvider> logger)
        {
            _option.HttpClient = factory.CreateClient(OnlineUsersServicesCollectionExtensions.IPSvrHttpClientName);
            _option.Logger = logger;
        }
 
        /// <summary>
        /// 定位方法
        /// </summary>
        /// <param name="ip"></param>
        /// <returns></returns>
        public string Locate(string ip)
        {
            _option.IP = ip;
            IPLocatorServicesCollectionExtensions.ConfigureOption(_option);
 
            // 解析本机地址
            if (string.IsNullOrEmpty(ip) || _option.Localhosts.Any(p => p == ip)) return "本地连接";
 
            // IP定向器地址未设置
            if (string.IsNullOrEmpty(_option.Url)) return string.Empty;
 
            return _ipPool.GetOrAdd(ip, key => new AutoExpireCacheEntry<string>(CreateLocator(_option.LocatorName, _option.LocatorFactory).Locate(_option) ?? string.Empty, _option.Period, __ => _ipPool.TryRemove(key, out _))).Value;
        }
 
        /// <summary>
        /// 根据指定定位器名称创建定位器方法
        /// </summary>
        /// <param name="name">IP定位器名称</param>
        /// <param name="locatorFactory">IP定位器工厂</param>
        /// <returns></returns>
        private static IIPLocator CreateLocator(string name, Func<string, IIPLocator>? locatorFactory = null) => (locatorFactory ??
            new Func<string, IIPLocator>(key => key.ToUpperInvariant() switch
        {
            "BAIDUIPSVR" => new BaiDuIPLocator(),
            "JUHEIPSVR" => new JuheIPLocator(),
            "BAIDUIP138SVR" => new BaiDuIp138Locator(),
            _ => NoneIPLocator.Instance
        })).Invoke(name);
    }
}