소스 검색

获取Ip .

CrazyIter_Bin 3 년 전
부모
커밋
e3d2a1fbf0

+ 0 - 284
TEAMModelOS.SDK/Helper/Network/IP2Region/FileSearcher.cs

@@ -1,284 +0,0 @@
-using IP2Region.Models;
-using System;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
-
-namespace IP2Region
-{
-    /// <summary>
-    /// 使用文件流的形式进行IP检索
-    /// </summary>
-    public class FileSearcher : IDisposable
-    {
-        /// <summary>
-        ///  文件流
-        /// </summary>
-        private readonly Stream _Stream;
-
-        /// <summary>
-        /// 头部索引区块缓存
-        /// </summary>
-        private readonly byte[] _HeaderBuffer;
-
-        /// <summary>
-        /// IP数据块索引描述
-        /// </summary>
-        private ref SuperBlock SuperBlock => ref Unsafe.As<byte, SuperBlock>(ref _HeaderBuffer[0]);
-
-        /// <summary>
-        /// HaderIndex总数量
-        /// </summary>
-        private readonly int _HeaderMaxIndex;
-
-        /// <summary>
-        /// IndexBlock总数量
-        /// </summary>
-        private readonly int _IndexBlockCcount;
-
-        /// <summary>
-        /// 使用文件流的形式进行IP检索
-        /// </summary>
-        /// <param name="dbPath">数据库文件路径</param>
-        public FileSearcher(string dbPath)
-        {
-            _Stream = new FileStream(dbPath, FileMode.Open, FileAccess.Read);
-
-            _HeaderBuffer = new byte[BlockSize.SuperBlockSize + 8192];
-            _Stream.Read(_HeaderBuffer, 0, _HeaderBuffer.Length);
-
-            ref SuperBlock superBlock = ref SuperBlock;
-            _IndexBlockCcount = (superBlock.LastIndexPtr - superBlock.FirstIndexPtr) / BlockSize.IndexBlockSize + 1;
-
-            int maxIndex = 0;
-            ref HeaderBlock headerCurrent = ref Unsafe.As<byte, HeaderBlock>(ref _HeaderBuffer[8]);
-            do
-            {
-                if (headerCurrent.IPIndexPtr == 0)
-                {
-                    break;
-                }
-
-                maxIndex++;
-                if (maxIndex < 1024)
-                {
-                    headerCurrent = ref Unsafe.Add(ref headerCurrent, 1);
-                }
-                else
-                {
-                    break;
-                }
-
-            } while (true);
-            _HeaderMaxIndex = maxIndex - 1;
-        }
-
-        /// <summary>
-        /// 使用Btree进行IP检索
-        /// </summary>
-        /// <param name="ipStr">IP字符串</param>
-        /// <returns></returns>
-        public DataBlock BtreeSearch(string ipStr)
-        {
-            return BtreeSearch(Utils.String2NetworkIP(ipStr));
-        }
-
-        /// <summary>
-        /// 使用Btree进行IP检索
-        /// </summary>
-        /// <param name="ipStr">网络字节序</param>
-        /// <returns></returns>
-        public DataBlock BtreeSearch(uint networkIP)
-        {
-            int index = _HeaderMaxIndex / 2, lower = 0, heighter = _HeaderMaxIndex;
-
-            ref HeaderBlock headerStart = ref Unsafe.As<byte, HeaderBlock>(ref _HeaderBuffer[BlockSize.SuperBlockSize]);
-
-            ref HeaderBlock headerCurrent = ref Unsafe.Add(ref headerStart, index);
-
-            //二分法检索ipVal在HeaderIndex的命中的二级索引
-            do
-            {
-                //Console.WriteLine("headerIndex:"+index);
-                //IP与HeaderIndex的StartIP相同,直接命中
-                if (headerCurrent.StartIP == networkIP)
-                {
-                    break;
-                }
-
-                //HeaderIndex的StartIP小于目标IP
-                if (headerCurrent.StartIP < networkIP)
-                {
-                    //如果下一个HeaderIndex的StartIP大于等于目标IP,或者当前已是最后一个视为命中
-                    //example 1: ipValue = 100.23.1.23,[100].StartIP = 100.0.0.0,[101].StartIP = 121.0.0.0 target!
-                    //example 1: ipValue = 254.23.1.23,[1023].StartIP = 254.0.0.0,1023是最后一个索引 target!
-                    if (index == _HeaderMaxIndex || (Unsafe.Add(ref headerCurrent, 1)).StartIP >= networkIP)
-                    {
-                        break;
-                    }
-                    lower = index + 1;
-                }
-                //HeaderIndex的StartIP大于目标IP
-                else
-                {
-                    if (index == 0)
-                    {
-                        break;
-                    }
-                    heighter = index - 1;
-                }
-
-                index = (lower + heighter) >> 1;
-                headerCurrent = ref Unsafe.Add(ref headerStart, index);
-            } while (true);
-
-
-            //计算2个HeaderIndex IPIndexPtr之间的IndexBlock的数量
-            int partLen = index < _HeaderMaxIndex
-                ? Unsafe.Add(ref headerCurrent, 1).IPIndexPtr - headerCurrent.IPIndexPtr
-                : BlockSize.IndexBlockSize;
-            int partCount = partLen / BlockSize.IndexBlockSize;
-
-            index = partCount >> 1;
-
-            heighter = partCount;
-
-            lower = 0;
-
-            //一次性加载整个HeaderIndex指向的IndexBlock块
-            byte[] buffer = new byte[partLen];
-
-            _Stream.Seek(headerCurrent.IPIndexPtr, SeekOrigin.Begin);
-            _Stream.Read(buffer, 0, buffer.Length);
-
-            ref IndexBlock blockStart = ref Unsafe.As<byte, IndexBlock>(ref buffer[0]);
-            ref IndexBlock blockCurrent = ref Unsafe.Add(ref blockStart, index);
-
-            //二分法检索ipVal在HeaderIndex的命中的二级索引
-            do
-            {
-
-                //IP与IndexBlock的StartIP和EndIp区间,直接命中
-                if (blockCurrent.StartIP <= networkIP && blockCurrent.EndIP >= networkIP)
-                {
-                    break;
-                }
-
-                //IndexBlock的EndIp小于目标IP
-                if (blockCurrent.StartIP < networkIP)
-                {
-                    lower = index + 1;
-                }
-                //HeaderIndex的StartIP大于目标IP
-                else
-                {
-                    heighter = index - 1;
-                }
-
-                index = (lower + heighter) >> 1;
-
-                blockCurrent = ref Unsafe.Add(ref blockStart, index);
-
-            } while (true);
-
-            buffer = new byte[blockCurrent.DataLen];
-
-            int ptr = blockCurrent.DataPtr;
-
-            _Stream.Seek(ptr, SeekOrigin.Begin);
-
-            _Stream.Read(buffer, 0, buffer.Length);
-
-            int cityId = Unsafe.As<byte, int>(ref buffer[0]);
-
-            string region = Encoding.UTF8.GetString(buffer, 4, buffer.Length - 4);
-
-            return new DataBlock(cityId, region, ptr);
-        }
-
-        /// <summary>
-        /// 使用Binary进行IP检索
-        /// </summary>
-        /// <param name="ipStr">IP字符串</param>
-        /// <returns></returns>
-        public DataBlock BinarySearch(string ipStr)
-        {
-            return BinarySearch(Utils.String2NetworkIP(ipStr));
-        }
-
-        /// <summary>
-        /// 使用Binary进行IP检索
-        /// </summary>
-        /// <param name="networkIP">网络字节序</param>
-        /// <returns></returns>
-        public DataBlock BinarySearch(uint networkIP)
-        {
-            int index = _IndexBlockCcount >> 1,
-                lower = 0,
-                heighter = _IndexBlockCcount,
-                ptr = SuperBlock.FirstIndexPtr,
-                indexLen = BlockSize.IndexBlockSize;
-
-
-            //一次性加载整个HeaderIndex指向的IndexBlock块
-            byte[] buffer = new byte[indexLen];
-
-            _Stream.Seek(ptr + index * indexLen, SeekOrigin.Begin);
-
-            _Stream.Read(buffer, 0, buffer.Length);
-
-            ref IndexBlock blockCurrent = ref Unsafe.As<byte, IndexBlock>(ref buffer[0]);
-
-            //二分法检索ipVal在HeaderIndex的命中的二级索引
-            do
-            {
-                //Console.WriteLine("File BinarySearch" + index);
-                //IP与IndexBlock的StartIP和EndIp区间,直接命中
-                if (blockCurrent.StartIP <= networkIP && blockCurrent.EndIP >= networkIP)
-                {
-                    break;
-                }
-
-                //IndexBlock的EndIp小于目标IP
-                if (blockCurrent.StartIP < networkIP)
-                {
-                    lower = index + 1;
-                }
-                //HeaderIndex的StartIP大于目标IP
-                else
-                {
-                    heighter = index - 1;
-                }
-
-                index = (lower + heighter) >> 1;
-
-                _Stream.Seek(ptr + index * indexLen, SeekOrigin.Begin);
-
-                _Stream.Read(buffer, 0, buffer.Length);
-
-                blockCurrent = ref Unsafe.As<byte, IndexBlock>(ref buffer[0]);
-
-            } while (true);
-
-            buffer = new byte[blockCurrent.DataLen];
-
-            ptr = blockCurrent.DataPtr;
-
-            _Stream.Seek(ptr, SeekOrigin.Begin);
-
-            _Stream.Read(buffer, 0, buffer.Length);
-
-            int cityId = Unsafe.As<byte, int>(ref buffer[0]);
-
-            string region = Encoding.UTF8.GetString(buffer, 4, buffer.Length - 4);
-
-            return new DataBlock(cityId, region, ptr);
-        }
-
-        public void Dispose()
-        {
-            _Stream.Dispose();
-        }
-    }
-}

+ 0 - 10
TEAMModelOS.SDK/Helper/Network/IP2Region/IPInValidException.cs

@@ -1,10 +0,0 @@
-using System;
-
-namespace IP2Region
-{
-    public class IPInValidException : Exception
-    {
-        const string ERROR_MSG = "IP Illigel. Please input a valid IP.";
-        public IPInValidException() : base(ERROR_MSG) { }
-    }
-}

+ 430 - 0
TEAMModelOS.SDK/Helper/Network/IP2Region/IPSearcher.cs

@@ -0,0 +1,430 @@
+using System;
+using System.IO;
+using System.Text;
+using System.Threading.Tasks;
+using TEAMModelOS.SDK.IP2Region;
+
+namespace TEAMModelOS.SDK
+{
+    public class IPSearcher : IDisposable
+    {
+        const int BTREE_ALGORITHM = 1;
+        const int BINARY_ALGORITHM = 2;
+        const int MEMORY_ALGORITYM = 3;
+
+        private IPConfig _dbConfig = null;
+
+        /// <summary>
+        /// db file access handler
+        /// </summary>
+        private Stream _raf = null;
+
+        /// <summary>
+        /// header blocks buffer
+        /// </summary>
+        private long[] _headerSip = null;
+        private int[] _headerPtr = null;
+        private int _headerLength;
+
+        /// <summary>
+        /// super blocks info 
+        /// </summary>
+        private long _firstIndexPtr = 0;
+        private long _lastIndexPtr = 0;
+        private int _totalIndexBlocks = 0;
+
+        /// <summary>
+        /// for memory mode
+        /// the original db binary string
+        /// </summary>
+        private byte[] _dbBinStr = null;
+
+        /// <summary>
+        /// Get by index ptr.
+        /// </summary>
+        private DataBlock GetByIndexPtr(long ptr)
+        {
+            _raf.Seek(ptr, SeekOrigin.Begin);
+            byte[] buffer = new byte[12];
+            _raf.Read(buffer, 0, buffer.Length);
+            long extra = Utils.GetIntLong(buffer, 8);
+            int dataLen = (int)((extra >> 24) & 0xFF);
+            int dataPtr = (int)((extra & 0x00FFFFFF));
+            _raf.Seek(dataPtr, SeekOrigin.Begin);
+            byte[] data = new byte[dataLen];
+            _raf.Read(data, 0, data.Length);
+            int city_id = (int)Utils.GetIntLong(data, 0);
+            string region = Encoding.UTF8.GetString(data, 4, data.Length - 4);
+            return new DataBlock(city_id, region, dataPtr);
+        }
+
+        public IPSearcher(IPConfig dbConfig, string dbFile)
+        {
+            if (_dbConfig == null)
+            {
+                _dbConfig = dbConfig;
+            }
+            try {
+                _raf = new FileStream(dbFile, FileMode.Open, FileAccess.Read, FileShare.Read);
+            } catch { }
+        }
+
+        public IPSearcher(string dbFile) : this(null, dbFile) { }
+
+        public IPSearcher(IPConfig dbConfig, Stream dbFileStream)
+        {
+            if (_dbConfig == null)
+            {
+                _dbConfig = dbConfig;
+            }
+
+            _raf = dbFileStream;
+        }
+
+        public IPSearcher(Stream dbFileStream) : this(null, dbFileStream) { }
+
+        #region Sync Methods
+        /// <summary>
+        /// Get the region with a int ip address with memory binary search algorithm.
+        /// </summary>
+        private DataBlock MemorySearch(long ip)
+        {
+            int blen = IndexBlock.LENGTH;
+            if (_dbBinStr == null)
+            {
+                if (_raf == null) { return null; }
+                try { _dbBinStr = new byte[(int)_raf.Length]; } catch (Exception) { return null; }
+                _raf.Seek(0L, SeekOrigin.Begin);
+                _raf.Read(_dbBinStr, 0, _dbBinStr.Length);
+
+                //initialize the global vars
+                _firstIndexPtr = Utils.GetIntLong(_dbBinStr, 0);
+                _lastIndexPtr = Utils.GetIntLong(_dbBinStr, 4);
+                _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1;
+            }
+
+            //search the index blocks to define the data
+            int l = 0, h = _totalIndexBlocks;
+            long sip = 0;
+
+            while (l <= h)
+            {
+                int m = (l + h) >> 1;
+                int p = (int)(_firstIndexPtr + m * blen);
+
+                sip = Utils.GetIntLong(_dbBinStr, p);
+
+                if (ip < sip)
+                {
+                    h = m - 1;
+                }
+                else
+                {
+                    sip = Utils.GetIntLong(_dbBinStr, p + 4);
+                    if (ip > sip)
+                    {
+                        l = m + 1;
+                    }
+                    else
+                    {
+                        sip = Utils.GetIntLong(_dbBinStr, p + 8);
+                        break;
+                    }
+                }
+            }
+
+            //not matched
+            if (sip == 0) return null;
+
+            //get the data
+            int dataLen = (int)((sip >> 24) & 0xFF);
+            int dataPtr = (int)((sip & 0x00FFFFFF));
+            int city_id = (int)Utils.GetIntLong(_dbBinStr, dataPtr);
+            string region = Encoding.UTF8.GetString(_dbBinStr, dataPtr + 4, dataLen - 4);//new String(dbBinStr, dataPtr + 4, dataLen - 4, Encoding.UTF8);
+
+            return new DataBlock(city_id, region, dataPtr);
+        }
+
+        /// <summary>
+        /// Get the region throught the ip address with memory binary search algorithm.
+        /// </summary>
+        public DataBlock MemorySearch(string ip)
+        {
+            return MemorySearch(Utils.Ip2long(ip));
+        }
+
+        /// <summary>
+        /// Get the region with a int ip address with b-tree algorithm.
+        /// </summary>
+        private DataBlock BtreeSearch(long ip)
+        {
+            //check and load the header
+            if (_headerSip == null)
+            {
+                _raf.Seek(8L, SeekOrigin.Begin);    //pass the super block
+                byte[] b = new byte[4096];
+                _raf.Read(b, 0, b.Length);
+                //fill the header
+                int len = b.Length >> 3, idx = 0;  //b.lenght / 8
+                _headerSip = new long[len];
+                _headerPtr = new int[len];
+                long startIp, dataPtrTemp;
+                for (int i = 0; i < b.Length; i += 8)
+                {
+                    startIp = Utils.GetIntLong(b, i);
+                    dataPtrTemp = Utils.GetIntLong(b, i + 4);
+                    if (dataPtrTemp == 0) break;
+
+                    _headerSip[idx] = startIp;
+                    _headerPtr[idx] = (int)dataPtrTemp;
+                    idx++;
+                }
+                _headerLength = idx;
+            }
+
+            //1. define the index block with the binary search
+            if (ip == _headerSip[0])
+            {
+                return GetByIndexPtr(_headerPtr[0]);
+            }
+            else if (ip == _headerPtr[_headerLength - 1])
+            {
+                return GetByIndexPtr(_headerPtr[_headerLength - 1]);
+            }
+            int l = 0, h = _headerLength, sptr = 0, eptr = 0;
+            int m = 0;
+            while (l <= h)
+            {
+                m = (l + h) >> 1;
+                //perfectly matched, just return it
+                if (ip == _headerSip[m])
+                {
+                    if (m > 0)
+                    {
+                        sptr = _headerPtr[m - 1];
+                        eptr = _headerPtr[m];
+                    }
+                    else
+                    {
+                        sptr = _headerPtr[m];
+                        eptr = _headerPtr[m + 1];
+                    }
+                }
+                //less then the middle value
+                else if (ip < _headerSip[m])
+                {
+                    if (m == 0)
+                    {
+                        sptr = _headerPtr[m];
+                        eptr = _headerPtr[m + 1];
+                        break;
+                    }
+                    else if (ip > _headerSip[m - 1])
+                    {
+                        sptr = _headerPtr[m - 1];
+                        eptr = _headerPtr[m];
+                        break;
+                    }
+                    h = m - 1;
+                }
+                else
+                {
+                    if (m == _headerLength - 1)
+                    {
+                        sptr = _headerPtr[m - 1];
+                        eptr = _headerPtr[m];
+                        break;
+                    }
+                    else if (ip <= _headerSip[m + 1])
+                    {
+                        sptr = _headerPtr[m];
+                        eptr = _headerPtr[m + 1];
+                        break;
+                    }
+                    l = m + 1;
+                }
+            }
+            //match nothing just stop it
+            if (sptr == 0) return null;
+            //2. search the index blocks to define the data
+            int blockLen = eptr - sptr, blen = IndexBlock.LENGTH;
+            byte[] iBuffer = new byte[blockLen + blen];    //include the right border block
+            _raf.Seek(sptr, SeekOrigin.Begin);
+            _raf.Read(iBuffer, 0, iBuffer.Length);
+            l = 0; h = blockLen / blen;
+            long sip = 0;
+            int p = 0;
+            while (l <= h)
+            {
+                m = (l + h) >> 1;
+                p = m * blen;
+                sip = Utils.GetIntLong(iBuffer, p);
+                if (ip < sip)
+                {
+                    h = m - 1;
+                }
+                else
+                {
+                    sip = Utils.GetIntLong(iBuffer, p + 4);
+                    if (ip > sip)
+                    {
+                        l = m + 1;
+                    }
+                    else
+                    {
+                        sip = Utils.GetIntLong(iBuffer, p + 8);
+                        break;
+                    }
+                }
+            }
+            //not matched
+            if (sip == 0) return null;
+            //3. get the data
+            int dataLen = (int)((sip >> 24) & 0xFF);
+            int dataPtr = (int)((sip & 0x00FFFFFF));
+            _raf.Seek(dataPtr, SeekOrigin.Begin);
+            byte[] data = new byte[dataLen];
+            _raf.Read(data, 0, data.Length);
+            int city_id = (int)Utils.GetIntLong(data, 0);
+            String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);// new String(data, 4, data.Length - 4, "UTF-8");
+            return new DataBlock(city_id, region, dataPtr);
+        }
+
+        /// <summary>
+        /// Get the region throught the ip address with b-tree search algorithm.
+        /// </summary>
+        public DataBlock BtreeSearch(string ip)
+        {
+            return BtreeSearch(Utils.Ip2long(ip));
+        }
+
+        /// <summary>
+        /// Get the region with a int ip address with binary search algorithm.
+        /// </summary>
+        private DataBlock BinarySearch(long ip)
+        {
+            int blen = IndexBlock.LENGTH;
+            if (_totalIndexBlocks == 0)
+            {
+                _raf.Seek(0L, SeekOrigin.Begin);
+                byte[] superBytes = new byte[8];
+                _raf.Read(superBytes, 0, superBytes.Length);
+                //initialize the global vars
+                _firstIndexPtr = Utils.GetIntLong(superBytes, 0);
+                _lastIndexPtr = Utils.GetIntLong(superBytes, 4);
+                _totalIndexBlocks = (int)((_lastIndexPtr - _firstIndexPtr) / blen) + 1;
+            }
+
+            //search the index blocks to define the data
+            int l = 0, h = _totalIndexBlocks;
+            byte[] buffer = new byte[blen];
+            long sip = 0;
+            while (l <= h)
+            {
+                int m = (l + h) >> 1;
+                _raf.Seek(_firstIndexPtr + m * blen, SeekOrigin.Begin);    //set the file pointer
+                _raf.Read(buffer, 0, buffer.Length);
+                sip = Utils.GetIntLong(buffer, 0);
+                if (ip < sip)
+                {
+                    h = m - 1;
+                }
+                else
+                {
+                    sip = Utils.GetIntLong(buffer, 4);
+                    if (ip > sip)
+                    {
+                        l = m + 1;
+                    }
+                    else
+                    {
+                        sip = Utils.GetIntLong(buffer, 8);
+                        break;
+                    }
+                }
+            }
+            //not matched
+            if (sip == 0) return null;
+            //get the data
+            int dataLen = (int)((sip >> 24) & 0xFF);
+            int dataPtr = (int)((sip & 0x00FFFFFF));
+            _raf.Seek(dataPtr, SeekOrigin.Begin);
+            byte[] data = new byte[dataLen];
+            _raf.Read(data, 0, data.Length);
+            int city_id = (int)Utils.GetIntLong(data, 0);
+            String region = Encoding.UTF8.GetString(data, 4, data.Length - 4);//new String(data, 4, data.Length - 4, "UTF-8");
+            return new DataBlock(city_id, region, dataPtr);
+        }
+
+        /// <summary>
+        /// Get the region throught the ip address with binary search algorithm.
+        /// </summary>
+        public DataBlock BinarySearch(String ip)
+        {
+            return BinarySearch(Utils.Ip2long(ip));
+        }
+        #endregion
+
+        #region Async Methods
+        /// <summary>
+        /// Get the region throught the ip address with memory binary search algorithm.
+        /// </summary>
+        public Task<DataBlock> MemorySearchAsync(string ip)
+        {
+            return Task.FromResult(MemorySearch(ip));
+        }
+        public async Task<string> SearchIpAsync( string ip)
+        {
+            try
+            {
+                DataBlock block = await MemorySearchAsync(ip);
+                if (block != null)
+                {
+                    string region = block.Region.Replace("0|0|0|0|", "").Replace("0|0|0|", "").Replace("|0|0|0|0", "").Replace("|0|0|0|", "").Replace("|0|0|0", "").Replace("|0|0|", "").Replace("|0|0", "").Replace("|0|", "¡¤").Replace("|0", "").Replace("|", "¡¤");
+                    return region;
+                }
+                else { return null; }
+               
+            }
+            catch (IPInValidException)
+            {
+                return "IP Illigel.";
+            }
+            catch (Exception) {
+                return null;
+            }
+           
+        }
+        /// <summary>
+        /// Get the region throught the ip address with b-tree search algorithm.
+        /// </summary>
+        public Task<DataBlock> BtreeSearchAsync(string ip)
+        {
+            return Task.FromResult(BtreeSearch(ip));
+        }
+        /// <summary>
+        /// Get the region throught the ip address with binary search algorithm.
+        /// </summary>
+        public Task<DataBlock> BinarySearchAsync(string ip)
+        {
+            return Task.FromResult(BinarySearch(ip));
+        }
+        #endregion
+
+        /// <summary>
+        /// Close the db.
+        /// </summary>
+        public void Close()
+        {
+            _headerSip = null;
+            _headerPtr = null;
+            _dbBinStr = null;
+            _raf.Close();
+        }
+
+        public void Dispose()
+        {
+            Close();
+        }
+    }
+}

+ 21 - 0
TEAMModelOS.SDK/Helper/Network/IP2Region/IPSearcherExtensions.cs

@@ -0,0 +1,21 @@
+using Microsoft.Extensions.DependencyInjection;
+using Microsoft.Extensions.DependencyInjection.Extensions;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace TEAMModelOS.SDK
+{
+    public static class IPSearcherExtensions
+    {
+        public static IServiceCollection AddIPSearcher(this IServiceCollection services, string path, string name = "Default")
+        {
+            if (services == null) throw new ArgumentNullException(nameof(services));
+            if (path == null) throw new ArgumentNullException(nameof(path));
+            services.TryAddSingleton(new IPSearcher($"{path}/ip2region.db"));
+            return services;
+        }
+    }
+}

+ 0 - 231
TEAMModelOS.SDK/Helper/Network/IP2Region/MemorySearcher.cs

@@ -1,231 +0,0 @@
-using IP2Region.Models;
-using System;
-using System.IO;
-using System.Runtime.CompilerServices;
-using System.Text;
-
-namespace IP2Region
-{
-    /// <summary>
-    /// 一次性加载整块内存,然后进行搜索
-    /// </summary>
-    public class MemorySearcher
-    {
-        /// <summary>
-        /// 数据缓存
-        /// </summary>
-        private readonly byte[] _Buffer;
-
-        /// <summary>
-        /// IP数据块索引描述
-        /// </summary>
-        private ref SuperBlock SuperBlock => ref Unsafe.As<byte, SuperBlock>(ref _Buffer[0]);
-
-        /// <summary>
-        /// HaderIndex总数量
-        /// </summary>
-        private readonly int _HeaderMaxIndex ;
-
-        /// <summary>
-        /// IndexBlock总数量
-        /// </summary>
-        private readonly int _IndexBlockCcount;
-
-
-
-        /// <summary>
-        /// 构造MemorySearcher,加载数据至内存中
-        /// </summary>
-        /// <param name="dbPath"></param>
-        public MemorySearcher(string dbPath)
-        {
-            _Buffer = LoadToMemory(dbPath);
-            ref SuperBlock superBlock = ref SuperBlock;
-            _IndexBlockCcount = (superBlock.LastIndexPtr - superBlock.FirstIndexPtr) / BlockSize.IndexBlockSize + 1;
-
-            int maxIndex = 0;
-            ref HeaderBlock headerCurrent = ref Unsafe.As<byte, HeaderBlock>(ref _Buffer[8]);
-            do
-            {
-                if (headerCurrent.IPIndexPtr == 0)
-                {
-                    break;
-                }
-
-                maxIndex++;
-                if (maxIndex < 1024)
-                {
-                    headerCurrent = ref Unsafe.Add(ref headerCurrent, 1);
-                }
-                else
-                {
-                    break;
-                }
-
-            } while (true);
-            _HeaderMaxIndex = maxIndex - 1;
-        }
-
-        /// <summary>
-        /// 加载数据到内存
-        /// </summary>
-        /// <param name="dbPath"></param>
-        /// <returns></returns>
-        private byte[] LoadToMemory(string dbPath)
-        {
-            using (FileStream stream = new FileStream(dbPath, FileMode.Open, FileAccess.Read))
-            {
-                byte[] buffer = new byte[stream.Length];
-                stream.Read(buffer, 0, buffer.Length);
-                return buffer;
-            }
-        }
-
-        /// <summary>
-        /// 使用Btree进行IP检索
-        /// </summary>
-        /// <param name="ipStr">IP字符串</param>
-        /// <returns></returns>
-        public DataBlock BtreeSearch(string ipStr)
-        {
-            return BtreeSearch(Utils.String2NetworkIP(ipStr));
-        }
-
-        /// <summary>
-        /// 使用Btree进行IP检索
-        /// </summary>
-        /// <param name="ipStr">网络字节序</param>
-        /// <returns></returns>
-        public DataBlock BtreeSearch(uint networkIP)
-        {
-            int index, lower = 0, heighter = _HeaderMaxIndex;
-
-            ref HeaderBlock headerStart = ref Unsafe.As<byte, HeaderBlock>(ref _Buffer[BlockSize.SuperBlockSize]);
-
-            ref HeaderBlock headerCurrent = ref headerStart;
-
-            //二分法检索ipVal在HeaderIndex的命中的二级索引
-            do
-            {
-                index = (heighter + lower) >> 1;
-
-                headerCurrent = ref Unsafe.Add(ref headerStart, index);
-
-                //IP与HeaderIndex的StartIP相同,直接命中
-                if (headerCurrent.StartIP == networkIP)
-                {
-                    break;
-                }
-
-                //HeaderIndex的StartIP小于目标IP
-                if (headerCurrent.StartIP < networkIP)
-                {
-                    //如果下一个HeaderIndex的StartIP大于等于目标IP,或者当前已是最后一个视为命中
-                    //example 1: ipValue = 100.23.1.23,[100].StartIP = 100.0.0.0,[101].StartIP = 121.0.0.0 target!
-                    //example 1: ipValue = 254.23.1.23,[1023].StartIP = 254.0.0.0,1023是最后一个索引 target!
-                    if (index == _HeaderMaxIndex || (Unsafe.Add(ref headerCurrent, 1)).StartIP >= networkIP)
-                    {
-                        break;
-                    }
-                    lower = index + 1;
-                }
-                //HeaderIndex的StartIP大于目标IP
-                else
-                {
-                    if (index == 0)
-                    {
-                        break;
-                    }
-                    heighter = index - 1;
-                }
-               
-            } while (true);
-
-            //计算2个HeaderIndex IPIndexPtr之间的IndexBlock的数量
-            int partLen = index < _HeaderMaxIndex
-                ? Unsafe.Add(ref headerCurrent, 1).IPIndexPtr - headerCurrent.IPIndexPtr
-                : BlockSize.IndexBlockSize;
-            int partCount = partLen / BlockSize.IndexBlockSize;
-
-            ref IndexBlock blockStart = ref Unsafe.As<byte, IndexBlock>(ref _Buffer[headerCurrent.IPIndexPtr]);
-
-            return DichotomySearch(networkIP, ref blockStart, partCount);
-        }
-
-        /// <summary>
-        /// 使用Binary进行IP检索
-        /// </summary>
-        /// <param name="ipStr">IP字符串</param>
-        /// <returns></returns>
-        public DataBlock BinarySearch(string ipStr)
-        {
-            return BinarySearch(Utils.String2NetworkIP(ipStr));
-        }
-
-        /// <summary>
-        /// 使用Binary进行IP检索
-        /// </summary>
-        /// <param name="networkIP">网络字节序</param>
-        /// <returns></returns>
-        public DataBlock BinarySearch(uint networkIP)
-        {
-            ref SuperBlock superBlock = ref SuperBlock;
-            ref IndexBlock blockStart = ref Unsafe.As<byte, IndexBlock>(ref _Buffer[superBlock.FirstIndexPtr]);
-            return DichotomySearch(networkIP, ref blockStart, _IndexBlockCcount);
-        }
-
-        /// <summary>
-        /// 二分法检索ipVal在HeaderIndex的命中的二级索引
-        /// </summary>
-        /// <param name="networkIP"></param>
-        /// <param name="blockStart"></param>
-        /// <param name="count"></param>
-        /// <returns></returns>
-        private DataBlock DichotomySearch(uint networkIP, ref IndexBlock blockStart, int count)
-        {
-            int index = count >> 1,
-                lower = 0,
-                heighter = count;
-
-            ref IndexBlock blockCurrent = ref Unsafe.Add(ref blockStart, index);
-
-            do
-            {
-                //Console.WriteLine("Memory BinarySearch" + index);
-                //IP与IndexBlock的StartIP和EndIp区间,直接命中
-                if (blockCurrent.StartIP <= networkIP && blockCurrent.EndIP >= networkIP)
-                {
-                    break;
-                }
-
-                //IndexBlock的EndIp小于目标IP
-                if (blockCurrent.StartIP < networkIP)
-                {
-                    //lower = index ;
-                    //index += Math.Max((heighter - lower) / 2, 1);
-                    lower = index + 1;
-                }
-                //HeaderIndex的StartIP大于目标IP
-                else
-                {
-                    //heighter = index;
-                    //index -= Math.Max((heighter - lower) / 2, 1);
-                    count = index - 1;
-                }
-
-                index = (lower + count) >> 1;
-                blockCurrent = ref Unsafe.Add(ref blockStart, index);
-
-            } while (true);
-
-
-            int dataPtr = blockCurrent.DataPtr;
-
-            int cityId = Unsafe.As<byte, int>(ref _Buffer[dataPtr]);
-
-            string region = Encoding.UTF8.GetString(_Buffer, blockCurrent.DataPtr + 4, blockCurrent.DataLen - 4);
-
-            return new DataBlock(cityId, region, dataPtr);
-        }
-    }
-}

+ 0 - 13
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/BlockSize.cs

@@ -1,13 +0,0 @@
-using System.Runtime.CompilerServices;
-
-namespace IP2Region.Models
-{
-    internal class BlockSize
-    {
-        internal readonly static int SuperBlockSize = Unsafe.SizeOf<HeaderBlock>();
-
-        internal readonly static int HeaderBlockSize = Unsafe.SizeOf<HeaderBlock>();
-
-        internal readonly static int IndexBlockSize = Unsafe.SizeOf<IndexBlock>();
-    }
-}

+ 4 - 3
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/DataBlock.cs

@@ -1,4 +1,5 @@
-namespace IP2Region.Models
+ 
+namespace TEAMModelOS.SDK
 {
     public class DataBlock
     {
@@ -30,7 +31,7 @@
             DataPtr = dataPtr;
         }
 
-        public DataBlock(int city_id, string region) : this(city_id, region, 0)
+        public DataBlock(int city_id, string region):this(city_id,region,0)
         {
         }
         #endregion
@@ -42,4 +43,4 @@
 
     }
 
-}
+}

+ 0 - 44
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/DbConfig.cs

@@ -1,44 +0,0 @@
-//using System;
-
-//namespace IP2Region.Models
-//{
-//    public class DbMakerConfigException : Exception
-//    {
-//        public string ErrMsg { get; private set; }
-//        public DbMakerConfigException(string errMsg)
-//        {
-//            ErrMsg = errMsg;
-//        }
-//    }
-
-//    public class DbConfig
-//    {
-//        public int TotalHeaderSize
-//        {
-//            get;
-//            private set;
-//        }
-
-//        public int indexBlockSize
-//        {
-//            get;
-//            private set;
-//        }
-
-//        public DbConfig(int totalHeaderSize)
-//        {
-//            if ((totalHeaderSize % 8) != 0)
-//            {
-//                throw new DbMakerConfigException("totalHeaderSize must be times of 8");
-//            }
-//            TotalHeaderSize = totalHeaderSize;
-//            //4 * 2048
-//            indexBlockSize = 8192;
-//        }
-
-//        public DbConfig() : this(8 * 2048)
-//        {
-//        }
-//    }
-
-//}

+ 36 - 7
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/HeaderBlock.cs

@@ -1,16 +1,45 @@
-namespace IP2Region.Models
+using TEAMModelOS.SDK.IP2Region;
+
+namespace TEAMModelOS.SDK
 {
-    internal struct HeaderBlock
+    internal class HeaderBlock
     {
+        public long IndexStartIp
+        {
+            get;
+            private set;
+        }
 
-        internal uint StartIP;
+        public int IndexPtr
+        {
+            get;
+            private set;
+        }
 
-        internal int IPIndexPtr;
+        public HeaderBlock(long indexStartIp, int indexPtr)
+        {
+            IndexStartIp = indexStartIp;
+            IndexPtr = indexPtr;
+        }
 
-        public HeaderBlock(uint indexStartIp, int indexPtr)
+        /// <summary>
+        /// Get the bytes for total storage
+        /// </summary>
+        /// <returns>
+        /// Bytes gotten.
+        /// </returns>
+        public byte[] GetBytes()
         {
-            StartIP = indexStartIp;
-            IPIndexPtr = indexPtr;
+            /*
+             * +------------+-----------+
+             * | 4bytes     | 4bytes    |
+             * +------------+-----------+
+             *  start ip      index ptr
+            */
+            byte[] b = new byte[8];
+            Utils.WriteIntLong(b, 0, IndexStartIp);
+            Utils.WriteIntLong(b, 4, IndexPtr);
+            return b;
         }
     }
 }

+ 45 - 0
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/IPConfig.cs

@@ -0,0 +1,45 @@
+ 
+using System;
+
+namespace TEAMModelOS.SDK
+{
+    public class DbMakerConfigException : Exception
+    {
+        public string ErrMsg { get; private set; }
+        public DbMakerConfigException(string errMsg)
+        {
+            ErrMsg = errMsg;
+        }
+    }
+
+    public class IPConfig
+    {
+        public int TotalHeaderSize
+        {
+            get;
+            private set;
+        }
+
+        public int indexBlockSize
+        {
+            get;
+            private set;
+        }
+
+        public IPConfig(int totalHeaderSize)
+        {
+            if ((totalHeaderSize % 8) != 0)
+            {
+                throw new DbMakerConfigException("totalHeaderSize must be times of 8");
+            }
+            TotalHeaderSize = totalHeaderSize;
+            //4 * 2048
+            indexBlockSize = 8192; 
+        }
+
+        public IPConfig():this(8 * 2048)
+        {
+        }
+    }
+
+}

+ 54 - 12
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/IndexBlock.cs

@@ -1,21 +1,63 @@
-namespace IP2Region.Models
+
+
+using TEAMModelOS.SDK.IP2Region;
+
+namespace TEAMModelOS.SDK
 {
-    /*
-     * +------------+-----------+-----------+-----------+
-     * | 4bytes     | 4bytes    | 3bytes    |  1bytes  |
-     * +------------+-----------+-----------+-----------+
-     *  start ip      end ip      data ptr     data len
-    */
-    internal struct IndexBlock
+    internal class IndexBlock
     {
         public const int LENGTH = 12;
 
-        public uint StartIP;
+        public long StartIP
+        {
+            get;
+            private set;
+        }
+
+        public long EndIp
+        {
+            get;
+            private set;
+        }
+
+        public uint DataPtr
+        {
+            get;
+            private set;
+        }
+
+        public int DataLen
+        {
+            get;
+            private set;
+        }
+
+        public IndexBlock(long startIp, long endIp, uint dataPtr, int dataLen)
+        {
+            StartIP = startIp;
+            EndIp = endIp;
+            DataPtr = dataPtr;
+            DataLen = dataLen;
+        }
+
+        public byte[] GetBytes()
+        {
+            /*
+             * +------------+-----------+-----------+
+             * | 4bytes     | 4bytes    | 4bytes    |
+             * +------------+-----------+-----------+
+             *  start ip      end ip      data ptr + len 
+            */
+            byte[] b = new byte[12];
 
-        public uint EndIP;
+            Utils.WriteIntLong(b, 0, StartIP);    //start ip
+            Utils.WriteIntLong(b, 4, EndIp);        //end ip
 
-        public Int24 DataPtr;
+            //write the data ptr and the length
+            long mix = DataPtr | ((DataLen << 24) & 0xFF000000L);
+            Utils.WriteIntLong(b, 8, mix);
 
-        public byte DataLen;
+            return b;
+        }
     }
 }

+ 0 - 100
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/Int24.cs

@@ -1,100 +0,0 @@
-using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-
-namespace IP2Region.Models
-{
-    internal struct Int24
-    {
-        private byte Byte1;
-
-        private byte Byte2;
-
-        private byte Byte3;
-
-        internal Int24(int value)
-        {
-            if (value > 0x00FFFFFF)
-            {
-                throw new ArgumentException("Int24 max value must be smaller than 0x00FFFFFF");
-            }
-            ref byte ptr = ref Unsafe.As<int, byte>(ref value);
-            Byte1 = ptr;
-            Byte2 = Unsafe.Add(ref ptr, 1);
-            Byte3 = Unsafe.Add(ref ptr, 2);
-        }
-
-        internal void SetValue(int value)
-        {
-            if (value > 0x00FFFFFF)
-            {
-                throw new ArgumentException("Int24 max value must be smaller than 0x00FFFFFF");
-            }
-            ref byte ptr = ref Unsafe.As<int, byte>(ref value);
-            Byte1 = ptr;
-            Byte2 = Unsafe.Add(ref ptr, 1);
-            Byte3 = Unsafe.Add(ref ptr, 2);
-        }
-
-        internal int GetValue()
-        {
-            int value = 0;
-            ref byte ptr = ref Unsafe.As<int, byte>(ref value);
-            ptr = Byte1;
-            Unsafe.Add(ref ptr, 1) = Byte2;
-            Unsafe.Add(ref ptr, 2) = Byte3;
-            return value;
-        }
-
-        public static int operator +(Int24 a, Int24 b)
-        {
-            return a.GetValue() + b.GetValue();
-        }
-
-        public static Int24 operator -(Int24 a, Int24 b)
-        {
-            return new Int24(a.GetValue() - b.GetValue());
-        }
-
-        public static int operator *(Int24 a, Int24 b)
-        {
-            return a.GetValue() * b.GetValue();
-        }
-
-        public static int operator /(Int24 a, Int24 b)
-        {
-            return new Int24(a.GetValue() / b.GetValue());
-        }
-
-        public static bool operator ==(int a, Int24 b)
-        {
-            return a == b.GetValue();
-        }
-
-        public static bool operator !=(int a, Int24 b)
-        {
-            return a == b.GetValue();
-        }
-
-        public static implicit operator int (Int24 operand)
-        {
-            return operand.GetValue();
-        }
-
-        public static explicit operator Int24(int operand)
-        {
-            return new Int24(operand);
-        }
-
-        public override bool Equals(object obj)
-        {
-            int value = (int)obj;
-            return value == GetValue();
-        }
-
-        public override int GetHashCode()
-        {
-            return GetValue();
-        }
-    }
-}

+ 0 - 15
TEAMModelOS.SDK/Helper/Network/IP2Region/Models/SuperBlock.cs

@@ -1,15 +0,0 @@
-namespace IP2Region.Models
-{
-    internal struct SuperBlock
-    {
-        /// <summary>
-        /// 指向INDEX起始位置的index block
-        /// </summary>
-        internal int FirstIndexPtr;
-
-        /// <summary>
-        /// 指向最后一个index block的地址
-        /// </summary>
-        internal int LastIndexPtr;
-    }
-}

+ 70 - 55
TEAMModelOS.SDK/Helper/Network/IP2Region/Utils.cs

@@ -1,102 +1,117 @@
-using IP2Region.Models;
+ 
 using System;
-using System.Runtime.CompilerServices;
-using System.Runtime.InteropServices;
-using System.Text;
 
-namespace IP2Region
+namespace TEAMModelOS.SDK.IP2Region
 {
-    public static class Utils
+    public class IPInValidException : Exception
     {
-        public static void Write<T>(byte[] b, int offset, T value)
-            where T : unmanaged
+        const string ERROR_MSG = "IP Illigel. Please input a valid IP.";
+        public IPInValidException() : base(ERROR_MSG) { }
+    }
+    internal static class Utils
+    {
+        /// <summary>
+        /// Write specfield bytes to a byte array start from offset.
+        /// </summary>
+        public static void Write(byte[] b, int offset, ulong v, int bytes)
         {
-            ref byte buffer = ref Unsafe.As<T, byte>(ref value);
-            Marshal.Copy((IntPtr)buffer, b, offset, Unsafe.SizeOf<T>());
+            for (int i = 0; i < bytes; i++)
+            {
+                b[offset++] = (byte)((v >> (8 * i)) & 0xFF);
+            }
         }
 
         /// <summary>
-        /// Get a int from a byte array start from the specifiled offset.
+        /// Write a int to a byte array.
         /// </summary>
-        public static uint GetUint(byte[] b, int offset)
+        public static void WriteIntLong(byte[] b, int offset, long v)
         {
-            return Unsafe.As<byte, uint>(ref b[offset]);
+            b[offset++] = (byte)((v >> 0) & 0xFF);
+            b[offset++] = (byte)((v >> 8) & 0xFF);
+            b[offset++] = (byte)((v >> 16) & 0xFF);
+            b[offset] = (byte)((v >> 24) & 0xFF);
         }
 
-        public static int GetInt(byte[] b, int offset)
+        /// <summary>
+        /// Get a int from a byte array start from the specifiled offset.
+        /// </summary>
+        public static long GetIntLong(byte[] b, int offset)
         {
-            return Unsafe.As<byte, int>(ref b[offset]);
+            return (
+                ((b[offset++] & 0x000000FFL)) |
+                ((b[offset++] << 8) & 0x0000FF00L) |
+                ((b[offset++] << 16) & 0x00FF0000L) |
+                ((b[offset] << 24) & 0xFF000000L)
+            );
         }
 
         /// <summary>
         /// Get a int from a byte array start from the specifield offset.
         /// </summary>
-        public static int GetInt24(byte[] b, int offset)
+        public static int GetInt3(byte[] b, int offset)
         {
-            return Unsafe.As<byte, Int24>(ref b[offset]);
+            return (
+                (b[offset++] & 0x000000FF) |
+                (b[offset++] & 0x0000FF00) |
+                (b[offset] & 0x00FF0000)
+            );
         }
 
-
-        public static ushort GetUshort(byte[] b, int offset)
+        public static int GetInt2(byte[] b, int offset)
         {
-            return Unsafe.As<byte, ushort>(ref b[offset]);
+            return (
+                (b[offset++] & 0x000000FF) |
+                (b[offset] & 0x0000FF00)
+            );
         }
 
-        public static byte GetByte(byte[] b, int offset)
+        public static int GetInt1(byte[] b, int offset)
         {
-            return b[offset];
+            return (
+                (b[offset] & 0x000000FF)
+            );
         }
-
         /// <summary>
         /// String ip to long ip.
         /// </summary>
-        public static uint String2NetworkIP(string ip)
+        public static long Ip2long(string ip)
         {
             string[] p = ip.Split('.');
-
             if (p.Length != 4) throw new IPInValidException();
 
-            uint ipVal = 0;
-
-            ref byte ipRef = ref Unsafe.As<uint, byte>(ref ipVal);
-
-            for (int i = 3; i > -1; i--)
+            foreach (string pp in p)
             {
-                if (byte.TryParse(p[i], out byte part))
-                {
-                    ref byte byteRef = ref Unsafe.Add(ref ipRef, i);
-                    byteRef = part;
-                }
-                else
+                if (pp.Length > 3) throw new IPInValidException();
+                if (!int.TryParse(pp, out int value) || value > 255)
                 {
                     throw new IPInValidException();
                 }
             }
+            var bip1 = long.TryParse(p[0], out long ip1);
+            var bip2 = long.TryParse(p[1], out long ip2);
+            var bip3 = long.TryParse(p[2], out long ip3);
+            var bip4 = long.TryParse(p[3], out long ip4);
 
-            return ipVal;
+            if (!bip1 || !bip2 || !bip3 || !bip4
+                || ip4 > 255 || ip1 > 255 || ip2 > 255 || ip3 > 255
+                || ip4 < 0 || ip1 < 0 || ip2 < 0 || ip3 < 0)
+            {
+                throw new IPInValidException();
+            }
+            long p1 = ((ip1 << 24) & 0xFF000000);
+            long p2 = ((ip2 << 16) & 0x00FF0000);
+            long p3 = ((ip3 << 8) & 0x0000FF00);
+            long p4 = ((ip4 << 0) & 0x000000FF);
+            return ((p1 | p2 | p3 | p4) & 0xFFFFFFFFL);
         }
 
         /// <summary>
         /// Int to ip string.
         /// </summary>
-        public static string IP2String(uint ipVal)
+        public static string Long2ip(long ip)
         {
-            ref byte ipRef = ref Unsafe.As<uint, byte>(ref ipVal);
-            StringBuilder ipString = new StringBuilder(15);
-            for(int i = 0; i < 4; i++)
-            {
-                if (i > 0)
-                {
-                    ipString.Append('.');
-                    ipString.Append(Unsafe.Add(ref ipRef, i));
-                }
-                else
-                {
-                    ipString.Append(ipRef);
-                }
-            }
-            return ipString.ToString();
+            return $"{(ip >> 24) & 0xFF}.{(ip >> 16) & 0xFF}.{(ip >> 8) & 0xFF}.{ip & 0xFF}";
         }
-
     }
-}
+
+}

+ 31 - 39
TEAMModelOS/Controllers/Client/HiScanController.cs

@@ -376,58 +376,51 @@ namespace TEAMModelOS.Controllers.Core
                 if (!request.TryGetProperty("id", out JsonElement id)) return BadRequest();
                 if (!request.TryGetProperty("schoolId", out JsonElement _schoolId)) return BadRequest();
                 if (!request.TryGetProperty("sheetNo", out JsonElement _sheetNo)) return BadRequest();
-                //if (!request.TryGetProperty("scope", out JsonElement _scope)) return BadRequest();
                 if (!request.TryGetProperty("owner", out JsonElement _owner)) return BadRequest();
                 var client = _azureCosmos.GetCosmosClient();
                 School school = null;
-                try
-                {
-                    school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
-                }
-                catch (CosmosException ex)
-                {
-                    if (ex.Status == 404)
-                    {
-                        school = null;
-                    }
-                }
-                var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
-               
+                school = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<School>($"{_schoolId}", new PartitionKey("Base"));
+                if (school == null) return BadRequest();
                 if ($"{_owner}".Equals("school", StringComparison.OrdinalIgnoreCase))
                 {
                     examData = await GetExamBySheet($"{_owner}", $"{_schoolId}", $"{_schoolId}", client,  classesSet, $"{_sheetNo}");
-                  
                 }
                 else {
-                    //获取scope=private
+                    var response = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync($"{id}", new PartitionKey("Base"));
                     examData = await GetExamBySheet($"{_owner}", null, $"{id}", client,  classesSet, $"{_sheetNo}");
-                    if (response.Status == 200 && examData == null && string.IsNullOrEmpty($"{_schoolId}")) {
-                        //获取scope=school
+                   
+                    if (examData == null && string.IsNullOrEmpty($"{_schoolId}")) {
                         examData = await GetExamBySheet($"{_owner}", $"{_schoolId}", $"{id}", client, classesSet, $"{_sheetNo}");
                     }
-                    
                 }
-
+                
                 (List<RMember> tmdIds, List<RGroupList> classInfo) = await GroupListService.GetStutmdidListids(client, _dingDing, classesSet.ToList(), $"{_schoolId}");
                 List<SheetConfig> configsN = new List<SheetConfig>();
                 if (examData.sheet != null) {
                     if (examData.sheet.scope.Equals("school"))
                     {
-                        try
+                        Azure.Response azure = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemStreamAsync(examData.sheet.id, new PartitionKey(examData.sheet.code));
+                        if (azure.Status == 200 && azure.Content!=null )
                         {
-                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "School").ReadItemAsync<SheetConfig>(examData.sheet.id, new PartitionKey(examData.sheet.code));
-                            configsN.Add(con);
+                            SheetConfig config = JsonDocument.Parse(azure.Content).RootElement.Deserialize<SheetConfig>();
+                            if (config != null)
+                            {
+                                configsN.Add(config);
+                            }
+                           
                         }
-                        catch (CosmosException ex) { }
                     }
                     else
                     {
-                        try
+                        Azure.Response azure = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemStreamAsync(examData.sheet.id, new PartitionKey(examData.sheet.code));
+                        if (azure.Status == 200 && azure.Content != null)
                         {
-                            SheetConfig con = await client.GetContainer(Constant.TEAMModelOS, "Teacher").ReadItemAsync<SheetConfig>(examData.sheet.id, new PartitionKey(examData.sheet.code));
-                            configsN.Add(con);
+                            SheetConfig config = JsonDocument.Parse(azure.Content).RootElement.Deserialize<SheetConfig>();
+                            if (config != null)
+                            {
+                                configsN.Add(config);
+                            }
                         }
-                        catch (CosmosException ex) { }
                     }
                 }
                 if (examData != null)
@@ -515,17 +508,16 @@ namespace TEAMModelOS.Controllers.Core
                 SheetConfig config = null;
                 if (!string.IsNullOrEmpty(pap.sheet))
                 {
-                    //if (pap.scope.Equals("school"))
-                    //{
-                    //    config = new SheetConfig { id = pap.sheet, scope = pap.scope, code = $"SheetConfig-{exam.school}" };
-                    //    paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
-                    //}
-                    //else {
-                    //    config = new SheetConfig { id = pap.sheet, scope = pap.scope, code = $"SheetConfig-{code}" };
-                    //    paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
-                    //}
-                    config = new SheetConfig { id = pap.sheet, scope = pap.scope, code = $"SheetConfig-{pap.code.Replace("Paper-", "")}" };
-                    paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
+                    if (exam.scope.Equals("school"))
+                    {
+                        config = new SheetConfig { id = pap.sheet, scope = exam.scope, code = $"SheetConfig-{exam.school}" };
+                        paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
+                    }
+                    else
+                    {
+                        config = new SheetConfig { id = pap.sheet, scope = exam.scope, code = $"SheetConfig-{code}" };
+                        paper = new PaperRcdData { name = pap.name, answers = pap.answers, point = pap.point };
+                    }
                 }
                 else
                 {

+ 19 - 3
TEAMModelOS/Controllers/System/CoreController.cs

@@ -15,6 +15,7 @@ using System.Text.RegularExpressions;
 using System.Threading.Tasks;
 using TEAMModelOS.Models;
 using TEAMModelOS.Models.Request;
+using TEAMModelOS.SDK;
 using TEAMModelOS.SDK.DI;
 using TEAMModelOS.SDK.Extension;
 using TEAMModelOS.SDK.Models.Service;
@@ -31,8 +32,10 @@ namespace TEAMModelOS.Controllers
         private readonly DingDing _dingDing;
         private readonly Option _option;
         private readonly HttpClient _httpClient;
-        public CoreController(AzureRedisFactory azureRedis, AzureStorageFactory azureStorage , DingDing dingDing, IOptionsSnapshot<Option> option, HttpClient httpClient)
+        private readonly IPSearcher _searcher;
+        public CoreController(IPSearcher searcher,AzureRedisFactory azureRedis, AzureStorageFactory azureStorage , DingDing dingDing, IOptionsSnapshot<Option> option, HttpClient httpClient)
         {
+            _searcher= searcher;
             _azureStorage = azureStorage;
             _dingDing = dingDing;
             _option = option?.Value;
@@ -74,7 +77,7 @@ namespace TEAMModelOS.Controllers
 
         [HttpPost("system-info")]
         [RequestSizeLimit(100_000_000)] //最大100m左右
-        public IActionResult SystemInfo(JsonElement request)
+        public async Task<IActionResult> SystemInfo(JsonElement request)
         {
 
             //var v1 = Assembly.GetEntryAssembly().GetName().Version;
@@ -92,7 +95,20 @@ namespace TEAMModelOS.Controllers
             //Console.WriteLine($"Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion:" +
 
             //                  $"{Assembly.GetEntryAssembly().GetCustomAttribute<AssemblyInformationalVersionAttribute>().InformationalVersion}");5.2107.12
-            return Ok(new { version, description, nowtime });
+
+            var IpPort = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+            if (string.IsNullOrEmpty(IpPort))
+            {
+                IpPort = HttpContext.Connection.RemoteIpAddress.ToString();
+            }
+            if (IpPort.Contains("::"))
+            {
+                IpPort = "127.0.0.1";
+            }
+            string ip = IpPort.Split(":")[0];
+            string region = await _searcher.SearchIpAsync(ip);
+
+            return Ok(new { version, description, nowtime , region,ip });
         }
         /// <summary>
         /// 等待P1V3,啟動Dcoker,支持EMF GDI+

+ 16 - 12
TEAMModelOS/Controllers/Teacher/InitController.cs

@@ -44,10 +44,10 @@ namespace TEAMModelOS.Controllers
         private readonly IConfiguration _configuration;
         private readonly NotificationService _notificationService;
         private readonly CoreAPIHttpService _coreAPIHttpService;
-        //private readonly IP2RegionFileSearcher _iP2Region;
-        public InitController( CoreAPIHttpService coreAPIHttpService,AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, NotificationService notificationService)
+        private readonly IPSearcher _searcher;
+        public InitController(IPSearcher searcher, CoreAPIHttpService coreAPIHttpService,AzureCosmosFactory azureCosmos, AzureStorageFactory azureStorage, DingDing dingDing, IOptionsSnapshot<Option> option, IConfiguration configuration, NotificationService notificationService)
         {
-           // _iP2Region = iP2Region;
+            _searcher = searcher;
             _azureCosmos = azureCosmos;
             _azureStorage = azureStorage;
             _dingDing = dingDing;
@@ -269,30 +269,34 @@ namespace TEAMModelOS.Controllers
         }
 
 
-        private   void LoginLog(string id, string name, int status) {
+        private   async void LoginLog(string id, string name, int status) {
             HttpContext.Request.Headers.TryGetValue("referer", out var referer);
             HttpContext.Request.Headers.TryGetValue("sec-ch-ua", out var chua);
             HttpContext.Request.Headers.TryGetValue("sec-ch-ua-platform", out var platform);
             HttpContext.Request.Headers.TryGetValue("user-agent", out var useragent);
        
-            var userHostAddress = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
-            if (string.IsNullOrEmpty(userHostAddress))
+            var IpPort = HttpContext.Request.Headers["X-Forwarded-For"].FirstOrDefault();
+            if (string.IsNullOrEmpty(IpPort))
             {
-                userHostAddress = HttpContext.Connection.RemoteIpAddress.ToString();
+                IpPort = HttpContext.Connection.RemoteIpAddress.ToString();
             }
-            if (userHostAddress.Contains("::")) 
+            if (IpPort.Contains("::")) 
             {
-                userHostAddress = "127.0.0.1";
+                IpPort = "127.0.0.1";
             }
+            string ip = IpPort.Split(":")[0];
+            string region= await _searcher.SearchIpAsync(ip);
+          
             if (status == 200)
             {
-                Trace.TraceInformation($"{_option.Location} -- {name}({id}):Login Succeed! --Time:{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")} " +
-                    $"--Browser Info( --referer:{referer}  --sec-ch-ua:{chua}  --sec-ch-ua-platform:{platform}  --user-agent:{useragent}  --ip:{userHostAddress} )");
+                string msg = $"{_option.Location} -- {name}({id}):Login Succeed! --Time:{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")} " +
+                    $"--Browser Info( --referer:{referer}  --sec-ch-ua:{chua}  --sec-ch-ua-platform:{platform}  --user-agent:{useragent}  --ip:{IpPort} --region:{region} )";
+                Trace.TraceInformation(msg);
             }
             else
             {
                 string msg = $"{_option.Location} -- {name}({id}):Login Failed! --Time:{DateTimeOffset.UtcNow.ToString("yyyy-MM-dd HH:mm:ss")} " +
-                         $"--Browser Info( --referer:{referer}  --sec-ch-ua:{chua}  --sec-ch-ua-platform:{platform}  --user-agent:{useragent}  --ip:{userHostAddress} )";
+                         $"--Browser Info( --referer:{referer}  --sec-ch-ua:{chua}  --sec-ch-ua-platform:{platform}  --user-agent:{useragent}  --ip:{IpPort} --region:{region} )";
                 Trace.TraceError(msg);
                 _ = _dingDing.SendBotMsg($"IES5,{_option.Location},{msg}",GroupNames.成都开发測試群組);
             }

+ 4 - 5
TEAMModelOS/Controllers/XTest/TestController.cs

@@ -3,7 +3,6 @@ using Azure.Messaging.ServiceBus;
 using Azure.Storage.Blobs.Models;
 using HTEXLib.COMM.Helpers;
 using HTEXLib.Helpers.ShapeHelpers;
-using IP2Region;
 using Microsoft.AspNetCore.Hosting;
 using Microsoft.AspNetCore.Http;
 using Microsoft.AspNetCore.Mvc;
@@ -51,8 +50,9 @@ namespace TEAMModelOS.Controllers
         private readonly AzureServiceBusFactory _serviceBus;
         private readonly CoreAPIHttpService _coreAPIHttpService;
         private readonly Option _option;
+        private readonly IPSearcher _searcher;
         public IConfiguration _configuration { get; set; }
-        public TestController(IOptionsSnapshot<Option> option, CoreAPIHttpService coreAPIHttpService, HttpClient httpClient,IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IConfiguration configuration, AzureServiceBusFactory serviceBus, DingDing dingDing)
+        public TestController(IPSearcher searcher,IOptionsSnapshot<Option> option, CoreAPIHttpService coreAPIHttpService, HttpClient httpClient,IWebHostEnvironment environment, AzureCosmosFactory azureCosmos, AzureRedisFactory azureRedis, AzureStorageFactory azureStorage, IConfiguration configuration, AzureServiceBusFactory serviceBus, DingDing dingDing)
         {
             _azureCosmos = azureCosmos;
             _azureRedis = azureRedis;
@@ -63,6 +63,7 @@ namespace TEAMModelOS.Controllers
             _httpClient= httpClient;
             _option= option.Value;
             _coreAPIHttpService= coreAPIHttpService;
+            _searcher= searcher;
         }
          
       
@@ -651,9 +652,7 @@ namespace TEAMModelOS.Controllers
         [HttpPost("get-ip")]
         public async Task<IActionResult> GetIp(JsonElement request)
         {
-            string path = $"{ _environment.ContentRootPath}/JsonFile/Core/ip2region.db";
-            FileSearcher iP2RegionFileSearcher = new FileSearcher(path);
-            var ip =   iP2RegionFileSearcher.BtreeSearch($"{request.GetProperty("ip")}");
+            string ip = await _searcher.SearchIpAsync($"{request.GetProperty("ip")}");
             return Ok(ip);
         }
     }

파일 크기가 너무 크기때문에 변경 상태를 표시하지 않습니다.
+ 0 - 683591
TEAMModelOS/JsonFile/Core/ip.merge.txt


BIN
TEAMModelOS/JsonFile/Core/ip2region.db


+ 1 - 1
TEAMModelOS/Startup.cs

@@ -118,7 +118,7 @@ namespace TEAMModelOS
             //注入word 標籤解析
             string path = $"{ environment.ContentRootPath}/JsonFile/Core";
             services.AddHtexTranslator(path);
-            //services.AddIP2Region(path);
+            services.AddIPSearcher(path);
             services.AddServerSentEvents(o =>
             {
                 o.KeepaliveMode = ServerSentEventsKeepaliveMode.Always;