Creating a Discord bot to monitor your witness, part one - set up the bot and notifying of missed blocks.

in #utopian-io6 years ago (edited)

Repository

https://github.com/markptrueman/

What Will I Learn?

  • How to set-up a discord bot and write Nodejs code to send it Steem based information
  • Future tutorials in this series will develop this basic start into a fully functional witness monitoring solution.

Requirements

  • Basic coding knowledge
  • Some level of javascript knowledge is advantageous but not required.
  • Basic linux skills (although this tutorial can be followed on any Operating System)

Difficulty

  • Basic

Tutorial Contents

Hey everyone,

Having just started up my own witness (please vote for me if you believe I add value to the blockchain), I thought I would start doing some more tech/developer orientated blogging. I figured a great place to start would be something on how I monitor my witness node. I could just dump a github link here, but I thought it would be cool to do a more tutorial-based approach. Hopefully that would give people the opportunity to build on what I have done, learn how I have done it and become more au fait with how it works.

I like to use discord bots for my day to day monitoring as well as SMS for stuff that needs me to be reactive 24/7 (such as missed blocks), but I am sure you could plug this into telegram/slack api too. Maybe I will do that in a future tutorial. I am coding these bots up in nodejs, primarily because I like the language, but also because providers like Heroku offer a free amount of uptime that should cover 24/7 on a bot. Plus their hobby plan is reasonably priced at $7 a month.

Set up a discord bot

Screen Shot 20180813 at 21.58.41.png

Create your application

The first thing you are going to need to do is to set up a Discord bot and then add it to your Discord server. I'll assume that you have a Discord server up and running, if not, log into Discord and create one. I have a test server that I use before making anything live.

Head over to the discord developer portal at

https://discordapp.com/developers/applications/

and create your application. This is what you will now turn into a discord bot.

Choose the Bot section on the left and build a bot.

Screen Shot 20180813 at 22.39.51.png

Build a Bot

I make my bots private, so turn off the public switch. You will also want to make a note of the Bot TOKEN value under the "Click to Reveal Token" option on the bot page


Adding the bot to your server.

Screen Shot 20180813 at 22.43.48.png

In order to add the bot to your server, you will need to generate an OAuth URL with the required permissions. You so that on the OAuth2 page

Choose the scope of "bot" and then the "Send Messages" permission.


Next step is to copy the OAuth URL into a browser and then add the bot into your server when prompted. You will end up with your bot appearing offline in the server as per the image below.

Screen Shot 20180814 at 20.48.08.png

Screen Shot 20180814 at 20.49.07.png


Now we move on to coding up the bot.....

Coding.

I am not going to go into the details of installing nodejs and npm on your system. Details are available on the Nodejs website. It varies from OS to OS. Ubuntu linux installations are pretty easy though. This set of commands will install node v10 on your machine.

sudo apt update
sudo apt install -y curl software-properties-common gnupg build-essential libssl-dev
curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -
sudo apt install -y nodejs
sudo npm i npm@latest -g

Next step is to create your basic node project. The easiest way to do this is to create a default project using npm init. This effectively creates you a package.json file which is the glue behind your project, linking all of your required libraries and project together.

~/workspace $ mkdir discordexample
~/workspace $ cd discordexample/
~/workspace/discordexample $ npm init
....

After running npm init, you will be asked a number of questions. For the purposes of this, just go with the default values and you will find a package.json file created for you.

Next we will add some required libraries by running these commands in the same folder as package.json

npm install steem --save
npm install moment --save
npm install discord.io --save
npm install woor/discord.io#gateway_v6 --save

These are pretty obvious additions apart from the last one (and maybe moment - that's a library that wraps up javascript date objects). There is a compatibility issue in the discord npm library, so you need to import the gateway_v6 library as well.

Links to the pages of these libraries are here : Steem-js, Momentjs, Discord-io

Once you have run these commands, you will see them added to your package.json

In the same folder as the package.json file, create an index.js file. Open in your favourite editor (i'm a surprised fan of Microsoft VSCode) and add in the following code. I've commented it as best as I feel necessary, but if you have any questions, happy to answer them in the comments.

The basic premise is that once the bot is connected, we enter a 60-second loop. Every minute the code checks to see what the count of missed blocks is on the witness object returned from getWitnessByAccountAsync. If the count is more than the last time we have checked then we have missed a block in the last 60 seconds and we send an alert to the discord bot.

One other thing to note before you look at the code is that you will need to get your discord user id in order to sent messages and edit that in the source below. You will also need the token that you grabbed when setting up the bot. Discord user id's can be retrieved on discord as described in the source below. You will also have to edit the accountname to be the witness you are monitoring.

/** you can get your discord user id by tagging yourself in discord and then adding a backslash in front of your username
* for example  \@MarkAngelTrueman#5965
* this will return your discord user id in the format 
* <@123234234123123234>
*/


// import required libraries.
const steem = require('steem')
const discord = require('discord.io')
const moment = require('moment')

const accountname = 'markangeltrueman' // witness that you are monitoring

let missedCount = -1;

/** you can get your discord user id by tagging yourself in discord and then adding a backslash in front of your username
* for example  \@MarkAngelTrueman#5965
* this will return your discord user id in the format 
* <@123234234123123234>
* Just add the numeric part here
*/

let discorduser = '123234234123123234';
let token = 'your discord token here'

// set the steem API to use the RPC url of your choice
steem.api.setOptions({ url: 'https://api.steemit.com' });

/**
 * 
 *  Bot configuration stuff
 * 
 */
// create a new bot instance
let bot = new discord.Client({
    token: token , 
    autorun: true
});

// ready callback is fired once the bot is connected.
bot.on('ready', function() {
    console.log('Logged in as %s - %s\n', bot.username, bot.id);

    // send a message to a user id when you are ready
    bot.sendMessage({
        to: discorduser,
        message: moment().utc().format("YYYY-MM-DD HH:mm:ss") + " : Witness Monitor Bot Starting....."
    });

});

// handle a disconnect from discord by attempting to reconnect
bot.on('disconnect', function(erMsg, code) {

    console.log('----- Bot disconnected from Discord with code', code, 'for reason:', erMsg, '-----');
    bot.connect();
});

/**
 * 
 *  Main program loop
 * 
 */

let start = async() => {
    try {

        // wait 10 seconds before you start for the bot to connect
        await timeout(10)


        while(true) {

            // if the blockcount is -1, we are initialising
            if (missedCount == -1)
            {
                console.log("Initialising current blockcount....");
               // go and get witness information
               try {    
                    let witness = await steem.api.getWitnessByAccountAsync(accountname);
                    missedCount = witness.total_missed;
                    bot.sendMessage({
                        to: discorduser,
                        message: moment().utc().format("YYYY-MM-DD HH:mm:ss") +  " : " + accountname + " Initial Missed Block Count = " + missedCount
                    });
                    console.log("Initial Missed Block count = " + missedCount)
               
                    }
                catch (e){
                    console.log("Error in getWitnessByAccount " + e)
                    bot.sendMessage({
                        to: discorduser,
                        message: moment().utc().format("YYYY-MM-DD HH:mm:ss") +  " : " + accountname + " Error in getWitnessByAccount " + e
                    });
                }
            

                
            }
            else {
                // check the  missedCount against the current live missed count
                
                try {    
                    let witness = await steem.api.getWitnessByAccountAsync(accountname);
        
                    if (witness.total_missed > missedCount) 
                    {
                        // we have missed a block!!!
                        console.log("Witness has missed a block");
                        bot.sendMessage({
                                to: discorduser,
                                message: moment().utc().format("YYYY-MM-DD HH:mm:ss") +  " : ⚠⚠⚠ Witness Missed a block ⚠⚠⚠"
                            });

                        missedCount = witness.total_missed;
                    }
                }
                catch (e)
                {
                    console.log("Error in getWitnessByAccount " + e)
                    bot.sendMessage({
                        to: discorduser,
                        message: moment().utc().format("YYYY-MM-DD HH:mm:ss") +  " : " + accountname + " Error in getWitnessByAccount " + e
                    });
                }
            }

            // wait 60 seconds for next check
            await timeout(60)
        }
    } catch (e) {
        console.error('start', e)
        release();
        start()
    }
}

// a helper function to to a wait
let timeout = (sec) => {
    return new Promise(resolve => setTimeout(resolve, sec * 1000))
}

// run the main loop
start();

So thats all the coding that we are going to do in this tutorial.

In order to run the bot, type the command node index.js in the containing folder and the bot should spring into life and you will see this in the console

~/workspace/discordexample $ node index.js
Logged in as My Test Application - 478668592280502272

Initialising current blockcount....
Initial Missed Block count = 527

Hopefully, the bot should connect up to discord and your discord user should get a couple of messages

Screen Shot 20180815 at 09.05.55.png

If you miss a block, you get the following message

Screen Shot 20180815 at 09.08.09.png


In the next tutorial(s) I'll go through some of the following

  • Pulling config out into a separate config file and general code refactoring.
  • Notifications on block creation
  • Daily statistics
  • Talk to the bot to get information
  • Log file monitoring on witness node
  • Switch to backup node/disable on missing blocks
  • Using backup API endpoints
  • Alternative alerting methods

Thanks for reading.

Mark

Proof of work done

https://github.com/markptrueman/witness_monitor_tutorial


witnesssm.jpg

Please vote for me as one of your witness choices if you appreciate what I do for the STEEM blockchain. We all have 30 votes to cast and this determines who has the responsibility to keep this blockchain going.

You can vote for me here

https://v2.steemconnect.com/sign/account-witness-vote?witness=markangeltrueman&approve=1

Or go to https://steemit.com/~witnesses

and enter my name and vote

wit.jpg

Sort:  

Thank you for your contribution.
While I liked the content of your contribution, I would still like to extend one advice for your upcoming contributions:

  • Include proof of work under the shape of a gist or your own github repository containing your code.

Your contribution has been evaluated according to Utopian policies and guidelines, as well as a predefined set of questions pertaining to the category.

To view those questions and the relevant answers related to your post, click here.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hi

I have linked to my own github repository at the top of the page

https://github.com/markptrueman/witness_monitor_tutorial

Regards

Mark

hey there,
@portugalcoin was suggesting that you add your own work as a link towards the end of your tutorial, similarly to how is shown under our template, and not replacing node as the repo :)
So it is best to retain nodejs repo at the start of the tutorial, and move your own code link to the end of the tutorial.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Hi @markangeltrueman,

Thank you.


Need help? Write a ticket on https://support.utopian.io/.
Chat with us on Discord.
[utopian-moderator]

Thank you for your review, @portugalcoin!

So far this week you've reviewed 18 contributions. Keep up the good work!

Congratulations! Your post has been selected as a daily Steemit truffle! It is listed on rank 10 of all contributions awarded today. You can find the TOP DAILY TRUFFLE PICKS HERE.

I upvoted your contribution because to my mind your post is at least 22 SBD worth and should receive 241 votes. It's now up to the lovely Steemit community to make this come true.

I am TrufflePig, an Artificial Intelligence Bot that helps minnows and content curators using Machine Learning. If you are curious how I select content, you can find an explanation here!

Have a nice day and sincerely yours,
trufflepig
TrufflePig

Hey @markangeltrueman
Thanks for contributing on Utopian.
We’re already looking forward to your next contribution!

Want to chat? Join us on Discord https://discord.gg/h52nFrV.

Vote for Utopian Witness!

Coin Marketplace

STEEM 0.32
TRX 0.11
JST 0.034
BTC 66654.57
ETH 3250.95
USDT 1.00
SBD 4.33