129 lines
3.6 KiB
JavaScript
129 lines
3.6 KiB
JavaScript
/**
|
||
* Notion Sync Layer · 模块入口(完整实现)
|
||
* GH-GMP-005 · M1 · Agent搬迁工程
|
||
*
|
||
* GMP标准模块接口 · init/start/stop/healthCheck
|
||
* 对外暴露:client, dbReader, pageRW, poller, cache
|
||
*/
|
||
|
||
'use strict';
|
||
|
||
const NotionSyncClient = require('./client');
|
||
const DBReader = require('./db-reader');
|
||
const PageRW = require('./page-rw');
|
||
const TicketPoller = require('./poller');
|
||
const TTLCache = require('./cache');
|
||
|
||
const MODULE_NAME = 'notion-sync';
|
||
const MODULE_VERSION = '1.0.0';
|
||
|
||
let client = null;
|
||
let dbReader = null;
|
||
let pageRW = null;
|
||
let poller = null;
|
||
let cache = null;
|
||
let logger = console;
|
||
|
||
module.exports = {
|
||
name: MODULE_NAME,
|
||
version: MODULE_VERSION,
|
||
type: 'service',
|
||
|
||
/**
|
||
* 初始化:创建Notion客户端,验证连接
|
||
*/
|
||
async init(context) {
|
||
logger = (context && context.logger) || console;
|
||
logger.info(`[${MODULE_NAME}] 初始化中 v${MODULE_VERSION}...`);
|
||
|
||
// 1. 创建客户端
|
||
client = new NotionSyncClient({ logger });
|
||
|
||
// 2. 验证Token有效性
|
||
const health = await client.healthCheck();
|
||
if (!health.ok) {
|
||
throw new Error(`[${MODULE_NAME}] Notion API连接失败: ${health.error}`);
|
||
}
|
||
logger.info(`[${MODULE_NAME}] Notion API连接成功 ✅`);
|
||
|
||
// 3. 读取工单数据库ID
|
||
const dbId = process.env.GH_NOTION_TICKET_DB_ID;
|
||
if (!dbId) {
|
||
throw new Error('[${MODULE_NAME}] GH_NOTION_TICKET_DB_ID 未配置');
|
||
}
|
||
|
||
// 4. 初始化子模块
|
||
cache = new TTLCache({ ttlMs: 10 * 60 * 1000, maxSize: 200 });
|
||
dbReader = new DBReader({ client, databaseId: dbId, logger });
|
||
pageRW = new PageRW({ client, logger });
|
||
|
||
logger.info(`[${MODULE_NAME}] 初始化完成 ✅ · DB: ${dbId.slice(0, 8)}...`);
|
||
return { status: 'ok', databaseId: dbId };
|
||
},
|
||
|
||
/**
|
||
* 启动轮询服务
|
||
* @param {object} context - 含 onNewTicket/onUpdatedTicket 回调
|
||
*/
|
||
async start(context) {
|
||
logger.info(`[${MODULE_NAME}] 启动同步服务...`);
|
||
|
||
const intervalMs = parseInt(process.env.AGENT_POLL_INTERVAL, 10) || 30000;
|
||
const stateDir = (context && context.dataDir) || process.cwd();
|
||
|
||
poller = new TicketPoller({
|
||
dbReader,
|
||
onNewTicket: (context && context.onNewTicket) || defaultNewTicketHandler,
|
||
onUpdatedTicket: (context && context.onUpdatedTicket) || null,
|
||
intervalMs,
|
||
stateDir,
|
||
logger,
|
||
});
|
||
|
||
poller.start();
|
||
logger.info(`[${MODULE_NAME}] 轮询已启动 · 间隔 ${intervalMs}ms`);
|
||
return { status: 'running', intervalMs };
|
||
},
|
||
|
||
async stop() {
|
||
logger.info(`[${MODULE_NAME}] 停止同步服务`);
|
||
if (poller) {
|
||
poller.stop();
|
||
poller = null;
|
||
}
|
||
if (cache) {
|
||
cache.clear();
|
||
}
|
||
return { status: 'stopped' };
|
||
},
|
||
|
||
async healthCheck() {
|
||
const clientHealth = client ? await client.healthCheck() : { ok: false, error: '未初始化' };
|
||
return {
|
||
status: clientHealth.ok ? 'ok' : 'error',
|
||
module: MODULE_NAME,
|
||
version: MODULE_VERSION,
|
||
notion: clientHealth,
|
||
poller: poller ? poller.stats : null,
|
||
cache: cache ? cache.stats : null,
|
||
};
|
||
},
|
||
|
||
// ─── 对外暴露子模块(供agent-engine调用)───
|
||
|
||
getClient: () => client,
|
||
getDBReader: () => dbReader,
|
||
getPageRW: () => pageRW,
|
||
getPoller: () => poller,
|
||
getCache: () => cache,
|
||
};
|
||
|
||
/**
|
||
* 默认新工单处理器(仅日志,实际由agent-engine覆盖)
|
||
*/
|
||
async function defaultNewTicketHandler(ticket) {
|
||
logger.info(
|
||
`[${MODULE_NAME}] 检测到新工单 · ${ticket['编号'] || '无编号'} · ${ticket['任务标题']} · 等待agent-engine处理`
|
||
);
|
||
}
|