class XNM::Telegram::HTTPCore

This class handles the direct connection to the Telegram API All it does is handle a receive loop with the fitting update IDs, as well as a rescue'd “perform post” message.

Public Class Methods

new(apikey) click to toggle source
# File lib/xnm/telegram/HTTPCore.rb, line 12
def initialize(apikey)
        @apikey = apikey;

        @lastUpdateID = 0;
        # Start the receive loop. Shouldn't crash, but if it does we
        # want to know.
        @receiveThread = Thread.new do
                receive_loop();
        end
        @receiveThread.abort_on_exception = true

        # Receptors are class instances that will receive updates
        # from the HTTP update connection
        @receptors = Array.new();
end

Public Instance Methods

attach_receptor(receptorClass) click to toggle source

TODO check if the class supports handle_packet

# File lib/xnm/telegram/HTTPCore.rb, line 126
def attach_receptor(receptorClass)
        @receptors << receptorClass;
end
feed_receptors(data) click to toggle source
# File lib/xnm/telegram/HTTPCore.rb, line 82
def feed_receptors(data)
        # Hand it out to the receptors
        @receptors.each do |r|
                begin
                        r.handle_packet(data);
                rescue => e
                        warn "Error in repector: #{e}"
                        warn e.backtrace.join("\n");
                end
        end
end
perform_post(method, data = nil) click to toggle source

Perform a POST request. @param method [String] The Telegram bot API method that should be called @param data [nil, Hash] The data to be sent with the command.

Caution, any nested Hashes and Arrays will be converted to JSON
BEFORE the Hash itself is also JSON-ified. Telegram apparently
needs this to work.
# File lib/xnm/telegram/HTTPCore.rb, line 61
def perform_post(method, data = nil)
        call_address = "https://api.telegram.org/bot#{@apikey}/#{method}"

        # Rescue-construct to prevent a HTTP error from
        # crashing our system.
        timeoutLen = data[:timeout] if data.is_a? Hash
        timeoutLen ||= 3;
        retryCount = 0;
        begin
                Timeout.timeout(timeoutLen*1.3) do
                        return _raw_post(call_address, _double_json_data(data));
                end
        rescue
                retryCount += 1;
                return {} if retryCount >= 3;

                sleep 0.5;
                retry
        end
end
receive_loop() click to toggle source

Handle receiving of the data from Telegram API This is done via the “getUpdates” HTTP Request, with a timeout of 20s Update-ID offset is handled automagically by the system, so you needn't worry about it.

# File lib/xnm/telegram/HTTPCore.rb, line 99
def receive_loop()
        loop do
                begin
                        # Perform the update request
                        packet = perform_post("getUpdates", {timeout: 20, offset: @lastUpdateID + 1})

                        next unless packet[:ok];
                        # Check if there even was a message sent by Telegram
                        # Due to the 20s timeout, a zero-length reply can happen
                        next if packet[:result].length == 0;

                        # Handle each result individually.
                        packet[:result].each do |data|
                                hUpdateID = data[:update_id].to_i
                                # Calculate the maximum Update ID (for the offset "getUpdates" parameter)
                                @lastUpdateID = [hUpdateID, @lastUpdateID].max

                                feed_receptors data
                        end
                rescue
                        sleep 1
                        retry
                end
        end
end

Private Instance Methods

_double_json_data(data) click to toggle source
# File lib/xnm/telegram/HTTPCore.rb, line 28
        def _double_json_data(data)
        return {} unless data

        out_data = {}
        # JSON-Ify nested Hashes and Arrays to a String before the main
        # POST request is performed. Needed by Telegram, it seems.
        data.each do |key, val|
                if(val.is_a? Hash or val.is_a? Array)
                        out_data[key] = val.to_json
                else
                        out_data[key] = val;
                end
        end

        out_data
end
_raw_post(addr, data) click to toggle source
# File lib/xnm/telegram/HTTPCore.rb, line 45
        def _raw_post(addr, data)
        response = '';

        IO.popen(['curl', '-s', '-XPOST', '-HContent-Type: application/json', "-d#{data.to_json}", "#{addr}"]) do |resp|
                response = resp.read
        end


        JSON.parse(response, symbolize_names: true)
end