Commit fbdd391d authored by nanahira's avatar nanahira

provide Cache API thing & cmd.use(CommandUserLock("field"))

parent 91e5937e
This diff is collapsed.
......@@ -44,11 +44,12 @@
"testEnvironment": "node"
},
"dependencies": {
"aragami": "^1.1.1",
"@koishijs/cache": "^0.1.3",
"aragami": "^1.1.2",
"koishi-thirdeye": "^11.1.21"
},
"peerDependencies": {
"koishi": "^4.11.1"
"koishi": "^4.11.4"
},
"devDependencies": {
"@koishijs/plugin-console": "^5.1.0",
......@@ -77,7 +78,8 @@
"koishi": {
"service": {
"implements": [
"aragami"
"aragami",
"cache"
]
}
}
......
import { AragamiConfig } from './config';
import {
DefinePlugin,
Inject,
koishiRegistrar,
LifecycleEvents,
PartialDeep,
PluginDef,
PluginSchema,
Provide,
UsePlugin,
} from 'koishi-thirdeye';
import { Channel, Command, Context, Session, User } from 'koishi';
import { Aragami, AragamiOptions, WrapDecoratorBuilder } from 'aragami';
import {
Aragami,
AragamiOptions,
CacheKey,
WrapDecoratorBuilder,
} from 'aragami';
export * from './config';
export * from 'aragami';
import Cache from '@koishijs/cache';
declare module 'koishi' {
interface Context {
......@@ -18,6 +27,50 @@ declare module 'koishi' {
}
}
class AdaptingCache {
table: string;
key: string;
value: any;
@CacheKey()
cacheKey() {
return `${this.table}:${this.key}`;
}
}
type CopyType<T> = { [P in keyof T]: T[P] };
@DefinePlugin()
export class AragamiCacheProvider extends Cache {
constructor(ctx: Context) {
super(ctx);
}
@Inject()
private aragami: CopyType<AragamiPlugin>;
async clear(table: string) {
return this.aragami.clear(AdaptingCache, table);
}
async get(table: string, key: string) {
const entry = await this.aragami.get(AdaptingCache, `${table}:${key}`);
return entry?.value;
}
async set(table: string, key: string, value: any, maxAge?: number) {
const entry = new AdaptingCache();
entry.table = table;
entry.key = key;
entry.value = value;
await this.aragami.set(entry, { ttl: maxAge ?? 0 });
}
async delete(table: string, key: string) {
await this.aragami.del(AdaptingCache, `${table}:${key}`);
}
}
@PluginSchema(AragamiConfig)
@Provide('aragami', { immediate: true })
@DefinePlugin({ name: 'cache-aragami' })
......@@ -29,16 +82,28 @@ export default class AragamiPlugin extends Aragami implements LifecycleEvents {
super(_config.getConfig());
}
@UsePlugin()
loadAdaptingProvider() {
//console.log('loadAdaptingProvider');
return PluginDef(AragamiCacheProvider);
}
onDisconnect() {
return this.destroy();
}
private commandLock<C extends Command>(
cmd: C,
private commandLock<
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(
cmd: Command<U, G, A, O>,
fields: string[],
info: { idFactory: (session: Session) => string; prefix: string },
) {
return cmd.action((argv) => {
return cmd.action((argv, ...args: any[]) => {
if (!argv.session) return argv.next();
const id = info.idFactory(argv.session);
if (!id) return argv.next();
......@@ -49,22 +114,43 @@ export default class AragamiPlugin extends Aragami implements LifecycleEvents {
}, true);
}
commandUserLock<C extends Command>(cmd: C, fields: (keyof User)[]) {
return this.commandLock(cmd.userFields(fields) as C, fields, {
commandUserLock<
T extends User.Field,
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(cmd: Command<U, G, A, O>, fields: T[]) {
return this.commandLock(cmd.userFields(fields), fields as string[], {
idFactory: (session: Session) => session.userId,
prefix: 'user',
});
}
commandChannelLock<C extends Command>(cmd: C, fields: (keyof Channel)[]) {
return this.commandLock(cmd.channelFields(fields) as C, fields, {
commandChannelLock<
T extends Channel.Field,
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(cmd: Command<U, G, A, O>, fields: T[]) {
return this.commandLock(cmd.channelFields(fields), fields as string[], {
idFactory: (session: Session) => session.channelId,
prefix: 'channel',
});
}
commandGuildLock<C extends Command>(cmd: C, fields: (keyof Channel)[]) {
return this.commandLock(cmd.channelFields(fields) as C, fields, {
commandGuildLock<
T extends Channel.Field,
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(cmd: Command<U, G, A, O>, fields: T[]) {
return this.commandLock(cmd.channelFields(fields), fields as string[], {
idFactory: (session: Session) => session.guildId || session.channelId,
prefix: 'guild',
});
......@@ -75,20 +161,44 @@ export const { UseCache, UseLock } = new WrapDecoratorBuilder(
(o) => ((o.ctx || o.__ctx) as Context).aragami,
).build();
export const CommandUserLock = koishiRegistrar.decorateCommandTransformer(
(ctx, cmd, ...fields: (keyof User)[]) =>
ctx.aragami.commandUserLock(cmd, fields),
);
export const CommandUserLock =
<T extends User.Field>(...fields: T[]) =>
<
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(
cmd: Command<U, G, A, O>,
) =>
cmd.ctx.aragami.commandUserLock(cmd, fields);
export const CommandChannelLock = koishiRegistrar.decorateCommandTransformer(
(ctx, cmd, ...fields: (keyof Channel)[]) =>
ctx.aragami.commandChannelLock(cmd, fields),
);
export const CommandChannelLock =
<T extends Channel.Field>(...fields: T[]) =>
<
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(
cmd: Command<U, G, A, O>,
) =>
cmd.ctx.aragami.commandChannelLock(cmd, fields);
export const CommandGuildLock = koishiRegistrar.decorateCommandTransformer(
(ctx, cmd, ...fields: (keyof Channel)[]) =>
ctx.aragami.commandGuildLock(cmd, fields),
);
export const CommandGuildLock =
<T extends Channel.Field>(...fields: T[]) =>
<
U extends User.Field = never,
G extends Channel.Field = never,
A extends any[] = any[],
// eslint-disable-next-line @typescript-eslint/ban-types
O extends {} = {},
>(
cmd: Command<U, G, A, O>,
) =>
cmd.ctx.aragami.commandGuildLock(cmd, fields);
export const PutLockingUser = koishiRegistrar.decorateCommandPut(
(info, ...fields: (keyof User)[]) => info.argv.session.user,
......
......@@ -3,6 +3,12 @@ import TargetPlugin, { UseCache } from '../src';
import { CacheKey, WithKey } from 'aragami';
import { DefinePlugin, Provide, StarterPlugin } from 'koishi-thirdeye';
declare module '@koishijs/cache' {
interface Tables {
aragami: any;
}
}
describe('Test of plugin.', () => {
let app: Context;
......@@ -12,6 +18,8 @@ describe('Test of plugin.', () => {
// redis: { uri: 'redis://localhost:6379' },
});
await app.start();
// console.log(app.aragami);
// console.log(app.__cache__);
});
class User {
......@@ -49,4 +57,14 @@ describe('Test of plugin.', () => {
await instance.getUser('Satori', 18);
await expect(app.aragami.has(User, 'Satori')).resolves.toBeTruthy();
});
it('should work with builtin cache', async () => {
expect(app.__cache__).toBeDefined();
const table = app.cache('aragami');
expect(table).toBeDefined();
await table.set('foo', { bar: 'baz' }, 10);
await expect(table.get('foo')).resolves.toEqual({ bar: 'baz' });
await new Promise((resolve) => setTimeout(resolve, 15));
await expect(table.get('foo')).resolves.toBeUndefined();
});
});
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