How To Listen To Steem Blockchain Events Using Meeseker In Node.js

in #utopian-io5 years ago (edited)

Repository

https://github.com/Vheissu/meseeker-node-tutorial

What Will I Learn?

  • How to install Redis (Step 1)
  • How to install Node.js and Node Package Manager (Step 2)
  • How to install Ruby via RVM (Step 3)
  • How to install the Meeseeker package (Step 4)
  • How to run the Meeseeker package (Step 5)
  • How to subscribe and listen to Redis channels and messages in Node.js (Step 6)

Requirements

  • A machine running Linux. If you're using Windows, you will need to install and configure the Windows Subsystem for Linux (WSL). An official guide for configuring and installing WSL can be found here on the Microsoft Docs website. I recommend installing the user-friendly Debian based Ubuntu distribution
  • A machine with at least 8gb of ram, if you're installing on a server for dApp usage, you will want 8gb, preferrably 16gb if you want to increase the Redis keys size
  • A decent understanding of Javascript and concepts
  • (preferably) experience working with Node.js previously
  • A code editor. I recommend Visual Studio Code by Microsoft. A free and fully-featured extensible coding environment

Difficulty

Intermediate

Tutorial Contents

While we will aim to cover quite a few topics as detailed in the, "What Will I Learn" section above, this tutorial will help you get comfortable with the Meeseeker package by @inertia and subscribe to Redis events and messages.

Please keep in mind this tutorial will be done from within Ubuntu Linux. Commands may differ for other operating systems, especially if you're a macOS user, you will most likely be using the Homebrew package manager to install packages. Please refer to the website for the packages and tools installed in this tutorial for macOS.

Step 1: Installing Redis

Before installing new packages, we need to call the Apt update command to update the Apt package cache:

sudo apt update

image.png

Then to install Redis all we need to do is run:

sudo apt install redis-server

image.png

Because I am using Windows Subsystem for Linux (WSL) I had to run the following command to ensure Redis server started:

sudo service redis-server start

image.png


Step 2: Install Node.js

We are going to be installing the LTS release, which is the most stable and recommended version of Node.js to install. It has the best compatibility with packages within the Node ecosystem.

At the time of writing, the latest LTS is 10.15.3. Please check the Node.js official website to check the latest Node.js LTS version before installing.

As per the officially provided instructions here we are going to be installing Node.js for version 10.x.

curl -sL https://deb.nodesource.com/setup_10.x | sudo -E bash -

image.png

Once this command completes, we can then install Node.js using the Apt package manager:

sudo apt-get install -y nodejs

image.png

This command will install both Node.js as well as the Node Package Manager (npm). In my instance, I already had an older version of Node.js and Npm installed, so it updated Node and removed the older version of Npm before installing the newer version. If you have not installed Node before, nothing changes.

Once this command has finished, you can confirm that Node.js has properly installed by running the following command:

node -v

image.png

Similarly, you can also confirm Node Package Manager (npm) also installed by running:

npm -v

image.png


Step 3: Install Ruby via Ruby Version Manager (RVM)

Install RVM

We are going to be following the officially provided installation instructions from the rvm.io website. Please refer to the official website to confirm the following instructions are still up-to-date and relevant, specifically, the GPG keys.

image.png

For brevity, we are going to be following along with the official installation instructions here in this tutorial, but please confirm they're up-to-date from the above link before continuing.

The first installation instruction is to add the GPG key to your machine. When I first ran this command, I ran encountered an error because the gnupg2 package was not installed by default in Ubuntu (as can be seen below).

image.png

As you can see, Ubuntu told me the package was missing and how to install it. So, if you get the same missing package message, run the provided command like below.

image.png

I then run the GPG command again from the rvm.io website:

image.png

It is worth noting in my particular instance, I had to run this command twice for some reason because of an RPC error (as the screenshot above highlights). So, if you encounter any issues, try running it a second time.

image.png

And now finally, we install Ruby using RVM:

\curl -sSL https://get.rvm.io | bash -s stable

image.png

Pay close attention to the line towards the bottom of the completed installation command about needing to start RVM. Run the following command so you can use RVM within the current terminal window.

Pay close attention to the /home/username part below, you will want to run the command provided to you, which coincides with your currently logged in user. Replace dwayne below with your own username, don't just copy and paste the command or you will get an error (unless your username is also dwayne, ha).

source /home/dwayne/.rvm/scripts/rvm

If you have any issues with the installation, the solution posted here on SuperUser will help you fix any problematic permissions on your folders.

Install Ruby

We now need to download and install the latest stable version of Ruby. At the time of writing this, the latest stable version is 2.6.2 please refer to the official Ruby website before installing to ensure you have the latest.

rvm install "ruby-2.6.2"

image.png

Depending on your machine and internet connection speed, this step might take a while as Ruby is downloaded and installed from source code (it's compiled). So, this step could take upwards of 10 or so minutes.


Step 4: Installing the Meeseeker Gem

This is by far the easiest step of them all, installing the Meeseeker package which is a Ruby Gem. Provided the previous Ruby installation went to plan, you should be able to run the following command to install Meeseeker.

gem install meeseeker

image.png

This step can take a few minutes depending on your machine and internet connection speed as packages are downloaded and built from source (similar to the Ruby installation process). Fortunately, this should be much faster than the previous step.

Once the installation of the Gem has completed, let's make sure Meeseeker installed correctly by running the help command:

meeseeker help

image.png


Step 5: Run Meeseeker

Now that we have meeseeker installed, we can run the sync command which will start streaming the Steem blockchain and add the results into Redis, which we can subscribe to using channels.

meeseeker sync

image.png

By default, the sync command does a lot and stores a lot of needless information (like virtual operations), which in many cases is not what you want to happen. A full list of supported configuration values via the command line can be found in the README for the official Meeseeker package here.

For the purposes of this tutorial, we only want to listen to transfers because we're making a transaction bot, so let's make Meeseeker run a little lighter.

We don't care about virtual operations, so let's set the MEESEEKER_INCLUDE_VIRTUAL environment variable to false. We also don't want the block header information (because it requires additional calls), so we set the MEESEEKER_INCLUDE_BLOCK_HEADER environment variable to false as well.

Finally, by default, keys are stored in Redis for 24 hours, which in some cases can use a lot of RAM, we want to reduce that to 10 minutes. By setting the MEESEEKER_EXPIRE_KEYS environment value (in seconds) we can reduce the memory usage of Redis.

The final command we arrive at is the following:

MEESEEKER_INCLUDE_VIRTUAL=false MEESEEKER_INCLUDE_BLOCK_HEADER=false MEESEEKER_EXPIRE_KEYS=600 meeseeker sync

image.png

Running the command will yield a constantly streaming wall of blockchain operations happening on Steem. In the next step, we'll create a simple Node.js application that subscribes to a Redis channel and gets transfers. Depending on your use case, you might want to explore different values to the above ones.

Keep this running and open up a new separate terminal window. We will be interfacing with Redis in the next step.

Step 6: Creating a Node.js application and subscribing to Redis channels

The Meeseeker package is publishing numerous Redis channels which we can subscribe to, depending on the events we are interested in. The official package repo provides a list of valid channels you can subscribe to here.

In Visual Studio Code (or editor of choice) we want to create a new file called api.js and save this somewhere (maybe a new folder specifically for the project).

The contents of our Node application will be the following:

const Redis = require('ioredis');
const subscriber = new Redis();
const redis = new Redis();

subscriber.subscribe('steem:op:transfer', () => {
        subscriber.on('message', async (channel, message) => {
                const payload = JSON.parse(message);
                const transfer = JSON.parse((await redis.get(payload['key'])));
                
                console.log(transfer);
        });
});

In your terminal window, navigate to the location of this file and run npm init:

npm init

image.png

We now need to install the ioredis package which allows us to communicate with our Redis server that we installed and started in Step 1.

npm install ioredis

image.png

If you copied and pasted the code snippet from above into api.js, and you still have meeseeker running, you can run our Node application by running the following:

node api.js

image.png

Every time I have ever run this code, I notice that @magicdice by far dominates the transfer operations here on Steem. When you run the code, you'll see the same thing most likely.

The code line-by-line

There would be no use to providing you with a snippet of code that might look pretty foreign to some and not explain what is going on. The code above when run produces a wall of text like the first time we ran meeseeker, but you might notice it's a stream of transfers.

const Redis = require('ioredis');

This imports the ioredis package which allows us to interface with the Redis service. It's a standard Node style CommonJS require import.

const subscriber = new Redis();
const redis = new Redis();

These two lines are probably self-explanatory, but worth pointing out why there are two of them. The first one sets up a Redis instance for subscribing to channels. When you subscribe to channels in Redis, it makes the instance become subscriber only, so querying commands like get will not work.

We set up a second identical instance which will only be used for querying.

subscriber.subscribe('steem:op:transfer', () => {

Using our subscriber instance, we call the subscribe method and pass in the channel name. In this instance, we want to listen to transfers, so we use the steem:op:transfer channel.

subscriber.on('message', async (channel, message) => {

Once you are listening to the channel, you want to listen to all of the messages being emitted from within. Every transfer will fire off an event. You'll notice on the callback function we use the async keyword, this is because we want to call the get method later on and it returns a Javascript promise with the data.

const payload = JSON.parse(message);

The message in this instance is a JSON string which we parse back into an object using JSON.parse. The payload has a key which we can then use to pull the data out of Redis.

const transfer = JSON.parse((await redis.get(payload['key'])));

This line gets the actual Steem transfer information. The payload itself has a key property which we use to query Redis itself using redis.get('thekeyname') this is because Redis is a key/data store, where each item is stored by a unique key.

You might notice the await keyword, this accompanies the async keyword on the callback and allows us to await the promise that redis.get returns with the data. Also worth noting is we use the redis instance, not the subscriber instance, so we can call get to query Redis for the data.

console.log(transfer);

Self-explanatory if you know Javascript, this is what prints out the data from the Redis query as we saw in the above screenshot with transfer object data.

Try subscribing to different channels...

The code above will work for all channel types. Try changing steem:op:transfer to steem:op:comment or steem:op:vote and run the code to see different data. The code inside remains the same.

If you wanted to create a bot that watched for transfers to a specific account you would write something like this:

if (transfer.value.from === 'beggars') {
    // Someone sent something to my @beggars account
    // we could send back a thank you or in exchange, send them some Steem Engine tokens
}

And if you wanted to get the amount being sent and other details:

// Destructure the amount from the object
const { amount } = transfer.value.amount;

// Who sent the transfer
const from = transfer.value.from;

// Get the memo for the transfer
const memo = transfer.value.memo;

Conclusion

What we have here is the workings of a bot capable of listening to transactions and then using a client like the Steem-js SDK, react to those transfers accordingly. One common use-case would be to watch transfers to a specific account, get the amount and then react accordingly (upvote, send a custom Steem Engine token).

In a future tutorial we might expand upon this code and build a bot, but that is outside of the scope of this tutorial.

Sort:  

Thank you for your contribution @beggars.
After reviewing your tutorial we suggest the following points listed below:

  • Avoid installation steps which are already well documented.

  • Code sections are better displayed using the code markup, instead of placing them as screenshots. Placing the code screenshot and then the code below the screenshot is unnecessary as it's repeating information.

  • The structure of your tutorial is fine and also well explained. Good work!

  • Why is the repository and proof of work the same link?

Thank you for your work in developing this tutorial.
Looking forward to your upcoming tutorials.

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? Chat with us on Discord.

[utopian-moderator]

Thanks for the thorough review, @portugalcoin

Avoid installation steps which are already well documented.

I am just a very verbose person, but this is good to know for future submissions, as it will mean less typing for me anyway, ha. I generally like being as descriptive as possible and from my own experiences learning from tutorials, it's a personal preference for me that the tutorial includes everything so I don't have to context switch. But, definitely, the kind of feedback I'll take on board.

Code sections are better displayed using the code markup, instead of placing them as screenshots. Placing the code screenshot and then the code below the screenshot is unnecessary as it's repeating information.

Are you referring to step 6? The code snippet from Visual Studio Code and then the code beneath? That was actually a mistake, I was in screenshot mode from the other steps and didn't realise. My apologies. Was this the only screenshot you were referring to?

If this was also in reference to the screenshots of the terminal window, those were provided for comparative purposes so that the tutorial follower would be able to reference the output of the commands with what I saw.

I removed the unnecessary code screenshot and just left the code example.

I noticed in the review under, "How would you describe the formatting, language and overall presentation of the post?" that it said average. What advice do you have to get that score up for future tutorials? Because I made sure that I made each step visually clear using proper headings, spacing out sections using horizontal lines, Markdown code blocks for code (both code and shell commands).

Why is the repository and proof of work the same link?

I think maybe this might be a good improvement to make in the official tutorial template provided by Utopian because I interpret a repository with the code in it as proof of the work done. For future reference, what is the distinction between the two of these? Should only one of them be provided in this instance?

Thanks for the thorough review, I greatly appreciate it.

Hi @beggars,

Are you referring to step 6? The code snippet from Visual Studio Code and then the code beneath? That was actually a mistake, I was in screenshot mode from the other steps and didn't realise. Was this the only screenshot you were referring to?

  • Yes, it was the only printscreen I mentioned ( Step 6 ).

For future reference, what is the distinction between the two of these?

  • The repository would be ideal to put for example the github link of Nodejs and the proof of work the link of your code as proof that is your code.

  • For more information see this link

I hope to see more of your tutorials and thank you for your interest in knowing what points to improve.


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

Legendary. Thanks for the response, @portugalcoin love your work.

Posted using Partiko Android

You are a class act!

Thank you for your review, @portugalcoin! Keep up the good work!

@lordnigel - this might be useful for you?

Absolutely brilliant post and work mate but with all due respect, I think I'll wait for the 'Dummies' guide to be published ;-)
Thanks for all the hard work you do here and best wishes to you and yours.

Posted using Partiko Android

Super cool step-by-step guide and awesome repository! I can see me using this in my next project somehow! Thanks for sharing!!

Peace!

Posted using Partiko Android

Hey, @beggars!

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

Get higher incentives and support Utopian.io!
Simply set @utopian.pay as a 5% (or higher) payout beneficiary on your contribution post (via SteemPlus or Steeditor).

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

Vote for Utopian Witness!

This post has been included in the latest edition of SoS Daily News - a digest of all the latest news on the Steem blockchain.

Wow I had no idea you are such a nerd! This looks cool.

Im a thickie in plain sight! lol

Posted using Partiko Android

Hi @beggars!

Your post was upvoted by @steem-ua, new Steem dApp, using UserAuthority for algorithmic post curation!
Your post is eligible for our upvote, thanks to our collaboration with @utopian-io!
Feel free to join our @steem-ua Discord server

Emailed 👌


Powered by witness untersatz!

Coin Marketplace

STEEM 0.18
TRX 0.17
JST 0.032
BTC 63686.15
ETH 2727.43
USDT 1.00
SBD 2.59