diff --git a/CHANGELOG.md b/CHANGELOG.md index 18a148bb..b0b36a9d 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,3 +1,41 @@ + +# [v1.13.4](https://github.com/fastapi-practices/fastapi-best-architecture/releases/tag/v1.13.4) - 2026-04-28 + +## What's Changed +* Update changelog for v1.13.3 by [@wu-clan](https://github.com/wu-clan) in [#1149](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1149) +* Update the architecture description in README by [@wu-clan](https://github.com/wu-clan) in [#1150](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1150) +* Fix app pytest client fixture scope by [@IAseven](https://github.com/IAseven) in [#1152](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1152) +* Remove cleanup operations after plugin install by [@wu-clan](https://github.com/wu-clan) in [#1154](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1154) +* Fix mysql enum data type mismatch by [@wu-clan](https://github.com/wu-clan) in [#1155](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1155) +* Bump dependencies and pre-commits by [@wu-clan](https://github.com/wu-clan) in [#1156](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1156) +* Add plugin depends on and lifecycle ordering by [@AH-Toby](https://github.com/AH-Toby) in [#1153](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1153) +* Update plugin README content format by [@wu-clan](https://github.com/wu-clan) in [#1158](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1158) +* Update Grafana dashboard and datasource config by [@wu-clan](https://github.com/wu-clan) in [#1159](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1159) +* Add database and queue observability by [@wu-clan](https://github.com/wu-clan) in [#1160](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1160) +* Fix Grafana tempo and observability config by [@wu-clan](https://github.com/wu-clan) in [#1161](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1161) +* Add the snowflake ID enabled config by [@wu-clan](https://github.com/wu-clan) in [#1162](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1162) +* Fix the add plugin CLI command config by [@wu-clan](https://github.com/wu-clan) in [#1163](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1163) +* Optimize the core code ordering of plugins by [@wu-clan](https://github.com/wu-clan) in [#1164](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1164) +* Add uninstall plugin operation checks by [@wu-clan](https://github.com/wu-clan) in [#1165](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1165) +* Fix multi level cache storage logic by [@wu-clan](https://github.com/wu-clan) in [#1166](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1166) +* Fix typing warnings for return methods by [@wu-clan](https://github.com/wu-clan) in [#1167](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1167) +* Bump dependencies and pre-commits by [@wu-clan](https://github.com/wu-clan) in [#1168](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1168) +* Update the version number to 1.13.4 by [@wu-clan](https://github.com/wu-clan) in [#1169](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1169) + +## New Contributors +* [@AH-Toby](https://github.com/AH-Toby) made their first contribution in [#1153](https://github.com/fastapi-practices/fastapi-best-architecture/pull/1153) + +**Full Changelog**: https://github.com/fastapi-practices/fastapi-best-architecture/compare/v1.13.3...v1.13.4 + +## Contributors + +@AH-Toby +@IAseven +@wu-clan + +[Changes][v1.13.4] + + # [v1.13.3](https://github.com/fastapi-practices/fastapi-best-architecture/releases/tag/v1.13.3) - 2026-04-08 @@ -1473,6 +1511,7 @@ [Changes][v1.0.0] +[v1.13.4]: https://github.com/fastapi-practices/fastapi-best-architecture/compare/v1.13.3...v1.13.4 [v1.13.3]: https://github.com/fastapi-practices/fastapi-best-architecture/compare/v1.13.2...v1.13.3 [v1.13.2]: https://github.com/fastapi-practices/fastapi-best-architecture/compare/v1.13.1...v1.13.2 [v1.13.1]: https://github.com/fastapi-practices/fastapi-best-architecture/compare/v1.13.0...v1.13.1 diff --git a/backend/static/ip2region_v4.xdb b/backend/static/ip2region_v4.xdb index 6f86c7d9..45edd141 100644 Binary files a/backend/static/ip2region_v4.xdb and b/backend/static/ip2region_v4.xdb differ diff --git a/backend/utils/request_parse.py b/backend/utils/request_parse.py index 4939e933..5a6f308c 100644 --- a/backend/utils/request_parse.py +++ b/backend/utils/request_parse.py @@ -1,7 +1,8 @@ import httpx +import ip2region.searcher as ip2region_xdb +import ip2region.util as ip2region_util from fastapi import Request -from ip2loc import XdbSearcher from user_agents import parse from backend.common.dataclasses import IpInfo, UserAgentInfo @@ -53,8 +54,9 @@ async def get_location_online(ip: str) -> dict | None: return None -# 离线 IP 搜索器单例(数据将缓存到内存,缓存大小取决于 IP 数据文件大小) -__xdb_searcher = XdbSearcher(contentBuff=XdbSearcher.loadContentFromFile(dbfile=STATIC_DIR / 'ip2region_v4.xdb')) +# 离线 IP 搜索器(数据将缓存到内存,缓存大小取决于 IP 数据文件大小) +__c_buffer: bytes = ip2region_util.load_content_from_file(STATIC_DIR / 'ip2region_v4.xdb') +__xdb_searcher: ip2region_xdb.Searcher = ip2region_xdb.new_with_buffer(ip2region_util.IPv4, __c_buffer) def get_location_offline(ip: str) -> dict | None: @@ -66,15 +68,16 @@ def get_location_offline(ip: str) -> dict | None: """ try: data = __xdb_searcher.search(ip) - data = data.split('|') - return { - 'country': data[0] if data[0] != '0' else None, - 'regionName': data[1] if data[1] != '0' else None, - 'city': data[2] if data[2] != '0' else None, - } + country, region_name, city, *_ = data.split('|') except Exception as e: - log.error(f'离线获取 IP 地址属地失败,错误信息:{e}') + log.error(f'离线获取 IP 地址属地失败:{e}') return None + else: + return { + 'country': country if country != '0' else None, + 'regionName': region_name if region_name != '0' else None, + 'city': city if city != '0' else None, + } async def parse_ip_info(request: Request) -> IpInfo: diff --git a/pyproject.toml b/pyproject.toml index b06f5950..c8f90861 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -28,7 +28,6 @@ dependencies = [ "flower>=2.0.1", "gevent>=25.9.1", "granian>=2.7.4", - "ip2loc>=1.0.0", "itsdangerous>=2.2.0", "jinja2>=3.1.6", "loguru>=0.7.3", @@ -47,6 +46,7 @@ dependencies = [ # https://github.com/fastapi-practices/fastapi_best_architecture/issues/887 "psycopg[binary]==3.2.10", "pwdlib>=0.3.0", + "py-ip2region>=3.0.4", "pydantic>=2.13.3", "pydantic-settings>=2.14.0", "pymysql>=1.1.2", diff --git a/requirements.txt b/requirements.txt index 198a171d..4908fb7a 100644 --- a/requirements.txt +++ b/requirements.txt @@ -138,8 +138,6 @@ importlib-metadata==8.7.1 # via opentelemetry-api iniconfig==2.3.0 # via pytest -ip2loc==1.0.0 - # via fastapi-best-architecture itsdangerous==2.2.0 # via fastapi-best-architecture jinja2==3.1.6 @@ -260,6 +258,8 @@ psycopg-binary==3.2.10 ; implementation_name != 'pypy' # via psycopg pwdlib==0.3.0 # via fastapi-best-architecture +py-ip2region==3.0.4 + # via fastapi-best-architecture pyasn1==0.6.3 # via # python-jose diff --git a/uv.lock b/uv.lock index 65338900..a7d07fe7 100644 --- a/uv.lock +++ b/uv.lock @@ -2252,7 +2252,6 @@ dependencies = [ { name = "flower" }, { name = "gevent" }, { name = "granian" }, - { name = "ip2loc" }, { name = "itsdangerous" }, { name = "jinja2" }, { name = "loguru" }, @@ -2270,6 +2269,7 @@ dependencies = [ { name = "psutil" }, { name = "psycopg", extra = ["binary"] }, { name = "pwdlib" }, + { name = "py-ip2region" }, { name = "pydantic" }, { name = "pydantic-settings" }, { name = "pymysql" }, @@ -2325,7 +2325,6 @@ requires-dist = [ { name = "flower", specifier = ">=2.0.1" }, { name = "gevent", specifier = ">=25.9.1" }, { name = "granian", specifier = ">=2.7.4" }, - { name = "ip2loc", specifier = ">=1.0.0" }, { name = "itsdangerous", specifier = ">=2.2.0" }, { name = "jinja2", specifier = ">=3.1.6" }, { name = "loguru", specifier = ">=0.7.3" }, @@ -2346,6 +2345,7 @@ requires-dist = [ { name = "psutil", specifier = ">=7.2.2" }, { name = "psycopg", extras = ["binary"], specifier = "==3.2.10" }, { name = "pwdlib", specifier = ">=0.3.0" }, + { name = "py-ip2region", specifier = ">=3.0.4" }, { name = "pydantic", specifier = ">=2.13.3" }, { name = "pydantic-settings", specifier = ">=2.14.0" }, { name = "pymysql", specifier = ">=1.1.2" }, @@ -3998,21 +3998,6 @@ wheels = [ }, ] -[[package]] -name = "ip2loc" -version = "1.0.0" -source = { registry = "https://mirrors.aliyun.com/pypi/simple" } -sdist = { - url = "https://mirrors.aliyun.com/pypi/packages/80/74/b6f68d92571a11274c2a9d68c1c434f82a6c48a362e03386d356d8f6535b/ip2loc-1.0.0.tar.gz", - hash = "sha256:6707400f1f8580386708e6072c82293ccbad496368b9bf2fea13cfc274ab1ea7" -} -wheels = [ - { - url = "https://mirrors.aliyun.com/pypi/packages/55/9f/dd1a683eb6c58fcd37cce62ef2c910948fd14bf5e6398f15c03c6f9308ad/ip2loc-1.0.0-py3-none-any.whl", - hash = "sha256:8094e071acfb3ce65c588d61da50de0eb26b21d3dc068cee85ff01823c3bc947" - }, -] - [[package]] name = "itsdangerous" version = "2.2.0" @@ -6819,6 +6804,21 @@ wheels = [ }, ] +[[package]] +name = "py-ip2region" +version = "3.0.4" +source = { registry = "https://mirrors.aliyun.com/pypi/simple" } +sdist = { + url = "https://mirrors.aliyun.com/pypi/packages/60/b8/c8b934effe827e5d159b51912dc8366f5a490d7383943e982a801f5c3591/py_ip2region-3.0.4.tar.gz", + hash = "sha256:a8b818ed502a17feb998bdcf7c7748466aff368bcc75592c443aedf4eb6987f7" +} +wheels = [ + { + url = "https://mirrors.aliyun.com/pypi/packages/86/04/ef28263025ef08ec581875468f7ba08df6803fc729a0d464c3ad2161c1c7/py_ip2region-3.0.4-py3-none-any.whl", + hash = "sha256:7668e3756bc941045cf317a2116fe8359b0a70d88cee326decb836caa14bd77d" + }, +] + [[package]] name = "pyasn1" version = "0.6.3"