How can I make code run after a certain time? Without blocking the rest

Hi there! I have the code below. It runs smoothly however the token expires after 1hr and I have to fetch a new one, create a new connection, new session etc. How can I do this 1hr after first obtaining the token? All my attempts with setTimout/setInterval have failed due to e.g. the endpoint becoming unavailable. TY

const fetch = require('node-fetch');
const WebSocket = require('ws');
let myconfig = {};

module.exports = function myNode(RED) {
  myconfig.RED = RED;
  // RED.nodes.registerType('sivideo-server', SiVideoServer, {});

  // ... any setup functions here...

  RED.nodes.registerType('sivideo-server', SiVideoServer);
};

// this is run once for each node instance of the node in flows
function SiVideoServer(config) {
  if (!myconfig.RED) {
    console.log('RED not set');
    return;
  }
  const RED = myconfig.RED;

  // Initialize "this"
  RED.nodes.createNode(this, config);
  const node = this;
  this.allEvents = [];
  this.host = config.host;
  this.username = config.username;
  this.password = config.password;
  this.getToken = getToken;
  this.registerListener = registerListener;
  this.deRegisterListener = deRegisterListener;
  const Listeners = {};

  console.log('Listeners at start:', Listeners);
  // Get the bearer token for websocket authentication
  if (this.host && this.username && this.password) {
     connectWithNewToken();


  } else {
    console.log('No host, username, or password provided');
  }
    
  function connectWithNewToken() {
    getToken(node.host, node.username, node.password)
      .then((token) => {
        node.context().set('token', token);
        if (token) {
          // Close the existing WebSocket connection if it exists
          if (node.ws) {
            node.ws.removeAllListeners();
            node.ws.close();
          }

          // Create a new WebSocket connection
          node.ws = new WebSocket(`ws://${node.host}/api/ws/events/v1`, {
            headers: {
              Authorization: `Bearer ${token}`,
            },
          });

          console.log('Websocket connection created');
          startSession(node);
          listenForAllEvents(node);

          // Listen for message events
          node.ws.on('message', (data) => {
            for (const [id, cb] of Object.entries(Listeners)) {
              console.log('Sending data to listener:', id);
              cb(data);
            }
          });
        } else {
          console.log('No token obtained');
        }
      })
      .catch((error) => {
        console.error('Error fetching token:', error);
        setTimeout(connectWithNewToken, 5000); // Reconnect after 5 seconds
      });
  }
  // Define a new endpoint to get the event types from the Milestone server
  RED.httpAdmin.get('/getEventTypes', function (req, res) {
    console.log('Get event types is running');
    // serverNode = RED.nodes.getNode(config.server); - not necessary
    const token = node.context().get('token');
    if (token) {
      const options = {
        method: 'GET',
        headers: {
          Authorization: `Bearer ${token}`,
        },
      };
      fetch(`http://${config.host}/API/rest/v1/eventTypes`, options)
        .then((response) => {
          if (!response.ok) {
            throw new Error('Error fetching event types');
          }
          return response.json();
        })
        .then((data) => {
          const result = data.array.map((item) => ({
            value: item.id,
            label: item.displayName,
          }));
          result.sort((a, b) => a.label.localeCompare(b.label));
          // add all EventTypes
          result.unshift({ value: 'all-events', label: 'All Events' });
          node.allEvents = result;
          res.status(200).send(result);
        })
        .catch((error) => {
          console.error('Error fetching event types:', error);
          res.status(500).send('Error fetching event types');
        });
    }
  });

  // Register and deregister listeners
  function registerListener(NodeID, Callback) {
    // start own session so that every node has its own session
    console.log('Registering listener:', NodeID);
    Listeners[NodeID] = Callback;
    console.log('Current Listeners:', Listeners);
  }

  function deRegisterListener(NodeID) {
    console.log('De-registering listener:', NodeID);
    delete Listeners[NodeID];
  }
}

// get the token from the server
async function getToken(host, username, password) {
  try {
    const formData = new URLSearchParams();
    formData.append('grant_type', 'password');
    formData.append('client_id', 'GrantValidatorClient');
    formData.append('username', username);
    formData.append('password', password);
    const response = await fetch(`http://${host}/idp/connect/token`, {
      method: 'POST',
      headers: {
        'Content-type': 'application/x-www-form-urlencoded',
      },
      body: formData,
    });

    if (response.ok) {
      const data = await response.json();
      // console.log('Token:', data.access_token);
      return data.access_token;
    } else {
      console.error('HTTP Error:', response.status);
      return null;
    }
  } catch (error) {
    console.error('Error fetching token:', error);
    throw error;
  }
}

function startSession(server) {
  // Start a session
  server.ws.on('open', () =>
    server.ws.send(
      JSON.stringify({
        command: 'startSession',
        commandId: 1,
        sessionId: '',
        eventId: '',
      }),
    ),
  );
  console.log('Session started');
}

function listenForAllEvents(server) {
  server.ws.on('open', () =>
    server.ws.send(
      JSON.stringify({
        command: 'addSubscription',
        commandId: 1,
        filters: [
          {
            modifier: 'include',
            resourceTypes: ['*'],
            sourceIds: ['*'],
            eventTypes: ['*'],
          },
        ],
      }),
    ),
  );
  console.log('Server listener for all Events added');
}

Off the top of my head and with no testing:

Add a statement at the start of connectWithNewToken to destroy the websocket connection (which should also destroy the event listener I think?) if it exists.

That means you can safely re-run that function.

Now set up a timer - setInterval() - that re-runs the function about every 55 minutes or so.

This topic was automatically closed 60 days after the last reply. New replies are no longer allowed.