Dish_Recognition/dao/base_registry.py

193 lines
6.9 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# coding=utf-8
"""本机基地编码:注册/解析 bases,供模板 source_base_id 与 API 上报使用。"""
import datetime
from dao.database import is_server_available, local_session_scope, server_session_scope
from dao.settings import DISH_BASE_CODE, DISH_BASE_NAME, DISH_BASE_REGION
from models.App_settings import AppSetting
from models.Bases import BaseInfo
SETTING_BASE_ID = 'local_base_id'
SETTING_BASE_CODE = 'local_base_code'
SETTING_BASE_NAME = 'local_base_name'
def _set_setting(session, key, value):
row = session.get(AppSetting, key)
if row:
row.value = str(value) if value is not None else ''
else:
session.add(AppSetting(key=key, value=str(value) if value is not None else ''))
def _get_setting(session, key, default=None):
row = session.get(AppSetting, key)
if row and row.value not in (None, ''):
return row.value
return default
def _cache_local(base_id, base_code, base_name, region=None, contact=None):
"""把基地信息写入本地 SQLite(AppSetting + bases 镜像,避免 FK 问题)。"""
with local_session_scope() as session:
_set_setting(session, SETTING_BASE_ID, base_id if base_id is not None else '')
_set_setting(session, SETTING_BASE_CODE, base_code or '')
_set_setting(session, SETTING_BASE_NAME, base_name or '')
if base_id is None:
return
existing = session.get(BaseInfo, base_id)
now = datetime.datetime.now()
if existing:
existing.base_code = base_code
existing.base_name = base_name
existing.region = region
existing.contact = contact
existing.is_active = 1
existing.last_heartbeat = now
else:
session.add(BaseInfo(
id=base_id,
base_code=base_code,
base_name=base_name,
region=region,
contact=contact,
is_active=1,
register_time=now,
last_heartbeat=now,
))
def _read_cached():
with local_session_scope() as session:
raw_id = _get_setting(session, SETTING_BASE_ID)
base_id = None
if raw_id is not None:
try:
base_id = int(raw_id)
except (TypeError, ValueError):
base_id = None
return {
'id': base_id,
'base_code': _get_setting(session, SETTING_BASE_CODE, DISH_BASE_CODE),
'base_name': _get_setting(session, SETTING_BASE_NAME, DISH_BASE_NAME),
'online': False,
'source': 'cache',
}
def resolve_local_base(force_refresh=False):
"""
解析本机基地:
- 先从管理系统拉取基地列表写入 MySQL(可关 DISH_MGMT_SYNC_ON_START)
- 有 MySQL:按 DISH_BASE_CODE 查找;找不到再注册
- 无 MySQL:用本地缓存 / 环境变量(source_base_id 可能为空)
"""
code = (DISH_BASE_CODE or '').strip() or 'BASE_LOCAL_01'
name = (DISH_BASE_NAME or '').strip() or code
region = (DISH_BASE_REGION or '').strip() or None
# 启动/刷新时同步管理系统基地(失败不阻断本机解析)
try:
from dao.base_sync import sync_bases_from_mgmt
sync_bases_from_mgmt(force=force_refresh)
except Exception as exc:
print(f"[WARN] mgmt bases sync skipped: {exc}")
if not is_server_available():
cached = _read_cached()
cached['base_code'] = code or cached.get('base_code')
cached['base_name'] = name or cached.get('base_name')
cached['online'] = False
cached['source'] = 'offline'
print(f"[WARN] base registry offline, code={cached.get('base_code')}, id={cached.get('id')}")
return cached
try:
with server_session_scope() as session:
row = (
session.query(BaseInfo)
.filter(BaseInfo.base_code == code)
.first()
)
now = datetime.datetime.now()
if row:
# 已从管理系统同步的基地:保留管理系统名称,除非环境变量显式覆盖默认名
if name and name != '本地基地' and name != code:
row.base_name = name
if region:
row.region = region
row.is_active = 1
row.last_heartbeat = now
created = False
else:
row = BaseInfo(
base_code=code,
base_name=name,
region=region,
is_active=1,
register_time=now,
last_heartbeat=now,
)
session.add(row)
session.flush()
created = True
info = {
'id': row.id,
'base_code': row.base_code,
'base_name': row.base_name,
'region': row.region,
'contact': row.contact,
'external_id': getattr(row, 'external_id', None),
'branch_name': getattr(row, 'branch_name', None),
'online': True,
'source': 'mysql',
'created': created,
}
_cache_local(
info['id'], info['base_code'], info['base_name'],
region=info.get('region'), contact=info.get('contact'),
)
action = 'registered' if info.get('created') else 'resolved'
print(f"[OK] base {action}: {info['base_code']} (id={info['id']})")
return info
except Exception as exc:
print(f"[WARN] base registry failed: {exc}")
cached = _read_cached()
cached['online'] = False
cached['source'] = 'error'
cached['error'] = str(exc)
return cached
def touch_base_heartbeat(base_id=None):
"""同步成功后刷新基地心跳。"""
if base_id is None:
cached = _read_cached()
base_id = cached.get('id')
if not base_id or not is_server_available():
return False
try:
with server_session_scope() as session:
row = session.get(BaseInfo, base_id)
if not row:
return False
row.last_heartbeat = datetime.datetime.now()
code, name, region = row.base_code, row.base_name, row.region
_cache_local(base_id, code, name, region=region)
return True
except Exception as exc:
print(f"[WARN] base heartbeat failed: {exc}")
return False
def get_base_status_text(base_info=None):
info = base_info or _read_cached()
code = info.get('base_code') or DISH_BASE_CODE
name = info.get('base_name') or DISH_BASE_NAME or code
bid = info.get('id')
if info.get('online'):
return f"基地:{code}({name}) ID={bid}"
if bid:
return f"基地:{code}({name}) ID={bid} [离线缓存]"
return f"基地:{code}({name}) [未注册到总库]"