cannot compare message timestamp with x amount of days - javascript

Hi I'm trying to delete messages that are 7 days old I'm using cron to schedule when this should happen. Here in my code I'm trying to fetch messages from a channel called log_channel then comparing the message timestamps to const days = moment().add(7, 'd'); However I'm stuck at the if statement if (msgs - days) as this does not seem to return anything.
Here is my code for reference:
const cron = require('node-cron');
const moment = require('moment');
module.exports = new Event("ready", client => {
try{
const log_channel = client.channels.cache.find(c => c.name == "log")
cron.schedule("0 18 22 * * *", function(){
console.log("Attempting to purge log messages...");
const days = moment().add(7, 'd'); // use moment the set how many days to compare timestamps with //
log_channel.messages.fetch({ limit: 100 }).then(messages => {
const msgs = Date.now(messages.createdTimestamp)
if (msgs < days){
log_channel.bulkDelete(100)
console.log("messages deleted")
}
})
})

First of all, I noticed your function wasn't an asynchronous function. We need to use a asynchronous function because we'll be using asynchronous, promise-based behavior your code. log_channel.messages.fetch should be await log_channel.messages.fetch According to the Message#fetch() docs The fetch() method in this case simply returns asynchronous message object. Promise.
The next part is that you missed out ForEach(), forEach() executes the callbackFn function once for each array element.
Finally, you are also comparing the timestamp (a snowflake) with a moment object which will not work and the reason your if doesn't return true. If you want to get messages 7 days prior you can do something like this moment.utc(msg.createdTimestamp).add( -7, 'd') this will return all timestamps 7 days prior the last 100 messages. Note that Discord API limits you to 14 days so keep that in mind.
cron.schedule("* 18 22 * * *", async function(){
console.log("Attempting to purge mod log messages...");
await log_channel.messages.fetch({ limit: 100 })
.then(messages => {
messages.forEach(msg => {
const timestamp = moment.utc(msg.createdTimestamp).add( -7, 'd');
if (timestamp) {
log_channel.bulkDelete(5);
} else {
return;
}
})

Related

Google Cloud Function delete Firestore document

I tested my javascript on local emulator. There are 2 actions, if Timestamp is over 7 days delete the document (this is working like a charm <3) but the else is he should check the "img" its a normal url if this return 404 then delete like on the first action, this is ONLY working on local emulator, when i deploy it to Cloud function its not working anymore and just says e.g "Function execution took 7957 ms, finished with status: 'ok'" BUT on local it works as expected.
exports.removeExpiredDocuments = functions.region('europe-west1').runWith({ memory: "256MB" }).pubsub.schedule("every 1 hours").onRun(async (context) => {
const db = admin.firestore();
const now = firestore.Timestamp.now();
const ts = firestore.Timestamp.fromMillis(now.toMillis() - 604800000); // 168 hours in milliseconds = 604800000
const snaps = await db.collection("products").get();
let promises = [];
snaps.forEach((snap) => {
// functions.logger.info("forEachSnap");
if (snap.data().created_time < ts) {
promises.push(snap.ref.delete());
functions.logger.info('[Time] older than 7 Days ' + snap.data().name, { structuredData: true });
} else {
requesth(snap.data().img, function (error, response) {
functions.logger.info('[img] error: ' + error, { structuredData: true });
if (response.statusCode == 404) {
promises.push(snap.ref.delete());
functions.logger.info('[img] not found ' + snap.data().name, { structuredData: true });
}
});
}
});
return Promise.all(promises);
});
Working on local emulator (with same url as in firebase) and i expect that its working on cloud aswell
firestore.Timestamp.now() does not return a value that can be correctly compared to other Timestamps with < and > comparisons. That means this line of code doesn't do what you think:
if (snap.data().created_time < ts)
If you want to compare two Timestamp objects with each other, you must take another approach. One way is to convert them both to milliseconds with toMillis() and compare those integers with each other. Or convert them to Date and compare them with the appropriate object method.

Limit calls to Facebook graph_url_engagement_count

I am getting this error, "(#613) Calls to graph_url_engagement_count have exceeded the rate of 10 calls per 3600 seconds." so I want to keep the calls to the API within the limit for a given link.
Note: That the limit of 10 calls per hour only applies to each link.
This is the function I am using:
const getFacebookStats = async (link) => {
try {
const resp = await axios.get(
`https://graph.facebook.com/v12.0/?id=${link}&fields=engagement&access_token=${BEARER_TOKEN_FACEBOOK}`
);
return resp.data.engagement;
} catch (err) {
// Handle Error Here
console.error(err);
}
};
Any help would be much appreciated.
Thank you
Solved this problem using LRU cache.
cache.set(link, cache.get(link) == undefined ? 1 : cache.get(link) + 1);
Everytime the link was passed onto the getFacebookStats function, the link and its count were stored in the LRU cache, if the same link was being called multiple times then its count got incremented.
In the settings of LRU cache, maxAge was set to 1 hour:
maxAge: 1000 * 60 * 60,

Limit messages to every 500 ms

I have some websocket that sends around 100's of data per second,I want to limit it to only 1 data per 500 ms.
onMessage(data) {
console.log(data); // This prints around 100 different times within 1 second
}
I tried something like below , Is this the right approach or is there any other better way to do it ? because this code runs 100 times per second.
var lastlog = new Date().getTime();
onMessage(data) {
currenttime = new Date().getTime();
if ( currenttime - lastlog > 500) {
console.log(data);
lastlog = new Date().getTime();
}
}
P.s : I can ignore remaining data and will be able to reduce the 500 ms to 200ms.. that is 5 data per second.
Here is another way of doing it, using the npm package throttle-debounce. This method is not "better". It can result is less code typed but you might not want the dependency on the package.
You can use the throttle function and specify how many milliseconds until it can be called again. Setting the second argument to true prevents the last request from being deffered -https://www.npmjs.com/package/throttle-debounce#notrailing.
The example below uses the library to throttle how often a button is pressed.
const { throttle } = throttleDebounce
const handleRequest = throttle(500, true, () => {
console.log('this request will be handled')
})
<script src='https://cdn.jsdelivr.net/npm/throttle-debounce#3.0.1/umd/index.js'></script>
<button onClick="handleRequest()">Mimick sending message</button>
Your use case might look like this:
import { throttle } from 'throttle-debounce'
const onMessage = throttle(500, true, () => {
console.log(data);
})
Less lines than your example, but that doesn't mean it's "better".

How to solve the invalid problem of electron's setInterval?

I encountered a difficult problem when trying to write an electron application. The following is a detailed description of the problem:
I plan to load a clock on the page of the electron rendering process. Just like our system time, it will refresh every second, 60 seconds is one minute, and so on, but I don’t use the system time, I use a current Time API, the json data returned by this API interface is the current time. I wrote a set of asynchronous execution functions in the main process main.js to get the data passed by this API. The following is the main process main.js Asynchronous get time API code:
const request = net.request('http://api.k780.com:88/?app=life.time&appkey=10003&sign=b59bc3ef6191eb9f747dd4e83c99f2a4&format=json')
request.on('response', (response) => {
console.log(response.statusCode);
console.log(response.headers);
response.on('data', (chunk) => {
let result = JSON.parse(chunk).result;
let datetime = result.datetime_1;
let week = result.week_4;
console.log(datetime, week)
mainWindow.webContents.send('datetime', { datetime, week });
})
response.on('end', () => {
console.log('end');
})
})
request.end();
The console information displayed by the main process is as follows:
200
{
server: 'nginx',
date: 'Thu, 06 May 2021 01:38:00 GMT',
'content-type': 'application/json; charset=utf-8;',
'transfer-encoding': 'chunked',
connection: 'keep-alive',
'access-control-allow-origin': '*'
}
2021-05-06 09:38:01 Thursday
end
Then after requesting this API, it will respond with a timestamp of the current time. After the main process obtains this timestamp, it will be sent to my rendering process through webContents.send. The following is the code sent by the main process to the rendering process:
mainWindow.webContents.send('datetime', { datetime, week });
The rendering process obtains the time data sent by the main process through ipcRenderer.on, and then formats this timestamp and outputs it to my rendering process page. I wrote this set of code as a function as follows:
function getNetTime() {
//Get the date and time passed by the main process
ipcRenderer.on('datetime', (event, arg) => {
let datetime = arg.datetime; //Get date and time
let week = arg.week; //Get the day of the week
let year = datetime.substring(0, 4); //Get year
let month = datetime.substring(5, 7); //Get month
let day = datetime.substring(8, 10); //Get the day
let hour = datetime.substring(10, 13); //Get hour
let min = datetime.substring(14, 16); //Get minutes
let sec = datetime.substring(17, 19); //Get seconds
let weekday = ""; //Get Chinese weekday
const timeText = document.querySelector('#timeText')
// console.log(datetime);
// console.log(week);
// console.log(year,month,day,hour,min);
switch (week) {
case'Monday':
weekday ='Monday';
break;
case'Tuesday':
weekday ='Tuesday';
break;
case'Wednesday':
weekday ='Wednesday';
break;
case'Thursday':
weekday ='Thursday';
break;
case'Friday':
weekday ='Friday';
break;
case'Saturday':
weekday ='Saturday';
break;
case'Sunday':
weekday ='Sunday';
break;
}
timeText.innerHTML =`${year}year${month}month${day}day ${weekday}${hour}:${min}:${sec}`;
});
The problem now encountered is that although the current time can be displayed normally on the page of the rendering process, it cannot be automatically refreshed. I want to set it to refresh every 1000 milliseconds through setTimeout or setInterval, which is equivalent to one step in 1 second of the clock. But it has no effect. The current time can only be displayed when the program is reopened, and it cannot be automatically refreshed. The following is the code of setInterval:
window.onload = () => {
getNetTime();
setInterval(getNetTime(),1000)
}
The above is the problem I am encountering now. Electron is also just getting in touch. I am searching for a long time on net. But no use. Please help or try to give some ideas how to achieve this.
The problem you're experiencing has nothing to do with Electron or how you request the data from the API. It's about how you set your interval.
The setInterval() function requires a function or a string of code as a parameter. However, you are specifying getNetTime() as the code it should call. This is not a function. It is a function call and will be evaluated before setInterval() is called. This will not do anything because the return type of getNetTime() is undefined.
To mitigate this, you can use a function, an arrow function or just leave out the parentheses. Whatever you choose is up to your liking.
setInterval (getNetTime, 1000);
// or
setInterval (() => getNetTime (), 1000);
// or
setInterval (function () { getNetTime (); }, 1000);

How to wait in one request till another request finishes the execution of same function in nodeJS

I am using meteor. I have a route defined in iron router as follows,
Router.route('/api/generatereceipt', {where: 'server'}).post(function(req, res, next) {
console.log("API: generatereceipt invoked.");
const reqBody = req.body;
....
}
I want to generate a receipt one at a time. i.e. the receipt needs to have a unique number which is incremental in nature.
Right now I'm reading the previously stored receipt number and incrementing it by one. I consider that as the receipt number for currently processing receipt.
However, This works fine as long as the generatereceipt API is not called concurrently by multiple clients. When the API is called simultaneously, the same receipt number is considered for all the concurrently processed receipts.
Therefore I want to make a request check if the same REST API is called by some other client in some other request is under process. If it is in the process then I want to wait till its execution in that request thread finishes.
There should be no issue with concurrent requests. See the following example:
import { Meteor } from 'meteor/meteor'
import { WebApp } from 'meteor/webapp'
import { HTTP } from 'meteor/http'
// create a simple HTTP route
WebApp.connectHandlers.use('/api/generatereceipt', function (req, res, next) {
// random 0 - 50ms timeout to simulate response delay
const randomTimeout = Math.floor(Math.random() * 50)
// use Meteor's Promise.await to await async in non-async functions
// --> should prevent troubles with legacy iron-router
const receipt = Promise.await(getReceipt())
setTimeout(() => {
res.writeHead(200)
res.end(String(receipt))
}, randomTimeout)
})
// increment id and return new value
let receiptId = 0
async function getReceipt () {
return receiptId++
}
Meteor.startup(function () {
let testCount = 0
const url = Meteor.absoluteUrl('/api/generatereceipt')
// simulate concurrent calls by using a timeout of 0
function call (id) {
setTimeout(Meteor.bindEnvironment(() => {
// simulate calling the /api/generatereceipt route
const response = HTTP.get(url)
console.log(id, ' => ', response.content) // should match
}, 0))
}
for (let i = 0; i < 25; i++) {
call(testCount++)
}
})
as you can see, the calls will resolve to the incremented ids:
=> Meteor server restarted
I20200703-09:59:15.911(2)? 9 => 9
I20200703-09:59:15.912(2)? 7 => 7
I20200703-09:59:15.913(2)? 4 => 4
I20200703-09:59:15.913(2)? 0 => 0
I20200703-09:59:15.913(2)? 21 => 21
I20200703-09:59:15.913(2)? 24 => 24
I20200703-09:59:15.913(2)? 17 => 17
I20200703-09:59:15.913(2)? 18 => 18
I20200703-09:59:15.915(2)? 2 => 2
I20200703-09:59:15.917(2)? 19 => 19
I20200703-09:59:15.923(2)? 6 => 6
I20200703-09:59:15.923(2)? 23 => 23
I20200703-09:59:15.925(2)? 11 => 11
I20200703-09:59:15.928(2)? 8 => 8
I20200703-09:59:15.931(2)? 16 => 16
I20200703-09:59:15.932(2)? 10 => 10
I20200703-09:59:15.934(2)? 5 => 5
I20200703-09:59:15.934(2)? 13 => 13
I20200703-09:59:15.934(2)? 22 => 22
I20200703-09:59:15.936(2)? 20 => 20
I20200703-09:59:15.936(2)? 15 => 15
I20200703-09:59:15.939(2)? 14 => 14
I20200703-09:59:15.940(2)? 1 => 1
I20200703-09:59:15.940(2)? 3 => 3
I20200703-09:59:15.943(2)? 12 => 12
I'm assuming this uses some kind of database/backend to store receipt ids? If so you should use constraints on your database to ensure that the receipt id is unique. Better yet, why not make the receipt id column an auto increment, then you don't need to check the previous receipt number and increment it yourself, it will be handled by the database layer and it just returned as part of the insert.
If it doesn't need to be auto incrementing, then just consider using a UUID.
I can't think of a single reason why you would want to wait on the execution. It would make your app slow for anyone other than the first request and would not be scalable.
If you really have a legitimate reason to structure it this way and generate the auto-increment yourself, then it would be better to explain in detail why this is the case as it might be there are better solutions then just "blocking" the next in line
Use async and await for waiting for completion of one request.

Categories