pbls/app/pbls.py

112 lines
5.0 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.

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""pbls —— PBL Agent OS 应用唯一入口(端口 9300见 projects/pbls/env/test.json:port
框架铁律web-application-spec
- 入口必须 `from ahserver.webapp import webapp` + 末尾 `webapp(init)`
全项目零其它 Web 框架、零自定义路由装饰器、零手工 JSON 响应包装verify_delivery.py 扫描零命中)。
- 加载顺序固定:`ServerEnv()` → 基础模块appbase/rbac/pybricks→ 业务模块。
基础模块必须**显式调用 loader**load_appbase/load_rbac/load_pybricks
只 importlib.import_module 就标 loaded 是反模式(登录/权限链路必崩)。
- 库名由应用统一决定get_module_dbname(m) 从 conf/config.json 的 module_dbmap 读,
模块侧禁止硬编码 DBNAME。
- 端口唯一来源 = projects/pbls/env/{test,prod}.json 的 port应用仓库不设 env/ 目录。
挂载规模对账QC #1320 个 load_* 调用 = 3 平台基础模块appbase/rbac/pybricks
+ 5 复用基座模块world/scene/entity/script_engine/scense_game
+ 12 个 pbl_* 模块(见下 MODULE_LOAD_ORDER编号 M1~M12 与 modules/*.md 一一对应)。
"""
import json
import os
from ahserver.webapp import webapp
from ahserver.serverenv import ServerEnv
import bricks_for_python # registers bui processor
from bricks_for_python.init import load_pybricks # registers UiWindow etc.
from appbase.init import load_appbase
from rbac.init import load_rbac
CONF = os.path.join(os.path.dirname(os.path.dirname(os.path.abspath(__file__))),
'conf', 'config.json')
# 12 个 pbl_* 业务模块(编号 ↔ 目录M10=pbl_appcodes 零表、M12=pbl_common 内核)
MODULE_LOAD_ORDER = [
('pbl', 'pbl_common'), # M12 公共内核(必须最先,提供租户/DB 出口)
('pbl', 'pbl_appcodes'), # M10 枚举 6+2 组幂等注入
('pbl', 'pbl_blueprint'), # M1 蓝图聚合根 + 子对象 + 版本 + 模板
('pbl', 'pbl_validation'), # M2 14 维校验 + 5 级质量状态
('pbl', 'pbl_compiler'), # M3 确定性编译 + Game Definition + Capability
('pbl', 'pbl_agent_runtime'), # M4 Designer/Critic + fail-closed 工具裁决
('pbl', 'pbl_domain_ext'), # M8 world/scene/entity 薄扩展(不改基表)
('pbl', 'pbl_runtime_ext'), # M11 单事务事件+状态写入与广播
('pbl', 'pbl_evidence'), # M5 产出物 + 证据幂等采集
('pbl', 'pbl_assessment'), # M6 Rubric 加权评估与报告
('pbl', 'pbl_kdb_ext'), # M7 KDB 只读桩 + 匿名聚合
('pbl', 'pbl_scense_ext'), # M9 前端覆盖层上下文 + 页面注册
]
# 复用基座模块(只读引用 + 薄扩展,不改基表;缺失时降级并明确回报,不静默假成功)
BASE_MODULE_LOADERS = ['world', 'scene', 'entity', 'script_engine', 'scense_game']
def _conf():
with open(CONF, encoding='utf-8') as f:
return json.load(f)
def get_module_dbname(m):
"""模块 → 库名映射(来自 conf/config.json:module_dbmap禁止写死单个库名"""
conf = _conf()
mapping = conf.get('module_dbmap') or {}
if m in mapping:
return mapping[m]
return mapping.get('*') or conf.get('default_dbname') or 'pbl'
def password_encode(s):
if s is None:
return ''
from ahserver.globalEnv import password_encode as _orig
return _orig(s)
def init():
env = ServerEnv() # ← MUST be before load_rbac
env.get_module_dbname = get_module_dbname
env.password_encode = password_encode
env.pbl_default_dbname = get_module_dbname('pbl')
env.pbl_default_tenant = _conf().get('default_tenant') or 'default'
# ── 基础模块:显式调用 loader反模式禁令不得只 import 就标 loaded──
load_appbase()
load_rbac()
load_pybricks()
# ── 复用基座模块world/scene/entity/script_engine/scense_game──
missing = []
for name in BASE_MODULE_LOADERS:
try:
pkg = __import__('importlib').import_module('%s.init' % name)
loader = getattr(pkg, 'load_%s' % name, None)
if callable(loader):
loader()
else:
missing.append(name) # 无 loader 即视为未挂载,不谎报 loaded
except ImportError:
missing.append(name)
# ── 12 个 pbl_* 业务模块(按 Wave 依赖顺序)──
loaded = []
for _db, name in MODULE_LOAD_ORDER:
pkg = __import__('importlib').import_module('%s.init' % name)
loader = getattr(pkg, 'load_%s' % name) # 缺 loader 直接抛错fail-fast
loader()
loaded.append(name)
env.pbl_modules_loaded = loaded
env.pbl_base_missing = missing
print('[pbls] modules loaded: %d pbl + base missing=%s' % (len(loaded), missing or 'none'))
return {'loaded': len(loaded) + 3, 'base_missing': missing}
if __name__ == '__main__':
webapp(init)