BootstrapAdmin/Bootstrap.Admin/OnlineUsers/DefaultOnlineUsers.cs

188 lines
6.0 KiB
C#

using Bootstrap.DataAccess;
using Longbow.Cache;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using System;
using System.Collections.Concurrent;
using System.Collections.Generic;
using System.Collections.Specialized;
using System.Linq;
using System.Net.Http;
using System.Threading.Tasks;
namespace Bootstrap.Admin
{
/// <summary>
///
/// </summary>
internal class DefaultOnlineUsers : IOnlineUsers
{
private readonly ConcurrentDictionary<string, AutoExpireCacheEntry<OnlineUser>> _onlineUsers = new ConcurrentDictionary<string, AutoExpireCacheEntry<OnlineUser>>();
private readonly ConcurrentDictionary<string, AutoExpireCacheEntry<string>> _ipLocator = new ConcurrentDictionary<string, AutoExpireCacheEntry<string>>();
private readonly HttpClient _client;
private readonly IEnumerable<string> _local = new string[] { "::1", "127.0.0.1" };
/// <summary>
///
/// </summary>
/// <param name="factory"></param>
public DefaultOnlineUsers(IHttpClientFactory factory)
{
_client = factory.CreateClient(OnlineUsersServicesCollectionExtensions.IPSvrHttpClientName);
}
/// <summary>
///
/// </summary>
/// <returns></returns>
public IEnumerable<OnlineUser> OnlineUsers
{
get { return _onlineUsers.Values.Select(v => v.Value); }
}
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="addValueFactory"></param>
/// <param name="updateValueFactory"></param>
/// <returns></returns>
public AutoExpireCacheEntry<OnlineUser> AddOrUpdate(string key, Func<string, AutoExpireCacheEntry<OnlineUser>> addValueFactory, Func<string, AutoExpireCacheEntry<OnlineUser>, AutoExpireCacheEntry<OnlineUser>> updateValueFactory) => _onlineUsers.AddOrUpdate(key, addValueFactory, updateValueFactory);
/// <summary>
///
/// </summary>
/// <param name="key"></param>
/// <param name="onlineUserCache"></param>
/// <returns></returns>
public bool TryRemove(string key, out AutoExpireCacheEntry<OnlineUser> onlineUserCache) => _onlineUsers.TryRemove(key, out onlineUserCache);
/// <summary>
///
/// </summary>
/// <param name="ip"></param>
/// <returns></returns>
public string RetrieveLocaleByIp(string ip = null) => _ipLocator.GetOrAdd(ip, key => new AutoExpireCacheEntry<string>(IPProxy(key), 1000 * 60, __ => _ipLocator.TryRemove(key, out _))).Value;
private string IPProxy(string ip)
{
var ipSvr = DictHelper.RetrieveLocaleIPSvr();
if (ipSvr.IsNullOrEmpty() || ipSvr.Equals("None", StringComparison.OrdinalIgnoreCase) || ip.IsNullOrEmpty() || _local.Any(p => p == ip)) return "本地连接";
var ipSvrUrl = DictHelper.RetrieveLocaleIPSvrUrl(ipSvr);
if (ipSvrUrl.IsNullOrEmpty()) return "本地连接";
var url = $"{ipSvrUrl}{ip}";
var task = ipSvr == "BaiDuIPSvr" ? RetrieveLocator<BaiDuIPLocator>(url) : RetrieveLocator<JuheIPLocator>(url);
task.Wait();
return task.Result;
}
private async Task<string> RetrieveLocator<T>(string url)
{
var ret = default(T);
try
{
ret = await _client.GetAsJsonAsync<T>(url);
}
catch (Exception ex)
{
ex.Log(new NameValueCollection()
{
["Url"] = url
});
}
return ret?.ToString();
}
/// <summary>
///
/// </summary>
private class BaiDuIPLocator
{
/// <summary>
/// 详细地址信息
/// </summary>
public string Address { get; set; }
/// <summary>
/// 结果状态返回码
/// </summary>
public string Status { get; set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Status == "0" ? string.Join(" ", Address.SpanSplit("|").Skip(1).Take(2)) : "XX XX";
}
}
private class JuheIPLocator
{
/// <summary>
///
/// </summary>
public string ResultCode { get; set; }
/// <summary>
///
/// </summary>
public string Reason { get; set; }
/// <summary>
///
/// </summary>
public JuheIPLocatorResult Result { get; set; }
/// <summary>
///
/// </summary>
/// <value></value>
public int Error_Code { get; set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Error_Code != 0 ? "XX XX" : Result.ToString();
}
}
private class JuheIPLocatorResult
{
/// <summary>
///
/// </summary>
public string Country { get; set; }
/// <summary>
///
/// </summary>
public string Province { get; set; }
/// <summary>
///
/// </summary>
public string City { get; set; }
/// <summary>
///
/// </summary>
public string Isp { get; set; }
/// <summary>
///
/// </summary>
/// <returns></returns>
public override string ToString()
{
return Country != "中国" ? $"{Country} {Province} {Isp}" : $"{Province} {City} {Isp}";
}
}
}
}