/**
* URC识别器实现
*/
import * as fs from 'fs';
import { logger } from '@/utils/logger';
import { IURCDetector, URCConfig, URCPattern, URCOptions, URCError } from '@/types';
import { ErrorCode } from '@/utils/error-codes';
/**
* URC识别器实现类
*/
export class URCDetector implements IURCDetector {
private config: URCConfig | null = null;
private configPath: string = '';
private compiledPatterns: Map<string, RegExp> = new Map();
private watcher?: fs.FSWatcher;
private isEnabled: boolean = false;
constructor() {
// TODO: 初始化URC检测器
logger.debug('URCDetector initialized');
}
/**
* 加载URC配置
*/
async loadConfig(configPath: string): Promise<void> {
try {
logger.info(`Loading URC configuration from: ${configPath}`);
const content = await fs.promises.readFile(configPath, 'utf8');
const config = this.parseConfig(content);
// 验证配置
this.validateConfig(config);
// 编译正则表达式
this.compilePatterns(config.patterns);
// 保存配置
this.config = config;
this.configPath = configPath;
this.isEnabled = true;
logger.info(`URC configuration loaded successfully`, {
patternCount: config.patterns.length,
configFile: configPath
});
// 监听配置文件变化
this.watchConfigFile();
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to load URC configuration: ${configPath}`, errorObj);
throw new URCError(`URC Config Error: ${errorObj.message}`, undefined, errorObj.message);
}
}
/**
* 重新加载配置
*/
async reloadConfig(): Promise<void> {
if (!this.configPath) {
throw new URCError('Configuration file path not set');
}
logger.info('Reloading URC configuration...');
await this.loadConfig(this.configPath);
logger.info('URC configuration reloaded successfully');
}
/**
* 判断是否为URC
*/
isURC(line: string, port?: string): boolean {
if (!this.isEnabled || !this.config || !this.config.options.enableFilter) {
return false;
}
try {
const trimmedLine = line.trim();
if (trimmedLine.length === 0) {
return false;
}
// 检查行长度限制
if (trimmedLine.length > this.config.options.maxLineLength) {
return false;
}
// 遍历所有模式进行匹配
for (const [patternId, regex] of this.compiledPatterns) {
if (regex.test(trimmedLine)) {
logger.debug(`URC detected: ${patternId}`, {
port,
line: trimmedLine,
patternId
});
return true;
}
}
return false;
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to check URC: ${line}`, errorObj);
return false;
}
}
/**
* 提取URC和数据
*/
extract(data: Buffer, port?: string): { urc: string[]; data: Buffer } {
if (!this.isEnabled || !this.config || !this.config.options.enableFilter) {
return {
urc: [],
data
};
}
try {
const text = data.toString(this.config.options.encoding as BufferEncoding);
const lines = text.split(/\r?\n/);
const urcLines: string[] = [];
const dataLines: string[] = [];
for (const line of lines) {
const trimmedLine = line.trim();
if (trimmedLine.length === 0) {
// 保留空行以保持数据结构
dataLines.push(line);
continue;
}
if (this.isURC(trimmedLine, port)) {
urcLines.push(trimmedLine);
// 如果配置要求上报被过滤的URC,发布事件
if (this.config.options.reportFiltered) {
// TODO: 发布URC事件
logger.debug(`Filtered URC reported: ${trimmedLine}`, { port });
}
} else {
dataLines.push(line);
}
}
const result = {
urc: urcLines,
data: dataLines.join('\r\n') ? Buffer.from(dataLines.join('\r\n'), this.config.options.encoding as BufferEncoding) : Buffer.alloc(0)
};
if (urcLines.length > 0) {
logger.debug(`URC extraction completed`, {
port,
totalLines: lines.length,
urcCount: urcLines.length,
dataLines: dataLines.length
});
}
return result;
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to extract URC from data`, errorObj);
return {
urc: [],
data
};
}
}
/**
* 获取当前配置
*/
getConfig(): URCConfig {
if (!this.config) {
throw new URCError('URC configuration not loaded');
}
return this.config;
}
/**
* 添加自定义模式
*/
addPattern(pattern: string | RegExp, description?: string): void {
const patternId = `custom_${Date.now()}`;
const patternString = pattern instanceof RegExp ? pattern.source : pattern;
try {
const urcPattern: URCPattern = {
id: patternId,
pattern: patternString,
description: description || 'Custom pattern',
module: 'Custom'
};
// 编译正则表达式
const regex = pattern instanceof RegExp ? pattern : new RegExp(pattern);
this.compiledPatterns.set(patternId, regex);
// 添加到配置
if (this.config) {
this.config.patterns.push(urcPattern);
}
logger.info(`Custom URC pattern added: ${patternId}`, {
pattern: patternString,
description
});
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to add custom pattern: ${pattern}`, errorObj);
throw new URCError(`Invalid pattern: ${errorObj.message}`, patternId, patternString);
}
}
/**
* 移除模式
*/
removePattern(id: string): void {
try {
// 从编译模式中移除
if (this.compiledPatterns.has(id)) {
this.compiledPatterns.delete(id);
}
// 从配置中移除
if (this.config) {
this.config.patterns = this.config.patterns.filter(p => p.id !== id);
}
logger.info(`URC pattern removed: ${id}`);
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to remove pattern: ${id}`, errorObj);
}
}
/**
* 获取模式统计
*/
getPatternStats(): any {
if (!this.config) {
return null;
}
const stats = {
totalPatterns: this.config.patterns.length,
patternsByModule: {} as Record<string, number>,
enabled: this.isEnabled,
configPath: this.configPath
};
for (const pattern of this.config.patterns) {
const module = pattern.module || 'Unknown';
stats.patternsByModule[module] = (stats.patternsByModule[module] || 0) + 1;
}
return stats;
}
/**
* 测试模式
*/
testPattern(patternId: string, testLines: string[]): any {
try {
const regex = this.compiledPatterns.get(patternId);
if (!regex) {
throw new URCError(`Pattern not found: ${patternId}`);
}
const results = testLines.map(line => ({
line,
matches: regex.test(line.trim()),
match: line.trim().match(regex)
}));
const matchCount = results.filter(r => r.matches).length;
return {
patternId,
totalLines: testLines.length,
matchCount,
matchRate: matchCount / testLines.length,
results
};
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to test pattern: ${patternId}`, errorObj);
throw errorObj;
}
}
/**
* 启用/禁用URC检测
*/
setEnabled(enabled: boolean): void {
this.isEnabled = enabled;
logger.info(`URC detection ${enabled ? 'enabled' : 'disabled'}`);
}
/**
* 检查是否启用
*/
isEnabledDetector(): boolean {
return this.isEnabled;
}
/**
* 解析配置
*/
private parseConfig(content: string): URCConfig {
try {
// TODO: 使用YAML解析器
// 这里简化处理,实际应该使用yaml.parse
const config = JSON.parse(content) as URCConfig;
// 设置默认选项
if (!config.options) {
config.options = {
enableFilter: true,
reportFiltered: true,
maxLineLength: 1024,
encoding: 'utf8',
caseSensitive: false
};
}
return config;
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
throw new Error(`Failed to parse configuration: ${errorObj.message}`);
}
}
/**
* 验证配置
*/
private validateConfig(config: URCConfig): void {
if (!config.version) {
throw new Error('Configuration version is required');
}
if (!config.patterns || !Array.isArray(config.patterns)) {
throw new Error('Patterns array is required');
}
if (!config.options) {
throw new Error('Options are required');
}
// 验证每个模式
for (const pattern of config.patterns) {
if (!pattern.id || !pattern.pattern) {
throw new Error('Pattern must have id and pattern');
}
}
}
/**
* 编译正则表达式
*/
private compilePatterns(patterns: URCPattern[]): void {
this.compiledPatterns.clear();
for (const pattern of patterns) {
try {
const flags = pattern.description?.includes('case-insensitive') ? 'i' : '';
const regex = new RegExp(pattern.pattern, flags);
this.compiledPatterns.set(pattern.id, regex);
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.warn(`Failed to compile pattern: ${pattern.id}`, errorObj);
// 继续处理其他模式
}
}
logger.info(`Compiled ${this.compiledPatterns.size} URC patterns`);
}
/**
* 监听配置文件变化
*/
private watchConfigFile(): void {
if (!this.configPath) {
return;
}
try {
// 停止之前的监听
if (this.watcher) {
this.watcher.close();
}
// 开始监听
this.watcher = fs.watch(this.configPath, async (eventType) => {
if (eventType === 'change') {
logger.info('URC configuration file changed, reloading...');
try {
await this.reloadConfig();
logger.info('URC configuration reloaded successfully');
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error('Failed to reload URC configuration', errorObj);
}
}
});
logger.debug(`Watching URC configuration file: ${this.configPath}`);
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error(`Failed to watch configuration file: ${this.configPath}`, errorObj);
}
}
/**
* 销毁URC检测器
*/
dispose(): void {
try {
// 停止监听
if (this.watcher) {
this.watcher.close();
this.watcher = undefined;
}
// 清理状态
this.config = null;
this.compiledPatterns.clear();
this.isEnabled = false;
logger.info('URCDetector disposed');
} catch (error) {
const errorObj = error instanceof Error ? error : new Error(String(error));
logger.error('Failed to dispose URCDetector', errorObj);
}
}
}