Commit 8c941730 authored by nanahira's avatar nanahira

support Koishi 4.8

parent 596ddeb9
# compiled output
/dist
/node_modules
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
lerna-debug.log*
# OS
.DS_Store
# Tests
/coverage
/.nyc_output
# IDEs and editors
/.idea
.project
.classpath
.c9/
*.launch
.settings/
*.sublime-workspace
# IDE - VSCode
.vscode/*
!.vscode/settings.json
!.vscode/tasks.json
!.vscode/launch.json
!.vscode/extensions.json
/data
/output
/config.yaml
.git*
Dockerfile
.dockerignore
......@@ -2,8 +2,8 @@ import { App } from 'koishi';
import TargetPlugin from '../src';
import ConsolePlugin from '@koishijs/plugin-console';
import SandboxPlugin from '@koishijs/plugin-sandbox';
import * as DatabasePlugin from '@koishijs/plugin-database-memory';
import CachePlugin from '@koishijs/plugin-cache-lru';
import DatabasePlugin from '@koishijs/plugin-database-memory';
// import CachePlugin from '@koishijs/plugin-cache-lru';
import ExtrasInDev from './extras';
const app = new App({
......@@ -19,7 +19,7 @@ app.plugin(ConsolePlugin, {
});
// Some services
app.plugin(CachePlugin);
// app.plugin(CachePlugin);
app.plugin(DatabasePlugin);
// Some extras
......
This diff is collapsed.
import { getSessionId, Random, Session } from 'koishi';
import { ApiBot } from './index';
import ApiBot from './index';
import { Prompt } from './def/prompt';
export class ApiSession extends Session {
......
......@@ -2,21 +2,30 @@
import { ApiPluginConfig, ApiPluginConfigLike } from './config';
import {
DefinePlugin,
LifecycleEvents,
Inject,
InjectConfig,
OnPlatform,
UseMiddleware,
Post,
KoaContext,
PluginSchema,
} from 'koishi-thirdeye';
import { Adapter, Bot, Context, getSessionId, Random, Router } from 'koishi';
import { Bot, Context, getSessionId, Next, Random } from 'koishi';
import { ApiSession } from './api-session';
import { Prompt } from './def/prompt';
export * from './config';
export class ApiBot extends Bot {
@PluginSchema(ApiPluginConfig)
@DefinePlugin()
export default class ApiBot extends Bot {
username = 'koishi';
selfId = 'koishi';
hidden = true;
prompts = new Map<string, Prompt>();
constructor(public ctx: Context, config: ApiPluginConfigLike) {
super(ctx, { platform: 'api', selfId: 'koishi' });
}
resolvePrompt(key: string, value: string) {
const prompt = this.prompts.get(key);
if (prompt) {
......@@ -28,23 +37,68 @@ export class ApiBot extends Bot {
return;
}
constructor(public adapter: ApiAdapter, config: Bot.BaseConfig) {
super(adapter, config);
this.adapter.ctx
.any()
.platform('api')
.self(this.selfId)
.middleware(async (session: ApiSession, next) => {
const identifier = getSessionId(session);
const prompt = this.resolvePrompt(identifier, session.content);
if (!prompt) {
return next();
}
session.storedMessages = session.storedMessages.concat(
await prompt.session.waitForPattern(),
);
@OnPlatform('api')
@UseMiddleware()
async handlePrompt(session: ApiSession, next: Next) {
const identifier = getSessionId(session);
const prompt = this.resolvePrompt(identifier, session.content);
if (!prompt) {
return next();
}
session.storedMessages = session.storedMessages.concat(
await prompt.session.waitForPattern(),
);
return;
}
@InjectConfig()
private pluginConfig: ApiPluginConfig;
@Post('{{path}}')
async onHttpPost(ctx: KoaContext) {
if (this.pluginConfig.token) {
const header = ctx.request.headers['authorization'];
const tokenFromRequest = header?.startsWith('Bearer ')
? header.slice(7)
: header;
if (tokenFromRequest !== this.pluginConfig.token) {
ctx.status = 401;
ctx.body = { error: 'Invalid token' };
return;
}, true);
}
}
if (typeof ctx.request.body === 'string') {
ctx.status = 400;
ctx.body = { error: 'Invalid body' };
return;
}
const body = ctx.request.body;
if (!body.content) {
ctx.status = 400;
ctx.body = { error: 'Missing content.' };
return;
}
const userId = body.userId || ctx.request.ip;
const session = new ApiSession(this, {
userId,
channelId: body.channelId || `private:${userId}`,
guildId: body.guildId,
messageId: body.messageId || Random.id(),
content: body.content,
platform: 'api',
selfId: 'koishi',
type: 'message',
subtype: body.channelId ? 'group' : 'private',
author: {
userId,
avatar: body.avatar,
username: body.username || userId,
},
});
const currentPromise = this.ctx.app.parallel('message', session);
session.currentPromise = currentPromise;
ctx.status = 200;
ctx.body = { messages: await session.waitForPattern() };
}
async sendMessage(channelId: string, content: string) {
......@@ -65,75 +119,3 @@ export interface MessageBody {
username?: string;
avatar?: string;
}
@DefinePlugin({ name: 'api', schema: ApiPluginConfig })
export default class ApiAdapter extends Adapter implements LifecycleEvents {
constructor(ctx: Context, config: ApiPluginConfigLike) {
super(ctx, config);
}
@Inject('bots', true)
private botList: Adapter.BotList;
@Inject(true)
private router: Router;
@InjectConfig()
private pluginConfig: ApiPluginConfig;
onApply() {
this.platform = 'api';
this.botList.adapters.api = this;
const bot = this.botList.create('api', {}, ApiBot);
this.router.post(this.pluginConfig.path, async (ctx) => {
if (this.pluginConfig.token) {
const header = ctx.request.headers['authorization'];
const tokenFromRequest = header?.startsWith('Bearer ')
? header.slice(7)
: header;
if (tokenFromRequest !== this.pluginConfig.token) {
ctx.status = 401;
ctx.body = { error: 'Invalid token' };
return;
}
}
if (typeof ctx.request.body === 'string') {
ctx.status = 400;
ctx.body = { error: 'Invalid body' };
return;
}
const body = ctx.request.body;
if (!body.content) {
ctx.status = 400;
ctx.body = { error: 'Missing content.' };
return;
}
const userId = body.userId || ctx.request.ip;
const session = new ApiSession(bot, {
userId,
channelId: body.channelId || `private:${userId}`,
guildId: body.guildId,
messageId: body.messageId || Random.id(),
content: body.content,
platform: 'api',
selfId: 'koishi',
type: 'message',
subtype: body.channelId ? 'group' : 'private',
author: {
userId,
avatar: body.avatar,
username: body.username || userId,
},
});
const currentPromise = this.ctx.app.parallel('message', session);
session.currentPromise = currentPromise;
ctx.status = 200;
ctx.body = { messages: await session.waitForPattern() };
});
}
async start() {}
async stop() {}
}
......@@ -12,21 +12,21 @@ describe('Test of plugin.', () => {
});
it('should check token', () => {
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'wwww' })
.expect(401);
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'wwww' })
.set('Authorization', 'dress')
.expect(200);
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'wwww' })
.set('Authorization', 'Bearer dress')
.expect(200);
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'wwww' })
.set('Authorization', 'Bearer skirt')
......@@ -35,7 +35,7 @@ describe('Test of plugin.', () => {
it('should reply message', () => {
app.command('dress').action((a) => '梦梦女装!');
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'dress' })
.set('Authorization', 'dress')
......@@ -47,7 +47,7 @@ describe('Test of plugin.', () => {
it('should correctly ref userId', () => {
app.command('dress').action((a) => `${a.session.userId} 让梦梦女装!`);
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'dress' })
.set('Authorization', 'dress')
......@@ -62,7 +62,7 @@ describe('Test of plugin.', () => {
await a.session.send('梦梦换衣服啦!');
return '梦梦女装啦!';
});
request(app._httpServer)
request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'dress' })
.set('Authorization', 'dress')
......@@ -82,7 +82,7 @@ describe('Test of plugin.', () => {
const colorOfSkirt = await a.session.prompt(100000);
return `原来 ${a.session.userId} 今天穿的是 ${colorOfShirt} 的衣服,和 ${colorOfSkirt} 的裙子!`;
});
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111111', content: 'ask' })
.set('Authorization', 'dress')
......@@ -93,7 +93,7 @@ describe('Test of plugin.', () => {
],
})
.then();
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111112', content: 'ask' })
.set('Authorization', 'dress')
......@@ -104,7 +104,7 @@ describe('Test of plugin.', () => {
],
})
.then();
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111111', content: '红色' })
.set('Authorization', 'dress')
......@@ -113,7 +113,7 @@ describe('Test of plugin.', () => {
messages: ['那你能告诉我你今天穿了什么颜色的裙子吗?'],
})
.then();
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111112', content: '蓝色' })
.set('Authorization', 'dress')
......@@ -122,7 +122,7 @@ describe('Test of plugin.', () => {
messages: ['那你能告诉我你今天穿了什么颜色的裙子吗?'],
})
.then();
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111111', content: '白色' })
.set('Authorization', 'dress')
......@@ -131,7 +131,7 @@ describe('Test of plugin.', () => {
messages: ['原来 111111 今天穿的是 红色 的衣服,和 白色 的裙子!'],
})
.then();
await request(app._httpServer)
await request(app.router._http)
.post('/api')
.send({ userId: '111112', content: '黑色' })
.set('Authorization', 'dress')
......@@ -144,6 +144,6 @@ describe('Test of plugin.', () => {
afterEach(async () => {
await app.stop();
app._httpServer.close();
app.router._http.close();
});
});
const path = require('path');
const packgeInfo = require('./package.json');
const { ESBuildMinifyPlugin } = require('esbuild-loader');
function externalsFromDep() {
return Object.fromEntries(
......@@ -43,4 +44,11 @@ module.exports = {
koishi: 'koishi',
...(packAll ? {} : externalsFromDep()),
},
optimization: {
minimizer: [
new ESBuildMinifyPlugin({
keepNames: true,
}),
],
},
};
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment