Command Line InterfaceΒΆ

The following example demonstrates a console application that is capable of saving and loading data from/to a Kademlia network.

The save & load requests are read from stdin. Depending on the request type, either load() or save() is called.

  1#include <cstdint>
  2#include <cstdlib>
  3
  4#include <future>
  5#include <iostream>
  6#include <iterator>
  7#include <sstream>
  8
  9#include <kademlia/endpoint.hpp>
 10#include <kademlia/session.hpp>
 11#include <kademlia/error.hpp>
 12
 13namespace k = kademlia;
 14
 15namespace {
 16
 17const char HELP[] =
 18"save <KEY> <VALUE>\n\tSave <VALUE> as <KEY>\n\n"
 19"load <KEY>\n\tLoad value associated with <KEY>\n\n"
 20"help\n\tPrint this message\n\n";
 21
 22std::vector< std::string >
 23split( std::string const& line )
 24{
 25    std::istringstream in{ line };
 26
 27    using iterator = std::istream_iterator< std::string >;
 28    return std::vector< std::string >{ iterator{ in }, iterator{} };
 29}
 30
 31void
 32load( k::session & session
 33    , std::string const& key )
 34{
 35    auto on_load = [ key ] ( std::error_code const& error
 36                           , k::session::data_type const& data )
 37    {
 38        if ( error )
 39            std::cerr << "Failed to load \"" << key << "\"" << std::endl;
 40        else
 41        {
 42            std::string const& str{ data.begin(), data.end() };
 43            std::cout << "Loaded \"" << key << "\" as \""
 44                      << str << "\"" << std::endl;
 45        }
 46    };
 47
 48    session.async_load( key, std::move( on_load ) );
 49}
 50
 51void
 52save( k::session & session
 53    , std::string const& key
 54    , std::string const& value )
 55{
 56    auto on_save = [ key ] ( std::error_code const& error )
 57    {
 58        if ( error )
 59            std::cerr << "Failed to save \"" << key << "\"" << std::endl;
 60        else
 61            std::cout << "Saved \"" << key << "\"" << std::endl;
 62    };
 63
 64    session.async_save( key, value, std::move( on_save ) );
 65
 66}
 67
 68void
 69print_interactive_help
 70        ( void )
 71{
 72    std::cout << HELP << std::flush;
 73}
 74
 75} // anonymous namespace
 76
 77int main
 78        ( int argc
 79        , char** argv )
 80{
 81    // Check command line arguments count
 82    if ( argc != 3 )
 83    {
 84        std::cerr << "usage: " << argv[0] << " <PORT> <INITIAL_PEER>" << std::endl;
 85        return EXIT_FAILURE;
 86    }
 87        
 88    // Parse command line arguments
 89    std::uint16_t const port = std::atoi( argv[1] );
 90    k::endpoint initial_peer;
 91    std::istringstream{ argv[2] } >> initial_peer;
 92
 93    // Create the session
 94    k::session session{ initial_peer
 95                      , k::endpoint{ "0.0.0.0", port }
 96                      , k::endpoint{ "::", port } };
 97
 98    // Start the main loop thread
 99    auto main_loop = std::async( std::launch::async
100                               , &k::session::run, &session );
101
102    // Parse stdin until EOF (CTRL-D in Unix, CTRL-Z-Enter on Windows))
103    std::cout << "Enter \"help\" to see available actions" << std::endl;
104    for ( std::string line; std::getline( std::cin, line ); )
105    {
106        auto const tokens = split( line );
107
108        if ( tokens.empty() )
109            continue;
110
111        if ( tokens[0] == "help" )
112        {
113            print_interactive_help();
114        }
115        else if ( tokens[0] == "save" )
116        {
117            if ( tokens.size() != 3 )
118                print_interactive_help();
119            else
120                save( session, tokens[1], tokens[2] );
121        }
122        else if ( tokens[0] == "load" )
123        {
124            if ( tokens.size() != 2 )
125                print_interactive_help();
126            else
127                load( session, tokens[1] );
128        }
129        else
130            print_interactive_help();
131    }
132
133    // Stop the main loop thread
134    session.abort();
135
136    // Wait for the main loop thread termination
137    auto failure = main_loop.get();
138    if ( failure != k::RUN_ABORTED )
139        std::cerr << failure.message() << std::endl;
140}