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}