リファクタリングなど

This commit is contained in:
syuilo 2018-08-11 02:28:31 +09:00
parent e6a0a5dcf4
commit 569036db73
6 changed files with 330 additions and 238 deletions

5
package-lock.json generated
View file

@ -359,6 +359,11 @@
"resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz",
"integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA=="
},
"reconnecting-websocket": {
"version": "4.0.0-rc5",
"resolved": "https://registry.npmjs.org/reconnecting-websocket/-/reconnecting-websocket-4.0.0-rc5.tgz",
"integrity": "sha512-ew+Twq9j66vhRtW9mT0xIgkLCQsDpslAideVYuB1JjW4U9wm27XZfA786K6pCKcUFkDWmktL+uI92ITLdn2eOQ=="
},
"request": {
"version": "2.87.0",
"resolved": "https://registry.npmjs.org/request/-/request-2.87.0.tgz",

View file

@ -8,6 +8,7 @@
"@types/node": "10.0.5",
"@types/ws": "5.1.2",
"misskey-reversi": "0.0.5",
"reconnecting-websocket": "4.0.0-rc5",
"request": "2.87.0",
"request-promise-native": "1.0.5",
"ts-node": "6.0.3",

View file

@ -1,237 +0,0 @@
/**
* -AI-
* Botのフロントエンド()
*
*
*
*/
import * as childProcess from 'child_process';
import * as WebSocket from 'ws';
import * as request from 'request-promise-native';
const config = require('../config.json');
const wsUrl = config.host.replace('http', 'ws');
const apiUrl = config.host + '/api';
/**
*
*/
const homeStream = new WebSocket(`${wsUrl}/?i=${config.i}`);
homeStream.addEventListener('open', () => {
console.log('home stream opened');
});
homeStream.addEventListener('close', () => {
console.log('home stream closed');
process.exit(1);
});
homeStream.addEventListener('message', message => {
const msg = JSON.parse(message.data);
// タイムライン上でなんか言われたまたは返信されたとき
if (msg.type == 'mention' || msg.type == 'reply') {
const note = msg.body;
if (note.userId == config.id) return;
// リアクションする
setTimeout(() => {
request.post(`${apiUrl}/notes/reactions/create`, {
json: {
i: config.i,
noteId: note.id,
reaction: 'love'
}
});
}, 2000);
if (note.text && note.text.indexOf('リバーシ') > -1) {
setTimeout(() => {
request.post(`${apiUrl}/notes/create`, {
json: {
i: config.i,
replyId: note.id,
text: '良いですよ~'
}
});
invite(note.userId);
}, 3000);
}
}
// メッセージでなんか言われたとき
if (msg.type == 'messaging_message') {
const message = msg.body;
if (message.text) {
if (message.text.indexOf('リバーシ') > -1) {
request.post(`${apiUrl}/messaging/messages/create`, {
json: {
i: config.i,
userId: message.userId,
text: '良いですよ~'
}
});
invite(message.userId);
}
}
}
});
// ユーザーを対局に誘う
function invite(userId) {
request.post(`${apiUrl}/games/reversi/match`, {
json: {
i: config.i,
userId: userId
}
});
}
/**
*
*/
const reversiStream = new WebSocket(`${wsUrl}/games/reversi?i=${config.i}`);
reversiStream.addEventListener('open', () => {
console.log('reversi stream opened');
});
reversiStream.addEventListener('close', () => {
console.log('reversi stream closed');
});
reversiStream.addEventListener('message', message => {
const msg = JSON.parse(message.data);
// 招待されたとき
if (msg.type == 'invited') {
onInviteMe(msg.body.parent);
}
// マッチしたとき
if (msg.type == 'matched') {
gameStart(msg.body);
}
});
/**
*
* @param game
*/
function gameStart(game) {
// ゲームストリームに接続
const gw = new WebSocket(`${wsUrl}/games/reversi-game?i=${config.i}&game=${game.id}`);
function send(msg) {
try {
gw.send(JSON.stringify(msg));
} catch (e) {
console.error(e);
}
}
gw.addEventListener('open', () => {
console.log('reversi game stream opened');
// フォーム
const form = [{
id: 'publish',
type: 'switch',
label: '藍が対局情報を投稿するのを許可',
value: true
}, {
id: 'strength',
type: 'radio',
label: '強さ',
value: 3,
items: [{
label: '接待',
value: 0
}, {
label: '弱',
value: 2
}, {
label: '中',
value: 3
}, {
label: '強',
value: 4
}, {
label: '最強',
value: 5
}]
}];
//#region バックエンドプロセス開始
const ai = childProcess.fork(__dirname + '/back.js');
// バックエンドプロセスに情報を渡す
ai.send({
type: '_init_',
game,
form
});
ai.on('message', msg => {
if (msg.type == 'put') {
send({
type: 'set',
pos: msg.pos
});
} else if (msg.type == 'close') {
gw.close();
}
});
// ゲームストリームから情報が流れてきたらそのままバックエンドプロセスに伝える
gw.addEventListener('message', message => {
const msg = JSON.parse(message.data);
ai.send(msg);
});
//#endregion
// フォーム初期化
setTimeout(() => {
send({
type: 'init-form',
body: form
});
}, 1000);
// どんな設定内容の対局でも受け入れる
setTimeout(() => {
send({
type: 'accept'
});
}, 2000);
});
gw.addEventListener('close', () => {
console.log('reversi game stream closed');
});
}
/**
*
* @param inviter
*/
async function onInviteMe(inviter) {
console.log(`Someone invited me: @${inviter.username}`);
// 承認
const game = await request.post(`${apiUrl}/games/reversi/match`, {
json: {
i: config.i,
userId: inviter.id
}
});
gameStart(game);
}

319
src/index.ts Normal file
View file

@ -0,0 +1,319 @@
import * as childProcess from 'child_process';
import * as WebSocket from 'ws';
import * as request from 'request-promise-native';
const ReconnectingWebSocket = require('../node_modules/reconnecting-websocket/dist/reconnecting-websocket-cjs.js');
import serifs from './serifs';
const config = require('../config.json');
const wsUrl = config.host.replace('http', 'ws');
const apiUrl = config.host + '/api';
class MessageLike {
private ai: ;
private messageOrNote: any;
public isMessage: boolean;
public get id() {
return this.messageOrNote.id;
}
public get userId() {
return this.messageOrNote.userId;
}
public get text() {
return this.messageOrNote.text;
}
constructor(ai: , messageOrNote: any, isMessage: boolean) {
this.ai = ai;
this.messageOrNote = messageOrNote;
this.isMessage = isMessage;
}
public reply = (text: string) => {
setTimeout(() => {
if (this.isMessage) {
this.ai.sendMessage(this.messageOrNote.userId, {
text: text
});
} else {
this.ai.post({
replyId: this.messageOrNote.id,
text: text
});
}
}, 2000);
}
}
/**
*
*/
class {
/**
*
*/
private connection: any;
/**
*
*/
private reversiConnection?: any;
constructor() {
this.connection = new ReconnectingWebSocket(`${wsUrl}/?i=${config.i}`, [], {
WebSocket: WebSocket
});
this.connection.addEventListener('open', () => {
console.log('home stream opened');
});
this.connection.addEventListener('close', () => {
console.log('home stream closed');
});
this.connection.addEventListener('message', message => {
const msg = JSON.parse(message.data);
this.onMessage(msg);
});
if (config.reversiEnabled) {
this.reversiConnection = new ReconnectingWebSocket(`${wsUrl}/games/reversi?i=${config.i}`, [], {
WebSocket: WebSocket
});
this.reversiConnection.addEventListener('open', () => {
console.log('reversi stream opened');
});
this.reversiConnection.addEventListener('close', () => {
console.log('reversi stream closed');
});
this.reversiConnection.addEventListener('message', message => {
const msg = JSON.parse(message.data);
this.onReversiConnectionMessage(msg);
});
}
}
private onMessage = (msg: any) => {
switch (msg.type) {
// メンションされたとき
case 'mention': {
if (msg.body.userId == config.id) return; // 自分は弾く
this.onMention(new MessageLike(this, msg.body, false));
break;
}
// 返信されたとき
case 'reply': {
if (msg.body.userId == config.id) return; // 自分は弾く
this.onMention(new MessageLike(this, msg.body, false));
break;
}
// メッセージ
case 'messaging_message': {
if (msg.body.userId == config.id) return; // 自分は弾く
this.onMention(new MessageLike(this, msg.body, true));
break;
}
default:
break;
}
}
private onReversiConnectionMessage = (msg: any) => {
switch (msg.type) {
// 招待されたとき
case 'invited': {
this.onReversiInviteMe(msg.body.parent);
break;
}
// マッチしたとき
case 'matched': {
this.onReversiGameStart(msg.body);
break;
}
default:
break;
}
}
private onReversiInviteMe = async (inviter: any) => {
console.log(`Someone invited me: @${inviter.username}`);
if (config.reversiEnabled) {
// 承認
const game = await request.post(`${apiUrl}/games/reversi/match`, {
json: {
i: config.i,
userId: inviter.id
}
});
this.onReversiGameStart(game);
} else {
// todo (リバーシできない旨をメッセージで伝えるなど)
}
}
private onReversiGameStart = (game: any) => {
// ゲームストリームに接続
const gw = new ReconnectingWebSocket(`${wsUrl}/games/reversi-game?i=${config.i}&game=${game.id}`, [], {
WebSocket: WebSocket
});
function send(msg) {
try {
gw.send(JSON.stringify(msg));
} catch (e) {
console.error(e);
}
}
gw.addEventListener('open', () => {
console.log('reversi game stream opened');
// フォーム
const form = [{
id: 'publish',
type: 'switch',
label: '藍が対局情報を投稿するのを許可',
value: true
}, {
id: 'strength',
type: 'radio',
label: '強さ',
value: 3,
items: [{
label: '接待',
value: 0
}, {
label: '弱',
value: 2
}, {
label: '中',
value: 3
}, {
label: '強',
value: 4
}, {
label: '最強',
value: 5
}]
}];
//#region バックエンドプロセス開始
const ai = childProcess.fork(__dirname + '/back.js');
// バックエンドプロセスに情報を渡す
ai.send({
type: '_init_',
game,
form
});
ai.on('message', msg => {
if (msg.type == 'put') {
send({
type: 'set',
pos: msg.pos
});
} else if (msg.type == 'close') {
gw.close();
}
});
// ゲームストリームから情報が流れてきたらそのままバックエンドプロセスに伝える
gw.addEventListener('message', message => {
const msg = JSON.parse(message.data);
ai.send(msg);
});
//#endregion
// フォーム初期化
setTimeout(() => {
send({
type: 'init-form',
body: form
});
}, 1000);
// どんな設定内容の対局でも受け入れる
setTimeout(() => {
send({
type: 'accept'
});
}, 2000);
});
gw.addEventListener('close', () => {
console.log('reversi game stream closed');
});
}
private onMention = (x: MessageLike) => {
// リアクションする
if (!x.isMessage) {
setTimeout(() => {
request.post(`${apiUrl}/notes/reactions/create`, {
json: {
i: config.i,
noteId: x.id,
reaction: 'love'
}
});
}, 1000);
}
if (x.text && x.text.indexOf('リバーシ') > -1) {
if (config.reversiEnabled) {
x.reply(serifs.REVERSI_OK);
request.post(`${apiUrl}/games/reversi/match`, {
json: {
i: config.i,
userId: x.userId
}
});
} else {
x.reply(serifs.REVERSI_DECLINE);
}
}
}
public post = (param: any) => {
setTimeout(() => {
request.post(`${apiUrl}/notes/create`, {
json: Object.assign({
i: config.i
}, param)
});
}, 2000);
}
public sendMessage = (userId: any, param: any) => {
setTimeout(() => {
request.post(`${apiUrl}/messaging/messages/create`, {
json: Object.assign({
i: config.i,
userId: userId,
}, param)
});
}, 2000);
}
}
const ai = new ();

4
src/serifs.ts Normal file
View file

@ -0,0 +1,4 @@
export default {
REVERSI_OK: '良いですよ~',
REVERSI_DECLINE: 'ごめんなさい、今リバーシはするなと言われてます...'
};

View file

@ -7,7 +7,7 @@
"noFallthroughCasesInSwitch": true,
"experimentalDecorators": true,
"sourceMap": false,
"target": "es2017",
"target": "es6",
"module": "commonjs",
"removeComments": false,
"noLib": false,