tangweijie 7b40485f60 feat: 初始化 Monorepo 项目结构
- 添加 pnpm workspace 和 Turborepo 配置
- 创建 packages/shared 共享类型和工具
- 创建 packages/core-sdk 核心 SDK
- 创建 packages/vscode-extension VSCode 插件
- 创建 packages/jetbrains-plugin JetBrains 插件基础结构
- 添加 README 文档
2026-01-05 18:08:18 +08:00

227 lines
5.6 KiB
TypeScript

import type { BaseEvent, CollectorConfig, UserInfo, CodeContext } from '@ide-collector/shared';
import { DEFAULT_COLLECTOR_CONFIG, generateAnonymousUserId } from '@ide-collector/shared';
import { EventQueue } from './storage/event-queue';
import { HttpReporter } from './reporters/http-reporter';
import { PrivacyHandler } from './privacy/privacy-handler';
import { ConfigManager } from './config/config-manager';
/**
* IDE 数据采集器主类
*/
export class Collector {
private static instance: Collector | null = null;
private config: CollectorConfig;
private userInfo: UserInfo | null = null;
private eventQueue: EventQueue;
private reporter: HttpReporter;
private privacyHandler: PrivacyHandler;
private configManager: ConfigManager;
private flushTimer: ReturnType<typeof setInterval> | null = null;
private isInitialized = false;
private constructor(config: Partial<CollectorConfig> = {}) {
this.config = { ...DEFAULT_COLLECTOR_CONFIG, ...config };
this.eventQueue = new EventQueue(this.config.batchSize);
this.reporter = new HttpReporter(this.config.apiEndpoint);
this.privacyHandler = new PrivacyHandler(this.config.privacy);
this.configManager = new ConfigManager();
}
/**
* 获取单例实例
*/
public static getInstance(config?: Partial<CollectorConfig>): Collector {
if (!Collector.instance) {
Collector.instance = new Collector(config);
}
return Collector.instance;
}
/**
* 初始化采集器
*/
public async initialize(userInfo: Omit<UserInfo, 'userId'>): Promise<void> {
if (this.isInitialized) {
return;
}
// 加载保存的配置
const savedConfig = await this.configManager.loadConfig();
if (savedConfig) {
this.config = { ...this.config, ...savedConfig };
}
// 生成或恢复用户ID
const savedUserId = await this.configManager.getUserId();
this.userInfo = {
...userInfo,
userId: savedUserId || generateAnonymousUserId(),
};
// 保存用户ID
if (!savedUserId) {
await this.configManager.saveUserId(this.userInfo.userId);
}
// 恢复未发送的事件
const pendingEvents = await this.eventQueue.loadFromStorage();
if (pendingEvents.length > 0) {
console.log(`[Collector] Restored ${pendingEvents.length} pending events`);
}
// 启动定时刷新
this.startFlushTimer();
this.isInitialized = true;
console.log('[Collector] Initialized successfully');
}
/**
* 记录事件
*/
public async trackEvent(event: Omit<BaseEvent, 'userInfo'>): Promise<void> {
if (!this.isInitialized || !this.config.enabled) {
return;
}
// 检查采样率
if (Math.random() > this.config.samplingRate) {
return;
}
// 检查事件类型是否需要采集
if (!this.config.eventsToCapture.includes(event.eventType)) {
return;
}
// 应用隐私处理
const sanitizedEvent = this.privacyHandler.sanitizeEvent({
...event,
userInfo: this.userInfo!,
});
// 添加到队列
await this.eventQueue.enqueue(sanitizedEvent);
// 如果开启实时上报,立即发送
if (this.config.realtimeEnabled) {
await this.flush();
}
}
/**
* 强制刷新队列
*/
public async flush(): Promise<void> {
if (!this.isInitialized) {
return;
}
const events = await this.eventQueue.dequeueAll();
if (events.length === 0) {
return;
}
try {
await this.reporter.sendBatch(events);
console.log(`[Collector] Successfully sent ${events.length} events`);
} catch (error) {
console.error('[Collector] Failed to send events:', error);
// 重新入队失败的事件
for (const event of events) {
await this.eventQueue.enqueue(event);
}
}
}
/**
* 更新配置
*/
public async updateConfig(config: Partial<CollectorConfig>): Promise<void> {
this.config = { ...this.config, ...config };
this.privacyHandler = new PrivacyHandler(this.config.privacy);
this.reporter = new HttpReporter(this.config.apiEndpoint);
this.eventQueue.setMaxSize(this.config.batchSize);
// 重启定时器
this.stopFlushTimer();
this.startFlushTimer();
// 保存配置
await this.configManager.saveConfig(this.config);
}
/**
* 获取当前配置
*/
public getConfig(): CollectorConfig {
return { ...this.config };
}
/**
* 获取队列状态
*/
public getQueueStatus(): { size: number; maxSize: number } {
return {
size: this.eventQueue.size(),
maxSize: this.config.batchSize,
};
}
/**
* 暂停采集
*/
public pause(): void {
this.config.enabled = false;
this.stopFlushTimer();
}
/**
* 恢复采集
*/
public resume(): void {
this.config.enabled = true;
this.startFlushTimer();
}
/**
* 销毁采集器
*/
public async destroy(): Promise<void> {
this.stopFlushTimer();
await this.flush();
this.isInitialized = false;
Collector.instance = null;
}
/**
* 创建代码上下文
*/
public createCodeContext(context: Partial<CodeContext>): CodeContext {
return this.privacyHandler.sanitizeContext({
filePath: context.filePath || '',
language: context.language || 'unknown',
...context,
});
}
private startFlushTimer(): void {
if (this.flushTimer) {
return;
}
this.flushTimer = setInterval(
() => this.flush(),
this.config.flushIntervalSeconds * 1000
);
}
private stopFlushTimer(): void {
if (this.flushTimer) {
clearInterval(this.flushTimer);
this.flushTimer = null;
}
}
}