using System;
using System.IO;
using System.Net;
using System.Text;
using System.Threading.Tasks;
using NewLife.Log;
using NewLife.Net;
using NewLife.Web;
#nullable enable
namespace NewLife.IP
{
/// <summary>IP搜索</summary>
public static class Ip
{
private static readonly Object lockHelper = new();
private static Zip? zip;
/// <summary>数据文件</summary>
public static String DbFile { get; set; } = "";
static Ip()
{
#if NETCOREAPP
Encoding.RegisterProvider(CodePagesEncodingProvider.Instance);
#endif
var set = Setting.Current;
var dir = set.DataPath;
var ip = dir.CombinePath("ip.gz").GetBasePath();
if (File.Exists(ip)) DbFile = ip;
// 如果本地没有IP数据库,则从网络下载
if (DbFile.IsNullOrWhiteSpace())
{
var task = Task.Factory.StartNew(() =>
{
var url = set.PluginServer;
XTrace.WriteLine("没有找到IP数据库{0},准备联网获取 {1}", ip, url);
// 无法下载ip地址库时,不要抛出异常影响业务层
try
{
var client = new WebClientX
{
Log = XTrace.Log
};
var file = client.DownloadLink(url, "ip.gz", dir.GetBasePath());
if (File.Exists(file))
{
DbFile = file;
zip = null;
// 让它重新初始化
_inited = null;
}
}
catch (Exception ex)
{
XTrace.WriteException(ex);
}
});
task.Wait(3_000);
}
}
static Boolean? _inited;
static Boolean Init()
{
if (_inited != null) return _inited.Value;
lock (typeof(Ip))
{
if (_inited != null) return _inited.Value;
_inited = false;
var z = new Zip();
if (!File.Exists(DbFile))
{
//throw new InvalidOperationException("无法找到IP数据库" + DbFile + "!");
XTrace.WriteLine("无法找到IP数据库{0}", DbFile);
return false;
}
XTrace.WriteLine("使用IP数据库{0}", DbFile);
using (var fs = File.OpenRead(DbFile))
{
try
{
z.SetStream(fs);
}
catch (Exception ex)
{
XTrace.WriteException(ex);
return false;
}
}
if (z.Stream != null) zip = z;
}
//if (zip.Stream == null) throw new InvalidOperationException("无法打开IP数据库" + DbFile + "!");
_inited = true;
return true;
}
/// <summary>获取IP地址</summary>
/// <param name="ip"></param>
/// <returns></returns>
public static String GetAddress(String ip)
{
if (String.IsNullOrEmpty(ip)) return "";
if (!Init() || zip == null) return "";
var ip2 = IPToUInt32(ip.Trim());
lock (lockHelper)
{
return zip.GetAddress(ip2) + "";
}
}
/// <summary>获取IP地址</summary>
/// <param name="addr"></param>
/// <returns></returns>
public static String GetAddress(IPAddress addr)
{
if (addr == null) return "";
if (!Init() || zip == null) return "";
var buf = addr.GetAddressBytes();
Array.Reverse(buf);
var ip2 = (UInt32)buf.ToInt();
lock (lockHelper)
{
return zip.GetAddress(ip2) + "";
}
}
static UInt32 IPToUInt32(String IpValue)
{
var ss = IpValue.Split('.');
//var buf = stackalloc Byte[4];
var val = 0u;
//var ptr = (Byte*)&val;
for (var i = 0; i < 4; i++)
{
if (i < ss.Length && UInt32.TryParse(ss[i], out var n))
{
//buf[3 - i] = (Byte)n;
// 感谢啊富弟(QQ125662872)指出错误,右边需要乘以8,这里为了避开乘法,采用位移实现
val |= n << ((3 - i) << 3);
//ptr[3 - i] = n;
}
}
//return BitConverter.ToUInt32(buf, 0);
return val;
}
}
class MyIpProvider : IIPResolver
{
public String GetAddress(IPAddress addr) => Ip.GetAddress(addr);
}
}
#nullable restore
|