129 lines
4.1 KiB
TypeScript
129 lines
4.1 KiB
TypeScript
/**
|
|
* 整个APP的环境配置逻辑
|
|
*/
|
|
import { sys } from "cc";
|
|
import { DEBUG, EDITOR, PREVIEW } from "cc/env";
|
|
import { Env, AppConfigShape } from "./env";
|
|
import { devConfig } from "./dev";
|
|
import { testConfig } from "./test";
|
|
import { prodConfig } from "./prod";
|
|
|
|
type PartialEndpoints = Partial<AppConfigShape["endpoints"]>;
|
|
|
|
const LS_ENV_KEY = "app_env";
|
|
const LS_OVERRIDE_KEY = "app_endpoints_override"; // 存JSON字符串
|
|
|
|
export class AppConfig {
|
|
private static _I: AppConfig | null = null;
|
|
static get I(): AppConfig {
|
|
if (!AppConfig._I) AppConfig._I = new AppConfig();
|
|
return AppConfig._I;
|
|
}
|
|
|
|
private _cfg!: AppConfigShape;
|
|
|
|
private constructor() {
|
|
const env = this.detectEnv();
|
|
this._cfg = this.byEnv(env);
|
|
|
|
// 运行时覆盖:query > localStorage
|
|
// this.applyQueryOverride();
|
|
// this.applyLocalOverride();
|
|
}
|
|
|
|
public getEnv(): Env { return this._cfg.env; }
|
|
public isDev(): boolean { return this._cfg.env === Env.Dev; }
|
|
public isTest(): boolean { return this._cfg.env === Env.Test; }
|
|
public isProd(): boolean { return this._cfg.env === Env.Prod; }
|
|
get endpoints() { return this._cfg.endpoints; }
|
|
|
|
/** 切换环境(开发工具用) */
|
|
public switchEnv(env: Env) {
|
|
this._cfg = this.byEnv(env);
|
|
sys.localStorage.setItem(LS_ENV_KEY, env);
|
|
}
|
|
|
|
/** 运行时局部覆盖 endpoints(紧急切换) */
|
|
public overrideEndpoints(patch: PartialEndpoints) {
|
|
this._cfg = {
|
|
...this._cfg,
|
|
endpoints: { ...this._cfg.endpoints, ...patch, cdn: { ...this._cfg.endpoints.cdn, ...(patch.cdn || {}) } }
|
|
};
|
|
sys.localStorage.setItem(LS_OVERRIDE_KEY, JSON.stringify(patch));
|
|
}
|
|
|
|
/** 清除覆盖,回到纯环境配置 */
|
|
public clearOverrides() {
|
|
sys.localStorage.removeItem(LS_OVERRIDE_KEY);
|
|
this._cfg = this.byEnv(this._cfg.env);
|
|
}
|
|
|
|
/** 获取 HTTP 基础地址
|
|
* @param stripTrailingSlash 是否去掉末尾斜杠,默认 true
|
|
*/
|
|
public getHttpBase(stripTrailingSlash: boolean = true): string {
|
|
const raw = this._cfg.endpoints.httpBase || "";
|
|
if (stripTrailingSlash) {
|
|
return raw.replace(/\/+$/, "");
|
|
}
|
|
// 保证有一个结尾斜杠
|
|
return raw.endsWith("/") ? raw : raw + "/";
|
|
}
|
|
|
|
// ------------ 内部 ------------
|
|
private byEnv(env: Env): AppConfigShape {
|
|
switch (env) {
|
|
case Env.Dev: return devConfig;
|
|
case Env.Test: return testConfig;
|
|
default: return prodConfig;
|
|
}
|
|
}
|
|
|
|
private isEnv(x: any): x is Env {
|
|
return x === Env.Dev || x === Env.Test || x === Env.Prod;
|
|
}
|
|
|
|
/** 默认环境:优先 localStorage,再看 EDITOR/DEBUG,最后 prod */
|
|
private detectEnv(): Env {
|
|
const saved = sys.localStorage.getItem(LS_ENV_KEY) as Env | null;
|
|
if (saved && this.isEnv(saved)) {
|
|
return saved;
|
|
}
|
|
// 编辑器/预览时默认 dev
|
|
if (EDITOR || (PREVIEW && DEBUG)) return Env.Dev;
|
|
// 调试构建默认 test
|
|
if (DEBUG) return Env.Test;
|
|
// 发行构建默认 prod
|
|
return Env.Prod;
|
|
}
|
|
|
|
private applyLocalOverride() {
|
|
const raw = sys.localStorage.getItem(LS_OVERRIDE_KEY);
|
|
if (raw) {
|
|
try {
|
|
this.overrideEndpoints(JSON.parse(raw));
|
|
} catch { /* ignore */ }
|
|
}
|
|
}
|
|
|
|
/** 支持浏览器 query 覆盖:?env=test&http=...&socket=...&cdn_bgm=... */
|
|
private applyQueryOverride() {
|
|
if (!sys.isBrowser) return;
|
|
const qs = new URLSearchParams(window.location.search);
|
|
const qEnv = qs.get("env") as Env | null;
|
|
if (qEnv && this.isEnv(qEnv)) {
|
|
this._cfg = this.byEnv(qEnv);
|
|
sys.localStorage.setItem(LS_ENV_KEY, qEnv);
|
|
}
|
|
const patch: PartialEndpoints = {};
|
|
if (qs.get("http")) (patch.httpBase = qs.get("http")!);
|
|
if (qs.get("socket")) (patch.socketBase = qs.get("socket")!);
|
|
const cdnPatch: any = {};
|
|
if (qs.get("cdn_bgm")) cdnPatch.bgm = qs.get("cdn_bgm");
|
|
if (qs.get("cdn_zhen")) cdnPatch.zhenCang = qs.get("cdn_zhen");
|
|
if (qs.get("cdn_bgvideo")) cdnPatch.bgVideo = qs.get("cdn_bgvideo");
|
|
if (Object.keys(cdnPatch).length) (patch.cdn = cdnPatch);
|
|
if (Object.keys(patch).length) this.overrideEndpoints(patch);
|
|
}
|
|
}
|