0

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:

  • Using setTimeout(), which doesn't do exactly what I'd like, since it will only call the function after the amount of time specified in the argument has passed. As far as I can tell, this will cause a delay in messages from the time the bot is called, but it won't actually prevent the bot from accepting new postMessage() calls in that time.
  • Using setInterval(), which just causes the function to be called forever at a certain interval.

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):

  • Would the best way to go about this be to set a timer on the response() function, since then it will only actually parse the incoming information once per minute? Is there a more elegant place to put this?

  • How should the timer work on that function? I don't think I can just run response() once every minute, since that seems to mean it'll only parse incoming json from the GroupMe API once per minute, so it could potentially miss incoming messages that I would want it to capture.

R. McManaman
  • 304
  • 2
  • 14
  • Why not have a flag that only allows the bot to post every minute? i.e have an additional variable for the timestamp of the last post, and then if the current time is greater than a minute then call the `postMessage` function – Sam Yuyitung Mar 29 '17 at 19:57

1 Answers1

1

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();
}
rckrd
  • 3,124
  • 1
  • 13
  • 23