Skip to content

Commit

Permalink
added automatic timeout to bot. removed ssh key copy from vagrant scr…
Browse files Browse the repository at this point in the history
…ipt.
  • Loading branch information
shukriadams committed Jan 21, 2018
1 parent ee6d911 commit 7bd6a1b
Show file tree
Hide file tree
Showing 7 changed files with 77 additions and 13 deletions.
28 changes: 19 additions & 9 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
# discord-giveawaybot

A demo version of the bot lives on Discord: https://discord.gg/gMEGQBj

[![Build Status](https://travis-ci.org/shukriadams/discord-giveawaybot.svg?branch=master)](https://travis-ci.org/shukriadams/discord-giveawaybot)

Gives away Steam games on Discord. Heavily inspired by https://github.com/jagrosh/GiveawayBot

A demo version can be seen on Discord: https://discord.gg/gMEGQBj

## Requirements

- NodeJS 7 or greater.
Expand All @@ -20,9 +20,11 @@ Gives away Steam games on Discord. Heavily inspired by https://github.com/jagros

## Host your bot

There are three ways to host your bot. In all cases, first create a sub folder called "discord-giveawaybot" in the root folder you're working from, to this sub folder copy exampleSettings.json, rename to settings.json, and add your bot token from Discord.
There are three ways to host your bot. In all cases, your should create a folder (this will be your bot's root folder).
In this create a sub folder called "discord-giveawaybot", in this sub folder copy exampleSettings.json, rename it
settings.json, open it with your favorite text editor, and add your Discord bot token (see above) to the "token" field.

### From Docker image
### 1) From Docker image

Image on Docker hub : https://hub.docker.com/r/shukriadams/discord-giveawaybot/

Expand All @@ -44,28 +46,27 @@ Image on Docker hub : https://hub.docker.com/r/shukriadams/discord-giveawaybot/

These settings can of course be tweaked to suite your host setup, only npm start and the volume map are required.

### From NPM
### 2) From NPM

- Install

npm install discord-giveawaybot --save

- Run
- Run

let Bot = require('discord-giveawaybot'),
bot = new Bot();

bot.start();

### From source
### 3) From source

- Clone this repo.
- Run

npm install
npm start


## Add your bot to your Discord server

- back on your app's Discord config page (from the first section above), copy your bot's client id and paste it into
Expand All @@ -79,6 +80,16 @@ should see your bot as a user on your server.
"@BOTNAME channel" where BOTNAME is whatever name you gave your bot.
- That's it, you're set to go.

## Known issues

The bot has a memory leak, and will hang periodically. I don't have a fix for this, a workaround is to enable self-timeout
in settings.json

"processLifetime" : 480

This value is in minutes, and after it has elapsed, the bot will cleanly exit and flush used memory. If you're hosting
with docker or pm2, they should automatically bring the bot back up, and you're good to run again.

## Additional config

By default, only admins can create and manage giveaways. If you want to delegate giveaway responsibilities to non-admins
Expand Down Expand Up @@ -207,7 +218,6 @@ If you want to run it directly on your machine, install Node 7 or higher. Then r
npm install
node index


## Tests

npm test
Expand Down
27 changes: 26 additions & 1 deletion lib/bot.js
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,7 @@ let codes = require('./codes'),
Trace = require('./trace'),
hi = require('./highlight'),
process = require('process'),
Store = require('./store'),
path = require('path'),
fs = require('fs'),
State = require('./state'),
Expand All @@ -19,6 +20,8 @@ class Bot{
constructor(options){
options = options || {};
this.cronEnabled = true;
this.busyProcessingMessage = false;
this.willShutdown = false;

if(options.cronEnabled === false)
this.cronEnabled = false;
Expand Down Expand Up @@ -68,6 +71,12 @@ class Bot{
try
{
this.daemon = Daemon.instance();
this.daemon.onProcessExpired = async function(){
this.willShutdown = true;
if (!this.busyProcessingMessage)
await this.shutdown();
}.bind(this);

if (this.cronEnabled)
await this.daemon.start();
} catch (ex){
Expand Down Expand Up @@ -105,14 +114,24 @@ class Bot{
* Called after bot connects to discord and is ready to receive messages.
*/
_onReady(){
console.log('Giveawaybot is ready.');
console.log('discord-giveawaybot is now running.');

// todo : validate settings

// todo : run diagnostics - does bot have a giveaway channel, does it exist, does bot have necessary
// permissions etc
}

async shutdown(){

// close Loki down gracefully
let store = await Store.instance();
await store.close();

console.log(`Bot lifetime (${this.settings.values.processLifetime}m) expired. Exiting now, this is not an error.`);
process.exitCode = 0;
process.exit();
}

/**
* Entry point for all incoming user messages. This is where all user-driven interaction (as opposed to daemon)
Expand All @@ -122,6 +141,8 @@ class Bot{
return new Promise(async function(resolve, reject){
try {

this.busyProcessingMessage = true;

// reject messages @bot (these are public messages), unless message is to set "channel"
if (message.content.indexOf(`<@${message.client.user.id}>`) === 0 && message.content.toLowerCase().trim() !== `<@${message.client.user.id}> channel`) {
await message.reply('Please message me directly.');
Expand Down Expand Up @@ -182,6 +203,10 @@ class Bot{
} catch (ex) {
this._handleUnexpectedError(ex, message);
return reject(ex);
} finally {
this.busyProcessingMessage = false;
if (this.willShutdown)
await this.shutdown();
}
}.bind(this));
}
Expand Down
16 changes: 15 additions & 1 deletion lib/daemon.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,11 @@ let winston = require('winston'),

class Daemon {

constructor(){
this.started = new Date();
this.willShutdown = false;
}

/**
* Starts the timer loop that calls .tick()
*/
Expand All @@ -35,7 +40,7 @@ class Daemon {
try
{
// use busy flag to prevent the daemon from running over itself
if (busy)
if (busy || this.willShutdown)
return;

busy = true;
Expand Down Expand Up @@ -259,6 +264,15 @@ class Daemon {
// clean old giveaways
store.clean();

// check if lifetime has passed
if (settings.values.processLifetime && this.onProcessExpired){
let shouldExpire = timeHelper.minutesSince(this.started) >= settings.values.processLifetime;
if (shouldExpire){
this.willShutdown = true;
this.onProcessExpired();
}
}

return codes.DAEMON_FINISHED;
}

Expand Down
4 changes: 4 additions & 0 deletions lib/settings.js
Original file line number Diff line number Diff line change
Expand Up @@ -38,6 +38,10 @@ class Settings {

if (this.values.joinGiveawayResponseCharacter === undefined)
this.values.joinGiveawayResponseCharacter = '🎉';

// int, and in minutes
if (this.values.processLifetime && !Number.isInteger(this.values.processLifetime))
throw new Error ('settings.json processLifetime value must an integer');
}

save(){
Expand Down
12 changes: 12 additions & 0 deletions lib/store.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,18 @@ class Store {
}
}

async close(){
return new Promise(async function(resolve, reject) {
try {
this.database.close(function(){
resolve();
});
} catch (ex){
reject(ex);
}
}.bind(this));
}

static _convert (record){
return {
id : record.$loki.toString(),
Expand Down
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "discord-giveawaybot",
"version": "0.1.2",
"version": "0.1.3",
"description": "A Discord bot that gives games away.",
"private": false,
"author": "[email protected]",
Expand Down
1 change: 0 additions & 1 deletion vagrant/Vagrantfile
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,5 @@ Vagrant.configure("2") do |config|
v.customize ["modifyvm", :id, "--memory", 1048]
end

config.vm.provision "file", source: "~/.ssh/id_rsa", destination: "~/.ssh/id_rsa"
config.vm.provision :shell, path: "provision.sh"
end

0 comments on commit 7bd6a1b

Please sign in to comment.