26 包 monorepo(TS 全源码): - snowcat-core: NT 内核 API 封装 + listener(含 9.9.37 六回调适配)+ Packet 发包 - snowcat-onebot: OneBot v11 全动作 + MCP Streamable HTTP 适配器 + 稳定线 - snowcat-webui-frontend/backend: 雪猫控制台(React+HeroUI) - snowcat-shell: 单文件 bundle 出口(vite inlineDynamicImports) - snowcat-native: napi2native / MoeHoo / ffmpeg / pty 运行时 - 56 项 SnowLuma 独门动作移植(qzone 全家桶/群相册/装扮/闪照/收藏) - 工具件: 解包器/启动器/便携制作器/doctor GitHub 关联已全量指向 DandanLLab/SnowCatQQ
120 lines
5.2 KiB
TypeScript
120 lines
5.2 KiB
TypeScript
import { ActionName, BaseCheckResult } from './router';
|
|
import { TypeCompiler, TypeCheck } from '@sinclair/typebox/compiler';
|
|
import { Value } from '@sinclair/typebox/value';
|
|
import { SnowCatCore } from 'snowcat-core';
|
|
import { NapCatOneBot11Adapter, OB11Return } from '@/snowcat-onebot/index';
|
|
import { NetworkAdapterConfig } from '../config/config';
|
|
import { TSchema } from '@sinclair/typebox';
|
|
import { StreamPacket, StreamPacketBasic, StreamStatus } from './stream/StreamBasic';
|
|
export const ActionExamples = {
|
|
Common: {
|
|
errors: [
|
|
{ code: 1400, description: '请求参数错误或业务逻辑执行失败' },
|
|
{ code: 1401, description: '权限不足' },
|
|
{ code: 1404, description: '资源不存在' },
|
|
],
|
|
},
|
|
};
|
|
|
|
export class OB11Response {
|
|
private static createResponse<T> (data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return<T> {
|
|
return {
|
|
status,
|
|
retcode,
|
|
data,
|
|
message,
|
|
wording: message,
|
|
echo,
|
|
stream: useStream ? 'stream-action' : 'normal-action',
|
|
};
|
|
}
|
|
|
|
static res<T> (data: T, status: string, retcode: number, message: string = '', echo: unknown = null, useStream: boolean = false): OB11Return<T> {
|
|
return this.createResponse(data, status, retcode, message, echo, useStream);
|
|
}
|
|
|
|
static ok<T> (data: T, echo: unknown = null, useStream: boolean = false): OB11Return<T> {
|
|
return this.createResponse(data, 'ok', 0, '', echo, useStream);
|
|
}
|
|
|
|
static error (err: string, retcode: number, echo: unknown = null, useStream: boolean = false): OB11Return<null | StreamPacketBasic> {
|
|
return this.createResponse(useStream ? { type: StreamStatus.Error, data_type: 'error' } : null, 'failed', retcode, err, echo, useStream);
|
|
}
|
|
}
|
|
export abstract class OneBotRequestToolkit {
|
|
abstract send<T> (packet: StreamPacket<T>): Promise<void>;
|
|
}
|
|
export abstract class OneBotAction<PayloadType, ReturnDataType> {
|
|
actionName: typeof ActionName[keyof typeof ActionName] = ActionName.Unknown;
|
|
core: SnowCatCore;
|
|
private validate?: TypeCheck<TSchema> = undefined;
|
|
payloadSchema?: TSchema = undefined;
|
|
returnSchema?: TSchema = undefined;
|
|
payloadExample?: unknown = undefined;
|
|
returnExample?: unknown = undefined;
|
|
actionSummary: string = '';
|
|
actionDescription: string = '';
|
|
actionTags: string[] = [];
|
|
obContext: NapCatOneBot11Adapter;
|
|
useStream: boolean = false;
|
|
errorExamples: Array<{ code: number, description: string; }> = ActionExamples.Common.errors;
|
|
|
|
constructor (obContext: NapCatOneBot11Adapter, core: SnowCatCore) {
|
|
this.obContext = obContext;
|
|
this.core = core;
|
|
}
|
|
|
|
protected async check (payload: PayloadType): Promise<BaseCheckResult> {
|
|
if (!this.payloadSchema) return { valid: true };
|
|
try {
|
|
this.validate = TypeCompiler.Compile(this.payloadSchema);
|
|
let data = payload;
|
|
data = Value.Parse(this.payloadSchema, data) as PayloadType;
|
|
if (typeof payload === 'object' && payload !== null && data !== null) {
|
|
Object.assign(payload, data);
|
|
}
|
|
} catch (e: any) {
|
|
return { valid: false, message: `Schema compilation error: ${e.message}` };
|
|
}
|
|
if (this.validate && !this.validate.Check(payload)) {
|
|
const errors = [...this.validate.Errors(payload)];
|
|
const errorMessages = errors.map(e => `Key: ${e.path.split('/').slice(1).join('.')}, Message: ${e.message}`);
|
|
return {
|
|
valid: false,
|
|
message: errorMessages.length > 0 ? errorMessages.join('\n') : '未知错误',
|
|
};
|
|
}
|
|
return { valid: true };
|
|
}
|
|
|
|
public async handle (payload: PayloadType, adaptername: string, config: NetworkAdapterConfig, req: OneBotRequestToolkit = { send: async () => { } }, echo?: string): Promise<OB11Return<ReturnDataType | StreamPacketBasic | null>> {
|
|
const result = await this.check(payload);
|
|
if (!result.valid) {
|
|
return OB11Response.error(result.message, 400);
|
|
}
|
|
try {
|
|
const resData = await this._handle(payload, adaptername, config, req);
|
|
return OB11Response.ok(resData, echo, this.useStream);
|
|
} catch (e: unknown) {
|
|
this.core.context.logger.logError('发生错误', e);
|
|
return OB11Response.error((e as Error).message.toString() || (e as Error)?.stack?.toString() || '未知错误,可能操作超时', 200, echo, this.useStream);
|
|
}
|
|
}
|
|
|
|
public async websocketHandle (payload: PayloadType, echo: unknown, adaptername: string, config: NetworkAdapterConfig, req: OneBotRequestToolkit = { send: async () => { } }): Promise<OB11Return<ReturnDataType | StreamPacketBasic | null>> {
|
|
const result = await this.check(payload);
|
|
if (!result.valid) {
|
|
return OB11Response.error(result.message, 1400, echo, this.useStream);
|
|
}
|
|
try {
|
|
const resData = await this._handle(payload, adaptername, config, req);
|
|
return OB11Response.ok(resData, echo, this.useStream);
|
|
} catch (e: unknown) {
|
|
this.core.context.logger.logError('发生错误', e);
|
|
return OB11Response.error(((e as Error).message.toString() || (e as Error).stack?.toString()) ?? 'Error', 1200, echo, this.useStream);
|
|
}
|
|
}
|
|
|
|
abstract _handle (payload: PayloadType, adaptername: string, config: NetworkAdapterConfig, req: OneBotRequestToolkit): Promise<ReturnDataType>;
|
|
}
|