mirror of
https://github.com/syuilo/ai.git
synced 2024-11-24 22:01:07 +00:00
Resolve #26
This commit is contained in:
parent
73c2ef516a
commit
70baea9d18
8
package-lock.json
generated
8
package-lock.json
generated
|
@ -44,6 +44,14 @@
|
|||
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz",
|
||||
"integrity": "sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE="
|
||||
},
|
||||
"@types/uuid": {
|
||||
"version": "3.4.4",
|
||||
"resolved": "https://registry.npmjs.org/@types/uuid/-/uuid-3.4.4.tgz",
|
||||
"integrity": "sha512-tPIgT0GUmdJQNSHxp0X2jnpQfBSTfGxUMc/2CXBU2mnyTFVYVa2ojpoQ74w0U2yn2vw3jnC640+77lkFFpdVDw==",
|
||||
"requires": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
},
|
||||
"@types/ws": {
|
||||
"version": "6.0.1",
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz",
|
||||
|
|
|
@ -11,6 +11,7 @@
|
|||
"@types/node": "10.0.5",
|
||||
"@types/promise-retry": "1.1.2",
|
||||
"@types/seedrandom": "2.4.27",
|
||||
"@types/uuid": "3.4.4",
|
||||
"@types/ws": "6.0.1",
|
||||
"autobind-decorator": "2.1.0",
|
||||
"chalk": "2.4.2",
|
||||
|
@ -25,6 +26,7 @@
|
|||
"timeout-as-promise": "1.0.0",
|
||||
"ts-node": "6.0.3",
|
||||
"typescript": "2.8.3",
|
||||
"uuid": "3.3.2",
|
||||
"ws": "6.0.0"
|
||||
}
|
||||
}
|
||||
|
|
70
src/ai.ts
70
src/ai.ts
|
@ -4,18 +4,20 @@ import autobind from 'autobind-decorator';
|
|||
import * as loki from 'lokijs';
|
||||
import * as request from 'request-promise-native';
|
||||
import chalk from 'chalk';
|
||||
import * as uuid from 'uuid/v4';
|
||||
const delay = require('timeout-as-promise');
|
||||
|
||||
import config from './config';
|
||||
import Module from './module';
|
||||
import Message from './message';
|
||||
import { FriendDoc } from './friend';
|
||||
import Friend, { FriendDoc } from './friend';
|
||||
import { User } from './misskey/user';
|
||||
import Stream from './stream';
|
||||
import log from './utils/log';
|
||||
|
||||
type MentionHook = (msg: Message) => Promise<boolean | HandlerResult>;
|
||||
type ContextHook = (msg: Message, data?: any) => Promise<void | HandlerResult>;
|
||||
type TimeoutCallback = (data?: any) => void;
|
||||
|
||||
export type HandlerResult = {
|
||||
reaction: string;
|
||||
|
@ -24,6 +26,7 @@ export type HandlerResult = {
|
|||
export type InstallerResult = {
|
||||
mentionHook?: MentionHook;
|
||||
contextHook?: ContextHook;
|
||||
timeoutCallback?: TimeoutCallback;
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -35,6 +38,7 @@ export default class 藍 {
|
|||
public modules: Module[] = [];
|
||||
private mentionHooks: MentionHook[] = [];
|
||||
private contextHooks: { [moduleName: string]: ContextHook } = {};
|
||||
private timeoutCallbacks: { [moduleName: string]: TimeoutCallback } = {};
|
||||
public db: loki;
|
||||
|
||||
private contexts: loki.Collection<{
|
||||
|
@ -46,6 +50,14 @@ export default class 藍 {
|
|||
data?: any;
|
||||
}>;
|
||||
|
||||
private timers: loki.Collection<{
|
||||
id: string;
|
||||
module: string;
|
||||
insertedAt: number;
|
||||
delay: number;
|
||||
data?: any;
|
||||
}>;
|
||||
|
||||
public friends: loki.Collection<FriendDoc>;
|
||||
|
||||
/**
|
||||
|
@ -86,6 +98,10 @@ export default class 藍 {
|
|||
indices: ['key']
|
||||
});
|
||||
|
||||
this.timers = this.getCollection('timers', {
|
||||
indices: ['module']
|
||||
});
|
||||
|
||||
this.friends = this.getCollection('friends', {
|
||||
indices: ['userId']
|
||||
});
|
||||
|
@ -143,9 +159,14 @@ export default class 藍 {
|
|||
if (res != null) {
|
||||
if (res.mentionHook) this.mentionHooks.push(res.mentionHook);
|
||||
if (res.contextHook) this.contextHooks[m.name] = res.contextHook;
|
||||
if (res.timeoutCallback) this.timeoutCallbacks[m.name] = res.timeoutCallback;
|
||||
}
|
||||
});
|
||||
|
||||
// タイマー監視
|
||||
this.crawleTimer();
|
||||
setInterval(this.crawleTimer, 1000);
|
||||
|
||||
this.log(chalk.green.bold('Ai am now running!'));
|
||||
}
|
||||
|
||||
|
@ -218,6 +239,19 @@ export default class 藍 {
|
|||
}
|
||||
}
|
||||
|
||||
@autobind
|
||||
private crawleTimer() {
|
||||
const timers = this.timers.find();
|
||||
for (const timer of timers) {
|
||||
// タイマーが時間切れかどうか
|
||||
if (Date.now() - (timer.insertedAt + timer.delay) >= 0) {
|
||||
this.log(`Timer expired: ${timer.module} ${timer.id}`);
|
||||
this.timers.remove(timer);
|
||||
this.timeoutCallbacks[timer.module](timer.data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* データベースのコレクションを取得します
|
||||
*/
|
||||
|
@ -234,6 +268,19 @@ export default class 藍 {
|
|||
return collection;
|
||||
}
|
||||
|
||||
@autobind
|
||||
public lookupFriend(userId: User['id']): Friend {
|
||||
const doc = this.friends.findOne({
|
||||
userId: userId
|
||||
});
|
||||
|
||||
if (doc == null) return null;
|
||||
|
||||
const friend = new Friend(this, { doc: doc });
|
||||
|
||||
return friend;
|
||||
}
|
||||
|
||||
/**
|
||||
* 投稿します
|
||||
*/
|
||||
|
@ -302,4 +349,25 @@ export default class 藍 {
|
|||
module: module.name
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定したミリ秒経過後に、そのモジュールのタイムアウトコールバックを呼び出します。
|
||||
* このタイマーは記憶に永続化されるので、途中でプロセスを再起動しても有効です。
|
||||
* @param module モジュール名
|
||||
* @param delay ミリ秒
|
||||
* @param data オプションのデータ
|
||||
*/
|
||||
@autobind
|
||||
public setTimeoutWithPersistence(module: Module, delay: number, data?: any) {
|
||||
const id = uuid();
|
||||
this.timers.insertOne({
|
||||
id: id,
|
||||
module: module.name,
|
||||
insertedAt: Date.now(),
|
||||
delay: delay,
|
||||
data: data
|
||||
});
|
||||
|
||||
this.log(`Timer persisted: ${module.name} ${id} ${delay}ms`);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -12,6 +12,7 @@ export type FriendDoc = {
|
|||
lastLoveIncrementedAt?: string;
|
||||
todayLoveIncrements?: number;
|
||||
perModulesData?: any;
|
||||
married?: boolean;
|
||||
};
|
||||
|
||||
export default class Friend {
|
||||
|
@ -29,6 +30,10 @@ export default class Friend {
|
|||
return this.doc.love || 0;
|
||||
}
|
||||
|
||||
public get married() {
|
||||
return this.doc.married;
|
||||
}
|
||||
|
||||
public doc: FriendDoc;
|
||||
|
||||
constructor(ai: 藍, opts: { user?: User, doc?: FriendDoc }) {
|
||||
|
|
|
@ -37,4 +37,15 @@ export default abstract class Module {
|
|||
protected unsubscribeReply(key: string) {
|
||||
this.ai.unsubscribeReply(this, key);
|
||||
}
|
||||
|
||||
/**
|
||||
* 指定したミリ秒経過後に、タイムアウトコールバックを呼び出します。
|
||||
* このタイマーは記憶に永続化されるので、途中でプロセスを再起動しても有効です。
|
||||
* @param delay ミリ秒
|
||||
* @param data オプションのデータ
|
||||
*/
|
||||
@autobind
|
||||
public setTimeoutWithPersistence(delay: number, data?: any) {
|
||||
this.ai.setTimeoutWithPersistence(this, delay, data);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -9,7 +9,8 @@ export default class extends Module {
|
|||
@autobind
|
||||
public install() {
|
||||
return {
|
||||
mentionHook: this.mentionHook
|
||||
mentionHook: this.mentionHook,
|
||||
timeoutCallback: this.timeoutCallback,
|
||||
};
|
||||
}
|
||||
|
||||
|
@ -23,34 +24,51 @@ export default class extends Module {
|
|||
const minutes = minutesQuery ? parseInt(minutesQuery[1], 10) : 0;
|
||||
const hours = hoursQuery ? parseInt(hoursQuery[1], 10) : 0;
|
||||
|
||||
if (secondsQuery || minutesQuery || hoursQuery) {
|
||||
if ((seconds + minutes + hours) == 0) {
|
||||
msg.reply(serifs.timer.invalid);
|
||||
return true;
|
||||
}
|
||||
|
||||
const time =
|
||||
(1000 * seconds) +
|
||||
(1000 * 60 * minutes) +
|
||||
(1000 * 60 * 60 * hours);
|
||||
|
||||
if (time > 86400000) {
|
||||
msg.reply(serifs.timer.tooLong);
|
||||
return true;
|
||||
}
|
||||
|
||||
msg.reply(serifs.timer.set);
|
||||
|
||||
const str = `${hours ? hoursQuery[0] : ''}${minutes ? minutesQuery[0] : ''}${seconds ? secondsQuery[0] : ''}`;
|
||||
|
||||
setTimeout(() => {
|
||||
const name = msg.friend.name;
|
||||
msg.reply(serifs.timer.notify(str, name));
|
||||
}, time);
|
||||
if (!(secondsQuery || minutesQuery || hoursQuery)) return false;
|
||||
|
||||
if ((seconds + minutes + hours) == 0) {
|
||||
msg.reply(serifs.timer.invalid);
|
||||
return true;
|
||||
}
|
||||
|
||||
const time =
|
||||
(1000 * seconds) +
|
||||
(1000 * 60 * minutes) +
|
||||
(1000 * 60 * 60 * hours);
|
||||
|
||||
if (time > 86400000) {
|
||||
msg.reply(serifs.timer.tooLong);
|
||||
return true;
|
||||
}
|
||||
|
||||
msg.reply(serifs.timer.set);
|
||||
|
||||
const str = `${hours ? hoursQuery[0] : ''}${minutes ? minutesQuery[0] : ''}${seconds ? secondsQuery[0] : ''}`;
|
||||
|
||||
// タイマーセット
|
||||
this.setTimeoutWithPersistence(time, {
|
||||
isDm: msg.isDm,
|
||||
msgId: msg.id,
|
||||
userId: msg.friend.userId,
|
||||
time: str
|
||||
});
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@autobind
|
||||
private timeoutCallback(data) {
|
||||
const friend = this.ai.lookupFriend(data.userId);
|
||||
const text = serifs.timer.notify(data.time, friend.name);
|
||||
if (data.isDm) {
|
||||
this.ai.sendMessage(friend.userId, {
|
||||
text: text
|
||||
});
|
||||
} else {
|
||||
return false;
|
||||
this.ai.post({
|
||||
replyId: data.msgId,
|
||||
text: text
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue