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",
|
"resolved": "https://registry.npmjs.org/@types/seedrandom/-/seedrandom-2.4.27.tgz",
|
||||||
"integrity": "sha1-nbVjk33YaRX2kJK8QyWdL0hXjkE="
|
"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": {
|
"@types/ws": {
|
||||||
"version": "6.0.1",
|
"version": "6.0.1",
|
||||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz",
|
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-6.0.1.tgz",
|
||||||
|
|
|
@ -11,6 +11,7 @@
|
||||||
"@types/node": "10.0.5",
|
"@types/node": "10.0.5",
|
||||||
"@types/promise-retry": "1.1.2",
|
"@types/promise-retry": "1.1.2",
|
||||||
"@types/seedrandom": "2.4.27",
|
"@types/seedrandom": "2.4.27",
|
||||||
|
"@types/uuid": "3.4.4",
|
||||||
"@types/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"autobind-decorator": "2.1.0",
|
"autobind-decorator": "2.1.0",
|
||||||
"chalk": "2.4.2",
|
"chalk": "2.4.2",
|
||||||
|
@ -25,6 +26,7 @@
|
||||||
"timeout-as-promise": "1.0.0",
|
"timeout-as-promise": "1.0.0",
|
||||||
"ts-node": "6.0.3",
|
"ts-node": "6.0.3",
|
||||||
"typescript": "2.8.3",
|
"typescript": "2.8.3",
|
||||||
|
"uuid": "3.3.2",
|
||||||
"ws": "6.0.0"
|
"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 loki from 'lokijs';
|
||||||
import * as request from 'request-promise-native';
|
import * as request from 'request-promise-native';
|
||||||
import chalk from 'chalk';
|
import chalk from 'chalk';
|
||||||
|
import * as uuid from 'uuid/v4';
|
||||||
const delay = require('timeout-as-promise');
|
const delay = require('timeout-as-promise');
|
||||||
|
|
||||||
import config from './config';
|
import config from './config';
|
||||||
import Module from './module';
|
import Module from './module';
|
||||||
import Message from './message';
|
import Message from './message';
|
||||||
import { FriendDoc } from './friend';
|
import Friend, { FriendDoc } from './friend';
|
||||||
import { User } from './misskey/user';
|
import { User } from './misskey/user';
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
import log from './utils/log';
|
import log from './utils/log';
|
||||||
|
|
||||||
type MentionHook = (msg: Message) => Promise<boolean | HandlerResult>;
|
type MentionHook = (msg: Message) => Promise<boolean | HandlerResult>;
|
||||||
type ContextHook = (msg: Message, data?: any) => Promise<void | HandlerResult>;
|
type ContextHook = (msg: Message, data?: any) => Promise<void | HandlerResult>;
|
||||||
|
type TimeoutCallback = (data?: any) => void;
|
||||||
|
|
||||||
export type HandlerResult = {
|
export type HandlerResult = {
|
||||||
reaction: string;
|
reaction: string;
|
||||||
|
@ -24,6 +26,7 @@ export type HandlerResult = {
|
||||||
export type InstallerResult = {
|
export type InstallerResult = {
|
||||||
mentionHook?: MentionHook;
|
mentionHook?: MentionHook;
|
||||||
contextHook?: ContextHook;
|
contextHook?: ContextHook;
|
||||||
|
timeoutCallback?: TimeoutCallback;
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -35,6 +38,7 @@ export default class 藍 {
|
||||||
public modules: Module[] = [];
|
public modules: Module[] = [];
|
||||||
private mentionHooks: MentionHook[] = [];
|
private mentionHooks: MentionHook[] = [];
|
||||||
private contextHooks: { [moduleName: string]: ContextHook } = {};
|
private contextHooks: { [moduleName: string]: ContextHook } = {};
|
||||||
|
private timeoutCallbacks: { [moduleName: string]: TimeoutCallback } = {};
|
||||||
public db: loki;
|
public db: loki;
|
||||||
|
|
||||||
private contexts: loki.Collection<{
|
private contexts: loki.Collection<{
|
||||||
|
@ -46,6 +50,14 @@ export default class 藍 {
|
||||||
data?: any;
|
data?: any;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
|
private timers: loki.Collection<{
|
||||||
|
id: string;
|
||||||
|
module: string;
|
||||||
|
insertedAt: number;
|
||||||
|
delay: number;
|
||||||
|
data?: any;
|
||||||
|
}>;
|
||||||
|
|
||||||
public friends: loki.Collection<FriendDoc>;
|
public friends: loki.Collection<FriendDoc>;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -86,6 +98,10 @@ export default class 藍 {
|
||||||
indices: ['key']
|
indices: ['key']
|
||||||
});
|
});
|
||||||
|
|
||||||
|
this.timers = this.getCollection('timers', {
|
||||||
|
indices: ['module']
|
||||||
|
});
|
||||||
|
|
||||||
this.friends = this.getCollection('friends', {
|
this.friends = this.getCollection('friends', {
|
||||||
indices: ['userId']
|
indices: ['userId']
|
||||||
});
|
});
|
||||||
|
@ -143,9 +159,14 @@ export default class 藍 {
|
||||||
if (res != null) {
|
if (res != null) {
|
||||||
if (res.mentionHook) this.mentionHooks.push(res.mentionHook);
|
if (res.mentionHook) this.mentionHooks.push(res.mentionHook);
|
||||||
if (res.contextHook) this.contextHooks[m.name] = res.contextHook;
|
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!'));
|
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;
|
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
|
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;
|
lastLoveIncrementedAt?: string;
|
||||||
todayLoveIncrements?: number;
|
todayLoveIncrements?: number;
|
||||||
perModulesData?: any;
|
perModulesData?: any;
|
||||||
|
married?: boolean;
|
||||||
};
|
};
|
||||||
|
|
||||||
export default class Friend {
|
export default class Friend {
|
||||||
|
@ -29,6 +30,10 @@ export default class Friend {
|
||||||
return this.doc.love || 0;
|
return this.doc.love || 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public get married() {
|
||||||
|
return this.doc.married;
|
||||||
|
}
|
||||||
|
|
||||||
public doc: FriendDoc;
|
public doc: FriendDoc;
|
||||||
|
|
||||||
constructor(ai: 藍, opts: { user?: User, doc?: FriendDoc }) {
|
constructor(ai: 藍, opts: { user?: User, doc?: FriendDoc }) {
|
||||||
|
|
|
@ -37,4 +37,15 @@ export default abstract class Module {
|
||||||
protected unsubscribeReply(key: string) {
|
protected unsubscribeReply(key: string) {
|
||||||
this.ai.unsubscribeReply(this, key);
|
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
|
@autobind
|
||||||
public install() {
|
public install() {
|
||||||
return {
|
return {
|
||||||
mentionHook: this.mentionHook
|
mentionHook: this.mentionHook,
|
||||||
|
timeoutCallback: this.timeoutCallback,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -23,7 +24,8 @@ export default class extends Module {
|
||||||
const minutes = minutesQuery ? parseInt(minutesQuery[1], 10) : 0;
|
const minutes = minutesQuery ? parseInt(minutesQuery[1], 10) : 0;
|
||||||
const hours = hoursQuery ? parseInt(hoursQuery[1], 10) : 0;
|
const hours = hoursQuery ? parseInt(hoursQuery[1], 10) : 0;
|
||||||
|
|
||||||
if (secondsQuery || minutesQuery || hoursQuery) {
|
if (!(secondsQuery || minutesQuery || hoursQuery)) return false;
|
||||||
|
|
||||||
if ((seconds + minutes + hours) == 0) {
|
if ((seconds + minutes + hours) == 0) {
|
||||||
msg.reply(serifs.timer.invalid);
|
msg.reply(serifs.timer.invalid);
|
||||||
return true;
|
return true;
|
||||||
|
@ -43,14 +45,30 @@ export default class extends Module {
|
||||||
|
|
||||||
const str = `${hours ? hoursQuery[0] : ''}${minutes ? minutesQuery[0] : ''}${seconds ? secondsQuery[0] : ''}`;
|
const str = `${hours ? hoursQuery[0] : ''}${minutes ? minutesQuery[0] : ''}${seconds ? secondsQuery[0] : ''}`;
|
||||||
|
|
||||||
setTimeout(() => {
|
// タイマーセット
|
||||||
const name = msg.friend.name;
|
this.setTimeoutWithPersistence(time, {
|
||||||
msg.reply(serifs.timer.notify(str, name));
|
isDm: msg.isDm,
|
||||||
}, time);
|
msgId: msg.id,
|
||||||
|
userId: msg.friend.userId,
|
||||||
|
time: str
|
||||||
|
});
|
||||||
|
|
||||||
return true;
|
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 {
|
} else {
|
||||||
return false;
|
this.ai.post({
|
||||||
|
replyId: data.msgId,
|
||||||
|
text: text
|
||||||
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue