M0: common 公共设施(T-M0-05)
框架 §10 横切层: - Logger:基于 HiLog 的分级日志(d/i/w/e/f),业务域 0x9527,tag 截断 31B - BridgeTracer:桥消息 traceId 自增 + 阶段打点,可还原全链路 - EventBus:封装 @ohos.events.emitter(on/once/emit/off,string eventId) - DIContainer:轻量 DI,支持单例/懒单例工厂注册与泛型解析 - ErrorCenter:异常收敛 + 处置策略(Notify/Silent/Report/Block),UI 处置经 sink 注入 - 经 entry 临时 smoke 验证编译通过(含 common→contracts 跨 HAR 引用) 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
26299c06ce
commit
f7f208e6c8
+8
-3
@@ -1,3 +1,8 @@
|
||||
// common HAR —— 横切基础设施(导出入口 SSOT)
|
||||
// 各子模块实现完成后在此统一 export。占位常量确保 HAR 可编译。
|
||||
export const common_MODULE_VERSION: string = '1.0.0';
|
||||
// common HAR —— 横切基础设施(框架 §10)
|
||||
// Logger/BridgeTracer/EventBus/DIContainer/ErrorCenter。Result/Errors 在 contracts 层。
|
||||
|
||||
export { Logger, LOG_DOMAIN } from './src/main/ets/log/Logger';
|
||||
export { BridgeTracer } from './src/main/ets/log/BridgeTracer';
|
||||
export { EventBus, EventPayload } from './src/main/ets/event/EventBus';
|
||||
export { DIContainer, Factory } from './src/main/ets/di/DIContainer';
|
||||
export { ErrorCenter, ErrorStrategy, ErrorSink } from './src/main/ets/error/ErrorCenter';
|
||||
|
||||
@@ -0,0 +1,49 @@
|
||||
/**
|
||||
* 轻量依赖注入容器(框架 §10)。组装根 AppModule 集中装配,避免在 struct/类内
|
||||
* 散落 new 业务对象。支持单例与工厂两种注册。
|
||||
*/
|
||||
export type Factory<T> = () => T;
|
||||
|
||||
export class DIContainer {
|
||||
private readonly singletons: Map<string, Object> = new Map<string, Object>();
|
||||
private readonly factories: Map<string, Factory<Object>> = new Map<string, Factory<Object>>();
|
||||
|
||||
/** 注册单例实例(立即持有)。 */
|
||||
registerInstance<T extends Object>(key: string, instance: T): void {
|
||||
this.singletons.set(key, instance);
|
||||
}
|
||||
|
||||
/** 注册工厂(懒创建;lazySingleton=true 时首次 resolve 后缓存为单例)。 */
|
||||
registerFactory<T extends Object>(key: string, factory: Factory<T>, lazySingleton: boolean = true): void {
|
||||
if (lazySingleton) {
|
||||
this.factories.set(key, () => {
|
||||
const existing: Object | undefined = this.singletons.get(key);
|
||||
if (existing !== undefined) {
|
||||
return existing;
|
||||
}
|
||||
const created: Object = factory();
|
||||
this.singletons.set(key, created);
|
||||
return created;
|
||||
});
|
||||
} else {
|
||||
this.factories.set(key, factory as Factory<Object>);
|
||||
}
|
||||
}
|
||||
|
||||
/** 解析依赖;未注册抛错。 */
|
||||
resolve<T>(key: string): T {
|
||||
const instance: Object | undefined = this.singletons.get(key);
|
||||
if (instance !== undefined) {
|
||||
return instance as T;
|
||||
}
|
||||
const factory: Factory<Object> | undefined = this.factories.get(key);
|
||||
if (factory !== undefined) {
|
||||
return factory() as T;
|
||||
}
|
||||
throw new Error(`DIContainer: no provider registered for key "${key}"`);
|
||||
}
|
||||
|
||||
has(key: string): boolean {
|
||||
return this.singletons.has(key) || this.factories.has(key);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,51 @@
|
||||
/**
|
||||
* 错误中心(框架 §10)。收敛全局异常,按策略处置:弹窗 / 静默 / 上报 / 阻断。
|
||||
*
|
||||
* common 层不直接依赖 UI,弹窗等需 UI 的处置由上层(entry)注入 sink 实现;
|
||||
* 本中心负责统一记录日志 + 分类 + 把错误分发给已注入的 sink。
|
||||
*/
|
||||
import { AppError, ErrorKind } from 'contracts';
|
||||
import { Logger } from '../log/Logger';
|
||||
|
||||
/** 处置策略。 */
|
||||
export enum ErrorStrategy {
|
||||
/** 轻提示用户(Toast/弹窗,由上层 sink 实现) */
|
||||
Notify = 'notify',
|
||||
/** 仅记录日志,不打扰用户 */
|
||||
Silent = 'silent',
|
||||
/** 上报到 APM/Crash(由上层 sink 实现) */
|
||||
Report = 'report',
|
||||
/** 阻断流程(如启动期 showmessage 公告) */
|
||||
Block = 'block',
|
||||
}
|
||||
|
||||
/** 上层注入的处置接收器。 */
|
||||
export type ErrorSink = (error: AppError, strategy: ErrorStrategy) => void;
|
||||
|
||||
export class ErrorCenter {
|
||||
private static readonly log: Logger = Logger.tag('ErrorCenter');
|
||||
private static sink: ErrorSink | undefined = undefined;
|
||||
|
||||
/** 由 entry 在启动时注入 UI 相关处置(弹窗/上报)。 */
|
||||
static setSink(sink: ErrorSink): void {
|
||||
ErrorCenter.sink = sink;
|
||||
}
|
||||
|
||||
/** 捕获并处置一个错误。默认策略:Notify。 */
|
||||
static capture(error: AppError, strategy: ErrorStrategy = ErrorStrategy.Notify): void {
|
||||
const line: string = `[${error.kind}]${error.code !== undefined ? '(' + error.code + ')' : ''} ${error.message}`;
|
||||
if (strategy === ErrorStrategy.Silent) {
|
||||
ErrorCenter.log.w(line);
|
||||
} else {
|
||||
ErrorCenter.log.e(line);
|
||||
}
|
||||
if (ErrorCenter.sink !== undefined) {
|
||||
ErrorCenter.sink(error, strategy);
|
||||
}
|
||||
}
|
||||
|
||||
/** 便捷:从原始异常收敛为 AppError 并处置。 */
|
||||
static captureException(kind: ErrorKind, message: string, cause?: Object, strategy?: ErrorStrategy): void {
|
||||
ErrorCenter.capture({ kind, message, cause }, strategy ?? ErrorStrategy.Notify);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,38 @@
|
||||
/**
|
||||
* 事件总线(框架 §10)。封装 @ohos.events.emitter,用于前后台、网络变化、
|
||||
* 容器间回传、TaskPool 进度等跨线程/跨模块解耦。
|
||||
*
|
||||
* 关键用途(框架 §5.5 / §9.1):能力在非 UI 线程产生的结果,可经 EventBus
|
||||
* emit,由 UI 线程订阅后再 callHandler 下发;TaskPool 进度只 emit Sendable 数据。
|
||||
*/
|
||||
import { emitter } from '@kit.BasicServicesKit';
|
||||
|
||||
/** 事件载荷:键值对,值为 Object(需可跨线程时只放 Sendable/基本类型)。 */
|
||||
export type EventPayload = Record<string, Object>;
|
||||
|
||||
export class EventBus {
|
||||
/** 持续订阅。 */
|
||||
static on(eventId: string, callback: (payload?: EventPayload) => void): void {
|
||||
emitter.on(eventId, (ev: emitter.EventData) => {
|
||||
callback(ev.data);
|
||||
});
|
||||
}
|
||||
|
||||
/** 单次订阅,触发后自动取消。 */
|
||||
static once(eventId: string, callback: (payload?: EventPayload) => void): void {
|
||||
emitter.once(eventId, (ev: emitter.EventData) => {
|
||||
callback(ev.data);
|
||||
});
|
||||
}
|
||||
|
||||
/** 发布事件。 */
|
||||
static emit(eventId: string, payload?: EventPayload): void {
|
||||
const data: emitter.EventData = { data: payload };
|
||||
emitter.emit(eventId, data);
|
||||
}
|
||||
|
||||
/** 取消该事件的全部订阅。 */
|
||||
static off(eventId: string): void {
|
||||
emitter.off(eventId);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
/**
|
||||
* 桥消息全链路追踪(框架 §10 / §13)。
|
||||
*
|
||||
* 每条桥消息分配一个 traceId,各阶段(拦截 yy:// → 解析 → 分发 handler →
|
||||
* 回执 → 出站下发)以同一 traceId 打点,可在日志里还原"H5 调用 → handler → 回传"。
|
||||
*/
|
||||
import { Logger } from './Logger';
|
||||
|
||||
export class BridgeTracer {
|
||||
private static seq: number = 0;
|
||||
private static readonly log: Logger = Logger.tag('BridgeTrace');
|
||||
|
||||
/** 生成新的 traceId(进程内自增唯一)。 */
|
||||
static next(): string {
|
||||
BridgeTracer.seq += 1;
|
||||
return `BR-${BridgeTracer.seq}`;
|
||||
}
|
||||
|
||||
/** 记录某条消息在某阶段的事件。 */
|
||||
static step(traceId: string, stage: string, detail: string): void {
|
||||
BridgeTracer.log.d(`[${traceId}] ${stage} | ${detail}`);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
/**
|
||||
* 分级日志封装(框架 §10 可观测)。基于 HiLog。
|
||||
*
|
||||
* 用法:`const log = Logger.tag('BridgeController'); log.i('xxx');`
|
||||
* 日志结果默认以 %{public} 明文输出(release 包对敏感字段务必先脱敏,见 ErrorCenter/调用方)。
|
||||
*/
|
||||
import { hilog } from '@kit.PerformanceAnalysisKit';
|
||||
|
||||
/** TSGame 业务域标识(0x0000~0xFFFF)。 */
|
||||
export const LOG_DOMAIN: number = 0x9527;
|
||||
|
||||
export class Logger {
|
||||
private readonly tag: string;
|
||||
|
||||
constructor(tag: string) {
|
||||
// HiLog tag 最多 31 字节,超出截断
|
||||
this.tag = tag.length > 31 ? tag.substring(0, 31) : tag;
|
||||
}
|
||||
|
||||
static tag(tag: string): Logger {
|
||||
return new Logger(tag);
|
||||
}
|
||||
|
||||
d(message: string): void {
|
||||
hilog.debug(LOG_DOMAIN, this.tag, '%{public}s', message);
|
||||
}
|
||||
|
||||
i(message: string): void {
|
||||
hilog.info(LOG_DOMAIN, this.tag, '%{public}s', message);
|
||||
}
|
||||
|
||||
w(message: string): void {
|
||||
hilog.warn(LOG_DOMAIN, this.tag, '%{public}s', message);
|
||||
}
|
||||
|
||||
e(message: string): void {
|
||||
hilog.error(LOG_DOMAIN, this.tag, '%{public}s', message);
|
||||
}
|
||||
|
||||
f(message: string): void {
|
||||
hilog.fatal(LOG_DOMAIN, this.tag, '%{public}s', message);
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user