25.09.05
parent
407c803550
commit
d6696ff765
|
@ -11,7 +11,7 @@ bind = "0.0.0.0:8000"
|
||||||
workers = 2
|
workers = 2
|
||||||
|
|
||||||
# 工作模式(sync、gevent、uvicorn.workers.UvicornWorker)
|
# 工作模式(sync、gevent、uvicorn.workers.UvicornWorker)
|
||||||
worker_class = "uvicorn.workers.UvicornWorker"
|
worker_class = "uvicorn_worker.UvicornWorker"
|
||||||
|
|
||||||
# 日志目录
|
# 日志目录
|
||||||
log_dir = Path("logs")
|
log_dir = Path("logs")
|
||||||
|
@ -34,7 +34,7 @@ accesslog = "logs/access.log"
|
||||||
errorlog = "-"
|
errorlog = "-"
|
||||||
|
|
||||||
# access_log_format 仅在 同步 worker 下有效,UvicornWorker下不可用;以 YAML 配置优先
|
# access_log_format 仅在 同步 worker 下有效,UvicornWorker下不可用;以 YAML 配置优先
|
||||||
# access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
||||||
raw_env = [
|
raw_env = [
|
||||||
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
|
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
|
||||||
]
|
]
|
||||||
|
@ -44,9 +44,3 @@ timeout = 120
|
||||||
|
|
||||||
# Keep-Alive超时
|
# Keep-Alive超时
|
||||||
keepalive = 5
|
keepalive = 5
|
||||||
|
|
||||||
# 进程名(ps aux 中显示)
|
|
||||||
# proc_name = "gunicorn"
|
|
||||||
|
|
||||||
# 守护进程运行(后台运行,默认 False)
|
|
||||||
# daemon = True
|
|
||||||
|
|
|
@ -11,7 +11,7 @@ bind = "0.0.0.0:8000"
|
||||||
workers = 2
|
workers = 2
|
||||||
|
|
||||||
# 工作模式(sync、gevent、uvicorn.workers.UvicornWorker)
|
# 工作模式(sync、gevent、uvicorn.workers.UvicornWorker)
|
||||||
worker_class = "uvicorn.workers.UvicornWorker"
|
worker_class = "uvicorn_worker.UvicornWorker"
|
||||||
|
|
||||||
# 日志目录
|
# 日志目录
|
||||||
log_dir = Path("logs")
|
log_dir = Path("logs")
|
||||||
|
@ -34,7 +34,7 @@ accesslog = "logs/access.log"
|
||||||
errorlog = "-"
|
errorlog = "-"
|
||||||
|
|
||||||
# access_log_format 仅在 同步 worker 下有效,UvicornWorker下不可用;以 YAML 配置优先
|
# access_log_format 仅在 同步 worker 下有效,UvicornWorker下不可用;以 YAML 配置优先
|
||||||
# access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
access_log_format = '%(h)s %(l)s %(u)s %(t)s "%(r)s" %(s)s %(b)s "%(f)s" "%(a)s" %(D)s'
|
||||||
raw_env = [
|
raw_env = [
|
||||||
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
|
"UVICORN_ACCESS_LOGFORMAT=%(h)s %(l)s %(u)s %(t)s \"%(r)s\" %(s)s %(b)s \"%(f)s\" \"%(a)s\" %(D)s"
|
||||||
]
|
]
|
||||||
|
@ -44,9 +44,3 @@ timeout = 120
|
||||||
|
|
||||||
# Keep-Alive超时
|
# Keep-Alive超时
|
||||||
keepalive = 5
|
keepalive = 5
|
||||||
|
|
||||||
# 进程名(ps aux 中显示)
|
|
||||||
# proc_name = "gunicorn"
|
|
||||||
|
|
||||||
# 守护进程运行(后台运行,默认 False)
|
|
||||||
# daemon = True
|
|
||||||
|
|
|
@ -311,10 +311,10 @@ class Favicon:
|
||||||
Returns:
|
Returns:
|
||||||
域名是否合法且非内网地址
|
域名是否合法且非内网地址
|
||||||
"""
|
"""
|
||||||
return _check_internal(domain) and _pattern_domain.match(domain)
|
return Favicon.check_internal(domain) and _pattern_domain.match(domain)
|
||||||
|
|
||||||
@staticmethod
|
@staticmethod
|
||||||
def _check_internal(domain: str) -> bool:
|
def check_internal(domain: str) -> bool:
|
||||||
"""检查网址是否非内网地址
|
"""检查网址是否非内网地址
|
||||||
|
|
||||||
Args:
|
Args:
|
||||||
|
@ -348,27 +348,4 @@ _pattern_domain = re.compile(
|
||||||
|
|
||||||
|
|
||||||
def _check_url(domain: str) -> Optional[Any]:
|
def _check_url(domain: str) -> Optional[Any]:
|
||||||
return _check_internal(domain) and _pattern_domain.match(domain)
|
return Favicon.check_internal(domain) and _pattern_domain.match(domain)
|
||||||
|
|
||||||
|
|
||||||
def _check_internal(domain: str) -> bool:
|
|
||||||
"""
|
|
||||||
检查网址是否非内网地址
|
|
||||||
Args:
|
|
||||||
domain:
|
|
||||||
|
|
||||||
Returns: True 非内网;False 是内网/无法解析
|
|
||||||
"""
|
|
||||||
try:
|
|
||||||
if domain.replace('.', '').isdigit():
|
|
||||||
return not ipaddress.ip_address(domain).is_private
|
|
||||||
else:
|
|
||||||
ips = socket.getaddrinfo(domain, None)
|
|
||||||
for ip_info in ips:
|
|
||||||
ip = ip_info[4][0]
|
|
||||||
if '.' in ip:
|
|
||||||
return not ipaddress.ip_address(ip).is_private
|
|
||||||
return True
|
|
||||||
except Exception as e:
|
|
||||||
print(f"解析网址出错: {e}")
|
|
||||||
return False
|
|
||||||
|
|
|
@ -344,7 +344,7 @@ class FaviconService:
|
||||||
with self._lock:
|
with self._lock:
|
||||||
if entity.domain in self.domain_list:
|
if entity.domain in self.domain_list:
|
||||||
self.domain_list.remove(entity.domain)
|
self.domain_list.remove(entity.domain)
|
||||||
# 同时从两个队列中移除元素(处理完成)
|
# 任务完成,从两个队列中移出元素
|
||||||
self._queue_pull(True, self.icon_queue)
|
self._queue_pull(True, self.icon_queue)
|
||||||
self._queue_pull(True, self.total_queue)
|
self._queue_pull(True, self.total_queue)
|
||||||
|
|
||||||
|
@ -401,7 +401,8 @@ class FaviconService:
|
||||||
if _cached and not cached_icon:
|
if _cached and not cached_icon:
|
||||||
# 缓存已过期,后台刷新缓存
|
# 缓存已过期,后台刷新缓存
|
||||||
logger.info(f"缓存已过期,加入后台队列刷新: {entity.domain}")
|
logger.info(f"缓存已过期,加入后台队列刷新: {entity.domain}")
|
||||||
# 只增加总队列计数,不增加实时队列计数(后台任务)
|
# 开始图标处理,加入两个队列
|
||||||
|
self.icon_queue.put(entity.domain)
|
||||||
self.total_queue.put(entity.domain)
|
self.total_queue.put(entity.domain)
|
||||||
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
||||||
|
|
||||||
|
@ -415,31 +416,33 @@ class FaviconService:
|
||||||
if not is_sync:
|
if not is_sync:
|
||||||
# 返回默认图片并加入后台队列
|
# 返回默认图片并加入后台队列
|
||||||
logger.info(f"返回默认图片并加入后台队列: {entity.domain}")
|
logger.info(f"返回默认图片并加入后台队列: {entity.domain}")
|
||||||
# 只增加总队列计数,不增加实时队列计数(后台任务)
|
# 开始图标处理,加入两个队列
|
||||||
|
self.icon_queue.put(entity.domain)
|
||||||
self.total_queue.put(entity.domain)
|
self.total_queue.put(entity.domain)
|
||||||
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
||||||
return self.get_default(0)
|
return self.get_default()
|
||||||
else:
|
else:
|
||||||
# 没有缓存,实时处理,检查队列大小
|
# 没有缓存,实时处理,检查队列大小
|
||||||
queue_size = self.icon_queue.qsize()
|
queue_size = self.icon_queue.qsize()
|
||||||
if queue_size >= self.MAX_QUEUE_SIZE:
|
if queue_size >= self.MAX_QUEUE_SIZE:
|
||||||
# 加入后台队列并返回默认图片
|
# 加入后台队列并返回默认图片
|
||||||
logger.info(f"队列大小({queue_size})>={self.MAX_QUEUE_SIZE},返回默认图片并加入后台队列: {entity.domain}")
|
logger.info(f"队列大小({queue_size})>={self.MAX_QUEUE_SIZE},返回默认图片并加入后台队列: {entity.domain}")
|
||||||
# 只增加总队列计数,不增加实时队列计数(后台任务)
|
# 开始图标处理,加入两个队列
|
||||||
|
self.icon_queue.put(entity.domain)
|
||||||
self.total_queue.put(entity.domain)
|
self.total_queue.put(entity.domain)
|
||||||
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
bg_tasks.add_task(self.get_icon_sync, entity, _cached)
|
||||||
return self.get_default(0)
|
return self.get_default()
|
||||||
else:
|
else:
|
||||||
# 队列<MAX_QUEUE_SIZE,实时处理
|
# 队列<MAX_QUEUE_SIZE,实时处理
|
||||||
logger.info(f"队列大小({queue_size})<{self.MAX_QUEUE_SIZE},实时处理: {entity.domain}")
|
logger.info(f"队列大小({queue_size})<{self.MAX_QUEUE_SIZE},实时处理: {entity.domain}")
|
||||||
# 同时增加两个队列计数(实时处理任务)
|
# 开始图标处理,加入两个队列
|
||||||
self.icon_queue.put(entity.domain)
|
self.icon_queue.put(entity.domain)
|
||||||
self.total_queue.put(entity.domain)
|
self.total_queue.put(entity.domain)
|
||||||
icon_content = self.get_icon_sync(entity, _cached)
|
icon_content = self.get_icon_sync(entity, _cached)
|
||||||
|
|
||||||
if not icon_content:
|
if not icon_content:
|
||||||
# 获取失败,返回默认图标,不缓存
|
# 获取失败,返回默认图标,不缓存
|
||||||
return self.get_default(0)
|
return self.get_default()
|
||||||
|
|
||||||
# 确定内容类型和缓存时间
|
# 确定内容类型和缓存时间
|
||||||
content_type = filetype.guess_mime(icon_content) if icon_content else ""
|
content_type = filetype.guess_mime(icon_content) if icon_content else ""
|
||||||
|
@ -451,7 +454,7 @@ class FaviconService:
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logger.error(f"处理图标请求时发生错误 {url}: {e}")
|
logger.error(f"处理图标请求时发生错误 {url}: {e}")
|
||||||
# 返回默认图标
|
# 返回默认图标
|
||||||
return self.get_default(0)
|
return self.get_default()
|
||||||
|
|
||||||
def get_header(self, content_type: str, cache_time: int = None) -> dict:
|
def get_header(self, content_type: str, cache_time: int = None) -> dict:
|
||||||
return self._get_header(content_type, cache_time)
|
return self._get_header(content_type, cache_time)
|
||||||
|
|
9
main.py
9
main.py
|
@ -30,13 +30,10 @@ app.include_router(favicon_router)
|
||||||
|
|
||||||
@app.middleware("http")
|
@app.middleware("http")
|
||||||
async def log_referer(request: Request, call_next):
|
async def log_referer(request: Request, call_next):
|
||||||
_flag = True if ('/icon' in request.url.path and 'url=' in request.url.query) else False
|
_referrer = request.headers.get('referrer') or request.headers.get('referer')
|
||||||
logger.info('#' * 60) if _flag else None
|
if _referrer:
|
||||||
referer = request.headers.get('referrer') or request.headers.get('referer')
|
FileUtil.write_file(referer_log_file, '%s\n' % _referrer, mode='a')
|
||||||
if referer:
|
|
||||||
FileUtil.write_file(referer_log_file, referer, mode='a', atomic=True)
|
|
||||||
response = await call_next(request)
|
response = await call_next(request)
|
||||||
logger.info('#' * 60) if _flag else None
|
|
||||||
return response
|
return response
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -8,4 +8,5 @@ beautifulsoup4~=4.13.5
|
||||||
lxml~=6.0.1
|
lxml~=6.0.1
|
||||||
PyYAML~=6.0.2
|
PyYAML~=6.0.2
|
||||||
uvicorn~=0.35.0
|
uvicorn~=0.35.0
|
||||||
|
uvicorn-worker~=0.3.0
|
||||||
gunicorn~=23.0.0
|
gunicorn~=23.0.0
|
||||||
|
|
4
run.py
4
run.py
|
@ -7,10 +7,8 @@ if __name__ == "__main__":
|
||||||
"main:app",
|
"main:app",
|
||||||
host="127.0.0.1",
|
host="127.0.0.1",
|
||||||
port=8000,
|
port=8000,
|
||||||
reload=False,
|
reload=True,
|
||||||
log_level="info",
|
log_level="info",
|
||||||
# log_level="warning",
|
|
||||||
workers=1,
|
|
||||||
)
|
)
|
||||||
server = uvicorn.Server(config)
|
server = uvicorn.Server(config)
|
||||||
server.run()
|
server.run()
|
||||||
|
|
Loading…
Reference in New Issue