2018-08-11 06:26:25 +00:00
|
|
|
// AI CORE
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
import autobind from 'autobind-decorator';
|
2018-08-26 21:16:56 +00:00
|
|
|
import * as loki from 'lokijs';
|
2018-08-11 06:26:25 +00:00
|
|
|
import * as request from 'request-promise-native';
|
2019-01-14 15:14:22 +00:00
|
|
|
import chalk from 'chalk';
|
2018-08-11 06:26:25 +00:00
|
|
|
import config from './config';
|
2019-01-14 15:14:22 +00:00
|
|
|
import Module from './module';
|
2018-08-11 06:26:25 +00:00
|
|
|
import MessageLike from './message-like';
|
2018-08-27 11:22:59 +00:00
|
|
|
import { FriendDoc } from './friend';
|
2018-08-28 21:30:48 +00:00
|
|
|
import { User } from './misskey/user';
|
2018-08-29 07:26:33 +00:00
|
|
|
import getCollection from './utils/get-collection';
|
2018-10-09 15:47:03 +00:00
|
|
|
import Stream from './stream';
|
2019-01-15 03:29:11 +00:00
|
|
|
import log from './log';
|
2018-08-11 06:26:25 +00:00
|
|
|
|
2019-01-15 03:01:58 +00:00
|
|
|
type MentionHook = (msg: MessageLike) => boolean | HandlerResult;
|
|
|
|
type ContextHook = (msg: MessageLike, data?: any) => void | HandlerResult;
|
2019-01-14 15:14:22 +00:00
|
|
|
|
|
|
|
export type HandlerResult = {
|
|
|
|
reaction: string;
|
|
|
|
};
|
|
|
|
|
|
|
|
export type InstallerResult = {
|
2019-01-15 03:01:58 +00:00
|
|
|
mentionHook?: MentionHook;
|
|
|
|
contextHook?: ContextHook;
|
2019-01-14 15:14:22 +00:00
|
|
|
};
|
|
|
|
|
2018-08-11 06:26:25 +00:00
|
|
|
/**
|
|
|
|
* 藍
|
|
|
|
*/
|
|
|
|
export default class 藍 {
|
2018-08-28 21:30:48 +00:00
|
|
|
public account: User;
|
2018-10-09 15:47:03 +00:00
|
|
|
public connection: Stream;
|
2019-01-14 15:14:22 +00:00
|
|
|
public modules: Module[] = [];
|
2019-01-15 03:01:58 +00:00
|
|
|
private mentionHooks: MentionHook[] = [];
|
|
|
|
private contextHooks: { [moduleName: string]: ContextHook } = {};
|
2018-08-26 21:16:56 +00:00
|
|
|
public db: loki;
|
|
|
|
|
|
|
|
private contexts: loki.Collection<{
|
|
|
|
isMessage: boolean;
|
|
|
|
noteId?: string;
|
|
|
|
userId?: string;
|
|
|
|
module: string;
|
|
|
|
key: string;
|
2018-08-26 21:59:18 +00:00
|
|
|
data?: any;
|
|
|
|
}>;
|
|
|
|
|
2018-08-27 11:22:59 +00:00
|
|
|
public friends: loki.Collection<FriendDoc>;
|
2018-08-26 21:16:56 +00:00
|
|
|
|
2019-01-15 01:23:54 +00:00
|
|
|
constructor(account: User, ready: (run: Function) => void) {
|
2018-08-11 06:26:25 +00:00
|
|
|
this.account = account;
|
|
|
|
|
2019-01-15 03:29:11 +00:00
|
|
|
this.log('Lodaing the memory...');
|
|
|
|
|
2018-08-26 21:16:56 +00:00
|
|
|
this.db = new loki('memory.json', {
|
|
|
|
autoload: true,
|
|
|
|
autosave: true,
|
|
|
|
autosaveInterval: 1000,
|
2019-01-14 15:14:22 +00:00
|
|
|
autoloadCallback: err => {
|
|
|
|
if (err) {
|
2019-01-15 03:29:11 +00:00
|
|
|
this.log(chalk.red(`Failed to load the memory: ${err}`));
|
2019-01-14 15:14:22 +00:00
|
|
|
} else {
|
2019-01-15 03:29:11 +00:00
|
|
|
this.log(chalk.green('The memory loaded successfully'));
|
2019-01-15 01:23:54 +00:00
|
|
|
ready(this.run);
|
2019-01-14 15:14:22 +00:00
|
|
|
}
|
|
|
|
}
|
2018-08-26 21:16:56 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public log(msg: string) {
|
2019-01-15 03:29:11 +00:00
|
|
|
log(chalk`[{magenta AiOS}]: ${msg}`);
|
2019-01-14 15:14:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
@autobind
|
2019-01-15 01:23:54 +00:00
|
|
|
private run() {
|
2018-08-26 21:16:56 +00:00
|
|
|
//#region Init DB
|
2018-08-29 07:26:33 +00:00
|
|
|
this.contexts = getCollection(this.db, 'contexts', {
|
|
|
|
indices: ['key']
|
|
|
|
});
|
|
|
|
|
|
|
|
this.friends = getCollection(this.db, 'friends', {
|
|
|
|
indices: ['userId']
|
|
|
|
});
|
2018-08-26 21:16:56 +00:00
|
|
|
//#endregion
|
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
// Init stream
|
|
|
|
this.connection = new Stream();
|
2018-08-11 06:26:25 +00:00
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
//#region Main stream
|
|
|
|
const mainStream = this.connection.useSharedConnection('main');
|
2018-08-11 06:26:25 +00:00
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
// メンションされたとき
|
|
|
|
mainStream.on('mention', data => {
|
|
|
|
if (data.userId == this.account.id) return; // 自分は弾く
|
2019-01-14 15:14:22 +00:00
|
|
|
if (data.text && data.text.startsWith('@' + this.account.username)) {
|
2018-10-09 15:47:03 +00:00
|
|
|
this.onMention(new MessageLike(this, data, false));
|
|
|
|
}
|
2018-08-13 21:14:47 +00:00
|
|
|
});
|
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
// 返信されたとき
|
|
|
|
mainStream.on('reply', data => {
|
|
|
|
if (data.userId == this.account.id) return; // 自分は弾く
|
|
|
|
this.onMention(new MessageLike(this, data, false));
|
2018-08-13 21:14:47 +00:00
|
|
|
});
|
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
// メッセージ
|
|
|
|
mainStream.on('messagingMessage', data => {
|
|
|
|
if (data.userId == this.account.id) return; // 自分は弾く
|
|
|
|
this.onMention(new MessageLike(this, data, true));
|
2018-08-13 21:14:47 +00:00
|
|
|
});
|
|
|
|
//#endregion
|
2018-08-11 06:26:25 +00:00
|
|
|
|
2018-10-09 15:47:03 +00:00
|
|
|
// Install modules
|
2019-01-14 15:14:22 +00:00
|
|
|
this.modules.forEach(m => {
|
|
|
|
this.log(`Installing ${chalk.cyan.italic(m.name)}\tmodule...`);
|
|
|
|
const res = m.install();
|
|
|
|
if (res != null) {
|
2019-01-15 03:01:58 +00:00
|
|
|
if (res.mentionHook) this.mentionHooks.push(res.mentionHook);
|
|
|
|
if (res.contextHook) this.contextHooks[m.name] = res.contextHook;
|
2019-01-14 15:14:22 +00:00
|
|
|
}
|
|
|
|
});
|
|
|
|
|
|
|
|
this.log(chalk.green.bold('Ai am now running!'));
|
2018-08-13 21:14:47 +00:00
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
private onMention(msg: MessageLike) {
|
2019-01-15 03:29:11 +00:00
|
|
|
this.log(chalk.gray(`<<< An message received: ${chalk.underline(msg.id)}`));
|
2018-08-11 06:26:25 +00:00
|
|
|
|
2019-01-15 09:34:42 +00:00
|
|
|
const isNoContext = !msg.isMessage && msg.replyId == null;
|
|
|
|
|
|
|
|
// Look up the context
|
|
|
|
const context = isNoContext ? null : this.contexts.findOne(msg.isMessage ? {
|
2018-08-12 14:03:00 +00:00
|
|
|
isMessage: true,
|
|
|
|
userId: msg.userId
|
|
|
|
} : {
|
|
|
|
isMessage: false,
|
|
|
|
noteId: msg.replyId
|
2018-08-11 06:26:25 +00:00
|
|
|
});
|
2018-08-12 14:03:00 +00:00
|
|
|
|
2018-09-18 23:52:06 +00:00
|
|
|
let reaction = 'love';
|
|
|
|
|
2018-08-12 14:03:00 +00:00
|
|
|
if (context != null) {
|
2019-01-15 03:01:58 +00:00
|
|
|
const handler = this.contextHooks[context.module];
|
2019-01-14 15:14:22 +00:00
|
|
|
const res = handler(msg, context.data);
|
2018-09-18 23:52:06 +00:00
|
|
|
|
|
|
|
if (res != null && typeof res === 'object') {
|
|
|
|
reaction = res.reaction;
|
|
|
|
}
|
2018-08-12 14:03:00 +00:00
|
|
|
} else {
|
2019-01-14 15:14:22 +00:00
|
|
|
let res: boolean | HandlerResult;
|
2018-09-18 23:52:06 +00:00
|
|
|
|
2019-01-15 03:01:58 +00:00
|
|
|
this.mentionHooks.some(handler => {
|
2019-01-14 15:14:22 +00:00
|
|
|
res = handler(msg);
|
2018-09-18 23:52:06 +00:00
|
|
|
return res === true || typeof res === 'object';
|
2018-08-12 14:03:00 +00:00
|
|
|
});
|
2018-09-18 23:52:06 +00:00
|
|
|
|
|
|
|
if (res != null && typeof res === 'object') {
|
|
|
|
reaction = res.reaction;
|
|
|
|
}
|
2018-08-12 14:03:00 +00:00
|
|
|
}
|
2018-09-18 23:52:06 +00:00
|
|
|
|
|
|
|
setTimeout(() => {
|
|
|
|
if (msg.isMessage) {
|
|
|
|
// 既読にする
|
|
|
|
this.api('messaging/messages/read', {
|
|
|
|
messageId: msg.id,
|
|
|
|
});
|
|
|
|
} else {
|
|
|
|
// リアクションする
|
2018-12-03 08:20:15 +00:00
|
|
|
if (reaction) {
|
|
|
|
this.api('notes/reactions/create', {
|
|
|
|
noteId: msg.id,
|
|
|
|
reaction: reaction
|
|
|
|
});
|
|
|
|
}
|
2018-09-18 23:52:06 +00:00
|
|
|
}
|
|
|
|
}, 1000);
|
2018-08-11 06:26:25 +00:00
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public async post(param: any) {
|
2018-08-12 14:03:00 +00:00
|
|
|
const res = await this.api('notes/create', param);
|
|
|
|
return res.createdNote;
|
2018-08-11 06:26:25 +00:00
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public sendMessage(userId: any, param: any) {
|
2018-08-12 14:03:00 +00:00
|
|
|
return this.api('messaging/messages/create', Object.assign({
|
2018-08-11 06:26:25 +00:00
|
|
|
userId: userId,
|
|
|
|
}, param));
|
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public api(endpoint: string, param?: any) {
|
2018-08-11 06:26:25 +00:00
|
|
|
return request.post(`${config.apiUrl}/${endpoint}`, {
|
|
|
|
json: Object.assign({
|
|
|
|
i: config.i
|
|
|
|
}, param)
|
|
|
|
});
|
|
|
|
};
|
2018-08-12 14:03:00 +00:00
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public subscribeReply(module: Module, key: string, isMessage: boolean, id: string, data?: any) {
|
2018-08-26 21:16:56 +00:00
|
|
|
this.contexts.insertOne(isMessage ? {
|
2018-08-12 14:03:00 +00:00
|
|
|
isMessage: true,
|
|
|
|
userId: id,
|
|
|
|
module: module.name,
|
|
|
|
key: key,
|
2018-08-26 21:59:18 +00:00
|
|
|
data: data
|
2018-08-12 14:03:00 +00:00
|
|
|
} : {
|
|
|
|
isMessage: false,
|
|
|
|
noteId: id,
|
|
|
|
module: module.name,
|
|
|
|
key: key,
|
2018-08-26 21:59:18 +00:00
|
|
|
data: data
|
2018-08-12 14:03:00 +00:00
|
|
|
});
|
|
|
|
}
|
|
|
|
|
2019-01-14 15:14:22 +00:00
|
|
|
@autobind
|
|
|
|
public unsubscribeReply(module: Module, key: string) {
|
2018-08-26 21:16:56 +00:00
|
|
|
this.contexts.findAndRemove({
|
2018-08-12 14:03:00 +00:00
|
|
|
key: key,
|
|
|
|
module: module.name
|
|
|
|
});
|
|
|
|
}
|
2018-08-11 06:26:25 +00:00
|
|
|
}
|