Node JS app works perfectly locally, but not on the server

I have this code for the backend of a MQTT app

require('dotenv').config();
const express = require('express');
const cors = require('cors');
const mysql = require('mysql2/promise');
const mqtt = require('mqtt');

const topicsConfig = {
  'Topic1': 'Table1',
  'Topic2': 'Table2',
  'Topic3': 'Table3',
  'Topic4': 'Table4',
  'Topic5': 'Table5',
};

// Assuming this is at the top level of your index.js
let statsPerTopic = Object.keys(topicsConfig).reduce((acc, topic) => {
  acc[topic] = {
    messageCount: 0,
    dbInsertCount: 0,
    lastInsertTime: Date.now(),
  };
  return acc;
}, {});

// Define the MQTT broker options
const options = {
  port: process.env.MQTT_PORT,
  username: process.env.MQTT_USERNAME,
  password: process.env.MQTT_PASSWORD,
  clientId: `mqttjs_${Math.random().toString(16).substr(2, 8)}`,
  protocol: 'wss',
};

// Connect to the MQTT broker
const client = mqtt.connect(process.env.MQTT_BROKER, options);

client.on('connect', function () {
  console.log('Connected to the MQTT broker');

  Object.keys(topicsConfig).forEach((topic) => {
    client.subscribe(topic, function (err) {
      if (!err) {
        console.log(`Successfully subscribed to ${topic}`);
      } else {
        console.error(`Failed to subscribe to ${topic}:`, err);
      }
    });
  });
});

// Latest message storage
let lastMessages = {};

// Function to insert data into the database using a new connection pool
async function insertData(topic, message) {
  const table = topicsConfig[topic];

  if (topic === 'ICR2431/Ch0') {
    // Handle the new format (ICR2431/Ch0) in a separate function
    await handleNewFormatData(message, table);
  } else {
    // Existing logic for handling the old format messages
    const data = JSON.parse(message.toString());
    let sql = `INSERT INTO `${table}` SET ?`;
    let dataObj = { Topic: topic };

    // Filter out values starting with "OFFSET_"
    data.d.forEach((item) => {
      if (!item.tag.startsWith('OFFSET_')) {
        dataObj[item.tag] = item.value;
      }
    });

    dataObj.timestamp = new Date(data.ts)
      .toISOString()
      .slice(0, 19)
      .replace('T', ' ');

    try {
      const pool = mysql.createPool({
        host: process.env.DB_HOST,
        user: process.env.DB_USER,
        password: process.env.DB_PASSWORD,
        database: process.env.DB_NAME,
        waitForConnections: true,
        connectionLimit: 10,
        queueLimit: 0,
      });
      const connection = await pool.getConnection();
      await connection.query(sql, dataObj);
      console.log('Data successfully inserted into the database (old format)');
      connection.release();
    } catch (error) {
      console.error(
        'Failed to insert data into the database (old format):',
        error
      );
    }
  }
}

// Function to handle the new JSON format (ICR2431/Ch0)
async function handleNewFormatData(message, table) {
  try {
    const data = JSON.parse(message.toString());
    let timestamp;

    if (data.hasOwnProperty('ts')) {
      // Existing format with timezone (ts: "2024-04-19T00:24:39+0300")
      timestamp = data.ts;
    } else if (data.hasOwnProperty('time')) {
      // New format without timezone (time: "2024-04-19 00:23:58.031")
      // Parse the string and adjust based on your needs
      const timeParts = data.time.split(' ');
      const dateString = timeParts[0];
      const timeString = timeParts[1] || '00:00:00'; // Handle missing time
      timestamp = `${dateString}T${timeString}`; // Assuming format YYYY-MM-DDTHH:mm:ss
    } else {
      throw new Error('Missing timestamp field in new format JSON');
    }

    const value = parseFloat(data.value); // Convert value to a number
    const SH = 6;
    const TL = 4;
    const SL = 0;
    const TH = 20;

    // Calculate b2
    const b2 = (SH * TL - SL * TH) / (SH - SL);

    // Calculate a2
    const a2 = (TH - b2) / SH;

    // Calculate value to be inserted
    const valueToBeInserted = Math.round((SH - (value - b2) / a2) * 100) / 100;

    const insertData = {
      topic: data.topic, // Assuming "topic" field exists for ICR2431/Ch0
      timestamp: timestamp, // Assuming "time" field holds the timestamp
      value: valueToBeInserted,
    };

    let sql = `INSERT INTO `${table}` SET ?`;

    const pool = mysql.createPool({
      host: process.env.DB_HOST,
      user: process.env.DB_USER,
      password: process.env.DB_PASSWORD,
      database: process.env.DB_NAME,
      waitForConnections: true,
      connectionLimit: 10,
      queueLimit: 0,
    });
    const connection = await pool.getConnection();
    await connection.query(sql, insertData);
    console.log('Data successfully inserted into the database (new format)');
    connection.release();
  } catch (error) {
    console.error(
      'Failed to insert data into the database (new format):',
      error
    );
  }
}

function calculateNextInsertTime(lastInsertTime) {
  return new Date(lastInsertTime + 30 * 60 * 1000).toISOString();
}

// Example usage in a function
function updateStats(topic, message) {
  if (statsPerTopic[topic]) {
    statsPerTopic[topic].messageCount += 1;
    statsPerTopic[topic].lastMessageTime = Date.now(); // Update the last message timestamp
  } else {
    console.error(`No stats entry found for topic: ${topic}`);
  }
}

client.on('message', (receivedTopic, message) => {
  console.log(`Received message on ${receivedTopic}:`, message.toString());
  if (topicsConfig.hasOwnProperty(receivedTopic)) {
    lastMessages[receivedTopic] = message; // Store the most recent message
    if (statsPerTopic[receivedTopic]) {
      statsPerTopic[receivedTopic].messageCount += 1;
      statsPerTopic[receivedTopic].lastMessageTime = Date.now(); // Update the last message time
    } else {
      console.error(`No stats entry found for topic: ${receivedTopic}`);
    }
  }
});

function calculateNextInsertTime(lastInsertTime) {
  const nextInsertTime = new Date(lastInsertTime + 30 * 60 * 1000); // 30 minutes from the last insert
  return nextInsertTime;
}

// In your interval where you insert data
setInterval(() => {
  const currentTime = Date.now();
  Object.keys(lastMessages).forEach((topic) => {
    if (lastMessages[topic]) {
      insertData(topic, lastMessages[topic]);
      statsPerTopic[topic].dbInsertCount += 1;
      statsPerTopic[topic].lastInsertTime = currentTime; // Update last insert time
      lastMessages[topic] = null; // Clear after insertion
    }
  });
}, 30 * 60 * 1000); // 30 minutes

// Define a different threshold for considering a topic as inactive
const INACTIVITY_THRESHOLD = 5 * 60 * 1000; // e.g., 5 minutes

// Interval for checking inactivity
setInterval(() => {
  const currentTime = Date.now();
  Object.keys(statsPerTopic).forEach((topic) => {
    if (
      currentTime - statsPerTopic[topic].lastMessageTime >
      INACTIVITY_THRESHOLD
    ) {
      // Mark the topic as inactive
      statsPerTopic[topic].active = false;
    } else {
      // Ensure the topic is marked as active
      statsPerTopic[topic].active = true;
    }
  });
}, INACTIVITY_THRESHOLD);

// Set up Express.js server
const app = express();

// Serve static files from the current directory
app.use(express.static(__dirname));

app.get('/', (req, res) => {
  res.sendFile(path.join(__dirname + '/index.html'));
});

app.use(cors());

app.get('/data', (req, res) => {
  const currentTime = new Date().getTime(); // Get the current time in milliseconds
  const preparedData = Object.keys(topicsConfig).map((topic) => {
    const stats = statsPerTopic[topic];
    const nextInsertTime = calculateNextInsertTime(stats.lastInsertTime);
    const timeRemaining = nextInsertTime - currentTime; // Time remaining in milliseconds
    const active = currentTime - stats.lastMessageTime <= INACTIVITY_THRESHOLD; // Check if the topic is active
    console.log(
      `Topic: ${topic}, Last Message: ${stats.lastMessageTime}, Current Time: ${currentTime}, Active: ${active}`
    );

    return {
      topic: topic,
      tableName: topicsConfig[topic],
      messageCount: stats.messageCount,
      dbInsertCount: stats.dbInsertCount,
      timeRemaining: timeRemaining,
      active: active, // Include the active status
    };
  });

  res.json({ stats: preparedData });
});

app.listen(8080, () => {
  console.log('Server is running on port 8080');
});

and this code for the front end

<!DOCTYPE html>
<html>
  <head>
    <title>Monitoring Page</title>
    <link
      href="https://cdn.jsdelivr.net/npm/[email protected]/dist/css/bootstrap.min.css"
      rel="stylesheet" />
    <link rel="stylesheet" type="text/css" href="custom.css" />
  </head>

  <body>
    <div id="panels" class="container panels-container">
      <!-- Pane for Topic 1 -->
      <div class="row g-5">
        <div class="col-md-4">
          <div class="panel" id="panel1">
            <h2>Topic<br /><span>VivusDigester003/Ecu</span></h2>
            <div class="info-box">
              <p>DB Table: <span class="tableName">Loading...</span></p>
              <p>
                Messages received:
                <span class="messages">Loading...</span>
              </p>
              <p>
                Messages stored:
                <span class="dbInserts">Loading...</span>
              </p>
              <p>
                Next insert in:
                <span class="timer">Loading...</span>
              </p>
            </div>
          </div>
        </div>

        <!-- Pane for Topic 2 -->
        <div class="col-md-4">
          <div class="panel" id="panel2">
            <h2>Topic<br /><span>Poursalidis/Ecu</span></h2>
            <div class="info-box">
              <p>DB Table: <span class="tableName">Loading...</span></p>
              <p>
                Messages received:
                <span class="messages">Loading...</span>
              </p>
              <p>
                Messages stored:
                <span class="dbInserts">Loading...</span>
              </p>
              <p>
                Next insert in:
                <span class="timer">Loading...</span>
              </p>
            </div>
          </div>
        </div>
        <!-- Pane for Topic 3 -->
        <div class="col-md-4">
          <div class="panel" id="panel3">
            <h2>Topic<br /><span>VivusTHDigester004/Ecu</span></h2>
            <div class="info-box">
              <p>DB Table: <span class="tableName">Loading...</span></p>
              <p>
                Messages received:
                <span class="messages">Loading...</span>
              </p>
              <p>
                Messages stored:
                <span class="dbInserts">Loading...</span>
              </p>
              <p>
                Next insert in:
                <span class="timer">Loading...</span>
              </p>
            </div>
          </div>
        </div>
        <div class="col-md-4">
          <div class="panel" id="panel4">
            <h2>Topic<br /><span>data/tsiap01</span></h2>
            <div class="info-box">
              <p>DB Table: <span class="tableName">Loading...</span></p>
              <p>
                Messages received:
                <span class="messages">Loading...</span>
              </p>
              <p>
                Messages stored:
                <span class="dbInserts">Loading...</span>
              </p>
              <p>
                Next insert in:
                <span class="timer">Loading...</span>
              </p>
            </div>
          </div>
        </div>
        <div class="col-md-4">
          <div class="panel" id="panel5">
            <h2>Topic<br /><span>ICR2431/Ch0</span></h2>
            <div class="info-box">
              <p>DB Table: <span class="tableName">Loading...</span></p>
              <p>
                Messages received:
                <span class="messages">Loading...</span>
              </p>
              <p>
                Messages stored:
                <span class="dbInserts">Loading...</span>
              </p>
              <p>
                Next insert in:
                <span class="timer">Loading...</span>
              </p>
            </div>
          </div>
        </div>
      </div>
    </div>

    <script>
      function updatePane(paneId, data) {
        const pane = document.getElementById(paneId);
        pane.querySelector('.tableName').textContent = data.tableName;
        pane.querySelector('.messages').textContent = data.active
          ? data.messageCount
          : `${data.messageCount} (stopped)`;
        pane.querySelector('.dbInserts').textContent = data.dbInsertCount;
        pane.querySelector('.timer').textContent = data.active
          ? formatTimeRemaining(data.timeRemaining)
          : 'No data received';
      }

      function formatTimeRemaining(timeRemainingMs) {
        const minutes = Math.floor(timeRemainingMs / 60000);
        const seconds = Math.floor((timeRemainingMs % 60000) / 1000);
        return `${minutes} minutes and ${
          seconds < 10 ? '0' : ''
        }${seconds} seconds`;
      }

      function fetchData() {
        // fetch('http://XX.XXX.XX.XXXX:8080/data')
        fetch('/data')
          .then((response) => response.json())
          .then((data) => {
            if (data.stats) {
              data.stats.forEach((stat) => {
                if (stat.topic === 'Topic1') {
                  updatePane('panel1', stat);
                } else if (stat.topic === 'Topic2') {
                  updatePane('panel2', stat);
                } else if (stat.topic === 'Topic3') {
                  updatePane('panel3', stat);
                } else if (stat.topic === 'Topic4') {
                  updatePane('panel4', stat);
                } else if (stat.topic === 'Topic5') {
                  updatePane('panel5', stat);
                }
              });
            }
          })
          .catch((error) => console.error('Fetch error:', error));
      }

      setInterval(fetchData, 5000);
    </script>
  </body>
</html>

It works perfectly locally, but when I upload it to a server I have to uncomment this line “// fetch(‘http://XX.XXX.XX.XXXX:8080/data’)” and declare the IP of the server and, of course, comment the “fetch(/data)” line.
Could someone explain why I have to do that?

I’m not using any subfolders on the web server. All files are located to the same folder

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật