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');
}