Remove warnings
[anna.git] / example / http / client / main.cpp
1 // ANNA - Anna is Not Nothingness Anymore                                                         //
2 //                                                                                                //
3 // (c) Copyright 2005-2015 Eduardo Ramos Testillano & Francisco Ruiz Rayo                         //
4 //                                                                                                //
5 // See project site at http://redmine.teslayout.com/projects/anna-suite                           //
6 // See accompanying file LICENSE or copy at http://www.teslayout.com/projects/public/anna.LICENSE //
7
8
9 /**
10    Realiza peticiones automaticas sobre el servidor HTTP de operaciones aritmeticas.
11
12    La cadencia de envio de mensajes se establece mediante un temporizador.
13    Los operadores se calculan de forma aleatoria.
14
15    El servidor de este cliente: http_server.p o http_rserver.p
16 */
17
18 #include <iostream>
19
20 #include <string.h>
21 #include <unistd.h>
22
23 #include <anna/core/core.hpp>
24 #include <anna/app/functions.hpp>
25 #include <anna/comm/comm.hpp>
26
27 #include <anna/timex/Engine.hpp>
28 #include <anna/timex/Clock.hpp>
29
30 #include <anna/http/Request.hpp>
31 #include <anna/http/Response.hpp>
32 #include <anna/http/Transport.hpp>
33 #include <anna/http/Handler.hpp>
34
35 #include <anna/test/Response.hpp>
36 #include <anna/test/Request.hpp>
37
38 class Sender : public anna::timex::Clock {
39 public:
40    Sender () : Clock ("Sender", (Millisecond)1000), 
41       a_messageBySecond (0), 
42       a_nquarter (0), 
43       a_errorCounter (0),
44       a_txMessageCounter (0)
45    {
46       a_httpRequest.setMethod (http::Method::Type::Post);
47       a_httpRequest.setURI ("HTTPKClient");
48    }
49
50    void setMessageBySecond (const int messageBySecond) throw () { a_messageBySecond = messageBySecond; }
51
52    int getTxMessageCounter () const throw () { return a_txMessageCounter; }
53
54 private:
55    int a_messageBySecond;
56    int a_nquarter;
57    int a_errorCounter;
58    int a_txMessageCounter;
59    http::Request a_httpRequest;
60    test::Request a_testRequest;
61
62    bool tick () throw (RuntimeException);
63 };
64
65 class MyHandler : public http::Handler {
66 public:
67    MyHandler () : http::Handler ("http_client::MyHandler") {;}
68
69 private:
70    http::Response a_httpResponse;
71    test::Response a_testResponse;
72
73    void evRequest (ClientSocket&, const http::Request&) throw (RuntimeException) {;}
74    void evResponse (ClientSocket&, const http::Response&) throw (RuntimeException);
75    
76    static bool isOk (const test::Response& response) throw ();
77 };
78
79 class MyCommunicator : public Communicator {
80 public:
81    MyCommunicator () : Communicator (), a_avgResponseTime (0), a_rxMessageCounter (0) {;}
82
83    void count (const int delay) throw (RuntimeException);
84
85 private:
86    using Communicator::eventBreakConnection;
87
88    int a_avgResponseTime;
89    int a_rxMessageCounter;
90    MyHandler a_httpHandler;
91
92    void eventReceiveMessage (ClientSocket&, const Message&) throw (RuntimeException);
93
94    void eventBreakConnection (const ClientSocket&) throw ();
95
96    void eventBreakConnection (Server* server) throw () {
97       comm::Communicator::eventBreakConnection (server);
98    }
99    void eventBreakConnection (const Service* service) throw () { 
100       comm::Communicator::eventBreakConnection (service);
101    }   
102 };
103
104 class HeavyClient : public anna::comm::Application {
105 public:
106    HeavyClient ();
107
108    Server* getServer () const throw () { return a_server; }
109    const Sender* getSender () const throw () { return &a_sender; }
110
111 private:
112    MyCommunicator a_communicator;
113    anna::timex::Engine a_timeController;
114    Sender a_sender;
115    Server* a_server;
116
117    void initialize () throw (RuntimeException);
118    void run () throw (RuntimeException);
119 };
120
121 using namespace std;
122
123 int main (int argc, const char** argv)
124 {
125    CommandLine& commandLine (CommandLine::instantiate ());
126    HeavyClient app;
127
128    srand (time (NULL));
129
130    try {
131       commandLine.initialize (argv, argc);
132       commandLine.verify ();
133
134       Logger::setLevel (Logger::Information);
135       string traceFile ("client.");
136       traceFile += anna::functions::asString ((int) getpid ());
137       traceFile += ".trace";
138       Logger::initialize ("http_client", new TraceWriter (traceFile.c_str (),4096000));
139
140       app.start ();
141    }
142    catch (Exception& ex) {
143       cout << ex.asString () << endl;
144    }
145
146    return 0;
147 }
148
149 HeavyClient::HeavyClient () :
150    Application ("http_client", "Cliente HTTP", "1.0"),
151    a_communicator (),
152    a_timeController ((Millisecond)1000, (Millisecond)250)
153 {
154    CommandLine& commandLine (CommandLine::instantiate ());
155
156    commandLine.add ("p", CommandLine::Argument::Mandatory, "Puerto en el que el servidor atiende respuestas.");
157    commandLine.add ("a", CommandLine::Argument::Mandatory, "Direccin IP Puerto en el que el servidor atiende respuestas.");
158    commandLine.add ("n", CommandLine::Argument::Mandatory, "Numero de mensajes por segundo");
159    commandLine.add ("trace", CommandLine::Argument::Optional, "Nivel de trazas (debug,warning, error,...)");
160 }
161
162 void HeavyClient::initialize ()
163    throw (RuntimeException)
164 {
165    CommandLine& cl (CommandLine::instantiate ());
166
167    Network& network = Network::instantiate ();
168
169    a_server = network.createServer (cl.getValue ("a"), cl.getIntegerValue ("p"), true, &http::Transport::getFactory ());
170    a_sender.setMessageBySecond (cl.getIntegerValue ("n"));
171
172    if (cl.exists ("trace"))
173       Logger::setLevel (Logger::asLevel (cl.getValue ("trace")));
174 }
175
176 void HeavyClient::run ()
177    throw (RuntimeException)
178 {
179    a_timeController.activate (a_sender);
180
181    a_communicator.accept ();
182 }
183
184 void MyCommunicator::eventReceiveMessage (ClientSocket& clientSocket, const Message& message)
185    throw (RuntimeException)
186 {
187    LOGMETHOD (TraceMethod tm ("MyCommunicator", "eventReceiveMessage", ANNA_FILE_LOCATION));
188
189    if (clientSocket.support (http::Transport::className ()) == false)
190       return;
191
192    a_httpHandler.apply (clientSocket, message);
193 }
194
195 void MyCommunicator::count (const int delay)
196    throw (RuntimeException)
197 {
198    Guard guard (this, "MyCommunicator::eventReceiveMessage");
199    
200    a_rxMessageCounter ++;
201    a_avgResponseTime += delay;
202 }
203
204 void MyCommunicator::eventBreakConnection (const ClientSocket& clientSocket)
205    throw ()
206 {
207    if (a_rxMessageCounter == 0)
208       return;
209
210    LOGNOTICE (
211       HeavyClient& app = static_cast <HeavyClient&> (anna::app::functions::getApp ());   
212       string msg ("Tiempo medio respuesta: ");
213       msg += anna::functions::asString (a_avgResponseTime / a_rxMessageCounter);
214       msg += " ms";
215       msg += anna::functions::asText (" | Rx: ", a_rxMessageCounter);
216       msg += anna::functions::asText (" | Tx: ", app.getSender ()->getTxMessageCounter ());
217       Logger::notice (msg, ANNA_FILE_LOCATION);
218
219       cout << msg << endl << endl;
220    );
221    requestStop ();
222    comm::Communicator::eventBreakConnection (clientSocket);
223 }
224
225 bool Sender::tick ()
226    throw (RuntimeException)
227 {
228    Server* server = static_cast <HeavyClient&> (anna::app::functions::getApp ()).getServer ();
229    Communicator* communicator = anna::app::functions::component <Communicator> (ANNA_FILE_LOCATION);
230
231    if (a_errorCounter > 100) {
232       communicator->requestStop ();
233       Logger::warning ("Terminado por errores continuos en la conexion", ANNA_FILE_LOCATION);
234       return false;
235    }
236
237    for (int n = 0; n < a_messageBySecond && communicator->hasRequestedStop () == false; n ++) {
238       a_testRequest.op = '+';
239       a_testRequest.x = rand () % 1000;
240       a_testRequest.y = rand () % 1000;
241       a_testRequest.initTime = anna::functions::millisecond ();
242
243       try {
244          a_httpRequest.setBody (a_testRequest.code ());
245          server->send (a_httpRequest);
246          a_txMessageCounter ++;
247       }
248       catch (RuntimeException& ex) {
249          a_errorCounter ++;
250          ex.trace ();
251          break;
252       }
253    }
254
255    return true;
256 }
257
258 void MyHandler::evResponse (ClientSocket& clientSocket, const http::Response& response)
259    throw (RuntimeException)
260 {
261    if (response.getStatusCode () == 200) {
262       a_testResponse.decode (response.getBody ());
263       
264       test::Response& response (a_testResponse);
265       
266       const anna::Millisecond now = anna::functions::millisecond ();
267       const int delay =  now - (Millisecond) response.initTime;
268
269       if (delay > 0 && isOk (response) == true) {
270          app::functions::component <MyCommunicator> (ANNA_FILE_LOCATION)->count (delay);
271
272          LOGINFORMATION (
273             string msg = anna::functions::asString (
274                "%d %c %d = %d", response.x, response.op, response.y, response.result
275             );
276             msg += anna::functions::asText (" | Delay: ", delay);
277             Logger::information (msg, ANNA_FILE_LOCATION);
278          );
279       }
280       else {
281          LOGWARNING (
282             string msg = anna::functions::asString (
283                "Flip: %d %c %d = %d", response.x, response.op, response.y, response.result
284             );
285             msg += anna::functions::asText (" | Message: ", response.getBody ());
286             msg += anna::functions::asText (" | Delay: ", delay);
287             Logger::warning (msg, ANNA_FILE_LOCATION);
288          );
289       }
290    }
291 }
292
293 bool MyHandler::isOk (const test::Response& response) 
294    throw ()
295 {
296    if (response.op != '+' && response.op != '-' && response.op != '*' && response.op != '/') 
297       return false;
298       
299    int result = 0;
300    
301    switch (response.op) {
302       case '+':
303          result = response.x + response.y;
304          break;
305       case '-':
306          result = response.x - response.y;
307          break;
308       case '*':
309          result = response.x * response.y;
310          break;
311       case '/':
312          result = (response.y != 0) ? (response.x / response.y): 0;
313          break;
314    }
315     
316    return result == response.result;   
317 }