DiscordJS components collector restart timer - node.js

I've set up a Message Component Collector via interaction.channel.createMessageComponentCollector, so I'm able to disable buttons after 15 seconds of inactivity. My problem is that after a button is pressed I want to restart the timer for disabling the buttons.
Simplified code demonstrating what i'm trying to acheive below.
const collector = interaction.channel.createMessageComponentCollector({ filter, time: 15000 })
collector.on('collect', i => {
i.update('some updated text here')
// restart the collector timer here
})
collector.on('end', () => { /* this bit disables the buttons */ })
I've looked in the docs, and the code for the collectors themselves and they don't seem to show any way to reset them. If there is any way to do this / workaround for this that would be what I'm looking for.

Related

Collector never reaches the "end" event in discord.js

I am having a little issue with the collector's time property. Right now I have the following code:
const collector = message.createReactionCollector({
time: timeInMilliseconds,
});
However, if I set a high value for timeInMilliseconds like 28800000 (8 hours) the collector.on('end', callback) is never triggered. Is this something related to the library or Node.js cleaning some stuff and preventing the collector to reach its end?
for more information to use, you can use package ms,
const ms = require('ms')
const collector = message.createReactionCollector({
time: ms('8h'), //You can use this as normal timer like s/m/h/d
});

A script that runs every second in a chrome extension with manifest v3

This is my first chrome extension using manifest v3, and I want to make a timer in it.
This is supposed to update every second, and not run on any specific tab nor the popup window.
I tried to do this in my service worker:
let counter = 0
setInterval(() => {
counter++
}, 1000)
But that didn't work well, because after around half a minute, the service worker would go "inactive", and thus stop this loop.
So I am just looking for a way to make a loop that executes some code every 1 second. This loop always has to be running. And I do not really have a way to "launch" say a function every second from another page. I can start it once, but because of the service worker that goes inactive after a while, then this script has to either just never die or relaunch itself every second.
Is this even possible?
Google recommends using their "Alarm API" instead of timers to schedule running code: https://developer.chrome.com/docs/extensions/mv3/migrating_to_service_workers/#alarms
So instead of running a "setTimeout" or "setInterval" in your background worker like this:
const TIMEOUT = 3 * 60 * 1000; // 3 minutes in milliseconds
setTimeout(() => {
chrome.action.setIcon({
path: getRandomIconPath(),
});
}, TIMEOUT);
You should instruct Chrome on when to run it instead:
chrome.alarms.create({ delayInMinutes: 3 });
chrome.alarms.onAlarm.addListener(() => {
chrome.action.setIcon({
path: getRandomIconPath(),
});
});

NodeJS SetInterval with Async/Await

I'm using the following code with a websocket to scrape data from a DB and return to users. It returns chat messages, users status and other things. The code works as expected (in testing) but I have a couple of questions.
setInterval(async () => {
if (connectedUserIDs.length > 0) {
logger.info("short loop...")
await eventsHelper.extractEvents(db, connectedUserIDs, connectedSockets, ws)
}
}, 5000)
Question 1. Will the SetInterval wait for the the "await" or will it just fire every 5 seconds? I assume it will fire every 5 seconds regardless.
If that is the case.
Question 2. Is there a way to repeat a task like above but ensure it only re-runs if the previous run as completed with a minimum time of 5 seconds? I want to avoid a situation where I get multiple queries running at the same time. Maybe the setInterval could be cancelled and restarted each time...
thankyou
Adam
Question 1. Will the SetInterval wait for the the "await" or will it just fire every 5 seconds? I assume it will fire every 5 seconds regardless.
Yes it will naively re-run every 5s
Question 2. Is there a way to repeat a task like above but ensure it only re-runs if the previous run as completed with a minimum time of 5 seconds
Easiest way to prevent collisions is to set the next run after the await:
let timeoutId;
const extractEvents = async () => {
if (connectedUserIDs.length > 0) {
logger.info("short loop...");
await eventsHelper.extractEvents(db, connectedUserIDs, connectedSockets, ws);
}
timeoutId = setTimeout(extractEvents, 5000);
};
timeoutId = setTimeout(extractEvents, 5000);
Storing timeoutId so you can clear it later

Node.js halts when console window is scrolled

If you run the following script in Node.js under Windows (at least 8)
const init = +new Date;
setInterval(() => {
console.log(+new Date - init);
}, 1000);
and drag the thumb of a scroll bar of console window, the output of the script looks similar to
1001
2003 // long drag here
12368 // its result
13370
14372
Looks like Node.js' event loop halts during the scroll. The same thing should happen to asynchronous actions inside of http package. Thus leaving a visible terminal window is dangerous to the running server.
How do I change the code to avoid such behavior?
NodeJS is not halted while scrolling or selecting text. The only functions that send data to stdout are halted.
In your server, you are able to send log data to a file, and this way your server will not halt.
For example, see this code:
const init = +new Date;
var str=''
setInterval(() => {
x=(+new Date - init).toString();;
str+=x + '\n'
}, 1000);
setTimeout(function(){
console.log(str)
},5000)
I have selected text during the first 5 seconds, and this was the result:
C:\me>node a
1002
2002
3002
4003
You can see that there is no 'pause'.
As you see, the first event loop setInterval wasn't halted, because there is no console.log inside.
Now, when you use an output file for logging, you can view live log using tail -f. This will show you each new line in the output file.
Your console is actually pausing when you scroll or click in the console, as it's entering into select mode. Have a look in the title bar as it's paused it will likely say select.
To prevent this behavior, edit the properties of the command prompt, and unselect "quick edit mode".
There are two pieces of information in the node documentation that may give some clues for the reason of that behaviour:
an excerpt from Console:
Warning: The global console object's methods are neither consistently synchronous like the browser APIs they resemble, nor are they consistently asynchronous like all other Node.js streams. See the note on process I/O for more information.
an excerpt from A note on process I/O:
Warning: Synchronous writes block the event loop until the write has completed. This can be near instantaneous in the case of output to a file, but under high system load, pipes that are not being read at the receiving end, or with slow terminals or file systems, its possible for the event loop to be blocked often enough and long enough to have severe negative performance impacts.
And it seems that partial solution can be built using method you already proposed:
const fs = require('fs');
const init = +new Date;
setInterval(() => {
fs.write(1,String(+new Date - init)+'\n',null,'utf8',()=>{});
}, 1000);
It still blocks UI if you start selection, but doesn't stop processing:
2296
3300 // long pause here when selection was started
4313 // all those lines printed at the same time after selection was aborted
5315
6316
7326
8331
9336
10346
11356
12366
13372
If you'd like to make your console.log and console.error always asynchronous on all platforms, you can do this by using fs.write to fd 1 (stdout) or fd 2 (stderr).
const fs = require('fs')
const util = require('util')
// used by console.log
process.stdout.write = function write (str) {
fs.write(1, str, ()=>{})
}
// used by console.error
process.stderr.write = function write (str) {
fs.write(2, str, ()=>{})
}

How to tell if a window failed to close in Electron?

Is there a way in Electron to tell if a window was not successfully closed?
win.once("closed", () => {
// send message to the page running in the renderer process that the window was closed
});
win.close();
Assuming that I'm not cancelling the close in the close or beforeunload handler, can the window still fail to close, or can I be sure that a message will always be sent to the guest page?
I just came to this issue as well, what I did is simply wait for a few hundred milliseconds, if the callback is called, then most likely, this window has failed to close:
win.on('close', () => setTimeout(() => console.log('failed to close'), 300))
Have a look at this property in the doc:
win.closed
A Boolean that is set to true after the child window gets closed.
And this other bit too:
win.destroy()
Force closing the window, the unload and beforeunload
event won’t be emitted for the web page, and close event will also not
be emitted for this window, but it guarantees the closed event will be
emitted.
With that, you should have all the info you need to create a function that insure you that the window closes:
function forceClose(window) {
// try close first
window.close()
// force with destroy
if(!window.closed) {
window.destroy()
}
//just logging out the event
window.on('closed', (e) => {
console.log(e)
})
}
// in your code, instead of calling win.close()
forceClose(win)

Resources