fix database system (maybe)

This commit is contained in:
Siwoo Jeon 2023-02-08 21:00:37 +09:00
parent 011467782d
commit 12fe84bb2d
Signed by: migan
GPG key ID: C4151385FFD2082A
11 changed files with 97 additions and 131 deletions

View file

@ -5,7 +5,6 @@
"license": "MIT",
"dependencies": {
"discord.js": "^14.7.1",
"dokdo": "^0.6.2",
"dotenv": "^16.0.3",
"mysql2": "^3.1.0"
},
@ -13,6 +12,7 @@
"@migan/prettier-config": "^1.0.0",
"@types/jest": "^29.4.0",
"@types/node": "^18.11.18",
"cross-env": "^7.0.3",
"jest": "^29.4.0",
"prettier": "^2.8.3",
"ts-jest": "^29.0.5",
@ -22,8 +22,8 @@
},
"scripts": {
"build": "tsup",
"dev": "ts-node src",
"start": "node dist",
"dev": "cross-env NODE_ENV=development ts-node src",
"start": "cross-env NODE_ENV=production node dist",
"test": "jest"
},
"prettier": "@migan/prettier-config"

View file

@ -5,8 +5,7 @@ import {
GatewayIntentBits,
TextChannel,
} from 'discord.js'
import { Command, noPerm, ChatBot } from './modules'
import Dokdo from 'dokdo'
import { Command, noPerm, ChatBot, NODE_ENV } from './modules'
import { readdirSync } from 'node:fs'
import { join } from 'node:path'
import 'dotenv/config'
@ -27,12 +26,14 @@ export default class MuffinAI extends Client {
}
public override login(): Promise<string> {
if (NODE_ENV === 'development') this.on('debug', console.info)
this.chatBot.train(this)
readdirSync(join(__dirname, 'Commands')).forEach(file => {
const a = require(join(__dirname, 'Commands', file))
const b: Command = new a.default()
this.#modules.set(b.name, b)
if (NODE_ENV === 'development') console.log(b.name)
})
this.once('ready', () => {
@ -43,17 +44,15 @@ export default class MuffinAI extends Client {
console.log(`먹힐 준비 완료`)
}).on('messageCreate', async msg => {
if (msg.author.bot) return
await new Dokdo(this, {
prefix,
noPerm,
aliases: ['테스트'],
owners: ['415135882006495242'],
}).run(msg)
if (msg.content.startsWith('머핀아 ')) {
if (msg.channel instanceof TextChannel) {
if (msg.channel.nsfw) return
await msg.channel.sendTyping()
await msg.channel.send(await this.chatBot.getResponse(msg))
this.chatBot //
.getResponse(msg)
.then(response => {
msg.channel.send(response)
})
}
} else if (msg.content.startsWith(prefix)) {
if (msg.channel instanceof TextChannel) if (msg.channel.nsfw) return
@ -61,12 +60,13 @@ export default class MuffinAI extends Client {
const args: string[] = msg.content
.slice(prefix.length)
.trim()
.split('/ +/g')
const command = this.#modules.get(args.toString())
.split(/ +/g)
if (NODE_ENV === 'development') console.log(args)
const command = this.#modules.get(args.shift()!.toLowerCase())
if (!command) return
if (command.noPerm && msg.author.id !== '415135882006495242')
return await noPerm(msg)
command.execute(msg, args)
}
})
@ -75,7 +75,6 @@ export default class MuffinAI extends Client {
public override destroy() {
super.destroy()
process.exit()
}
}

20
src/Commands/테스트.ts Normal file
View file

@ -0,0 +1,20 @@
import { Command } from '../modules'
import { Message } from 'discord.js'
import { inspect } from 'node:util'
export default class extends Command {
public constructor() {
super('테스트', true)
}
public async execute(msg: Message, args: string[]) {
if (!args) return msg.channel.send('전달받은 인자가 없습니다.')
try {
const a = eval(args.join(' '))
if (inspect(a) === `'${msg.client.token}'`)
return msg.channel.send('[discord_token]')
await msg.channel.send(`\`\`\`js\n${inspect(a)}\n\`\`\``)
} catch (err) {
await msg.channel.send(`\`\`\`js\n${err}\n\`\`\``)
}
}
}

View file

@ -7,9 +7,9 @@ export default class extends Command {
}
public async execute(msg: Message, args: string[]) {
const conn = await database.getConnection()
const [rows] = await conn.query('SELECT * FROM statement;')
const [rows] = await conn.query<ResponseData[]>('SELECT * FROM statement;')
const muffin: ResponseData[] = []
;(rows as ResponseData[]).forEach(row => {
rows.forEach(row => {
if (row.persona === 'muffin') muffin.push(row)
else return
})

View file

@ -1,42 +1,41 @@
import type { Client, Message } from 'discord.js'
import database, { ResponseData } from './Database'
import database, { ResponseData } from './database'
export default class ChatBot {
public async getResponse(msg: Message): Promise<string> {
const conn = await database.getConnection()
const request = msg.content.replace('머핀아 ', '')
console.log(`⌨️ㅣ${request}`)
const [rows] = await conn.query('SELECT * FROM statement;')
let response = (rows as ResponseData[])[
Math.floor(Math.random() * (rows as ResponseData[]).length)
].text
console.log(`req: ${request}`)
const [rows] = await conn.query<ResponseData[]>('SELECT * FROM statement;')
let response = rows[Math.floor(Math.random() * rows.length)].text
if (!response) response = '살ㄹ려주세요'
console.log(`🍰ㅣ${response}`)
console.log(`res: ${response}`)
conn.release()
return response
}
public async train(client: Client): Promise<ChatBot> {
public train(client: Client): ChatBot {
client.on('messageCreate', async msg => {
const conn = await database.getConnection()
if (msg.author.bot) return
if (msg.author.id !== '1026185545837191238') return
const response = this.getResponse(msg)
const result = await conn.query('SELECT * FROM statement;')
const rows = result[0] as ResponseData[]
await conn.beginTransaction()
try {
await conn.execute(
`INSERT INTO statement(id, text, persona, in_response_to) VALUES(?, ?, ?, ?);`,
[++rows[rows.length - 1].id, msg.content, 'muffin', response]
const conn = await database.getConnection()
if (msg.author.id === '1026185545837191238') {
const response = await this.getResponse(msg)
const [rows] = await conn.query<ResponseData[]>(
'SELECT * FROM statement;'
)
await conn.commit()
} catch (err) {
console.log(err)
await conn.rollback()
} finally {
conn.release()
try {
await conn.beginTransaction()
await conn.execute(
'INSERT INTO statement (id, text, persona, in_response_to) VALUES (?, ?, ?, ?);',
[++rows[rows.length - 1].id, msg.content, 'muffin', response]
)
await conn.commit()
} catch (err) {
console.log(err)
await conn.rollback()
} finally {
conn.release()
}
}
})
return this

View file

@ -1,7 +1,7 @@
import { createPool } from 'mysql2/promise'
import { PoolOptions, createPool, RowDataPacket } from 'mysql2/promise'
import 'dotenv/config'
export interface ResponseData {
export interface ResponseData extends RowDataPacket {
id: number
text: string
search_text: string
@ -12,10 +12,13 @@ export interface ResponseData {
persona: string
}
export default createPool({
export const config: PoolOptions = {
host: process.env.MYSQL_HOST,
user: process.env.MYSQL_USER,
password: process.env.MYSQL_PASSWORD,
database: process.env.MYSQL_DATABASE,
port: (process.env.MYSQL_PORT as unknown as number) || 3306,
})
enableKeepAlive: true,
}
export default createPool(config)

5
src/modules/env.ts Normal file
View file

@ -0,0 +1,5 @@
type NODE_ENV_TYPE = 'production' | 'development' | string
export const NODE_ENV: NODE_ENV_TYPE = process.env.NODE_ENV
? process.env.NODE_ENV
: 'production'

View file

@ -1,5 +1,6 @@
import ChatBot from './ChatBot'
import Command from './Command'
import database, { ResponseData } from './Database'
import database, { ResponseData, config } from './database'
import noPerm from './noPerm'
export { ChatBot, Command, database, noPerm, ResponseData }
import { NODE_ENV } from './env'
export { ChatBot, Command, database, noPerm, ResponseData, config, NODE_ENV }

View file

@ -1,49 +0,0 @@
/*
import Database from '../src/modules/Database'
import sqlite3 from 'sqlite3'
describe('Test Database', () => {
const DBPATH = `${__dirname}/../db/db.sqlite3`
const db = new sqlite3.Database(DBPATH)
const getData = () => {
return new Promise((resolve, reject) => {
db.all('SELECT * FROM statement;', async (err, rows) => {
if (err) reject(err)
resolve(rows)
}).close()
})
}
test('Get rows', () => {
getData().then(async rows =>
expect(await new Database(DBPATH).all()).toEqual(rows)
)
})
test('Insert row', () => {
const db = new Database(DBPATH)
return db.all().then(async data1 => {
db.run(
'INSERT INTO statement(id, text) VALUES(?, ?)',
[++data1[data1.length - 1].id, 'TEST'],
err => {
if (err) throw err
}
)
const data2 = await db.all()
expect(data1[data1.length - 1]).not.toEqual(data2[data2.length - 1])
})
})
test('Delete row', () => {
const db = new Database(DBPATH)
return db.all().then(async data1 => {
db.run('DELETE FROM statement WHERE text=?;', ['TEST'], err => {
if (err) throw err
})
const data2 = await db.all()
expect(data1[data1.length - 1]).not.toEqual(data2[data2.length - 1])
})
})
})
*/

13
tests/database.test.ts Normal file
View file

@ -0,0 +1,13 @@
import { database, config } from '../src/modules'
import { createConnection } from 'mysql2/promise'
describe('test database system', () => {
test('Validate rows', async () => {
return database.getConnection().then(async conn1 => {
const [rows1] = await conn1.query('SELECT * FROM statement;')
const conn2 = await createConnection(config)
const [rows2] = await conn2.query(`SELECT * FROM statement;`)
expect(rows1).toEqual(rows2)
})
})
})

View file

@ -1135,7 +1135,14 @@ create-require@^1.1.0:
resolved "https://registry.yarnpkg.com/create-require/-/create-require-1.1.1.tgz#c1d7e8f1e5f6cfc9ff65f9cd352d37348756c333"
integrity sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==
cross-spawn@^7.0.3:
cross-env@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-env/-/cross-env-7.0.3.tgz#865264b29677dc015ba8418918965dd232fc54cf"
integrity sha512-+/HKd6EgcQCJGh2PSjZuUitQBQynKor4wrFbRg4DtAgS1aWO+gU52xpH7M9ScGgXSYmAVS9bIJ8EzuaGw0oNAw==
dependencies:
cross-spawn "^7.0.1"
cross-spawn@^7.0.1, cross-spawn@^7.0.3:
version "7.0.3"
resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6"
integrity sha512-iRDPJKUPVEND7dHPO8rkbOnPpyDygcDFtWjpeWNCgy8WP2rXcxXL8TskReQl6OrB2G7+UJrags1q15Fudc7G6w==
@ -1211,13 +1218,6 @@ discord.js@^14.7.1:
undici "^5.13.0"
ws "^8.11.0"
dokdo@^0.6.2:
version "0.6.2"
resolved "https://registry.yarnpkg.com/dokdo/-/dokdo-0.6.2.tgz#1e276999f9230f0df54f561992f33a79044d31dc"
integrity sha512-o0m3SSFok+OOvX+Oh8hD17Gx4K/AXSeIv7nZtLPmjkUWDzXO4d4mgQK1s82PDy/QOkDEipV9mm5x8gUNoYHRqA==
dependencies:
node-fetch "^2.6.1"
dotenv@^16.0.3:
version "16.0.3"
resolved "https://registry.yarnpkg.com/dotenv/-/dotenv-16.0.3.tgz#115aec42bac5053db3c456db30cc243a5a836a07"
@ -2311,13 +2311,6 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
node-fetch@^2.6.1:
version "2.6.8"
resolved "https://registry.yarnpkg.com/node-fetch/-/node-fetch-2.6.8.tgz#a68d30b162bc1d8fd71a367e81b997e1f4d4937e"
integrity sha512-RZ6dBYuj8dRSfxpUSu+NsdF1dpPpluJxwOp+6IoDp/sH2QNDSvurYsAa+F1WxY2RjA1iP93xhcsUoYbF2XBqVg==
dependencies:
whatwg-url "^5.0.0"
node-int64@^0.4.0:
version "0.4.0"
resolved "https://registry.yarnpkg.com/node-int64/-/node-int64-0.4.0.tgz#87a9065cdb355d3182d8f94ce11188b825c68a3b"
@ -2808,11 +2801,6 @@ tr46@^1.0.1:
dependencies:
punycode "^2.1.0"
tr46@~0.0.3:
version "0.0.3"
resolved "https://registry.yarnpkg.com/tr46/-/tr46-0.0.3.tgz#8184fd347dac9cdc185992f3a6622e14b9d9ab6a"
integrity sha512-N3WMsuqV66lT30CrXNbEjx4GEwlow3v6rr4mCcv6prnfwhS01rkgyFdjPNBYd9br7LpXV1+Emh01fHnq2Gdgrw==
tree-kill@^1.2.2:
version "1.2.2"
resolved "https://registry.yarnpkg.com/tree-kill/-/tree-kill-1.2.2.tgz#4ca09a9092c88b73a7cdc5e8a01b507b0790a0cc"
@ -2942,24 +2930,11 @@ walker@^1.0.8:
dependencies:
makeerror "1.0.12"
webidl-conversions@^3.0.0:
version "3.0.1"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-3.0.1.tgz#24534275e2a7bc6be7bc86611cc16ae0a5654871"
integrity sha512-2JAn3z8AR6rjK8Sm8orRC0h/bcl/DqL7tRPdGZ4I1CjdF+EaMLmYxBHyXuKL849eucPFhvBoxMsflfOb8kxaeQ==
webidl-conversions@^4.0.2:
version "4.0.2"
resolved "https://registry.yarnpkg.com/webidl-conversions/-/webidl-conversions-4.0.2.tgz#a855980b1f0b6b359ba1d5d9fb39ae941faa63ad"
integrity sha512-YQ+BmxuTgd6UXZW3+ICGfyqRyHXVlD5GtQr5+qjiNW7bF0cqrzX500HVXPBOvgXb5YnzDd+h0zqyv61KUD7+Sg==
whatwg-url@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-5.0.0.tgz#966454e8765462e37644d3626f6742ce8b70965d"
integrity sha512-saE57nupxk6v3HY35+jzBwYa0rKSy0XR8JSxZPwgLr7ys0IBzhGviA1/TUGJLmSVqs8pb9AnvICXEuOHLprYTw==
dependencies:
tr46 "~0.0.3"
webidl-conversions "^3.0.0"
whatwg-url@^7.0.0:
version "7.1.0"
resolved "https://registry.yarnpkg.com/whatwg-url/-/whatwg-url-7.1.0.tgz#c2c492f1eca612988efd3d2266be1b9fc6170d06"