update and fix
This commit is contained in:
parent
eb437e4fbc
commit
d41932c930
|
@ -0,0 +1,9 @@
|
|||
.idea
|
||||
.git
|
||||
node_modules
|
||||
README.md
|
||||
LICENSE
|
||||
.env.example
|
||||
Dockerfile
|
||||
.dockerignore
|
||||
yarn.lock
|
|
@ -5,4 +5,5 @@ ADMIN_ID = 1652565652
|
|||
# Example ( BOT_CLUSTER_CORE = 2 ) or AutoScale ( BOT_CLUSTER_CORE = 0 )
|
||||
BOT_CLUSTER_CORE = 0
|
||||
# Mongoose databse
|
||||
#MONGOOSE_URL = 'mongodb+srv://secven:[private]@cluster0.myekb.mongodb.net/secven'
|
||||
MONGOOSE_URL = 'mongodb://127.0.0.1/secven'
|
||||
|
|
|
@ -0,0 +1,42 @@
|
|||
FROM node:alpine
|
||||
|
||||
RUN mkdir -p /usr/src/app
|
||||
|
||||
WORKDIR /usr/src/app
|
||||
|
||||
RUN echo -e " \n\
|
||||
fs.file-max = 51200 \n\
|
||||
\n\
|
||||
net.core.rmem_max = 67108864 \n\
|
||||
net.core.wmem_max = 67108864 \n\
|
||||
net.ipv4.ip_forward = 1 \n\
|
||||
net.core.netdev_max_backlog = 250000 \n\
|
||||
net.core.somaxconn = 4096 \n\
|
||||
\n\
|
||||
net.ipv4.tcp_syncookies = 1 \n\
|
||||
net.ipv4.tcp_tw_reuse = 1 \n\
|
||||
net.ipv4.tcp_tw_recycle = 0 \n\
|
||||
net.ipv4.tcp_fin_timeout = 30 \n\
|
||||
net.ipv4.tcp_keepalive_time = 1200 \n\
|
||||
net.ipv4.tcp_max_syn_backlog = 8192 \n\
|
||||
net.ipv4.tcp_max_tw_buckets = 5000 \n\
|
||||
net.ipv4.tcp_fastopen = 3 \n\
|
||||
net.ipv4.tcp_mem = 25600 51200 102400 \n\
|
||||
net.ipv4.tcp_rmem = 4096 87380 67108864 \n\
|
||||
net.ipv4.tcp_wmem = 4096 65536 67108864 \n\
|
||||
net.ipv4.tcp_mtu_probing = 1 \n\
|
||||
net.ipv4.tcp_congestion_control = hybla \n\
|
||||
# for low-latency network, use cubic instead \n\
|
||||
# net.ipv4.tcp_congestion_control = cubic \n\
|
||||
" | sed -e 's/^\s\+//g' | tee -a /etc/sysctl.conf && \
|
||||
mkdir -p /etc/security && \
|
||||
echo -e " \n\
|
||||
* soft nofile 51200 \n\
|
||||
* hard nofile 51200 \n\
|
||||
" | sed -e 's/^\s\+//g' | tee -a /etc/security/limits.conf
|
||||
|
||||
COPY . .
|
||||
|
||||
RUN yarn install
|
||||
|
||||
CMD ["yarn", "prod"]
|
16
README.md
16
README.md
|
@ -1,6 +1,8 @@
|
|||
# Telegraf Bot Pattern
|
||||
## Telegraf Bot Pattern
|
||||
|
||||
### Change .env.example to .env
|
||||
![example](https://i.imgur.com/5lbe3pl.png)
|
||||
|
||||
#### Change .env.example to .env
|
||||
|
||||
> Started init: `yarn install`
|
||||
|
||||
|
@ -8,12 +10,6 @@
|
|||
|
||||
> Mode Cluster: `yarn prod` - In Production bot
|
||||
|
||||
> Mode Production PM2: `yarn pm:prod` `yarn pm:stop` `yarn pm:up` // pm2 startup
|
||||
|
||||
> Example `.env` ( BOT_CLUSTER_CORE = 2 ) or AutoScale ( BOT_CLUSTER_CORE = 0 )
|
||||
|
||||
## Todo
|
||||
|
||||
* _Mongoose_ [Soon]
|
||||
|
||||
* _Encryption Mongoose_ [Soon]
|
||||
|
||||
* _Webhook Cluster_ [Soon]
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
module.exports = {
|
||||
apps: [
|
||||
{
|
||||
name: 'APP-BOT',
|
||||
script: './index.js',
|
||||
max_memory_restart: '1000M',
|
||||
wait_ready: true,
|
||||
restart_delay: 5000,
|
||||
env_production: {
|
||||
NODE_ENV: 'production'
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
|
@ -7,7 +7,10 @@
|
|||
"private": false,
|
||||
"scripts": {
|
||||
"dev": "cross-env NODE_ENV=development nodemon index.js",
|
||||
"prod": "cross-env NODE_ENV=production node index.js"
|
||||
"prod": "cross-env NODE_ENV=production node index.js",
|
||||
"pm:stop": "cross-env NODE_ENV=production pm2 stop ecosystem.config.js",
|
||||
"pm:prod": "cross-env NODE_ENV=production pm2 start ecosystem.config.js",
|
||||
"pm:up": "pm2 startup"
|
||||
},
|
||||
"dependencies": {
|
||||
"chalk": "^4.1.1",
|
||||
|
@ -16,7 +19,7 @@
|
|||
"mongoose": "^5.13.1",
|
||||
"ms": "^2.1.3",
|
||||
"telegraf": "git+https://notabug.org/Secven/telegraf",
|
||||
"telegraf-i18n": "^6.6.0",
|
||||
"telegraf-i18n": "git+https://notabug.org/Secven/telegraf-i18n.git",
|
||||
"telegraf-middleware-console-time": "^2.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
|
|
10
src/app.js
10
src/app.js
|
@ -39,7 +39,7 @@ class App {
|
|||
`****** Creating instances [ ${cS.green.bold(setWorker)} ] ******`
|
||||
)
|
||||
for (let i = 0; i < setWorker; i += 1) {
|
||||
cluster.schedulingPolicy = cluster.SCHED_RR
|
||||
cluster.schedulingPolicy = cluster.SCHED_NONE
|
||||
const worker = cluster.fork()
|
||||
_workers.push(worker)
|
||||
}
|
||||
|
@ -49,9 +49,7 @@ class App {
|
|||
console.log(cS.red.bold(`Worker ${worker.process.pid} died`))
|
||||
})
|
||||
|
||||
process.on('uncaughtException', err => {
|
||||
console.error('Cluster crashed:', err.message)
|
||||
})
|
||||
console.log(cS.green.bold('****** Mode: Started to Production ******'))
|
||||
} else {
|
||||
console.info(cS.blue(`[ Worker to ${process.pid} started ]`))
|
||||
process.on('message', update => {
|
||||
|
@ -61,9 +59,7 @@ class App {
|
|||
|
||||
if (cluster.isMaster) {
|
||||
initTelegraf.use(ctx => handlerUpdater(ctx))
|
||||
const starter = initTelegraf.launch().then(() => {
|
||||
console.log(cS.green.bold('****** Mode: Started to Production ******'))
|
||||
})
|
||||
const starter = initTelegraf.launch()
|
||||
this.killGetUpdates(starter).catch(err => console.error(err.message))
|
||||
}
|
||||
|
||||
|
|
|
@ -10,15 +10,18 @@ config.isDev = process.env.NODE_ENV === 'development'
|
|||
|
||||
config.consignOpts = {
|
||||
cwd: process.cwd() + '/src',
|
||||
extensions: ['.js', '.json'],
|
||||
extensions: ['.js'],
|
||||
verbose: false
|
||||
}
|
||||
|
||||
config.limitSecurity = {
|
||||
window: ms('15s'),
|
||||
limit: 6,
|
||||
onLimitExceeded: async ctx =>
|
||||
await ctx.replyWithHTML('<b>❗️Please wait a second (5s)</b>')
|
||||
onLimitExceeded: ({ message, i18n, replyWithHTML }) =>
|
||||
replyWithHTML(i18n.t('default.rateLimit'), {
|
||||
reply_to_message_id: message.message_id,
|
||||
disable_notification: true
|
||||
})
|
||||
}
|
||||
|
||||
config.i18nOpts = {
|
||||
|
@ -27,6 +30,21 @@ config.i18nOpts = {
|
|||
defaultLanguageOnMissing: true
|
||||
}
|
||||
|
||||
config.settings = {
|
||||
setCommand: async ctx => {
|
||||
ctx.setMyCommands([
|
||||
{
|
||||
command: 'start',
|
||||
description: 'Start bot or restart'
|
||||
},
|
||||
{
|
||||
command: 'lang',
|
||||
description: 'Change language'
|
||||
}
|
||||
])
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = {
|
||||
config,
|
||||
readdirSync,
|
||||
|
|
|
@ -1,16 +1,12 @@
|
|||
const consign = require('consign')
|
||||
const I18n = require('telegraf-i18n')
|
||||
const Telegraf = require('telegraf')
|
||||
const Router = require('telegraf/router')
|
||||
const Markup = require('telegraf/markup')
|
||||
const Extra = require('telegraf/extra')
|
||||
const session = require('telegraf/session')
|
||||
const { Telegraf, Router, Markup, Extra, session } = require('telegraf')
|
||||
const { I18n } = require('telegraf-i18n')
|
||||
const { db } = require('../db/db')
|
||||
const { config } = require('./config')
|
||||
const { rateLimit, reportErr, updaterUser } = require('../middle')
|
||||
const {
|
||||
generateUpdateMiddleware: cliUpdateTime
|
||||
} = require('telegraf-middleware-console-time')
|
||||
const consign = require('consign')
|
||||
|
||||
const bot = new Telegraf(process.env.BOT_TOKEN, {
|
||||
handlerTimeout: 1
|
||||
|
@ -30,6 +26,7 @@ const Route = new Router(({ callbackQuery }) => {
|
|||
;(async () => {
|
||||
if (config.isDev) {
|
||||
console.log(await bot.telegram.getMe())
|
||||
await bot.use(config.settings.setCommand)
|
||||
// Dev handlers
|
||||
bot.use(cliUpdateTime())
|
||||
bot.use(Telegraf.log())
|
||||
|
@ -45,11 +42,23 @@ bot.use(rateLimit(config.limitSecurity))
|
|||
bot.use(session())
|
||||
bot.use(new I18n(config.i18nOpts))
|
||||
bot.use(updaterUser)
|
||||
|
||||
bot.use(reportErr)
|
||||
|
||||
bot.on('callback_query', Route)
|
||||
|
||||
consign(config.consignOpts).include('handlers').then('route').into(bot)
|
||||
|
||||
bot.use(({ reply, i18n, message }) =>
|
||||
reply(
|
||||
i18n.t('default.noAnswer'),
|
||||
Extra.HTML()
|
||||
.inReplyTo(message.message_id)
|
||||
.markup(m =>
|
||||
m.inlineKeyboard([
|
||||
m.callbackButton(i18n.t('default.closeMessage'), 'delete')
|
||||
])
|
||||
)
|
||||
)
|
||||
)
|
||||
|
||||
module.exports = { bot }
|
||||
|
|
10
src/db/db.js
10
src/db/db.js
|
@ -8,4 +8,14 @@ Object.keys(__MODELS__).forEach(model => {
|
|||
return (db[model.toString()] = __MODELS__[model.toString()])
|
||||
})
|
||||
|
||||
/*
|
||||
readdirSync(path.resolve(__dirname, MODEL_PATTERN)).forEach(model => {
|
||||
const setModels = model.split('.')[0].toString().trim().match(DEFAULT_CHECK)
|
||||
if (!setModels)
|
||||
throw new Error(`Error: secure loaded ${MODEL_PATTERN}${model.trim()}`)
|
||||
// eslint-disable-next-line security/detect-non-literal-require
|
||||
db[setModels.toString()] = require(MODEL_PATTERN + setModels)
|
||||
})
|
||||
*/
|
||||
|
||||
module.exports = { db }
|
||||
|
|
|
@ -1,4 +1,5 @@
|
|||
const mongoose = require('mongoose')
|
||||
const { cS } = require('../config/config')
|
||||
|
||||
class Mongoose {
|
||||
async mongooseConnect() {
|
||||
|
@ -12,7 +13,13 @@ class Mongoose {
|
|||
connectTimeoutMS: 30000
|
||||
})
|
||||
|
||||
.catch(err => console.error(err.stack))
|
||||
.catch(err => {
|
||||
console.error(err.stack)
|
||||
console.error(
|
||||
cS.red.bold(`Mongoose error: ${process.env.MONGOOSE_URL}`)
|
||||
)
|
||||
process.exit(0)
|
||||
})
|
||||
|
||||
process.on('SIGINT', () => {
|
||||
mongoose.connection.close(() => {
|
||||
|
|
|
@ -19,10 +19,12 @@ stackError:
|
|||
default:
|
||||
lang: |
|
||||
🤖 Language settings
|
||||
├ 🇺🇸 English
|
||||
└ 🇷🇺 Русский
|
||||
|
||||
├ 🇺🇸 English (en)
|
||||
└ 🇷🇺 Русский (ru)
|
||||
langDone: |
|
||||
✅ Language changed successfully (${value})
|
||||
noAnswer: 🤨 I do not understand you
|
||||
closeMessage: ❌ Close
|
||||
rateLimit: <b>❗️Please wait a second (5s)</b>
|
||||
|
||||
|
||||
|
|
|
@ -19,8 +19,10 @@ stackError:
|
|||
default:
|
||||
lang: |
|
||||
🤖 Языковые настройки
|
||||
├ 🇺🇸 English
|
||||
└ 🇷🇺 Русский
|
||||
|
||||
├ 🇺🇸 English (en)
|
||||
└ 🇷🇺 Русский (ru)
|
||||
langDone: |
|
||||
✅ Язык успешно изменен (${value})
|
||||
noAnswer: 🤨 Я не понимаю тебя
|
||||
closeMessage: ❌ Закрыть
|
||||
rateLimit: <b>❗️Пожалуйста, подождите секунд (5s)</b>
|
||||
|
|
|
@ -1,29 +1,29 @@
|
|||
const { escapeHtml } = require('../util/escapeHTML')
|
||||
|
||||
module.exports = async (ctx, next) => {
|
||||
if (!ctx.from.id) return await next()
|
||||
module.exports = async ({ db, from, i18n, session }, next) => {
|
||||
// eslint-disable-next-line camelcase
|
||||
const { id, first_name, username, language_code } = ctx.from
|
||||
await ctx.db.User.findOne({ user_id: ctx.from.id })
|
||||
const { id, first_name, username, language_code } = from
|
||||
if (!id) return await next()
|
||||
await db.User.findOne({ user_id: id })
|
||||
.then(root => {
|
||||
if (!root) {
|
||||
root = new ctx.db.User()
|
||||
root = new db.User()
|
||||
root.user_id = id
|
||||
// eslint-disable-next-line camelcase
|
||||
root.first_name = escapeHtml(first_name) ?? 'Unknown'
|
||||
root.username = username ?? 'Unknown'
|
||||
}
|
||||
// eslint-disable-next-line camelcase
|
||||
root.first_name = first_name
|
||||
root.first_name = escapeHtml(first_name) ?? 'Unknown'
|
||||
root.username = username
|
||||
// eslint-disable-next-line camelcase
|
||||
root.language_code = language_code
|
||||
ctx.session.root = root
|
||||
ctx.i18n.locale(ctx.session.root.settings.lang)
|
||||
session.root = root
|
||||
i18n.locale(session.root.settings.lang)
|
||||
})
|
||||
.finally(() => {
|
||||
return next().then(async () => {
|
||||
await ctx.session.root.save()
|
||||
await session.root.save()
|
||||
})
|
||||
})
|
||||
.catch(err => console.log(err.message))
|
||||
|
|
|
@ -0,0 +1,5 @@
|
|||
const DEFAULT_CHECK = /^[a-zA-Z0-9.\-_]{3,20}$/gi
|
||||
|
||||
module.exports = {
|
||||
DEFAULT_CHECK
|
||||
}
|
Loading…
Reference in New Issue