74 lines
2.7 KiB
TypeScript
74 lines
2.7 KiB
TypeScript
/**
|
||
* 平台服务入口(架构设计第 2 节)。
|
||
*
|
||
* 组装:应用服务 + HTTP / SSE 入口。控制面(core)与引擎适配(agent)在后续阶段接入。
|
||
*/
|
||
import { randomUUID } from 'node:crypto';
|
||
import type { Server } from 'node:http';
|
||
import type { AddressInfo } from 'node:net';
|
||
|
||
import type { AgentRuntime } from './agent/runtime.js';
|
||
import { loadConfig } from './config.js';
|
||
import { ApplicationService } from './app/service.js';
|
||
import { createHttpServer } from './entry/http.js';
|
||
|
||
export { ApplicationService } from './app/service.js';
|
||
export type { Subject } from './app/subject.js';
|
||
export { createHttpServer } from './entry/http.js';
|
||
|
||
export interface StartOptions {
|
||
host?: string;
|
||
port?: number;
|
||
version?: string;
|
||
/** 引擎实现:默认假引擎;A3.3 起可换成 Pi 子进程,测试也可注入脚本化假引擎 */
|
||
runtime?: AgentRuntime;
|
||
}
|
||
|
||
export interface RunningServer {
|
||
url: string;
|
||
port: number;
|
||
service: ApplicationService;
|
||
/** 引擎工具回调的内部令牌:由平台生成,启动引擎子进程时注入(A3.11) */
|
||
internalToken: string;
|
||
close(): Promise<void>;
|
||
}
|
||
|
||
export async function startServer(options: StartOptions = {}): Promise<RunningServer> {
|
||
const config = loadConfig();
|
||
const host = options.host ?? config.server.host;
|
||
const port = options.port ?? config.server.port;
|
||
const service = new ApplicationService({
|
||
...(options.version === undefined ? {} : { version: options.version }),
|
||
...(options.runtime === undefined ? {} : { runtime: options.runtime }),
|
||
});
|
||
// 开发期可选:APS_DEV_PROVIDER=1 时注册假 Provider,用于本地联调与演示(默认不注册,能力清单为空)
|
||
if (process.env.APS_DEV_PROVIDER === '1') {
|
||
const { createFakeProvider } = await import('@aps/provider-sdk/testing');
|
||
await service.registerProvider(createFakeProvider());
|
||
}
|
||
|
||
const internalToken = randomUUID();
|
||
const server: Server = createHttpServer(service, internalToken);
|
||
|
||
await new Promise<void>((resolve, reject) => {
|
||
server.once('error', reject);
|
||
server.listen(port, host, () => resolve());
|
||
});
|
||
|
||
const address = server.address() as AddressInfo | null;
|
||
const actualPort = address ? address.port : port;
|
||
|
||
return {
|
||
url: `http://${host}:${actualPort}`,
|
||
port: actualPort,
|
||
service,
|
||
internalToken,
|
||
close: () =>
|
||
new Promise<void>((resolve, reject) => {
|
||
server.close((error) => (error ? reject(error) : resolve()));
|
||
// 事件流是长连接,关停时必须主动断开,否则 close 会一直等它们
|
||
// 客户端断线后按 Last-Event-ID 重连,不会丢事件(协议文档第 5 节)
|
||
server.closeAllConnections();
|
||
}),
|
||
};
|
||
} |