This commit is contained in:
syuilo 2019-02-02 02:06:51 +09:00
parent 73c2ef516a
commit 70baea9d18
No known key found for this signature in database
GPG key ID: BDC4C49D06AB9D69
6 changed files with 139 additions and 27 deletions

8
package-lock.json generated
View file

@ -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",

View file

@ -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"
} }
} }

View file

@ -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`);
}
} }

View file

@ -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 }) {

View file

@ -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);
}
} }

View file

@ -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,34 +24,51 @@ 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) {
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 ((seconds + minutes + hours) == 0) {
msg.reply(serifs.timer.invalid);
return true; 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 { } else {
return false; this.ai.post({
replyId: data.msgId,
text: text
});
} }
} }
} }