eosauthority / eosio-watcher-plugin

EOSIO watcher plugin: HTTP POST to endpoint for on chain actions
MIT License
66 stars 30 forks source link

pr/14 #17

Open ghost opened 4 years ago

ghost commented 4 years ago

+#pragma once

include <boost/asio/ip/tcp.hpp>

include <boost/asio/use_future.hpp>

include <fc/variant.hpp>

include <fc/reflect/variant.hpp>

include <fc/time.hpp>

include <fc/network/http/http_client.hpp>

include

namespace eosio {

using namespace fc; namespace asio = boost::asio;

template struct final_action { final_action(F f) : clean{f} {} ~final_action() { clean(); } private: F clean; };

template final_action finally(F f) { return final_action(f); }

class http_async_client { public:

  http_async_client() : sync_client(std::make_unique<http_client>()),
                        work_guard(asio::make_work_guard(ioc)) {
  }

  ~http_async_client() {
     work_guard.reset();
  }

  void start() {
     worker = std::make_unique<std::thread>( [this]() {
        ioc.run();
     });
  }

  void stop() {
     work_guard.reset();
     worker->join();
  }

  // TODO: return result as future
  template<typename T>
  void post(const url& dest, const T& payload,
            const time_point& deadline = time_point::maximum()) {

     // Make sure only sync_client and these arguments (copied by value) are accessed from
     //  separate tread.
     // T type could have pointers, but it doesn't make sense for payload to have them anyway.
     asio::post( ioc.get_executor(), [this, dest, payload, deadline]() {
        post_sync(dest, payload, deadline);
     });
  }

  // TODO: implement. Add call_impl function which could be used by post as well as these.

// void add_cert(const std::string& cert_pem_string); // void set_verify_peers(bool enabled);

private: template void post_sync(const url& dest, const T& payload, const time_point& deadline = time_point::maximum()) {

     auto exit = finally( [this](){ retry = true; } );

     try {
        sync_client->post_sync(dest, payload, deadline);
     } catch( const fc::eof_exception& exc) {
        // FIXME: http_client expects body in response and throws eof if it doesn't get it.
     } catch( const fc::assert_exception& exc ) {
        // Thrown when sending or reading response fails
        // Try once more
        wlog("Exception while trying to send: ${exc}", ("exc", exc.to_detail_string()));
        if( retry ) {
           wlog("Trying again");
           retry = false;
           post_sync(dest, payload, deadline);
        }
     }
     FC_CAPTURE_AND_LOG( (dest)(payload)(deadline) )

  }

  std::unique_ptr<http_client>                               sync_client;
  std::unique_ptr<std::thread>                               worker;
  asio::io_context                                           ioc;
  asio::executor_work_guard<asio::io_context::executor_type> work_guard;
  bool                                                       retry = true;

}; }