finish pipe

This commit is contained in:
锦恢 2024-06-01 02:14:46 +08:00
parent a13a6ba34f
commit c27bb27ec3
8 changed files with 487 additions and 147 deletions

View File

@ -14,7 +14,7 @@ import * as Lagrange from '../type';
* @param message
* @param auto_escape CQ message
*/
export function sendPrivateMsg(user_id: number, message: Lagrange.Message, auto_escape: boolean = false) {
export function sendPrivateMsg(user_id: number, message: string | Lagrange.Send.Default[], auto_escape: boolean = false) {
return {
action: 'send_private_msg',
params: { user_id, message, auto_escape }
@ -27,7 +27,7 @@ export function sendPrivateMsg(user_id: number, message: Lagrange.Message, auto_
* @param message
* @param auto_escape CQ message
*/
export function sendGroupMsg(group_id: number, message: Lagrange.Message, auto_escape: boolean = false) {
export function sendGroupMsg(group_id: number, message: string | Lagrange.Send.Default[], auto_escape: boolean = false) {
return {
action: 'send_group_msg',
params: { group_id, message, auto_escape }
@ -42,7 +42,7 @@ export function sendGroupMsg(group_id: number, message: Lagrange.Message, auto_e
* @param message
* @param auto_escape CQ message
*/
export function sendMsg(message_type: string, user_id: number, group_id: number, message: Lagrange.Message, auto_escape: boolean = false) {
export function sendMsg(message_type: string, user_id: number, group_id: number, message: string | Lagrange.Send.Default[], auto_escape: boolean = false) {
return {
action: 'send_msg',
params: { message_type, user_id, group_id, message, auto_escape }

View File

@ -1,46 +1,59 @@
import type * as Lagrange from './type';
import lagrangeMapper from './lagrange-mapping';
function runPipe(message: Lagrange.Message) {
import type * as Lagrange from './type';
import type { LagrangeContext } from './context';
class Pipe {
context: LagrangeContext | undefined;
send: Lagrange.SendApi | undefined;
public injectContext(context: LagrangeContext) {
this.context = context;
this.send = context.send.bind(context);
}
public run(message: Lagrange.Message) {
switch (message.post_type) {
case 'message': messagePipe(message); break;
case 'notice': noticePipe(message); break;
case 'request': requestPipe(message); break;
case 'message': this.messagePipe(message); break;
case 'notice': this.noticePipe(message); break;
case 'request':this.requestPipe(message); break;
default: break;
}
}
}
// 处理 message 类型的 post_type 的
function messagePipe(message: Lagrange.MessagePostType) {
// 处理 message 类型的 post_type 消息
public messagePipe(message: Lagrange.MessagePostType) {
switch (message.message_type) {
case 'private':
lagrangeMapper.resolvePrivateUser(message, this.send);
break;
case 'group':
lagrangeMapper.resolveGroup(message, this.send);
break;
default:
break;
}
}
// 处理 notice 类型的 post_type 消息
public noticePipe(message: Lagrange.NoticePostType) {
}
// 处理 request 类型的 post_type 消息
public requestPipe(message: Lagrange.RequestPostType) {
}
}
// 处理 notice 类型的 post_type 消息
function noticePipe(message: Lagrange.NoticePostType) {
}
// 处理 request 类型的 post_type 消息
function requestPipe(message: Lagrange.RequestPostType) {
}
export const pipe = new Pipe();
export function onMessage(event: Buffer) {
const messageBuffer = event.toString('utf-8');
const messageJson = JSON.parse(messageBuffer) as Lagrange.Message;
// 忽略系统 message
if (messageJson.post_type !== 'meta_event') {
runPipe(messageJson);
console.log('进入 runPipe');
pipe.run(messageJson);
}
}

View File

@ -1,13 +1,15 @@
import lagrangeMapper from './lagrange-mapping';
import { apiQueryVecdb } from './api/vecdb';
import type * as Lagrange from './type';
class Impl {
export class Impl {
@lagrangeMapper.onPrivateUser({ user_id: 1193466151 })
async handleJinhui(message: Lagrange.PrivateMessage) {
@lagrangeMapper.onPrivateUser(1193466151)
async handleJinhui(c: Lagrange.PrivateUserInvokeContext) {
console.log('raw message:' + c.message.raw_message);
}
}

View File

@ -1,8 +1,9 @@
import assert from 'assert';
import type * as Lagrange from './type';
type PrivateUserInvoker = (message: Lagrange.PrivateMessage) => void;
type GroupUserInvoker = (message: Lagrange.GroupMessage) => void;
type PrivateUserInvoker = (context: Lagrange.PrivateUserInvokeContext) => Lagrange.Thenable<undefined | void | string | Lagrange.Send.Default>;
type GroupUserInvoker = (context: Lagrange.GroupUserInvokeContext) => Lagrange.Thenable<undefined | void | string | Lagrange.Send.Default>;
type MessageInvoker = PrivateUserInvoker | GroupUserInvoker;
@ -17,7 +18,7 @@ interface CustomDescriptor<T extends MessageInvoker> {
interface MessageInvokerStorage<T extends MessageInvoker> {
invoker: T;
config: Partial<Lagrange.CommonMessage>
config?: Partial<Lagrange.CommonMessage>
}
class LagrangeMapper {
@ -37,24 +38,33 @@ class LagrangeMapper {
return this._groupStorage;
}
public matchPrivateUser(message: Lagrange.PrivateMessage) {
public resolvePrivateUser(message: Lagrange.PrivateMessage, send: Lagrange.SendApi) {
const user_id = message.user_id;
const userStorage = this._privateUserStorage.get(user_id);
console.log(user_id);
console.log(userStorage);
if (userStorage) {
userStorage.invoker(message);
userStorage.invoker({ message, send });
}
}
public onPrivateUser(config: Partial<Lagrange.CommonMessage>) {
assert(config.user_id, 'onPrivateUser 中 user_id 不能为空');
public resolveGroup(message: Lagrange.GroupMessage, send: Lagrange.SendApi) {
const group_id = message.group_id;
const groupStorage = this._groupStorage.get(group_id);
if (groupStorage) {
groupStorage.invoker({ message, send });
}
}
public onPrivateUser(user_id: number) {
const _this = this;
return function(target: any, propertyKey: string, descriptor: CustomDescriptor<PrivateUserInvoker>) {
const user_id = config.user_id;
if (_this.privateUserStorage.has(user_id)) {
if (_this._privateUserStorage.has(user_id)) {
console.warn(`${propertyKey} -> 用户 ${user_id} 已经被注册过了,该操作将覆盖原本的!`);
}
const invoker = descriptor.value;
_this.privateUserStorage.set(user_id, { invoker, config });
_this._privateUserStorage.set(user_id, { invoker });
}
}

View File

@ -1,35 +1,14 @@
import * as fs from 'fs';
import WebSocket from 'ws';
import lagServer from './context';
import './impl';
import { onMessage, onClose } from './event';
import { apiQueryVecdb } from './api/vecdb';
const buffer = fs.readFileSync('./app/publish/appsettings.json', 'utf-8');
const config = JSON.parse(buffer);
const impl = config.Implementations[0];
const lagrangeBuffer = fs.readFileSync('./app/publish/appsettings.json', 'utf-8');
const lagrangeConfig = JSON.parse(lagrangeBuffer);
const impl = lagrangeConfig.Implementations[0];
const connectionParam = {
lagServer.run({
host: impl.Host,
port: impl.Port,
path: impl.Suffix
};
const socket = new WebSocket.Server(connectionParam);
socket.on('connection', (ws: WebSocket) => {
console.log('完成 ws 连接,启动参数如下');
console.table(connectionParam);
ws.on('message', onMessage);
ws.on('close', onClose);
const testMsg = {
action: 'send_private_msg',
params: {
user_id: 1193466151,
message: '你好'
}
}
ws.send(JSON.stringify(testMsg));
});

View File

@ -1,4 +1,5 @@
import type * as Lagrange from './type';
import * as Lagrange from './type';
class Plugins {
registeredPlugins: Map<string, Function>;

View File

@ -38,14 +38,23 @@ export interface Sender {
title?: string
}
export interface MsgText {
// 参考文档: https://github.com/botuniverse/onebot-11/blob/master/message/segment.md
export namespace Receive {
export interface Text {
type: 'text',
data: {
text: string
}
}
}
export interface MsgImage {
export interface Face {
type: 'face',
data: {
id: string
}
}
export interface Image {
type: 'image',
data: {
file: string,
@ -53,22 +62,334 @@ export interface MsgImage {
// 在简略窗口可以看到的信息,对于图片来说,这就是 [图片]
summary: string
}
}
export interface MsgFace {
type: 'face',
data: {
id: string
}
}
export interface MsgAt {
export interface Audio {
type: 'record',
data: {
file: string,
magic: 0 | 1,
url: string
}
}
export interface Video {
type: 'video',
data: {
file: string,
url: string
}
}
export interface At {
type: 'at',
data: {
qq: string
}
}
// 猜拳魔法表情
export interface FingerGuess {
type: 'rps',
data: {}
}
// 掷骰子魔法表情
export interface Dice {
type: 'dice',
data: {}
}
// 窗口抖动(戳一戳)
export interface WindowJitter {
type: 'shake',
data: {}
}
// 戳一戳
export interface Poke {
type: 'poke',
data: {
type: string,
id: string,
name: string
}
}
export interface Link {
type: 'share',
data: {
// URL
url: string,
// 标题
title: string,
// 发送时可选,内容描述
content?: string,
// 发送时可选,图片 URL
image?: string
}
}
export interface RecommendFriend {
type: 'contact',
data: {
type: 'qq',
// 被推荐人的 QQ 号
id: string
}
}
export interface RecommendGroup {
type: 'contact',
data: {
type: 'group',
// 被推荐群的群号
id: string
}
}
export interface Location {
type: 'location',
data: {
// 纬度
lat: string,
// 经度
lon: string,
// 发送时可选,标题
title?: string,
// 发送时可选,内容描述
content?: string
}
}
export interface Reply {
type: 'reply',
data: {
id: string
}
}
export interface Forward {
type: 'forward',
data: {
id: string
}
}
export interface XML {
type: 'xml',
data: {
// XML 内容
data: string
}
}
export interface JSON {
type: 'json',
data: {
data: string
}
}
export type Default = Text | Face | Image | Audio | Video | At | FingerGuess | Dice | WindowJitter | Poke | Link | RecommendFriend | RecommendGroup | Location | Reply | Forward | XML | JSON;
}
export namespace Send {
export interface Text {
type: 'text',
data: {
text: string
}
}
export interface Face {
type: 'face',
data: {
id: string
}
}
export interface Image {
type: 'image',
data: {
/**
* file
* 1. file:///C:\\Users\Richard\Pictures\1.png
* 2. URL http://i1.piimg.com/567571/fdd6e7b6d93f1ef0.jpg
* Base64 base64://iVBORw0KGgoAAAANSUhEUgAAABQAAAAVCAIAAADJt1n/AAAAKElEQVQ4EWPk5+RmIBcwkasRpG9UM4mhNxpgowFGMARGEwnBIEJVAAAdBgBNAZf+QAAAAABJRU5ErkJggg==
*/
file: string,
// 只在通过网络 URL 发送时有效,表示是否使用已缓存的文件,默认 1
cache: 0 | 1,
// 只在通过网络 URL 发送时有效,表示是否通过代理下载文件(需通过环境变量或配置文件配置代理),默认 1
proxy: 0 | 1,
// 只在通过网络 URL 发送时有效,单位秒,表示下载网络文件的超时时间,默认不超时
timeout: number
}
}
export interface Audio {
type: 'record',
data: {
file: string,
magic: 0 | 1,
cache: 0 | 1,
proxy: 0 | 1,
timeout: number
}
}
export interface Video {
type: 'video',
data: {
file: string,
cache: 0 | 1,
proxy: 0 | 1,
timeout: number
}
}
export interface At {
type: 'at',
data: {
qq: string
}
}
export interface FingerGuess {
type: 'rps',
data: {}
}
export interface Dice {
type: 'dice',
data: {}
}
export interface WindowJitter {
type: 'shake',
data: {}
}
// 戳一戳
export interface Poke {
type: 'poke',
data: {
type: string,
id: string,
}
}
export interface Anonymous {
type: 'anonymous',
data: {}
}
export interface Link {
type: 'share',
data: {
// URL
url: string,
// 标题
title: string,
// 发送时可选,内容描述
content?: string,
// 发送时可选,图片 URL
image?: string
}
}
export interface RecommendFriend {
type: 'contact',
data: {
type: 'qq',
// 被推荐人的 QQ 号
id: string
}
}
export interface RecommendGroup {
type: 'contact',
data: {
type: 'group',
// 被推荐群的群号
id: string
}
}
export interface Location {
type: 'location',
data: {
// 纬度
lat: string,
// 经度
lon: string,
// 发送时可选,标题
title?: string,
// 发送时可选,内容描述
content?: string
}
}
export interface MusicShare {
type: 'music',
data: {
// 分别表示使用 QQ 音乐、网易云音乐、虾米音乐
type: 'qq' | '163' | 'xm',
// 歌曲 ID
id: string
}
}
export interface CustomMusicShare {
type: 'music',
data: {
type: 'custom',
url: string,
audio: string,
title: string,
content: string,
image: string
}
}
export interface Reply {
type: 'reply',
data: {
id: string
}
}
export interface ForwardNode {
type: 'node',
data: {
id: string
}
}
export interface XML {
type: 'xml',
data: {
// XML 内容
data: string
}
}
export interface JSON {
type: 'json',
data: {
data: string
}
}
export type Default = Text | Face | Image | Audio | Video | At | FingerGuess | Dice | WindowJitter | Poke | Anonymous | Link | RecommendFriend | RecommendGroup | Location | MusicShare | CustomMusicShare | Reply | ForwardNode | XML | JSON;
}
export interface MsgFile {
// 一般是 ''
id: string,
@ -103,7 +424,7 @@ export interface CommonMessage {
// 是否为匿名发言,一般都是 null
anonymous?: null | boolean,
// 消息内容(结构化)
message?: MsgText | MsgImage | MsgFace | MsgAt,
message?: Receive.Default,
// 消息内容(纯文本)
raw_message?: string,
// 发送的时间戳
@ -125,7 +446,7 @@ export interface PrivateMessage {
// 发消息的人的 QQ 号
user_id: number,
// 消息内容(结构化)
message: MsgText | MsgImage | MsgFace | MsgAt,
message: Receive.Default,
// 消息内容(纯文本)
raw_message: string,
// 发送的时间戳
@ -136,6 +457,7 @@ export interface PrivateMessage {
font?: number
}
export interface GroupMessage {
// 事件类型
post_type: 'message',
@ -152,7 +474,7 @@ export interface GroupMessage {
// 是否为匿名发言,一般都是 null
anonymous: null | boolean,
// 消息内容(结构化)
message: MsgText | MsgImage | MsgFace | MsgAt,
message: Receive.Default,
// 消息内容(纯文本)
raw_message: string,
// 发送的时间戳
@ -205,3 +527,16 @@ export type Message = MetaMessage | PrivateMessage | GroupMessage | FileMessage
export type MessagePostType = PrivateMessage | GroupMessage;
export type NoticePostType = FileMessage | ApproveMessage;
export type RequestPostType = AddMessage;
export type Thenable<T> = T | Promise<T>;
export type SendApi = (msg: string | Send.Default[]) => Thenable<void | Error>;
export interface InvokerContext<M = Message> {
message: M,
send: SendApi
}
export type PrivateUserInvokeContext = InvokerContext<PrivateMessage>;
export type GroupUserInvokeContext = InvokerContext<GroupMessage>;

View File

@ -96,11 +96,11 @@ for el in soup.find_all('h2'):
}
if param['type'] == 'message':
param['type'] = 'Lagrange.Message'
param['type'] = 'string | Lagrange.Send.Default[]'
params.append(param)
t1 = function_desc
t1 = function_desc.strip()
t2 = '\n'
for param in params:
t2 += ' * @param {} {}\n'.format(param['name'], param['desc'])