diff --git a/unipay/init.py b/unipay/init.py index b950a26..fbe3793 100644 --- a/unipay/init.py +++ b/unipay/init.py @@ -1,5 +1,6 @@ # init.py import os +import traceback from appPublic.log import debug,exception from ahserver.configuredServer import add_startup from ahserver.serverenv import ServerEnv @@ -7,40 +8,85 @@ from .notify import get_provider, get_provider_channel from .paylog import PaymentLog, unipay_accounting from .payfee import get_pay_fee, sor_get_pay_fee, get_paychannels, get_pay_feerate -# 从 env 或配置载入 provider conf(这里只示例) -CONF = { - "transfer":{ - "pop3server": os.getenv("POP3SERVER", ""), - "mail": os.getenv("MAIL", ""), - "password": os.getenv("PASSWORD", ""), - "from_mail": os.getenv("FROM_MAIL", ""), - "account_no": os.getenv("ACCOUNT_NO", "") +# ────────────────────────────────────────────── +# 延迟加载:只存储 env key 名称,不在此处打开文件 +# 避免 import 阶段因文件缺失或 env 未设置而崩溃 +# ────────────────────────────────────────────── +CONF_ENV = { + "transfer": { + "pop3server": "POP3SERVER", + "mail": "MAIL", + "password": "PASSWORD", + "from_mail": "FROM_MAIL", + "account_no": "ACCOUNT_NO" }, "wechat": { - "mchid": os.getenv("WXP_MCHID",""), - "appid": os.getenv("WXP_APPID", ""), - "cert_serial_no": os.getenv("WXP_SERIAL",""), - "private_key_pem": open(os.getenv("WXP_PRIVKEY","./merchant_private_key.pem"),"rb").read(), - "api_v3_key": os.getenv("WXP_API_V3_KEY","") + "mchid": "WXP_MCHID", + "appid": "WXP_APPID", + "cert_serial_no": "WXP_SERIAL", + "private_key_pem_file": "WXP_PRIVKEY", + "api_v3_key": "WXP_API_V3_KEY" }, "paypal": { - "client_id": os.getenv("PP_ID",""), - "client_secret": os.getenv("PP_SECRET",""), - "sandbox": True + "client_id": "PP_ID", + "client_secret": "PP_SECRET", + "sandbox": True # 静态值 }, "alipay": { - "app_id": os.getenv("ALIPAY_APPID",""), - "app_private_key_pem": open(os.getenv("ALIPAY_PRIV","./alipay_priv.pem"),"rb").read(), - "alipay_public_key_pem": open(os.getenv("ALIPAY_PUB",""),"rb").read() + "app_id": "ALIPAY_APPID", + "app_private_key_pem_file": "ALIPAY_PRIV", + "alipay_public_key_pem_file": "ALIPAY_PUB" }, "stripe": { - "api_key": os.getenv("STRIPE_KEY","") + "api_key": "STRIPE_KEY" } } PROVIDERS = {} +def _build_provider_conf(provider_name: str) -> dict: + """从环境变量构造 provider 配置。打开文件、处理默认值。 + 如果关键环境变量缺失或文件打不开,抛异常由调用方处理。""" + conf_def = CONF_ENV.get(provider_name, {}) + conf = {} + for key, env_name in conf_def.items(): + if isinstance(env_name, bool): + conf[key] = env_name + continue + val = os.getenv(env_name, "") + conf[key] = val + + # 特殊处理:读取密钥文件 + if provider_name == "wechat": + privkey_path = conf.get("private_key_pem_file", "") + if not privkey_path: + raise FileNotFoundError(f"环境变量 WXP_PRIVKEY 未设置") + with open(privkey_path, "rb") as f: + conf["private_key_pem"] = f.read() + del conf["private_key_pem_file"] + + elif provider_name == "alipay": + priv_path = conf.get("app_private_key_pem_file", "") + pub_path = conf.get("alipay_public_key_pem_file", "") + if not priv_path: + raise FileNotFoundError(f"环境变量 ALIPAY_PRIV 未设置") + if not pub_path: + raise FileNotFoundError(f"环境变量 ALIPAY_PUB 未设置") + with open(priv_path, "rb") as f: + conf["app_private_key_pem"] = f.read() + with open(pub_path, "rb") as f: + conf["alipay_public_key_pem"] = f.read() + del conf["app_private_key_pem_file"] + del conf["alipay_public_key_pem_file"] + + return conf + + +# ────────────────────────────────────────────── +# 业务函数(不变) +# ────────────────────────────────────────────── + # 下单接口(统一) async def create_payment(request, params_kw=None): env = request._run_ns @@ -189,11 +235,19 @@ async def setup_callback_path(app): # callback url= "/unipay/notify/{provider}" def load_unipay(): - PROVIDERS["transfer"] = get_provider("transfer", CONF["transfer"]) - PROVIDERS["wechat"] = get_provider("wechat", CONF["wechat"]) - PROVIDERS["paypal"] = get_provider("paypal", CONF["paypal"]) - PROVIDERS["alipay"] = get_provider("alipay", CONF["alipay"]) - PROVIDERS["stripe"] = get_provider("stripe", CONF["stripe"]) + """注册各支付渠道到 PROVIDERS。初始化失败的渠道设为 None(disabled)。""" + for name in ("transfer", "wechat", "paypal", "alipay", "stripe"): + try: + conf = _build_provider_conf(name) + PROVIDERS[name] = get_provider(name, conf) + if PROVIDERS[name] is not None: + print(f"[unipay] {name} 初始化成功") + else: + print(f"[unipay] {name} 初始化返回 None(渠道 disabled)") + except Exception as e: + PROVIDERS[name] = None + print(f"[unipay] {name} 初始化失败,已禁用: {e}", flush=True) + env = ServerEnv() env.get_paychannels = get_paychannels env.get_pay_feerate = get_pay_feerate