ana/apps/chat/client.cpp

Go to the documentation of this file.
00001 /* $Id: client.cpp 52533 2012-01-07 02:35:17Z shadowmaster $ */
00002 
00003 /**
00004  * @file
00005  * @brief Client side chat application. Example for the ana project.
00006  *
00007  * ana: Asynchronous Network API.
00008  * Copyright (C) 2010 - 2012 Guillermo Biset.
00009  *
00010  * This file is part of the ana project.
00011  *
00012  * System:         ana
00013  * Language:       C++
00014  *
00015  * Author:         Guillermo Biset
00016  * E-Mail:         billybiset AT gmail DOT com
00017  *
00018  * ana is free software: you can redistribute it and/or modify
00019  * it under the terms of the GNU General Public License as published by
00020  * the Free Software Foundation, either version 2 of the License, or
00021  * (at your option) any later version.
00022  *
00023  * ana is distributed in the hope that it will be useful,
00024  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00025  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
00026  * GNU General Public License for more details.
00027  *
00028  * You should have received a copy of the GNU General Public License
00029  * along with ana.  If not, see <http://www.gnu.org/licenses/>.
00030  *
00031  */
00032 
00033 #include <iostream>
00034 #include <iomanip>
00035 
00036 #include "ana.hpp"
00037 
00038 using namespace ana;
00039 
00040 const port DEFAULT_PORT = "30303";
00041 
00042 const char* const DEFAULT_ADDRESS = "127.0.0.1";
00043 const char* const DEFAULT_NAME    = "Unnamed";
00044 
00045 
00046 void show_help(char* const command)
00047 {
00048     std::cout << "The following options should be given in order and are all optional:\n"
00049         "\tName:            [recommended] Set name. Default=" << DEFAULT_NAME << std::endl <<
00050         "\tAddress:         [optional]    Set address. Default=" << DEFAULT_ADDRESS << std::endl <<
00051         "\tPort:            [optional]    Set port. Default=" << DEFAULT_PORT << std::endl <<
00052         "\tProxy address:   [optional]    Set proxy address." << std::endl <<
00053         "\tProxy port:      [optional]    Set proxy port." << std::endl <<
00054         "\tProxy user:      [optional]    Set proxy authentication user name." << std::endl <<
00055         "\tProxy password:  [optional]    Set proxy authentication password." << std::endl <<
00056         "Examples:\n" <<
00057         "\t" << command << " billy localhost 12345\n" <<
00058         "\t\tConnect to a local server on port 12345 with nick billy.\n" <<
00059         "\t" << command << " billy X.K.C.D 12345 localhost 3128 foo bar\n" <<
00060         "\t\tConnect to a remote server at X.K.C.D:12345 with proxy credentials foo:bar.\n\n";
00061         ;
00062 }
00063 
00064 struct connection_info
00065 {
00066     connection_info() :
00067         pt(DEFAULT_PORT),
00068         address(DEFAULT_ADDRESS),
00069         name(DEFAULT_NAME),
00070         proxyaddr(),
00071         proxyport(),
00072         user(),
00073         password()
00074     {
00075     }
00076 
00077     bool use_proxy() const
00078     {
00079         return proxyaddr != "" && proxyport != "";
00080     }
00081 
00082     port        pt;
00083     std::string address;
00084     std::string name;
00085     std::string proxyaddr;
00086     std::string proxyport;
00087     std::string user;
00088     std::string password;
00089 };
00090 
00091 class ChatClient : public ana::listener_handler,
00092                    public ana::send_handler,
00093                    public ana::connection_handler
00094 {
00095     public:
00096         ChatClient(connection_info ci) :
00097             conn_info_( ci ),
00098             continue_(true),
00099             client_( ana::client::create(ci.address, ci.pt) ),
00100             name_(ci.name)
00101         {
00102         }
00103 
00104         std::string get_name(const std::string& msg)
00105         {
00106             size_t pos = msg.find(" ");
00107 
00108             return msg.substr(pos+1);
00109         }
00110 
00111         double get_seconds(const std::string& msg)
00112         {
00113             size_t pos = msg.find(" ");
00114 
00115             std::stringstream ss( msg.substr(pos+1) );
00116 
00117             double result;
00118 
00119             ss >> result;
00120 
00121             return result;
00122         }
00123 
00124 
00125         void parse_command(const std::string& msg)
00126         {
00127             if (msg[1] == 'n') //Lame: assume name command
00128                 name_ = get_name(msg);
00129             else if (msg[1] == 's')
00130             {
00131                 const ana::stats* acum_stats = client_->get_stats( ana::ACCUMULATED );
00132                 const ana::stats* sec_stats  = client_->get_stats( ana::SECONDS );
00133                 const ana::stats* min_stats  = client_->get_stats( ana::MINUTES );
00134                 const ana::stats* hour_stats = client_->get_stats( ana::HOURS );
00135                 const ana::stats* day_stats  = client_->get_stats( ana::DAYS );
00136 
00137                 std::cout << "                  Network  Statistics\n\n"
00138                     << "Uptime : " << acum_stats->uptime() << " seconds.\n\n"
00139                     << "+-----------------+-----------------+-----------------+\n"
00140                     << "|                 |     Packets     |      Bytes      |\n"
00141                     << "|                 +-----------------+--------+--------+\n"
00142                     << "|                 |   In   |  Out   |   In   |   Out  |\n"
00143                     << "+-----------------+--------+--------+--------+--------+\n"
00144                     << "|   Accumulated   |" << std::setw(8) << acum_stats->packets_in() <<"|"
00145                                             << std::setw(8) << acum_stats->packets_out() <<"|"
00146                                             << std::setw(8) << acum_stats->bytes_in() <<"|"
00147                                             << std::setw(8) << acum_stats->bytes_out() <<"|\n"
00148                     << "+-----------------+-----------------+-----------------+\n"
00149                     << "|   Last second   |" << std::setw(8) << sec_stats->packets_in() <<"|"
00150                                             << std::setw(8) << sec_stats->packets_out() <<"|"
00151                                             << std::setw(8) << sec_stats->bytes_in() <<"|"
00152                                             << std::setw(8) << sec_stats->bytes_out() <<"|\n"
00153                     << "+-----------------+-----------------+-----------------+\n"
00154                     << "|   Last minute   |" << std::setw(8) << min_stats->packets_in() <<"|"
00155                                             << std::setw(8) << min_stats->packets_out() <<"|"
00156                                             << std::setw(8) << min_stats->bytes_in() <<"|"
00157                                             << std::setw(8) << min_stats->bytes_out() <<"|\n"
00158                     << "+-----------------+-----------------+-----------------+\n"
00159                     << "|    Last hour    |" << std::setw(8) << hour_stats->packets_in() <<"|"
00160                                             << std::setw(8) << hour_stats->packets_out() <<"|"
00161                                             << std::setw(8) << hour_stats->bytes_in() <<"|"
00162                                             << std::setw(8) << hour_stats->bytes_out() <<"|\n"
00163                     << "+-----------------+-----------------+-----------------+\n"
00164                     << "|    Last  day    |" << std::setw(8) << day_stats->packets_in() <<"|"
00165                                             << std::setw(8) << day_stats->packets_out() <<"|"
00166                                             << std::setw(8) << day_stats->bytes_in() <<"|"
00167                                             << std::setw(8) << day_stats->bytes_out() <<"|\n"
00168                     << "+-----------------+-----------------+-----------------+\n";
00169             }
00170             else if ( msg[1] == 'h' )
00171             {
00172                 double seconds = get_seconds( msg );
00173                 client_->expecting_message( ana::time::seconds( seconds ) );
00174             }
00175         }
00176 
00177         void run_input()
00178         {
00179             std::string msg;
00180             do
00181             {
00182                 std::cout << name_ << " : ";
00183                 std::getline(std::cin, msg);
00184 
00185                 if (msg[0] == '/')
00186                     parse_command(msg);
00187 
00188                 if (msg == "/quit")
00189                     std::cout << "\nExiting.\n";
00190                 else if (msg == "/empty")
00191                 {
00192                     const std::string empty_str;
00193 
00194                     client_->send( ana::buffer( empty_str ), this );
00195                 }
00196                 else
00197                     if (!msg.empty())
00198                         client_->send( ana::buffer( msg ), this);
00199 
00200             } while ( (msg != "/quit") && continue_);
00201 
00202             client_->disconnect();
00203         }
00204 
00205         void run()
00206         {
00207             try
00208             {
00209                 if ( ! conn_info_.use_proxy() )
00210                     client_->connect( this );
00211                 else
00212                     client_->connect_through_proxy(conn_info_.proxyaddr,
00213                                                    conn_info_.proxyport,
00214                                                    this,
00215                                                    conn_info_.user,
00216                                                    conn_info_.password);
00217 
00218                 client_->set_listener_handler( this );
00219                 client_->run();
00220                 client_->set_timeouts(ana::FixedTime, ana::time::seconds(10));
00221 
00222                 std::cout << "Available commands: \n"  <<
00223                              "    '/quit'      : Quit. \n"
00224                              "    '/who'       : List connected users. \n" <<
00225                              "    '/stats'     : Print full network stats. \n" <<
00226                              "    '/hold secs' : Wait secs for a new message. \n" <<
00227                              "    '/name name' : Change name." << std::endl;
00228 
00229                 run_input();
00230 
00231             }
00232             catch(const std::exception& e)
00233             {
00234                 std::cerr << e.what() << std::endl;
00235             }
00236 
00237             delete client_;
00238         }
00239 
00240     private:
00241 
00242         virtual void handle_connect( ana::error_code error, net_id server_id )
00243         {
00244             if ( error )
00245             {
00246                 std::cerr << "\nError connecting." << std::endl;
00247                 continue_ = false;
00248             }
00249             else
00250                 client_->send( ana::buffer( std::string("/name ") + name_) , this);
00251         }
00252 
00253         virtual void handle_disconnect( ana::error_code error, net_id server_id)
00254         {
00255             std::cerr << "\nServer disconnected. Enter to exit." << std::endl;
00256             continue_ = false;
00257         }
00258 
00259         virtual void handle_receive( ana::error_code error, net_id, ana::read_buffer msg)
00260         {
00261             if (! error)
00262             {
00263                 std::cout << std::endl << msg->string()
00264                           << std::endl << name_ << " : ";
00265                 std::cout.flush();
00266             }
00267             else if ( error == ana::timeout_error )
00268                 std::cerr << "\nTimeout for waiting message.\n";
00269         }
00270 
00271         virtual void handle_send( ana::error_code error, net_id client, ana::operation_id op_id)
00272         {
00273             if ( error )
00274                 std::cout << "Error. Timeout?" << std::endl;
00275         }
00276 
00277         connection_info     conn_info_;
00278         bool                continue_;
00279         ana::client*        client_;
00280         std::string         name_;
00281 };
00282 
00283 int main(int argc, char **argv)
00284 {
00285     show_help(argv[0]);
00286 
00287     connection_info ci;
00288 
00289     if ( argc > 1 )
00290         ci.name      = argv[1];
00291     if ( argc > 2 )
00292         ci.address   = argv[2];
00293     if ( argc > 3 )
00294         ci.pt        = argv[3];
00295     if ( argc > 4 )
00296         ci.proxyaddr = argv[4];
00297     if ( argc > 5 )
00298         ci.proxyport = argv[5];
00299     if ( argc > 6 )
00300         ci.user      = argv[6];
00301     if ( argc > 7 )
00302         ci.password  = argv[7];
00303 
00304     std::cout << "Main client app.: Starting client" << std::endl;
00305 
00306     ChatClient client(ci);
00307     client.run();
00308 }
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Defines

Generated by doxygen 1.7.1 on Tue May 22 2012 01:03:34 for The Battle for Wesnoth
Gna! | Forum | Wiki | CIA | devdocs