mirror of
https://github.com/syuilo/ai.git
synced 2024-11-25 06:01:07 +00:00
Refactor
This commit is contained in:
parent
69bf95e6bf
commit
3d467c2629
34
package-lock.json
generated
34
package-lock.json
generated
|
@ -3,6 +3,14 @@
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"lockfileVersion": 1,
|
"lockfileVersion": 1,
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/chalk": {
|
||||||
|
"version": "2.2.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@types/chalk/-/chalk-2.2.0.tgz",
|
||||||
|
"integrity": "sha512-1zzPV9FDe1I/WHhRkf9SNgqtRJWZqrBWgu7JGveuHmmyR9CnAPCie2N/x+iHrgnpYBIcCJWHBoMRv2TRWktsvw==",
|
||||||
|
"requires": {
|
||||||
|
"chalk": "*"
|
||||||
|
}
|
||||||
|
},
|
||||||
"@types/events": {
|
"@types/events": {
|
||||||
"version": "1.2.0",
|
"version": "1.2.0",
|
||||||
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
"resolved": "https://registry.npmjs.org/@types/events/-/events-1.2.0.tgz",
|
||||||
|
@ -142,9 +150,9 @@
|
||||||
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
"integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw="
|
||||||
},
|
},
|
||||||
"chalk": {
|
"chalk": {
|
||||||
"version": "2.4.1",
|
"version": "2.4.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.1.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz",
|
||||||
"integrity": "sha512-ObN6h1v2fTJSmUXoS3nMQ92LbDK9be4TV+6G+omQlGJFdcUX5heKi1LZ1YnRMIgwTLEj3E24bT6tYni50rlCfQ==",
|
"integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"ansi-styles": "^3.2.1",
|
"ansi-styles": "^3.2.1",
|
||||||
"escape-string-regexp": "^1.0.5",
|
"escape-string-regexp": "^1.0.5",
|
||||||
|
@ -157,17 +165,17 @@
|
||||||
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
"integrity": "sha1-bqa989hTrlTMuOR7+gvz+QMfsYQ="
|
||||||
},
|
},
|
||||||
"color-convert": {
|
"color-convert": {
|
||||||
"version": "1.9.2",
|
"version": "1.9.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.2.tgz",
|
"resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz",
|
||||||
"integrity": "sha512-3NUJZdhMhcdPn8vJ9v2UQJoH0qqoGUkYTgFEPZaPjEtwmmKUfNV46zZmgB2M5M4DCEQHMaCfWHCxiBflLm04Tg==",
|
"integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"color-name": "1.1.1"
|
"color-name": "1.1.3"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"color-name": {
|
"color-name": {
|
||||||
"version": "1.1.1",
|
"version": "1.1.3",
|
||||||
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz",
|
||||||
"integrity": "sha1-SxQVMEz1ACjqgWQ2Q72C6gWANok="
|
"integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU="
|
||||||
},
|
},
|
||||||
"combined-stream": {
|
"combined-stream": {
|
||||||
"version": "1.0.6",
|
"version": "1.0.6",
|
||||||
|
@ -561,9 +569,9 @@
|
||||||
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
"integrity": "sha1-NbCYdbT/SfJqd35QmzCQoyJr8ks="
|
||||||
},
|
},
|
||||||
"supports-color": {
|
"supports-color": {
|
||||||
"version": "5.4.0",
|
"version": "5.5.0",
|
||||||
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.4.0.tgz",
|
"resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz",
|
||||||
"integrity": "sha512-zjaXglF5nnWpsq470jSv6P9DwPvgLkuapYmfDm3JWOm0vkNTVF2tI4UrN2r6jH1qM/uc/WtxYY1hYoA2dOKj5w==",
|
"integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==",
|
||||||
"requires": {
|
"requires": {
|
||||||
"has-flag": "^3.0.0"
|
"has-flag": "^3.0.0"
|
||||||
}
|
}
|
||||||
|
|
|
@ -6,12 +6,14 @@
|
||||||
"build": "tsc"
|
"build": "tsc"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@types/chalk": "2.2.0",
|
||||||
"@types/lokijs": "1.5.2",
|
"@types/lokijs": "1.5.2",
|
||||||
"@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/ws": "6.0.1",
|
"@types/ws": "6.0.1",
|
||||||
"autobind-decorator": "2.1.0",
|
"autobind-decorator": "2.1.0",
|
||||||
|
"chalk": "2.4.2",
|
||||||
"lokijs": "1.5.5",
|
"lokijs": "1.5.5",
|
||||||
"mecab-async": "0.1.2",
|
"mecab-async": "0.1.2",
|
||||||
"misskey-reversi": "0.0.5",
|
"misskey-reversi": "0.0.5",
|
||||||
|
|
82
src/ai.ts
82
src/ai.ts
|
@ -1,22 +1,38 @@
|
||||||
// AI CORE
|
// AI CORE
|
||||||
|
|
||||||
|
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 config from './config';
|
import config from './config';
|
||||||
import IModule from './module';
|
import Module from './module';
|
||||||
import MessageLike from './message-like';
|
import MessageLike from './message-like';
|
||||||
import { FriendDoc } from './friend';
|
import { FriendDoc } from './friend';
|
||||||
import { User } from './misskey/user';
|
import { User } from './misskey/user';
|
||||||
import getCollection from './utils/get-collection';
|
import getCollection from './utils/get-collection';
|
||||||
import Stream from './stream';
|
import Stream from './stream';
|
||||||
|
|
||||||
|
type OnMentionHandler = (msg: MessageLike) => boolean | HandlerResult;
|
||||||
|
type OnContextReplyHandler = (msg: MessageLike, data?: any) => void | HandlerResult;
|
||||||
|
|
||||||
|
export type HandlerResult = {
|
||||||
|
reaction: string;
|
||||||
|
};
|
||||||
|
|
||||||
|
export type InstallerResult = {
|
||||||
|
onMention?: OnMentionHandler;
|
||||||
|
onContextReply?: OnContextReplyHandler;
|
||||||
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 藍
|
* 藍
|
||||||
*/
|
*/
|
||||||
export default class 藍 {
|
export default class 藍 {
|
||||||
public account: User;
|
public account: User;
|
||||||
public connection: Stream;
|
public connection: Stream;
|
||||||
private modules: IModule[] = [];
|
public modules: Module[] = [];
|
||||||
|
private onMentionHandlers: OnMentionHandler[] = [];
|
||||||
|
private onContextReplyHandlers: { [moduleName: string]: OnContextReplyHandler } = {};
|
||||||
public db: loki;
|
public db: loki;
|
||||||
|
|
||||||
private contexts: loki.Collection<{
|
private contexts: loki.Collection<{
|
||||||
|
@ -30,19 +46,30 @@ export default class 藍 {
|
||||||
|
|
||||||
public friends: loki.Collection<FriendDoc>;
|
public friends: loki.Collection<FriendDoc>;
|
||||||
|
|
||||||
constructor(account: User, modules: IModule[]) {
|
constructor(account: User, ready?: Function) {
|
||||||
this.account = account;
|
this.account = account;
|
||||||
this.modules = modules;
|
|
||||||
|
|
||||||
this.db = new loki('memory.json', {
|
this.db = new loki('memory.json', {
|
||||||
autoload: true,
|
autoload: true,
|
||||||
autosave: true,
|
autosave: true,
|
||||||
autosaveInterval: 1000,
|
autosaveInterval: 1000,
|
||||||
autoloadCallback: this.init
|
autoloadCallback: err => {
|
||||||
|
if (err) {
|
||||||
|
this.log(chalk.red(`Failed to load DB: ${err}`));
|
||||||
|
} else {
|
||||||
|
if (ready) ready();
|
||||||
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
private init = () => {
|
@autobind
|
||||||
|
public log(msg: string) {
|
||||||
|
console.log(`[AiOS]: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public run() {
|
||||||
//#region Init DB
|
//#region Init DB
|
||||||
this.contexts = getCollection(this.db, 'contexts', {
|
this.contexts = getCollection(this.db, 'contexts', {
|
||||||
indices: ['key']
|
indices: ['key']
|
||||||
|
@ -62,7 +89,7 @@ export default class 藍 {
|
||||||
// メンションされたとき
|
// メンションされたとき
|
||||||
mainStream.on('mention', data => {
|
mainStream.on('mention', data => {
|
||||||
if (data.userId == this.account.id) return; // 自分は弾く
|
if (data.userId == this.account.id) return; // 自分は弾く
|
||||||
if (data.text.startsWith('@' + this.account.username)) {
|
if (data.text && data.text.startsWith('@' + this.account.username)) {
|
||||||
this.onMention(new MessageLike(this, data, false));
|
this.onMention(new MessageLike(this, data, false));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
@ -81,11 +108,21 @@ export default class 藍 {
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
// Install modules
|
// Install modules
|
||||||
this.modules.forEach(m => m.install(this));
|
this.modules.forEach(m => {
|
||||||
|
this.log(`Installing ${chalk.cyan.italic(m.name)}\tmodule...`);
|
||||||
|
const res = m.install();
|
||||||
|
if (res != null) {
|
||||||
|
if (res.onMention) this.onMentionHandlers.push(res.onMention);
|
||||||
|
if (res.onContextReply) this.onContextReplyHandlers[m.name] = res.onContextReply;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
this.log(chalk.green.bold('Ai am now running!'));
|
||||||
}
|
}
|
||||||
|
|
||||||
private onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
console.log(`mention received: ${msg.id}`);
|
private onMention(msg: MessageLike) {
|
||||||
|
this.log(`mention received: ${msg.id}`);
|
||||||
|
|
||||||
const context = !msg.isMessage && msg.replyId == null ? null : this.contexts.findOne(msg.isMessage ? {
|
const context = !msg.isMessage && msg.replyId == null ? null : this.contexts.findOne(msg.isMessage ? {
|
||||||
isMessage: true,
|
isMessage: true,
|
||||||
|
@ -98,17 +135,17 @@ export default class 藍 {
|
||||||
let reaction = 'love';
|
let reaction = 'love';
|
||||||
|
|
||||||
if (context != null) {
|
if (context != null) {
|
||||||
const module = this.modules.find(m => m.name == context.module);
|
const handler = this.onContextReplyHandlers[context.module];
|
||||||
const res = module.onReplyThisModule(msg, context.data);
|
const res = handler(msg, context.data);
|
||||||
|
|
||||||
if (res != null && typeof res === 'object') {
|
if (res != null && typeof res === 'object') {
|
||||||
reaction = res.reaction;
|
reaction = res.reaction;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let res: ReturnType<IModule['onMention']>;
|
let res: boolean | HandlerResult;
|
||||||
|
|
||||||
this.modules.filter(m => m.hasOwnProperty('onMention')).some(m => {
|
this.onMentionHandlers.some(handler => {
|
||||||
res = m.onMention(msg);
|
res = handler(msg);
|
||||||
return res === true || typeof res === 'object';
|
return res === true || typeof res === 'object';
|
||||||
});
|
});
|
||||||
|
|
||||||
|
@ -135,18 +172,21 @@ export default class 藍 {
|
||||||
}, 1000);
|
}, 1000);
|
||||||
}
|
}
|
||||||
|
|
||||||
public post = async (param: any) => {
|
@autobind
|
||||||
|
public async post(param: any) {
|
||||||
const res = await this.api('notes/create', param);
|
const res = await this.api('notes/create', param);
|
||||||
return res.createdNote;
|
return res.createdNote;
|
||||||
}
|
}
|
||||||
|
|
||||||
public sendMessage = (userId: any, param: any) => {
|
@autobind
|
||||||
|
public sendMessage(userId: any, param: any) {
|
||||||
return this.api('messaging/messages/create', Object.assign({
|
return this.api('messaging/messages/create', Object.assign({
|
||||||
userId: userId,
|
userId: userId,
|
||||||
}, param));
|
}, param));
|
||||||
}
|
}
|
||||||
|
|
||||||
public api = (endpoint: string, param?: any) => {
|
@autobind
|
||||||
|
public api(endpoint: string, param?: any) {
|
||||||
return request.post(`${config.apiUrl}/${endpoint}`, {
|
return request.post(`${config.apiUrl}/${endpoint}`, {
|
||||||
json: Object.assign({
|
json: Object.assign({
|
||||||
i: config.i
|
i: config.i
|
||||||
|
@ -154,7 +194,8 @@ export default class 藍 {
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
public subscribeReply = (module: IModule, key: string, isMessage: boolean, id: string, data?: any) => {
|
@autobind
|
||||||
|
public subscribeReply(module: Module, key: string, isMessage: boolean, id: string, data?: any) {
|
||||||
this.contexts.insertOne(isMessage ? {
|
this.contexts.insertOne(isMessage ? {
|
||||||
isMessage: true,
|
isMessage: true,
|
||||||
userId: id,
|
userId: id,
|
||||||
|
@ -170,7 +211,8 @@ export default class 藍 {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
public unsubscribeReply = (module: IModule, key: string) => {
|
@autobind
|
||||||
|
public unsubscribeReply(module: Module, key: string) {
|
||||||
this.contexts.findAndRemove({
|
this.contexts.findAndRemove({
|
||||||
key: key,
|
key: key,
|
||||||
module: module.name
|
module: module.name
|
||||||
|
|
50
src/index.ts
50
src/index.ts
|
@ -16,42 +16,48 @@ import ServerModule from './modules/server';
|
||||||
import FollowModule from './modules/follow';
|
import FollowModule from './modules/follow';
|
||||||
import ValentineModule from './modules/valentine';
|
import ValentineModule from './modules/valentine';
|
||||||
|
|
||||||
|
import chalk from 'chalk';
|
||||||
import * as request from 'request-promise-native';
|
import * as request from 'request-promise-native';
|
||||||
import IModule from './module';
|
|
||||||
const promiseRetry = require('promise-retry');
|
const promiseRetry = require('promise-retry');
|
||||||
|
|
||||||
console.log('--- starting ai... ---');
|
function log(msg: string): void {
|
||||||
|
console.log(`[Boot]: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
log(chalk.bold('Ai v1.0'));
|
||||||
|
|
||||||
promiseRetry(retry => {
|
promiseRetry(retry => {
|
||||||
|
log(`Account fetching... >>> ${config.host}`);
|
||||||
return request.post(`${config.apiUrl}/i`, {
|
return request.post(`${config.apiUrl}/i`, {
|
||||||
json: {
|
json: {
|
||||||
i: config.i
|
i: config.i
|
||||||
}
|
}
|
||||||
}).catch(retry);
|
}).catch(retry);
|
||||||
|
}, {
|
||||||
|
retries: 3
|
||||||
}).then(account => {
|
}).then(account => {
|
||||||
console.log(`account fetched: @${account.username}`);
|
log(chalk.green(`Account fetched successfully: @${account.username}`));
|
||||||
|
|
||||||
const modules: IModule[] = [
|
log('Starting AiOS...');
|
||||||
new EmojiModule(),
|
|
||||||
new FortuneModule(),
|
|
||||||
new GuessingGameModule(),
|
|
||||||
new ReversiModule(),
|
|
||||||
new TimerModule(),
|
|
||||||
new DiceModule(),
|
|
||||||
new CoreModule(),
|
|
||||||
new PingModule(),
|
|
||||||
new WelcomeModule(),
|
|
||||||
new ServerModule(),
|
|
||||||
new FollowModule(),
|
|
||||||
new BirthdayModule(),
|
|
||||||
new ValentineModule(),
|
|
||||||
];
|
|
||||||
|
|
||||||
if (config.keywordEnabled) modules.push(new KeywordModule());
|
const ai = new 藍(account);
|
||||||
|
|
||||||
new 藍(account, modules);
|
new EmojiModule(ai);
|
||||||
|
new FortuneModule(ai);
|
||||||
|
new GuessingGameModule(ai);
|
||||||
|
new ReversiModule(ai);
|
||||||
|
new TimerModule(ai);
|
||||||
|
new DiceModule(ai);
|
||||||
|
new CoreModule(ai);
|
||||||
|
new PingModule(ai);
|
||||||
|
new WelcomeModule(ai);
|
||||||
|
new ServerModule(ai);
|
||||||
|
new FollowModule(ai);
|
||||||
|
new BirthdayModule(ai);
|
||||||
|
new ValentineModule(ai);
|
||||||
|
if (config.keywordEnabled) new KeywordModule(ai);
|
||||||
|
|
||||||
console.log('--- ai started! ---');
|
ai.run();
|
||||||
}).catch(e => {
|
}).catch(e => {
|
||||||
console.error('failed to fetch account', e);
|
log(chalk.red('Failed to fetch the account'));
|
||||||
});
|
});
|
||||||
|
|
|
@ -50,7 +50,7 @@ export default class MessageLike {
|
||||||
public reply = async (text: string, cw?: string) => {
|
public reply = async (text: string, cw?: string) => {
|
||||||
if (text == null) return;
|
if (text == null) return;
|
||||||
|
|
||||||
console.log(`sending reply of ${this.id} ...`);
|
this.ai.log(`sending reply of ${this.id} ...`);
|
||||||
|
|
||||||
await delay(2000);
|
await delay(2000);
|
||||||
|
|
||||||
|
|
|
@ -1,13 +1,30 @@
|
||||||
import 藍 from './ai';
|
import autobind from 'autobind-decorator';
|
||||||
import MessageLike from './message-like';
|
import 藍, { InstallerResult } from './ai';
|
||||||
|
|
||||||
export default interface IModule {
|
export default abstract class Module {
|
||||||
name: string;
|
public abstract name: string;
|
||||||
install?: (ai: 藍) => void;
|
|
||||||
onMention?: (msg: MessageLike) => boolean | Result;
|
protected ai: 藍;
|
||||||
onReplyThisModule?: (msg: MessageLike, data?: any) => void | Result;
|
|
||||||
|
constructor(ai: 藍) {
|
||||||
|
this.ai = ai;
|
||||||
|
this.ai.modules.push(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
public abstract install(): InstallerResult;
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
protected log(msg: string) {
|
||||||
|
this.ai.log(`[module ${this.name}]: ${msg}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public subscribeReply(key: string, isMessage: boolean, id: string, data?: any) {
|
||||||
|
this.ai.subscribeReply(this, key, isMessage, id, data);
|
||||||
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
|
public unsubscribeReply(key: string) {
|
||||||
|
this.ai.unsubscribeReply(this, key);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
export type Result = {
|
|
||||||
reaction: string;
|
|
||||||
};
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import Friend from '../../friend';
|
import Friend from '../../friend';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
|
||||||
|
@ -7,22 +7,22 @@ function zeroPadding(num: number, length: number): string {
|
||||||
return ('0000000000' + num).slice(-length);
|
return ('0000000000' + num).slice(-length);
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class BirthdayModule implements IModule {
|
export default class BirthdayModule extends Module {
|
||||||
public readonly name = 'birthday';
|
public readonly name = 'birthday';
|
||||||
|
|
||||||
private ai: 藍;
|
@autobind
|
||||||
|
public install() {
|
||||||
public install = (ai: 藍) => {
|
|
||||||
this.ai = ai;
|
|
||||||
|
|
||||||
this.crawleBirthday();
|
this.crawleBirthday();
|
||||||
setInterval(this.crawleBirthday, 1000 * 60 * 3);
|
setInterval(this.crawleBirthday, 1000 * 60 * 3);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* 誕生日のユーザーがいないかチェック(いたら祝う)
|
* 誕生日のユーザーがいないかチェック(いたら祝う)
|
||||||
*/
|
*/
|
||||||
private crawleBirthday = () => {
|
@autobind
|
||||||
|
private crawleBirthday() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
const m = now.getMonth();
|
const m = now.getMonth();
|
||||||
const d = now.getDate();
|
const d = now.getDate();
|
||||||
|
|
|
@ -1,5 +1,6 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule, { Result } from '../../module';
|
import { HandlerResult } from '../../ai';
|
||||||
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs, { getSerif } from '../../serifs';
|
import serifs, { getSerif } from '../../serifs';
|
||||||
import getDate from '../../utils/get-date';
|
import getDate from '../../utils/get-date';
|
||||||
|
@ -8,15 +9,19 @@ const titles = ['さん', 'くん', '君', 'ちゃん', '様', '先生'];
|
||||||
|
|
||||||
const invalidChars = ['@', '#', '*', ':', '(', '[', ' ', ' '];
|
const invalidChars = ['@', '#', '*', ':', '(', '[', ' ', ' '];
|
||||||
|
|
||||||
export default class CoreModule implements IModule {
|
export default class CoreModule extends Module {
|
||||||
public readonly name = 'core';
|
public readonly name = 'core';
|
||||||
private ai: 藍;
|
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention,
|
||||||
|
onContextReply: this.onContextReply
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (!msg.text) return false;
|
if (!msg.text) return false;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
|
@ -34,7 +39,8 @@ export default class CoreModule implements IModule {
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
private setName = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private setName(msg: MessageLike): boolean {
|
||||||
if (!msg.text) return false;
|
if (!msg.text) return false;
|
||||||
if (!msg.text.includes('って呼んで')) return false;
|
if (!msg.text.includes('って呼んで')) return false;
|
||||||
if (msg.text.startsWith('って呼んで')) return false;
|
if (msg.text.startsWith('って呼んで')) return false;
|
||||||
|
@ -66,7 +72,7 @@ export default class CoreModule implements IModule {
|
||||||
msg.reply(serifs.core.setNameOk(name));
|
msg.reply(serifs.core.setNameOk(name));
|
||||||
} else {
|
} else {
|
||||||
msg.reply(serifs.core.san).then(reply => {
|
msg.reply(serifs.core.san).then(reply => {
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id, {
|
this.subscribeReply(msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id, {
|
||||||
name: name
|
name: name
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
@ -75,7 +81,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private greet = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private greet(msg: MessageLike): boolean {
|
||||||
if (msg.text == null) return false;
|
if (msg.text == null) return false;
|
||||||
|
|
||||||
const incLove = () => {
|
const incLove = () => {
|
||||||
|
@ -143,7 +150,8 @@ export default class CoreModule implements IModule {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
private nadenade = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private nadenade(msg: MessageLike): boolean {
|
||||||
if (!msg.includes(['なでなで'])) return false;
|
if (!msg.includes(['なでなで'])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -177,7 +185,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private kawaii = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private kawaii(msg: MessageLike): boolean {
|
||||||
if (!msg.includes(['かわいい', '可愛い'])) return false;
|
if (!msg.includes(['かわいい', '可愛い'])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -191,7 +200,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private suki = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private suki(msg: MessageLike): boolean {
|
||||||
if (!msg.or(['好き', 'すき'])) return false;
|
if (!msg.or(['好き', 'すき'])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -205,7 +215,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private hug = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private hug(msg: MessageLike): boolean {
|
||||||
if (!msg.or(['ぎゅ', 'むぎゅ', /^はぐ(し(て|よ|よう)?)?$/])) return false;
|
if (!msg.or(['ぎゅ', 'むぎゅ', /^はぐ(し(て|よ|よう)?)?$/])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -238,7 +249,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private humu = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private humu(msg: MessageLike): boolean {
|
||||||
if (!msg.includes(['踏んで'])) return false;
|
if (!msg.includes(['踏んで'])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -252,7 +264,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private batou = (msg: MessageLike): boolean => {
|
@autobind
|
||||||
|
private batou(msg: MessageLike): boolean {
|
||||||
if (!msg.includes(['罵倒して', '罵って'])) return false;
|
if (!msg.includes(['罵倒して', '罵って'])) return false;
|
||||||
|
|
||||||
// メッセージのみ
|
// メッセージのみ
|
||||||
|
@ -266,7 +279,8 @@ export default class CoreModule implements IModule {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
private ponkotu = (msg: MessageLike): boolean | Result => {
|
@autobind
|
||||||
|
private ponkotu(msg: MessageLike): boolean | HandlerResult {
|
||||||
if (!msg.includes(['ぽんこつ'])) return false;
|
if (!msg.includes(['ぽんこつ'])) return false;
|
||||||
|
|
||||||
msg.friend.decLove();
|
msg.friend.decLove();
|
||||||
|
@ -276,7 +290,8 @@ export default class CoreModule implements IModule {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private rmrf = (msg: MessageLike): boolean | Result => {
|
@autobind
|
||||||
|
private rmrf(msg: MessageLike): boolean | HandlerResult {
|
||||||
if (!msg.includes(['rm -rf'])) return false;
|
if (!msg.includes(['rm -rf'])) return false;
|
||||||
|
|
||||||
msg.friend.decLove();
|
msg.friend.decLove();
|
||||||
|
@ -286,7 +301,8 @@ export default class CoreModule implements IModule {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
private shutdown = (msg: MessageLike): boolean | Result => {
|
@autobind
|
||||||
|
private shutdown(msg: MessageLike): boolean | HandlerResult {
|
||||||
if (!msg.includes(['shutdown'])) return false;
|
if (!msg.includes(['shutdown'])) return false;
|
||||||
|
|
||||||
msg.reply(serifs.core.shutdown);
|
msg.reply(serifs.core.shutdown);
|
||||||
|
@ -296,12 +312,13 @@ export default class CoreModule implements IModule {
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onReplyThisModule = (msg: MessageLike, data: any) => {
|
@autobind
|
||||||
|
private onContextReply(msg: MessageLike, data: any) {
|
||||||
if (msg.text == null) return;
|
if (msg.text == null) return;
|
||||||
|
|
||||||
const done = () => {
|
const done = () => {
|
||||||
msg.reply(serifs.core.setNameOk(msg.friend.name));
|
msg.reply(serifs.core.setNameOk(msg.friend.name));
|
||||||
this.ai.unsubscribeReply(this, msg.userId);
|
this.unsubscribeReply(msg.userId);
|
||||||
};
|
};
|
||||||
|
|
||||||
if (msg.text.includes('はい')) {
|
if (msg.text.includes('はい')) {
|
||||||
|
@ -312,7 +329,7 @@ export default class CoreModule implements IModule {
|
||||||
done();
|
done();
|
||||||
} else {
|
} else {
|
||||||
msg.reply(serifs.core.yesOrNo).then(reply => {
|
msg.reply(serifs.core.yesOrNo).then(reply => {
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, reply.id, data);
|
this.subscribeReply(msg.userId, msg.isMessage, reply.id, data);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
|
||||||
export default class DiceModule implements IModule {
|
export default class DiceModule extends Module {
|
||||||
public readonly name = 'dice';
|
public readonly name = 'dice';
|
||||||
private ai: 藍;
|
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.text == null) return false;
|
if (msg.text == null) return false;
|
||||||
|
|
||||||
const query = msg.text.match(/([0-9]+)[dD]([0-9]+)/);
|
const query = msg.text.match(/([0-9]+)[dD]([0-9]+)/);
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
|
||||||
|
@ -126,12 +126,18 @@ const faces = [
|
||||||
'👽'
|
'👽'
|
||||||
]
|
]
|
||||||
|
|
||||||
export default class EmojiModule implements IModule {
|
export default class EmojiModule extends Module {
|
||||||
public readonly name = 'emoji';
|
public readonly name = 'emoji';
|
||||||
|
|
||||||
public install = (ai: 藍) => { }
|
@autobind
|
||||||
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.includes(['顔文字', '絵文字', 'emoji', '福笑い'])) {
|
if (msg.includes(['顔文字', '絵文字', 'emoji', '福笑い'])) {
|
||||||
const hand = hands[Math.floor(Math.random() * hands.length)];
|
const hand = hands[Math.floor(Math.random() * hands.length)];
|
||||||
const face = faces[Math.floor(Math.random() * faces.length)];
|
const face = faces[Math.floor(Math.random() * faces.length)];
|
||||||
|
|
|
@ -1,16 +1,19 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
|
|
||||||
export default class FollowModule implements IModule {
|
export default class FollowModule extends Module {
|
||||||
public readonly name = 'follow';
|
public readonly name = 'follow';
|
||||||
private ai: 藍;
|
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.text && msg.includes(['フォロー', 'フォロバ', 'follow me'])) {
|
if (msg.text && msg.includes(['フォロー', 'フォロバ', 'follow me'])) {
|
||||||
if (!msg.user.isFollowing) {
|
if (!msg.user.isFollowing) {
|
||||||
this.ai.api('following/create', {
|
this.ai.api('following/create', {
|
||||||
|
|
|
@ -1,16 +1,22 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
import * as seedrandom from 'seedrandom';
|
import * as seedrandom from 'seedrandom';
|
||||||
import { blessing, itemPrefixes, items } from './vocabulary';
|
import { blessing, itemPrefixes, items } from './vocabulary';
|
||||||
|
|
||||||
export default class FortuneModule implements IModule {
|
export default class FortuneModule extends Module {
|
||||||
public readonly name = 'fortune';
|
public readonly name = 'fortune';
|
||||||
|
|
||||||
public install = (ai: 藍) => { }
|
@autobind
|
||||||
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.includes(['占', 'うらな', '運勢', 'おみくじ'])) {
|
if (msg.includes(['占', 'うらな', '運勢', 'おみくじ'])) {
|
||||||
const date = new Date();
|
const date = new Date();
|
||||||
const seed = `${date.getFullYear()}/${date.getMonth()}/${date.getDate()}@${msg.userId}`;
|
const seed = `${date.getFullYear()}/${date.getMonth()}/${date.getDate()}@${msg.userId}`;
|
||||||
|
|
|
@ -1,13 +1,12 @@
|
||||||
|
import autobind from 'autobind-decorator';
|
||||||
import * as loki from 'lokijs';
|
import * as loki from 'lokijs';
|
||||||
import 藍 from '../../ai';
|
import Module from '../../module';
|
||||||
import IModule from '../../module';
|
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
import getCollection from '../../utils/get-collection';
|
import getCollection from '../../utils/get-collection';
|
||||||
|
|
||||||
export default class GuessingGameModule implements IModule {
|
export default class GuessingGameModule extends Module {
|
||||||
public readonly name = 'guessingGame';
|
public readonly name = 'guessingGame';
|
||||||
private ai: 藍;
|
|
||||||
private guesses: loki.Collection<{
|
private guesses: loki.Collection<{
|
||||||
userId: string;
|
userId: string;
|
||||||
secret: number;
|
secret: number;
|
||||||
|
@ -17,17 +16,22 @@ export default class GuessingGameModule implements IModule {
|
||||||
endedAt: number;
|
endedAt: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
|
||||||
//#region Init DB
|
//#region Init DB
|
||||||
this.guesses = getCollection(this.ai.db, 'guessingGame', {
|
this.guesses = getCollection(this.ai.db, 'guessingGame', {
|
||||||
indices: ['userId']
|
indices: ['userId']
|
||||||
});
|
});
|
||||||
//#endregion
|
//#endregion
|
||||||
|
|
||||||
|
return {
|
||||||
|
onMention: this.onMention,
|
||||||
|
onContextReply: this.onContextReply
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.includes(['数当て', '数あて'])) {
|
if (msg.includes(['数当て', '数あて'])) {
|
||||||
const exist = this.guesses.findOne({
|
const exist = this.guesses.findOne({
|
||||||
userId: msg.userId,
|
userId: msg.userId,
|
||||||
|
@ -56,7 +60,7 @@ export default class GuessingGameModule implements IModule {
|
||||||
});
|
});
|
||||||
|
|
||||||
msg.reply(serifs.guessingGame.started).then(reply => {
|
msg.reply(serifs.guessingGame.started).then(reply => {
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id);
|
this.subscribeReply(msg.userId, msg.isMessage, msg.isMessage ? msg.userId : reply.id);
|
||||||
});
|
});
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
|
@ -65,7 +69,8 @@ export default class GuessingGameModule implements IModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public onReplyThisModule = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onContextReply(msg: MessageLike) {
|
||||||
if (msg.text == null) return;
|
if (msg.text == null) return;
|
||||||
|
|
||||||
const exist = this.guesses.findOne({
|
const exist = this.guesses.findOne({
|
||||||
|
@ -78,7 +83,7 @@ export default class GuessingGameModule implements IModule {
|
||||||
exist.isEnded = true;
|
exist.isEnded = true;
|
||||||
exist.endedAt = Date.now();
|
exist.endedAt = Date.now();
|
||||||
this.guesses.update(exist);
|
this.guesses.update(exist);
|
||||||
this.ai.unsubscribeReply(this, msg.userId);
|
this.unsubscribeReply(msg.userId);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -86,7 +91,7 @@ export default class GuessingGameModule implements IModule {
|
||||||
|
|
||||||
if (guess == null) {
|
if (guess == null) {
|
||||||
msg.reply(serifs.guessingGame.nan).then(reply => {
|
msg.reply(serifs.guessingGame.nan).then(reply => {
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, reply.id);
|
this.subscribeReply(msg.userId, msg.isMessage, reply.id);
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
if (guess.length > 3) return;
|
if (guess.length > 3) return;
|
||||||
|
@ -116,14 +121,14 @@ export default class GuessingGameModule implements IModule {
|
||||||
if (end) {
|
if (end) {
|
||||||
exist.isEnded = true;
|
exist.isEnded = true;
|
||||||
exist.endedAt = Date.now();
|
exist.endedAt = Date.now();
|
||||||
this.ai.unsubscribeReply(this, msg.userId);
|
this.unsubscribeReply(msg.userId);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.guesses.update(exist);
|
this.guesses.update(exist);
|
||||||
|
|
||||||
msg.reply(text).then(reply => {
|
msg.reply(text).then(reply => {
|
||||||
if (!end) {
|
if (!end) {
|
||||||
this.ai.subscribeReply(this, msg.userId, msg.isMessage, reply.id);
|
this.subscribeReply(msg.userId, msg.isMessage, reply.id);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
|
import autobind from 'autobind-decorator';
|
||||||
import * as loki from 'lokijs';
|
import * as loki from 'lokijs';
|
||||||
import 藍 from '../../ai';
|
import Module from '../../module';
|
||||||
import IModule from '../../module';
|
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
import getCollection from '../../utils/get-collection';
|
import getCollection from '../../utils/get-collection';
|
||||||
|
@ -13,19 +13,17 @@ function kanaToHira(str: string) {
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
export default class KeywordModule implements IModule {
|
export default class KeywordModule extends Module {
|
||||||
public readonly name = 'keyword';
|
public readonly name = 'keyword';
|
||||||
|
|
||||||
private ai: 藍;
|
|
||||||
private tokenizer: any;
|
private tokenizer: any;
|
||||||
private learnedKeywords: loki.Collection<{
|
private learnedKeywords: loki.Collection<{
|
||||||
keyword: string;
|
keyword: string;
|
||||||
learnedAt: number;
|
learnedAt: number;
|
||||||
}>;
|
}>;
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
|
||||||
//#region Init DB
|
//#region Init DB
|
||||||
this.learnedKeywords = getCollection(this.ai.db, '_keyword_learnedKeywords', {
|
this.learnedKeywords = getCollection(this.ai.db, '_keyword_learnedKeywords', {
|
||||||
indices: ['userId']
|
indices: ['userId']
|
||||||
|
@ -36,9 +34,12 @@ export default class KeywordModule implements IModule {
|
||||||
this.tokenizer.command = config.mecab;
|
this.tokenizer.command = config.mecab;
|
||||||
|
|
||||||
setInterval(this.say, 1000 * 60 * 60);
|
setInterval(this.say, 1000 * 60 * 60);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
private say = async () => {
|
@autobind
|
||||||
|
private async say() {
|
||||||
const tl = await this.ai.api('notes/local-timeline', {
|
const tl = await this.ai.api('notes/local-timeline', {
|
||||||
limit: 30
|
limit: 30
|
||||||
});
|
});
|
||||||
|
|
|
@ -1,13 +1,19 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
|
|
||||||
export default class PingModule implements IModule {
|
export default class PingModule extends Module {
|
||||||
public readonly name = 'ping';
|
public readonly name = 'ping';
|
||||||
|
|
||||||
public install = (ai: 藍) => { }
|
@autobind
|
||||||
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.text && msg.text.includes('ping')) {
|
if (msg.text && msg.text.includes('ping')) {
|
||||||
msg.reply('PONG!');
|
msg.reply('PONG!');
|
||||||
return true;
|
return true;
|
||||||
|
|
|
@ -1,27 +1,23 @@
|
||||||
import * as childProcess from 'child_process';
|
import * as childProcess from 'child_process';
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import * as WebSocket from 'ws';
|
|
||||||
import Friend from '../../friend';
|
import Friend from '../../friend';
|
||||||
import getDate from '../../utils/get-date';
|
import getDate from '../../utils/get-date';
|
||||||
|
|
||||||
export default class ReversiModule implements IModule {
|
export default class ReversiModule extends Module {
|
||||||
public readonly name = 'reversi';
|
public readonly name = 'reversi';
|
||||||
|
|
||||||
private ai: 藍;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* リバーシストリーム
|
* リバーシストリーム
|
||||||
*/
|
*/
|
||||||
private reversiConnection?: any;
|
private reversiConnection?: any;
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
if (!config.reversiEnabled) return;
|
public install() {
|
||||||
|
if (!config.reversiEnabled) return {};
|
||||||
this.ai = ai;
|
|
||||||
|
|
||||||
this.reversiConnection = this.ai.connection.useSharedConnection('gamesReversi');
|
this.reversiConnection = this.ai.connection.useSharedConnection('gamesReversi');
|
||||||
|
|
||||||
|
@ -30,9 +26,14 @@ export default class ReversiModule implements IModule {
|
||||||
|
|
||||||
// マッチしたとき
|
// マッチしたとき
|
||||||
this.reversiConnection.on('matched', msg => this.onReversiGameStart(msg));
|
this.reversiConnection.on('matched', msg => this.onReversiGameStart(msg));
|
||||||
|
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
if (msg.includes(['リバーシ', 'オセロ', 'reversi', 'othello'])) {
|
if (msg.includes(['リバーシ', 'オセロ', 'reversi', 'othello'])) {
|
||||||
if (config.reversiEnabled) {
|
if (config.reversiEnabled) {
|
||||||
msg.reply(serifs.reversi.ok);
|
msg.reply(serifs.reversi.ok);
|
||||||
|
@ -50,8 +51,9 @@ export default class ReversiModule implements IModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onReversiInviteMe = async (inviter: any) => {
|
@autobind
|
||||||
console.log(`Someone invited me: @${inviter.username}`);
|
private async onReversiInviteMe(inviter: any) {
|
||||||
|
this.log(`Someone invited me: @${inviter.username}`);
|
||||||
|
|
||||||
if (config.reversiEnabled) {
|
if (config.reversiEnabled) {
|
||||||
// 承認
|
// 承認
|
||||||
|
@ -65,8 +67,9 @@ export default class ReversiModule implements IModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onReversiGameStart = (game: any) => {
|
@autobind
|
||||||
console.log('enter reversi game room');
|
private onReversiGameStart(game: any) {
|
||||||
|
this.log('enter reversi game room');
|
||||||
|
|
||||||
// ゲームストリームに接続
|
// ゲームストリームに接続
|
||||||
const gw = this.ai.connection.connectToChannel('gamesReversiGame', {
|
const gw = this.ai.connection.connectToChannel('gamesReversiGame', {
|
||||||
|
@ -144,6 +147,7 @@ export default class ReversiModule implements IModule {
|
||||||
}, 2000);
|
}, 2000);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@autobind
|
||||||
private onGameEnded(game: any) {
|
private onGameEnded(game: any) {
|
||||||
const user = game.user1Id == this.ai.account.id ? game.user2 : game.user1;
|
const user = game.user1Id == this.ai.account.id ? game.user2 : game.user1;
|
||||||
|
|
||||||
|
|
|
@ -1,12 +1,11 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
import config from '../../config';
|
import config from '../../config';
|
||||||
|
|
||||||
export default class ServerModule implements IModule {
|
export default class ServerModule extends Module {
|
||||||
public readonly name = 'server';
|
public readonly name = 'server';
|
||||||
|
|
||||||
private ai: 藍;
|
|
||||||
private connection?: any;
|
private connection?: any;
|
||||||
private recentStat: any;
|
private recentStat: any;
|
||||||
private warned = false;
|
private warned = false;
|
||||||
|
@ -17,10 +16,9 @@ export default class ServerModule implements IModule {
|
||||||
*/
|
*/
|
||||||
private statsLogs: any[] = [];
|
private statsLogs: any[] = [];
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
if (!config.serverMonitoring) return;
|
public install() {
|
||||||
|
if (!config.serverMonitoring) return {};
|
||||||
this.ai = ai;
|
|
||||||
|
|
||||||
this.connection = this.ai.connection.useSharedConnection('serverStats');
|
this.connection = this.ai.connection.useSharedConnection('serverStats');
|
||||||
this.connection.on('stats', this.onStats);
|
this.connection.on('stats', this.onStats);
|
||||||
|
@ -33,9 +31,12 @@ export default class ServerModule implements IModule {
|
||||||
setInterval(() => {
|
setInterval(() => {
|
||||||
this.check();
|
this.check();
|
||||||
}, 3000);
|
}, 3000);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
private check = () => {
|
@autobind
|
||||||
|
private check() {
|
||||||
const average = (arr) => arr.reduce((a, b) => a + b) / arr.length;
|
const average = (arr) => arr.reduce((a, b) => a + b) / arr.length;
|
||||||
|
|
||||||
const cpuPercentages = this.statsLogs.map(s => s && s.cpu_usage * 100 || 0);
|
const cpuPercentages = this.statsLogs.map(s => s && s.cpu_usage * 100 || 0);
|
||||||
|
@ -47,11 +48,13 @@ export default class ServerModule implements IModule {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private onStats = async (stats: any) => {
|
@autobind
|
||||||
|
private async onStats(stats: any) {
|
||||||
this.recentStat = stats.body;
|
this.recentStat = stats.body;
|
||||||
}
|
}
|
||||||
|
|
||||||
private warn = () => {
|
@autobind
|
||||||
|
private warn() {
|
||||||
//#region 前に警告したときから一旦落ち着いた状態を経験していなければ警告しない
|
//#region 前に警告したときから一旦落ち着いた状態を経験していなければ警告しない
|
||||||
// 常に負荷が高いようなサーバーで無限に警告し続けるのを防ぐため
|
// 常に負荷が高いようなサーバーで無限に警告し続けるのを防ぐため
|
||||||
if (this.warned) return;
|
if (this.warned) return;
|
||||||
|
|
|
@ -1,17 +1,20 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import MessageLike from '../../message-like';
|
import MessageLike from '../../message-like';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
|
||||||
export default class TimerModule implements IModule {
|
export default class TimerModule extends Module {
|
||||||
public readonly name = 'timer';
|
public readonly name = 'timer';
|
||||||
private ai: 藍;
|
|
||||||
|
|
||||||
public install = (ai: 藍) => {
|
@autobind
|
||||||
this.ai = ai;
|
public install() {
|
||||||
|
return {
|
||||||
|
onMention: this.onMention
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onMention = (msg: MessageLike) => {
|
@autobind
|
||||||
|
private onMention(msg: MessageLike) {
|
||||||
const secondsQuery = (msg.text || '').match(/([0-9]+)秒/);
|
const secondsQuery = (msg.text || '').match(/([0-9]+)秒/);
|
||||||
const minutesQuery = (msg.text || '').match(/([0-9]+)分/);
|
const minutesQuery = (msg.text || '').match(/([0-9]+)分/);
|
||||||
const hoursQuery = (msg.text || '').match(/([0-9]+)時間/);
|
const hoursQuery = (msg.text || '').match(/([0-9]+)時間/);
|
||||||
|
|
|
@ -1,24 +1,24 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
import Friend from '../../friend';
|
import Friend from '../../friend';
|
||||||
import serifs from '../../serifs';
|
import serifs from '../../serifs';
|
||||||
|
|
||||||
export default class ValentineModule implements IModule {
|
export default class ValentineModule extends Module {
|
||||||
public readonly name = 'valentine';
|
public readonly name = 'valentine';
|
||||||
|
|
||||||
private ai: 藍;
|
@autobind
|
||||||
|
public install() {
|
||||||
public install = (ai: 藍) => {
|
|
||||||
this.ai = ai;
|
|
||||||
|
|
||||||
this.crawleValentine();
|
this.crawleValentine();
|
||||||
setInterval(this.crawleValentine, 1000 * 60 * 3);
|
setInterval(this.crawleValentine, 1000 * 60 * 3);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* チョコ配り
|
* チョコ配り
|
||||||
*/
|
*/
|
||||||
private crawleValentine = () => {
|
@autobind
|
||||||
|
private crawleValentine() {
|
||||||
const now = new Date();
|
const now = new Date();
|
||||||
|
|
||||||
const isValentine = now.getMonth() == 1 && now.getDate() == 14;
|
const isValentine = now.getMonth() == 1 && now.getDate() == 14;
|
||||||
|
|
|
@ -1,20 +1,20 @@
|
||||||
import 藍 from '../../ai';
|
import autobind from 'autobind-decorator';
|
||||||
import IModule from '../../module';
|
import Module from '../../module';
|
||||||
|
|
||||||
export default class WelcomeModule implements IModule {
|
export default class WelcomeModule extends Module {
|
||||||
public readonly name = 'welcome';
|
public readonly name = 'welcome';
|
||||||
|
|
||||||
private ai: 藍;
|
@autobind
|
||||||
|
public install() {
|
||||||
public install = (ai: 藍) => {
|
|
||||||
this.ai = ai;
|
|
||||||
|
|
||||||
const tl = this.ai.connection.useSharedConnection('localTimeline');
|
const tl = this.ai.connection.useSharedConnection('localTimeline');
|
||||||
|
|
||||||
tl.on('note', this.onLocalNote);
|
tl.on('note', this.onLocalNote);
|
||||||
|
|
||||||
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
public onLocalNote = (note: any) => {
|
@autobind
|
||||||
|
private onLocalNote(note: any) {
|
||||||
if (note.isFirstNote) {
|
if (note.isFirstNote) {
|
||||||
setTimeout(() => {
|
setTimeout(() => {
|
||||||
this.ai.api('notes/create', {
|
this.ai.api('notes/create', {
|
||||||
|
|
Loading…
Reference in a new issue