Как исправить повторную регистрацию пользователя в игровом боте ВКонтакте на 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 при загрузке, чтобы при повреждении файла бот не упал.

    После внесения этих изменений бот перестанет дублировать пользователей при перезапуске. Данные будут сохраняться в файле и корректно загружаться при старте.

    Часто задаваемые вопросы