X-Git-Url: https://git.llucax.com/z.facultad/75.42/plaqui.git/blobdiff_plain/bcbe297964b0ad7393385f1dd240448c340ed5ed..HEAD:/Server/src/server.cpp diff --git a/Server/src/server.cpp b/Server/src/server.cpp index 37f5c1c..692db97 100644 --- a/Server/src/server.cpp +++ b/Server/src/server.cpp @@ -26,13 +26,14 @@ // #include "plaqui/server/server.h" +#include "plaqui/server/string.h" #include "plaqui/server/connection.h" #include "plaqui/server/controlserver.h" #include -// FIXME - sacar sstream (a menos que se necesite) +#include #include +#include #ifdef DEBUG -# include "plaqui/server/string.h" # include #endif // DEBUG @@ -44,164 +45,402 @@ namespace Server { Server::~Server(void) { #ifdef DEBUG - cerr << __FILE__ << ": destructor." << endl; + cerr << __FILE__ << "(" << __LINE__ << ")" + << ": destructor." << endl; #endif // DEBUG + // Mando a terminar todas las plantas. + plants_mutex.lock(); + for (PlantList::iterator i = plants.begin(); i != plants.end(); i++) { + i->second->finish(); + } + PlantList::size_type count = plants.size(); + plants_mutex.unlock(); + // Espero que terminen realmente. + while (count) { + Glib::usleep(10000); // 10 milisegundos + plants_mutex.lock(); + count = plants.size(); + plants_mutex.unlock(); + } } -Server::Server(int port): - TCPServer(port) { +Server::Server(const Connection::Port& port) + throw(sockerr): TCPServer(port) { #ifdef DEBUG - cerr << __FILE__ << ": port = " << port << endl; + cerr << __FILE__ << "(" << __LINE__ << ")" + << ": port = " << port << endl; #endif // DEBUG } -/// \todo Implementar. -bool Server::start_transmission(string host, int port) { -#ifdef DEBUG - cerr << __FILE__ << ": start_transmission(host = " << host - << " | port = " << port << ")" << endl; -#endif // DEBUG - // TODO +bool Server::add_plant(const string& name, const string& filename) { + Glib::Mutex::Lock lock(plants_mutex); + if (plants.find(name) == plants.end()) { // No existe + plants[name] = new Plant(filename); + plants[name]->signal_finished().connect(SigC::bind( + SigC::slot_class(*this, &Server::on_plant_finished), + name.c_str())); + plants[name]->run(); + return true; + } return false; } - -Connection* Server::new_connection( - const sockbuf::sockdesc& sd) { + +Connection* Server::new_connection(const sockbuf::sockdesc& sd) { #ifdef DEBUG - cerr << __FILE__ << ": new_connection(sd = " << sd.sock << ")" + cerr << __FILE__ << "(" << __LINE__ << ")" + << ": new_connection(sd = " << sd.sock << ")" << endl; #endif // DEBUG ControlServer* connection = new ControlServer(sd); - // TODO verificar si el new se hace bien? no creo. - connection->signal_command_received().connect( - SigC::bind( - SigC::slot_class(*this, &Server::on_control_command_received), - connection)); - // TODO: + connection->signal_command_received().connect(SigC::bind( + SigC::slot_class(*this, &Server::on_control_command_received), + connection)); return connection; } -/// \todo Implementar. -bool Server::stop_transmission(string host, int port) { +void Server::on_plant_finished(const char* plant) { #ifdef DEBUG - cerr << __FILE__ << ": stop_transmission(host = " << host - << " | port = " << port << ")" << endl; + cerr << __FILE__ << "(" << __LINE__ << ")" + << ": on_plant_finished(plant_name = " << plant << endl; #endif // DEBUG - // TODO - return false; + Glib::Mutex::Lock lock(plants_mutex); + plants.erase(plant); } -/// \todo Implementar. void Server::on_control_command_received(const Command& command, - ControlServer* server) { + ControlServer* controlserver) { #ifdef DEBUG - cerr << __FILE__ << ": on_control_command_received(target = " + cerr << __FILE__ << "(" << __LINE__ << ")" + << ": on_control_command_received(target = " << command.get_target() << ", command = " << command.get_command() << ", args = [" << String::join(command.get_args(), ", ") << "])" << endl; #endif // DEBUG - HTTPResponse response(HTTPMessage::OK); + Response* response; if (command.get_target() == "server") { -#ifdef DEBUG - cerr << __FILE__ << ": server" << endl; -#endif // DEBUG - if (command.get_command() == "status") { - // FIXME - stringstream response_xml; - response_xml << "" << endl; - response_xml << " " << endl; - response_xml << " PlaQui v0.6" << endl; - response_xml << " " << endl; - response_xml << " " << endl; - response_xml << "

PlaQui

" << endl; - response_xml << "

versión 0.6

" << endl; - response_xml << "

Comando

" << endl; - response_xml << "
    " << endl; - response_xml << "
  • Target: " << command.get_target() << endl; - response_xml << "
  • Command: " << command.get_command() << endl; - response_xml << "
  • Argumentos:" << endl; - response_xml << "
      " << endl; - for (Command::Arguments::const_iterator i = command.get_args().begin(); - i != command.get_args().end(); i++) { - response_xml << "
    1. " << *i << "
    2. " << endl; - } - response_xml << "
    " << endl; - response_xml << "
" << endl; - response_xml << "

Desarrollado por

" << endl; - response_xml << "
    " << endl; - response_xml << "
  • Nicolás Dimov.
  • " << endl; - response_xml << "
  • Leandro Lucarella.
  • " << endl; - response_xml << "
  • Ricardo Markiewicz.
  • " << endl; - response_xml << "
" << endl; - response_xml << "
" << endl; - response_xml << " Copyleft 2003 - bajo los " << endl; - response_xml << " términos de la licencia GPL" << endl; - response_xml << "
" << endl; - response_xml << " " << endl; - response_xml << "" << endl; - response.status_code = HTTPMessage::OK; - response.set_body(response_xml.str()); + if (command.get_command() == "info") { + response = cmd_server_info(); } else if (command.get_command() == "stop") { - stop = true; - response.set_body("El server se apagará en instantes..."); + response = new Response(Response::OK, + "El server se cerrará en instantes"); + // XXX - Sin mandar la respuesta enseguida podría ser que el server + // cierre la conexión antes de mandar la respuesta. En las pruebas + // esto nunca pasó. + //response->headers["Content-Type"] = "text/xml; charset=iso-8859-1"; + //controlserver->send(*response); + //delete response; + finish(); + //return; } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'server' taget!"); + response = new Response(Response::INVALID_COMMAND, + command.get_command() + " es un comando inválido para " + + "el destino 'server'"); } } else if (command.get_target() == "connection") { if (command.get_command() == "list") { - // FIXME - TCPServer::ConnectionInfoList cil = get_connected(); - stringstream response_xml; - response_xml << "" << endl; - response_xml << " " << endl; - response_xml << " PlaQui v0.6" << endl; - response_xml << " " << endl; - response_xml << " " << endl; - response_xml << "

PlaQui

" << endl; - response_xml << "

versión 0.6

" << endl; - response_xml << "

Lista de conexiones:

" << endl; - response_xml << "
    " << endl; - for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin(); - i != cil.end(); i++) { - response_xml << "
  • " << i->host - << ":" << i->port << " [host << "/" << i->port << "\">deconectar]
  • " - << endl; - } - response_xml << "
" << endl; - response_xml << "
" << endl; - response_xml << " Copyleft 2003 - bajo los " << endl; - response_xml << " términos de la licencia GPL" << endl; - response_xml << "
" << endl; - response_xml << " " << endl; - response_xml << "" << endl; - response.status_code = HTTPMessage::OK; - response.set_body(response_xml.str()); + response = cmd_connection_list(); } else if (command.get_command() == "stop") { - // TODO server->finish(); - response.set_body("La conexión se cerrará en instantes..."); + response = cmd_connection_stop(command); } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'connection' taget!"); + response = new Response(Response::INVALID_COMMAND, + command.get_command() + " es un comando inválido para " + + "el destino 'connection'"); } } else if (command.get_target() == "transmission") { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'transmission' taget!"); + if (command.get_command() == "list") { + response = cmd_transmission_list(); + } else if (command.get_command() == "start") { + response = cmd_transmission_start(command); + } else if (command.get_command() == "stop") { + response = cmd_transmission_stop(command); + } else { + response = new Response(Response::INVALID_COMMAND, + command.get_command() + " es un comando inválido para " + + "el destino 'transmission'"); + } } else if (command.get_target() == "plant") { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid command for 'plant' taget!"); + if (command.get_command() == "list") { + response = cmd_plant_list(); + } else if (command.get_command() == "get") { + response = cmd_plant_get(command); + } else if (command.get_command() == "set") { + response = cmd_plant_set(command); + } else if (command.get_command() == "set_frequency") { + response = cmd_plant_set_frequency(command); + } else if (command.get_command() == "start") { + response = cmd_plant_start(command); + } else if (command.get_command() == "stop") { + response = cmd_plant_stop(command); + } else if (command.get_command() == "remove") { + response = cmd_plant_remove(command); + } else { + response = new Response(Response::INVALID_COMMAND, + command.get_command() + " es un comando inválido para " + + "el destino 'plant'"); + } + } else { + response = new Response(Response::INVALID_TARGET, command.get_target() + + " es un destino inválido"); + } + controlserver->send(*response); + delete response; +} + +Response* Server::cmd_server_info(void) const { + stringstream xml; + xml << "" << endl; + xml << "\t" VERSION "" << endl; + xml << "\t" << endl; + xml << "\t\tNicolás Dimov" << endl; + xml << "\t\tLeandro Lucarella" << endl; + xml << "\t\tRicardo Markiewicz" << endl; + xml << "\t" << endl; + xml << "" << endl; + return new Response(xml.str()); +} + +Response* Server::cmd_connection_list(void) { + // TODO implementar con lista genérica. + TCPServer::ConnectionInfoList cil = get_connected(); + stringstream xml; + xml << "" << endl; + for (TCPServer::ConnectionInfoList::const_iterator i = cil.begin(); + i != cil.end(); i++) { + xml << "\t" << endl; + xml << "\t\t" << i->host << "" << endl; + xml << "\t\t" << i->port << "" << endl; + xml << "\t" << endl; + } + xml << "" << endl; + return new Response(xml.str()); +} + +Response* Server::cmd_connection_stop(const Command& command) { + const Command::Arguments& args = command.get_args(); + Connection::Port port; + if (args.size() < 2) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'stop' del destino 'connection'"); + } else if (disconnect(args[0], to(args[1], port))) { + return new Response(Response::OK, string("La conexión a ") + args[0] + + ":" + args[1] + " se cerrará en instantes"); + } else { + return new Response(Response::CONNECTION_NOT_FOUND, + string("No existe una conexión a ") + args[0] + ":" + args[1]); + } +} + +Response* Server::cmd_transmission_list(void) { + // TODO implementar con lista genérica. + stringstream xml; + xml << "" << endl; +/*FIXME plants_mutex.lock(); + for (PlantList::const_iterator i = plants.begin(); + i != plants.end(); i++) { + trans + xml << "
  • " << (*i)->get_host() << ":" + << (*i)->get_port() << " [get_host() << "/" << (*i)->get_port() + << "\">desconectar]
  • " << endl; + } + transmissions_mutex.unlock();*/ + xml << "
    " << endl; + return new Response(xml.str()); +} + +Response* Server::cmd_transmission_start(const Command& command) { + const Command::Arguments& args = command.get_args(); + if (args.size() < 3) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'start' del destino 'transmission'"); + } else { + string plant = args[0]; + string host = args[1]; + Connection::Port port = to(args[2], port); + Glib::Mutex::Lock lock(plants_mutex); + PlantList::iterator p = plants.find(plant); + if (p == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + plant + "'"); + // FIXME - agregar chequeo de que la transmision a ese host:port no exista. + // que use respuesta ALLREADY_EXISTS + } else if (plants[plant]->transmission_start(host, port)) { + return new Response(Response::OK, + string("Se empieza a transmitir la planta '") + plant + + "' a " + host + ":" + String().from(port)); + } else { + return new Response(Response::ERROR_STARTING_TRANSMISSION, + string("Error al crear la transmisión a de la planta '") + + plant + "' a " + host + ":" + args[2]); + } + } +} + +Response* Server::cmd_transmission_stop(const Command& command) { + const Command::Arguments& args = command.get_args(); + if (args.size() < 2) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'stop' del destino 'transmission'"); } else { - response.status_code = HTTPMessage::NOT_FOUND; - response.set_body("Invalid Target!"); - } - // FIXME - response.headers["Content-Type"] = "text/html; charset=iso-8859-1"; - response.headers["Connection"] = "close"; - server->send(response); - // FIXME con timeout no debería ser necesario. Verificar cabecera Connection - // para saber si hay que finish()earlo o no. - // server->finish(); + const string& host = args[0]; + Connection::Port port = to(args[1], port); + for (PlantList::iterator i = plants.begin(); i != plants.end(); i++) { + // TODO - agregar chequeo para saber si existe una conexion (para + // tirar error de que no hay conexion o de que no se pudo + // desconectar. + if (i->second->transmission_stop(host, port)) { + return new Response(Response::OK, + string("La transmisión de la planta '") + i->first + + "' a " + host + ":" + args[1] + + " se cerrará en instantes"); + } + } + return new Response(Response::TRANSMISSION_NOT_FOUND, + string("No existe una transmisión a ") + host + ":" + args[1]); + } +} + +Response* Server::cmd_plant_list(void) { + // FIXME hacer con ResponseList + stringstream xml; + xml << "" << endl; + plants_mutex.lock(); + for (PlantList::const_iterator i = plants.begin(); + i != plants.end(); i++) { + xml << "\t" << endl; + xml << "\t\t" << i->first << "" << endl; + xml << "\t" << endl; + } + plants_mutex.unlock(); + xml << "" << endl; + return new Response(xml.str()); +} + +Response* Server::cmd_plant_get(const Command& command) { + if (!command.get_args().size()) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'get' del destino 'plant'"); + } + Glib::Mutex::Lock lock(plants_mutex); + string plant = command.get_args()[0]; + if (plants.find(plant) == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + plant + "'"); + } + string xml = plants[plant]->get_xml(); + if (xml.length()) { + return new Response(xml); + } else { + return new Response(Response::ERROR_GETING_PLANT_XML, + ("No se pudo obtener el XML de la planta '") + plant + "'"); + } +} + +Response* Server::cmd_plant_set(const Command& command) { + const Command::Arguments& args = command.get_args(); + if (args.size() < 4) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'set' del destino 'plant'"); + } + string plant = args[0]; + string element = args[1]; + string input = args[2]; + if (input != "open") { + return new Response(Response::ELEMENT_INPUT_NOT_FOUND, + string("El elemento '") + element + "' de la planta '" + plant + + "' no tiene una entrada '" + input + "'"); + } + string value = args[3]; + Glib::Mutex::Lock lock(plants_mutex); + PlantList::iterator p = plants.find(plant); + if (p == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + plant + "'"); + } + bool open = true; + if ((value == "false") || (value == "0") || (value == "off") + || (value == "no")) { + open = false; + } + if (!plants[plant]->set_open(element, open)) { + return new Response(Response::ERROR_CHANGING_ELEMENT_INPUT, + string("No se pudo cambiar la entrada '") + input + + "' del elemento '" + element + "' de la planta '" + + plant + "'"); + } + return new Response(Response::OK, + string("Se cambió la entrada '") + input + "' del elemento '" + + element + "' de la planta '" + plant + "' a '" + value + "'"); +} + +Response* Server::cmd_plant_set_frequency(const Command& command) { + if (command.get_args().size() < 2) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'set_frequency' del destino 'plant'"); + } + Glib::Mutex::Lock lock(plants_mutex); + const string name = command.get_args()[0]; + if (plants.find(name) == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + name + "'"); + } + unsigned hz; + to(command.get_args()[1], hz); + plants[name]->set_frequency(hz); + String shz; + shz.from(hz); + return new Response(Response::OK, + string("Se cambió la frecuencia de refresco de la planta '") + name + + "' a '" + shz + "' veces por segundo"); +} + +Response* Server::cmd_plant_start(const Command& command) { + if (!command.get_args().size()) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'start' del destino 'plant'"); + } + Glib::Mutex::Lock lock(plants_mutex); + const string name = command.get_args()[0]; + if (plants.find(name) == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + name + "'"); + } + plants[name]->set_paused(false); + return new Response(Response::OK, + string("La planta '") + name + "' fue reanudada"); +} + +Response* Server::cmd_plant_stop(const Command& command) { + if (!command.get_args().size()) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'stop' del destino 'plant'"); + } + Glib::Mutex::Lock lock(plants_mutex); + const string name = command.get_args()[0]; + if (plants.find(name) == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + name + "'"); + } + plants[name]->set_paused(true); + return new Response(Response::OK, + string("La planta '") + name + "' fue pausada"); +} + +Response* Server::cmd_plant_remove(const Command& command) { + if (!command.get_args().size()) { + return new Response(Response::ARGUMENT_MISSING, "Faltan argumentos " + " para el comando 'remove' del destino 'plant'"); + } + Glib::Mutex::Lock lock(plants_mutex); + const string name = command.get_args()[0]; + if (plants.find(name) == plants.end()) { + return new Response(Response::PLANT_NOT_FOUND, + string("No existe la planta '") + name + "'"); + } + plants[name]->finish(); + return new Response(Response::OK, + string("La planta '") + name + "' fue será removida del servidor " + "en instantes"); } } // namespace Server