Как исправить повторную регистрацию пользователя в игровом боте ВКонтакте на Node.js
При создании игрового бота для ВКонтакте на Node.js с библиотеками vk-io и @vk-io/hear часто возникает проблема: после перезапуска сервера все пользователи регистрируются заново. Это происходит, потому что данные хранятся только в оперативной памяти (массив users), а не в файле или базе данных. Разберём решение шаг за шагом.
Почему возникает дублирование записей?
В исходном коде массив users объявляется пустым при каждом запуске бота. Функция Save() записывает данные в файл users.json, но при старте бота этот файл не читается. В результате после перезапуска бот не знает о существующих пользователях и добавляет их снова при первом же сообщении.
Как правильно загружать пользователей из файла?
Необходимо при старте бота загружать сохранённые данные из users.json обратно в массив. Для этого используйте fs.readFileSync или асинхронный fs.readFile перед запуском прослушивания обновлений.
Пример загрузки данных при старте
const fs = require('fs');
let users = [];
try {
const data = fs.readFileSync('./database/users.json', 'utf8');
users = JSON.parse(data);
console.log(`Загружено пользователей: ${users.length}`);
} catch (err) {
console.log('Файл не найден, создаём новый');
}Этот код необходимо разместить до вызова updates.start(). Если файл существует, массив заполняется сохранёнными объектами. Если файла нет (первый запуск), создаётся пустой массив.
Оптимизация функции сохранения
В текущей версии Save() запускает setInterval с записью каждую секунду. Это избыточно и может снижать производительность. Лучше записывать данные только при изменении - например, сразу после добавления нового пользователя.
Улучшенная версия сохранения
function saveUsers() {
fs.writeFileSync('./database/users.json', JSON.stringify(users, null, 4));
console.log(`Пользователей в БД: ${users.length}`);
}Вызывайте saveUsers() только внутри блока if(!user) после users.push(...). Так запись будет происходить только при реальной регистрации, а не каждую секунду.
Полный исправленный код регистрации
Объединим все изменения. Ниже приведён фрагмент, который заменяет проблемную часть вашего бота.
const { VK, Keyboard } = require('vk-io');
const fs = require('fs');
// Загружаем пользователей из файла при старте
let users = [];
try {
const data = fs.readFileSync('./database/users.json', 'utf8');
users = JSON.parse(data);
console.log(`Загружено пользователей: ${users.length}`);
} catch (err) {
console.log('Файл не найден, создаём новый');
}
function saveUsers() {
fs.writeFileSync('./database/users.json', JSON.stringify(users, null, 4));
}
const vk = new VK({ token: 'MY_GROUP_TOKEN' });
const { updates } = vk;
updates.on('message_new', async (bot) => {
const user = users.find(u => u.id === bot.senderId);
const info = await vk.api.users.get({ user_ids: bot.senderId });
if (!user) {
users.push({
id: bot.senderId,
name: info[0].first_name,
balance: 5000,
ban: false,
admin: 0,
regDate: `${new Date().toLocaleDateString()} : ${new Date().toLocaleTimeString()}`
});
saveUsers();
bot.reply(`✅ ${info[0].first_name}, вы успешно зарегистрировались!`);
} else {
bot.reply(`${info[0].first_name}, добро пожаловать в Diamond Game Bot.`, {
keyboard: Keyboard.builder()
.textButton({ label: 'Профиль', color: Keyboard.POSITIVE_COLOR }).inline()
.textButton({ label: 'Помощь', color: Keyboard.POSITIVE_COLOR }).inline()
.urlButton({ label: 'Поддержка', url: 'https://vk.com/support' })
});
}
});
updates.start().then(() => console.log('Бот запущен!'));Дополнительные рекомендации
- Используйте асинхронное чтение/запись для больших файлов -
fs.promises.readFile/writeFile. - Рассмотрите переход на СУБД (SQLite, MongoDB) - это надёжнее для многопользовательских проектов.
- Добавьте проверку валидности JSON при загрузке, чтобы при повреждении файла бот не упал.
После внесения этих изменений бот перестанет дублировать пользователей при перезапуске. Данные будут сохраняться в файле и корректно загружаться при старте.