HTTPS REST (Crypto Price monitor)

in #utopian-io6 years ago (edited)

Godot Engine Logo (Expert).png How to gather real-time value for Bitcoin (any Crypto)!
Welcome to my first Expert tutorial!

I plan to create an app that runs on my Mobile devices, PC and Laptop. I want to log my Crypto currency purchases and have the app report, in real-time, price fluctations etc.

YES, this has been done, plenty of times! I.E. you don't have to look any further than Blockfolio for a fantastic App!

However, I want to build my own, because:

  • I don't truly trust these tools. As my portfolio grows, I don't want a leakage of how much I own (there's a VERY long way before that day!). I know the Blockfolio tool, for example, connects to a server and I have NO idea whether this information leaks back. If it does, and I had a large amount, I would NOT appreciate it.
  • I potentially would like to add my own price monitoring and buy/sell positions.
  • I can :-)

Given my reasons, the first concern to address is:

  • How do I connect to a web service that provides real-time price information?

There are LOTS of free providers for this information! Yes, it is possible to connect to your exchanges too! For example, Bittrex provides a great API, that not only provides information, but enable you to buy and sell too!

However, for this tutorial, I needed something more publicly availalbe. I found Cryptocompare, which is a great service, because they kindly provide a public API.

So before getting into code, let's test their API:

https://min-api.cryptocompare.com/data/price?fsym=BTC&tsyms=GBP

Which returns a simple JSON string, containing the current price of Bitcoin in British Pounds. You can probably figure out the parameters above, but refer to the API documentation for more options! The following was the price I received on Jan 27th 2018 (it has most likely changed dramatically since then!)

Note:

  • The price wont necessarily match other services or exchanges, because their source data will likely be different.

Given the API, it is evident that HTTP connections from Godot Engine, over SSL (Secure Sockets Layer) have to be made. SSL Provides the encryption required to safely transmit and receive data with Cryptocompare.

Godot Engine provides two capabilities to do this:

  1. HTTPClient - an HTTP conforming class that enables Godot Engine to send and receive requests; i.e. to send a request to a server and receive its content back, such as a webpage or JSON response.
  2. StreePeerSSL - a SSL wrapper, used by HTTPClient to encrypt and de-encrypt HTTP messages; thereby supporting the HTTPS protocol standard.

Programming this call is straight forward, however, configuration is a little more tricky because of the SSL element. SSL requires a trust certificate to be included with the code. When the program is executed, a negotiation between the App and Cryptocompare is attempted. The certificate is required to ensure that security keys between them are swapped and established. I will explain more further down.

Example code

A new project is required with a simple Node, Timer and Text Label:

I called my project CryptoPriceChecker, but you can call yours what you like.

The Timer was configured to:

  • Execute with a wait time of 60 seconds (lets not swamp Cryptocompare)
  • Autostart:

I wanted the Timer to continually timeout, every second, thereby triggering a call to Cryptocompare to get the latest price for the price to be placed into the Label.

The Label was just placed into the scene to be run. It can be sized and changed as required.

The key to the success of this Tutorial is assigning a script to a Node, called PriceChecker in my scene:

extends Node

const DOMAIN = "min-api.cryptocompare.com"
const PORT = 443
const QUERY_STRING = "/data/price?fsym=BTC&tsyms=GBP"

const HTTP_HEADER = [
    "User-Agent: Pirulo/1.0 (Godot)",
    "Accept: */*"
]

const WAIT_STATES_REQUEST = [HTTPClient.STATUS_REQUESTING, 
                             HTTPClient.STATUS_RESOLVING, 
                             HTTPClient.STATUS_CONNECTING]

var http

func _ready():
    http = HTTPClient.new()
    update()
    get_node("Timer").connect("timeout", self, "update")

func update():
    get_node("Label").set_text("£"+str(getPrice().GBP))

func getPrice():
    var err = http.connect(DOMAIN,PORT,true,true)
    httpWait(WAIT_STATES_REQUEST)
    if (http.get_status() == HTTPClient.STATUS_CONNECTED):
        http.request(HTTPClient.METHOD_GET, QUERY_STRING, HTTP_HEADER)
        httpWait(WAIT_STATES_REQUEST)
        return getDataAsJson()
    else:
        return {"GBP":"error!"}

func httpWait(waitStates):
    while (waitStates.has(http.get_status())):
        http.poll()
        OS.delay_msec(500)

func getDataAsJson():
    var json = {}
    var rb = RawArray() 
    while(http.get_status()==HTTPClient.STATUS_BODY):
        http.poll()
        var chunk = http.read_response_body_chunk()
        if (chunk.size()==0):
            OS.delay_usec(1000)
        else
            rb = rb + chunk
    json.parse_json(rb.get_string_from_ascii())
    return json

An explanation of the code:

  • The Ready function initialises an HTTPClient to the global variable, triggers a get request to update the Label and then connects the Timer to call 'update' every 60 seconds.
  • The Update function accepts a JSON in the format of {"GBP": "#value#"} and places the #value# into the Label.
  • The getPrice function initiates a connection to the domain, waits until the connection returns a non-connecting state and then issues the API call if a connection is established. The result of which is returned OR "error!" is returned to indicate a problem with the Request failed.
  • The httpWait function is a helper. Given an array of statuses, it loops until the status is not in the list. Using the OS.delay_msec to ensure the thread of the App is not blocked whilst waiting.
  • The getDataAsJson function is also a helper. It takes a connected HTTP connection and retreives the body of the http request by requesting each HTTP chunk and concatenating to an array. Once all chunks are received, the array is converted to a string and parsed as a JSON element.

This script delivers the regular updating of the Label, based on the Timer's execution.

There is little Error handling, therefore it could be significantly improved. It's purpose is to demonstrate how to establish an HTTPS request/response invocation.

An output can be seen here:


IMPORTANT - Certificates before it will execute

Before this App can be executed, there is a requirement to configure the SSL certificate. As stated above, the SSL mechanism requires a trust store to negotiate the encryption handshake.

After the request is made, Cryptocompare will return it's private key to the App. The App will store it in its trust store and pass on it's own private key. Without the certificate store, the handshake negotiation cannot occur and you will receive an error in the output console (as highlighted below) if you start the App before configuring a certificate:

To configure the App correctly, you will need to either create a Self-Sign Certificate or obtain a valid one.

An explaination is provided in the documentation, however I found it frustrating and I understand how certificates are used. The article states what is required, but NOT how to create it!

I'm used to creating Java Trust Stores and they generate certificates via a standard tool. For Windows and Godot Engine, my knowledge was lacking and googling didn't help, until I stumbled over a Bug Report against Godot Engine. If you scroll down to Gramps comment on 31 Aug 2017, you'll find the Certificate file that would normally be extracted from Linux. I'm not sure how long it will remain in that post, but you can download the certificate.

  • Unzip the file and copy the ca-certificates.crt into your project.
  • Open your Project Settings:

  • Enable and Configure the SSL certificate to point to the file you downloaded and placed into your project

Finally, the example should execute!

Good luck reusing this technique. You are more than welcome to reuse any of the code (I place it under a MIT license; not that there is a lot of code there).

I plan to create a GitHub repository eventually. If you really need the entire project, please let me know here and I'll prioritise doing so.

Please do Upvote this and provide me feedback.


Tutorials Index

Sort:  

Late to the party, but this had a good quick overview that answered my question (on example of https in godot) I was about to google. Glad I found it here instead!

Never late! Welcome to my articles! Thanks that you found it as I hope it helps. Let me know if there are other things you are looking for and I'll see if I can write about them.

Coin Marketplace

STEEM 0.20
TRX 0.13
JST 0.030
BTC 64752.70
ETH 3455.13
USDT 1.00
SBD 2.50