fix(config): VersionResolver 改为 4 层逐级回退(agent/game/channel/market 每层 merge 全字段)
原实现资源字段 game_zip/game_version 只在 game/channel/market 三层覆盖、app 字段只在 market 层,漏了 agent 层。按 4 层模型:每个字段取最深命中层非空值、深层缺省逐级回退到根。 Acc 合并为单个 merge() 每层调用。新增 agent层回退/app上浮回退/四层全覆盖 3 个单测。 Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.8
parent
763ee42345
commit
a6ef891507
@@ -8,8 +8,9 @@
|
||||
* 真实字段要点(与旧实现的差异,均为"破坏 H5 适配"的根因):
|
||||
* - 资源下载字段名是 **game_zip**(非 game_download)。
|
||||
* - marketid / app_version / game_version 在 JSON 里是**数字**,匹配/比较需做 string↔number 归一。
|
||||
* - app 升级字段 app_download/app_version 落在 market 层;资源字段 game_zip/game_version
|
||||
* 可出现在 game / channel / market 各层,越深越后、覆盖前层("0"/空视为未设置不覆盖)。
|
||||
* - **4 层逐级回退**:game_zip/game_version 与 app_download/app_version 等所有升级字段,
|
||||
* 可出现在 agent / game / channel / market 任一层(节点类型均 extends VersionFields),
|
||||
* 取最深命中层的非空值、深层缺省则逐级回退到浅层直至根("0"/空视为未设置不覆盖)。
|
||||
*/
|
||||
|
||||
/** JSON 里既可能是字符串也可能是数字的标量(id、版本号等)。 */
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
/**
|
||||
* 分层版本决策 —— **复刻 Android `chuliversion_1` 真实逻辑**(纯函数,无 IO,便于单测)。
|
||||
* 分层版本决策 —— **4 层逐级回退模型**(纯函数,无 IO,便于单测)。
|
||||
*
|
||||
* 遍历真实层级 agentlist → gamelist → channellist → marketlist,逐层下钻匹配
|
||||
* agentid / gameid / channelid / marketid(marketid 数字与本地字符串归一比较)。
|
||||
* 层级(由浅入深 1→4):agentlist(1) → gamelist(2) → channellist(3) → marketlist(4),
|
||||
* 逐层用 agentid / gameid / channelid / marketid 匹配(marketid 数字与本地字符串归一比较)。
|
||||
*
|
||||
* 累积规则(与 Android 一致):
|
||||
* - 资源升级 game_zip/game_version:在 game、channel、market 三层累积,越深越后、覆盖前层;
|
||||
* "0" 或空的 game_version 不覆盖(视为未设置)。
|
||||
* - App 升级 app_download/app_version:取 market 层值。
|
||||
* - showmessage:任一命中层非空即生效(阻断)。
|
||||
* - 最终资源版本与本地 version.xml 比较由调用方决定是否下载 game_zip。
|
||||
* 取值规则(**每个字段独立**):取**最深命中层**的非空值;该层缺失则逐级回退到上一层,
|
||||
* 直到根节点(showmessage 根层可携带;game/app 升级字段根层无、回退至多到 agent 层)。
|
||||
* 实现等价:由浅入深遍历,每命中一层就对全字段做"非空(zip/download/size/msg)或非零(version)即覆盖前层",
|
||||
* 故越深的非空值覆盖越浅、深层缺省则保留浅层值。"0"/空视为未设置、不覆盖。
|
||||
* 不再区分"资源字段只在 game/channel/market、app 字段只在 market"——四层对所有字段一视同仁。
|
||||
*/
|
||||
import { AgentNode, ChannelNode, GameNode, MarketNode,
|
||||
MatchKeys, RemoteConfig, Scalar, VersionDecision, VersionFields, asStr } from '../config/RemoteConfig';
|
||||
@@ -24,12 +23,12 @@ function parseVer(v: Scalar | undefined): number {
|
||||
return isNaN(n) ? 0 : n;
|
||||
}
|
||||
|
||||
/** game_version 是否为"有效非零"(用于决定是否覆盖累积值)。 */
|
||||
/** 版本是否"有效非零"(用于决定是否覆盖累积值)。 */
|
||||
function hasVer(v: Scalar | undefined): boolean {
|
||||
return parseVer(v) > 0;
|
||||
}
|
||||
|
||||
/** 累积器:复刻 chuliversion_1 的 newgame_zip / newgame_version + app 字段 + showmessage。 */
|
||||
/** 累积器:由浅入深逐层 merge,每字段非空/非零覆盖前层(= 取最深命中层值、深层缺省回退浅层)。 */
|
||||
class Acc {
|
||||
gameZip: string = '';
|
||||
gameVersion: number = 0;
|
||||
@@ -39,8 +38,8 @@ class Acc {
|
||||
appSize: string = '';
|
||||
showmessage: string = '';
|
||||
|
||||
/** 资源字段覆盖(game/channel/market 各层调用):非空 zip 覆盖;非零 version 覆盖。 */
|
||||
mergeGame(n: VersionFields): void {
|
||||
/** 单层全字段覆盖(agent/game/channel/market 每命中一层都调用)。 */
|
||||
merge(n: VersionFields): void {
|
||||
const zip: string = n.game_zip ?? '';
|
||||
if (zip !== '') {
|
||||
this.gameZip = zip;
|
||||
@@ -48,25 +47,21 @@ class Acc {
|
||||
if (hasVer(n.game_version)) {
|
||||
this.gameVersion = parseVer(n.game_version);
|
||||
}
|
||||
const size: string = n.game_size ?? '';
|
||||
if (size !== '') {
|
||||
this.gameSize = size;
|
||||
const gsize: string = n.game_size ?? '';
|
||||
if (gsize !== '') {
|
||||
this.gameSize = gsize;
|
||||
}
|
||||
}
|
||||
|
||||
/** App 升级字段(market 层):下载地址与版本均非空才采纳。 */
|
||||
mergeApp(n: VersionFields): void {
|
||||
const dl: string = n.app_download ?? '';
|
||||
const ver: string = asStr(n.app_version);
|
||||
if (dl !== '' && ver !== '') {
|
||||
if (dl !== '') {
|
||||
this.appDownload = dl;
|
||||
this.appVersion = parseVer(n.app_version);
|
||||
this.appSize = n.app_size ?? '';
|
||||
}
|
||||
}
|
||||
|
||||
/** 命中层公告非空即记录(最后非空者生效)。 */
|
||||
mergeMsg(n: VersionFields): void {
|
||||
if (hasVer(n.app_version)) {
|
||||
this.appVersion = parseVer(n.app_version);
|
||||
}
|
||||
const asize: string = n.app_size ?? '';
|
||||
if (asize !== '') {
|
||||
this.appSize = asize;
|
||||
}
|
||||
const msg: string = n.showmessage ?? '';
|
||||
if (msg !== '') {
|
||||
this.showmessage = msg;
|
||||
@@ -75,7 +70,7 @@ class Acc {
|
||||
}
|
||||
|
||||
export class VersionResolver {
|
||||
/** 真实层级遍历:agent → game → channel → market。 */
|
||||
/** 4 层逐级回退:agent → game → channel → market,逐层 merge 全字段(深层覆盖浅层、缺省回退)。 */
|
||||
static resolve(remote: RemoteConfig, keys: MatchKeys): VersionDecision {
|
||||
const acc: Acc = new Acc();
|
||||
const rootMsg: string = remote.showmessage ?? '';
|
||||
@@ -86,23 +81,19 @@ export class VersionResolver {
|
||||
const agent: AgentNode | undefined =
|
||||
(remote.agentlist ?? []).find((a: AgentNode) => (a.agentid ?? '') === keys.agentid);
|
||||
if (agent !== undefined) {
|
||||
acc.mergeMsg(agent);
|
||||
acc.merge(agent); // 层1 agent
|
||||
const game: GameNode | undefined =
|
||||
(agent.gamelist ?? []).find((g: GameNode) => (g.gameid ?? '') === keys.gameid);
|
||||
if (game !== undefined) {
|
||||
acc.mergeMsg(game);
|
||||
acc.mergeGame(game);
|
||||
acc.merge(game); // 层2 game
|
||||
const channel: ChannelNode | undefined =
|
||||
(game.channellist ?? []).find((c: ChannelNode) => (c.channelid ?? '') === keys.channelid);
|
||||
if (channel !== undefined) {
|
||||
acc.mergeMsg(channel);
|
||||
acc.mergeGame(channel);
|
||||
acc.merge(channel); // 层3 channel
|
||||
const market: MarketNode | undefined =
|
||||
(channel.marketlist ?? []).find((m: MarketNode) => asStr(m.marketid) === keys.marketid);
|
||||
if (market !== undefined) {
|
||||
acc.mergeMsg(market);
|
||||
acc.mergeGame(market);
|
||||
acc.mergeApp(market);
|
||||
acc.merge(market); // 层4 market
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user