javascriptnode.jstimergroupme

Allow a function to be called only after a set amount of time has passed


To provide context, here's the problem I'm attempting to solve:

I've made a giphy bot for a casual groupchat with friends of mine. By typing /giphy [terms] in a message, it will automatically post the top result for [terms]. My friends, being the rambunctious assholes that they are, quickly started abusing it to spam the groupchat. What I would like to do to prevent this is only allow my postMessage function to be called once per minute.

What I've tried:

What I think might work:

Right now, I'm working with two .js files.

Index.js

var http, director, cool, bot, router, server, port;

http        = require('http');
director    = require('director');
bot         = require('./bot.js');

router = new director.http.Router({
  '/' : {
    post: bot.respond,
    get: ping
  }
});

server = http.createServer(function (req, res) {
  req.chunks = [];
  req.on('data', function (chunk) {
    req.chunks.push(chunk.toString());
  });

  router.dispatch(req, res, function(err) {
    res.writeHead(err.status, {"Content-Type": "text/plain"});
    res.end(err.message);
  });
});

port = Number(process.env.PORT || 5000);
server.listen(port);

function ping() {
  this.res.writeHead(200);
  this.res.end("This is my giphy side project!");
}

Bot.js

var HTTPS = require('https');
var botID = process.env.BOT_ID;
var giphy = require('giphy-api')();

function respond() {
  var request = JSON.parse(this.req.chunks[0]);
  var giphyRegex = /^\/giphy (.*)$/;
  var botMessage = giphyRegex.exec(request.text);
  var offset = Math.floor(Math.random() * 10);

  if(request.text && giphyRegex.test(request.text) && botMessage != null) {
    this.res.writeHead(200);
    giphy.search({
      q: botMessage[1],
      rating: 'pg-13'
    }, function (err, res) {
      try {
        postMessage(res.data[offset].images.downsized.url);
      } catch (err) {
        postMessage("There is no gif of that.");
      }
    });
    this.res.end();
  } else {
    this.res.writeHead(200);
    this.res.end();
  }

function postMessage(phrase) {
  var botResponse, options, body, botReq;
  botResponse = phrase;

  options = {
    hostname: 'api.groupme.com',
    path: '/v3/bots/post',
    method: 'POST'
  };

  body = {
    "bot_id" : botID,
    "text" : botResponse
  };

  botReq = HTTPS.request(options, function(res) {
      if(res.statusCode == 202) {
      } else {
        console.log('Rejecting bad status code: ' + res.statusCode);
      }
  });

  botReq.on('error', function(err) {
    console.log('Error posting message: '  + JSON.stringify(err));
  });

  botReq.on('timeout', function(err) {
    console.log('Timeout posting message: '  + JSON.stringify(err));
  });

  botReq.end(JSON.stringify(body));
}
exports.respond = respond;

Basically, I'm wondering where would be the ideal place to implement the timer that I'm envisioning. It seems like I would want to have it only listen for /giphy [terms] after one minute, rather than waiting one minute to post.

My Question(s):


Solution

  • Store the time when a request is made and then use that to see if subsequent requests should be ignored if these are executed to fast.

    var waitTime = 10*1000; // 10 s in millis 
    var lastRequestTime = null;
    function respond() {
      if(lastRequestTime){
        var now = new Date();
        if(now.getTime() - lastRequestTime.getTime() <= waitTime){
            this.res.writeHead(200);
            this.res.end("You have to wait "+waitTime/1000+" seconds.");
            return;
        } 
      }
      lastRequestTime = new Date();
      postMessage();
    }