Subversion Repositories HomeAutomation

Rev

Rev 1648 | Rev 1664 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | SVN | RSS feed

  1. /*
  2.  *
  3.  *  Copyright (C) 2010  Mattias Runge
  4.  *
  5.  *  This program is free software; you can redistribute it and/or modify
  6.  *  it under the terms of the GNU General Public License as published by
  7.  *  the Free Software Foundation; either version 2 of the License, or
  8.  *  (at your option) any later version.
  9.  *
  10.  *  This program is distributed in the hope that it will be useful,
  11.  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  *  GNU General Public License for more details.
  14.  *
  15.  *  You should have received a copy of the GNU General Public License along
  16.  *  with this program; if not, write to the Free Software Foundation, Inc.,
  17.  *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
  18.  *
  19.  */
  20.  
  21. #include "Console.h"
  22.  
  23. #include <boost/lexical_cast.hpp>
  24. #include <boost/algorithm/string/trim.hpp>
  25. #include <boost/algorithm/string/split.hpp>
  26.  
  27. #include "net/Manager.h"
  28. #include "vm/Manager.h"
  29. #include "common/common.h"
  30.  
  31. namespace atom {
  32. namespace vm {
  33. namespace plugin {
  34.    
  35. logging::Logger Console::LOG("vm::plugin::Console");
  36. net::ClientId Console::current_client_id_;
  37.    
  38. Console::Console(boost::asio::io_service& io_service, unsigned int port) : Plugin(io_service)
  39. {
  40.     this->name_ = "console";
  41.     Console::current_client_id_ = 0;
  42.    
  43.     net::Manager::Instance()->ConnectSlots(net::Manager::SignalOnNewState::slot_type(&Console::SlotOnNewState, this, _1, _2, _3).track(this->tracker_),
  44.                                            net::Manager::SignalOnNewData::slot_type(&Console::SlotOnNewData, this, _1, _2, _3).track(this->tracker_));
  45.    
  46.     this->ExportFunction("ConsoleExport_PromptRequest",        Console::Export_PromptRequest);
  47.     this->ExportFunction("ConsoleExport_AutoCompleteResponse", Console::Export_AutoCompleteResponse);
  48.     this->ExportFunction("ConsoleExport_LogToClient",          Console::Export_LogToClient);
  49.    
  50.     try
  51.     {
  52.         this->server_id_ = net::Manager::Instance()->StartServer(net::PROTOCOL_TCP, port);
  53.         LOG.Info("Started TCP server on port " + boost::lexical_cast<std::string>(port) + ".");
  54.         LOG.Debug("Server id is " + boost::lexical_cast<std::string>(this->server_id_) + ".");
  55.     }
  56.     catch (std::runtime_error& e)
  57.     {
  58.         LOG.Error(e.what());
  59.     }
  60. }
  61.  
  62. Console::~Console()
  63. {
  64.     net::Manager::Instance()->StopServer(this->server_id_);
  65.     this->server_id_ = 0;
  66. }
  67.  
  68. void Console::InitializeDone()
  69. {
  70.     Plugin::InitializeDone();
  71.    
  72.     this->ImportFunction("Console_AutocompleteRequest");
  73.     this->ImportFunction("Console_PromptResponse");
  74.     this->ImportFunction("Console_NewConnection");
  75. }
  76.  
  77. void Console::CallOutput(unsigned int request_id, std::string output)
  78. {
  79.     std::string packet = "TEXT";
  80.     packet += common::PadNumber(output.length() + 1, 4);
  81.     packet += output;
  82.    
  83.     net::Manager::Instance()->SendTo(request_id, packet);
  84. }
  85.  
  86. void Console::SlotOnNewData(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
  87. {
  88.     if (server_id != this->server_id_)
  89.     {
  90.         return;
  91.     }
  92.    
  93.     this->io_service_.post(boost::bind(&Console::SlotOnNewDataHandler, this, client_id, server_id, data));
  94. }
  95.  
  96. void Console::SlotOnNewState(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
  97. {
  98.     if (server_id != this->server_id_)
  99.     {
  100.         return;
  101.     }
  102.    
  103.     this->io_service_.post(boost::bind(&Console::SlotOnNewStateHandler, this, client_id, server_id, client_state));
  104. }
  105.  
  106. void Console::SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, common::Byteset data)
  107. {
  108.     v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
  109.  
  110.     //LOG.Debug(std::string(__FUNCTION__) + " called!");
  111.  
  112.     std::string s(data.ToCharString());
  113.    
  114.     std::string command = s.substr(0, 4);
  115.     unsigned int payload_length = boost::lexical_cast<unsigned int>(s.substr(4, 4));
  116.  
  117.     Console::current_client_id_ = client_id;
  118.    
  119.     if (command == "COMP")
  120.     {
  121.         ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
  122.        
  123.         call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
  124.         call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(s.substr(8, 4))));
  125.         call_arguments->push_back(v8::String::New(s.substr(12).data()));
  126.        
  127.         if (!this->Call(client_id, "Console_AutocompleteRequest", call_arguments))
  128.         {
  129.             LOG.Error("Console_AutocompleteRequest failed, we are now in an undefined state!");
  130.         }
  131.     }
  132.     else if (command == "RESP")
  133.     {
  134.         ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
  135.        
  136.         call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
  137.         call_arguments->push_back(v8::String::New(s.substr(8).data()));
  138.        
  139.         if (!this->Call(client_id, "Console_PromptResponse", call_arguments))
  140.         {
  141.             LOG.Error("Console_PromptResponse failed, we are now in an undefined state!");
  142.         }
  143.     }
  144.     else
  145.     {
  146.         LOG.Error("Unknown packat received, we are now in an undefined state!");
  147.     }
  148.    
  149.     Console::current_client_id_ = 0;
  150. }
  151.  
  152. void Console::SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
  153. {
  154.     v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
  155.  
  156.     //LOG.Debug(std::string(__FUNCTION__) + " called!");
  157.    
  158.     if (client_state == net::CLIENT_STATE_DISCONNECTED)
  159.     {
  160.         LOG.Info("Client " + boost::lexical_cast<std::string>(client_id) + " has disconnected.");
  161.     }
  162.     else if (client_state == net::CLIENT_STATE_CONNECTED)
  163.     {
  164.         LOG.Info("Client " + boost::lexical_cast<std::string>(client_id) + " has connected.");
  165.      
  166.         Console::current_client_id_ = client_id;
  167.        
  168.         ArgumentListPointer call_arguments = ArgumentListPointer(new ArgumentList);
  169.        
  170.         call_arguments->push_back(v8::Integer::New(boost::lexical_cast<unsigned int>(client_id)));
  171.        
  172.         if (!this->Call(client_id, "Console_NewConnection", call_arguments))
  173.         {
  174.             LOG.Error("Console_NewConnection failed, we are now in an undefined state!");
  175.         }
  176.        
  177.         Console::current_client_id_ = 0;
  178.     }
  179.     else
  180.     {
  181.         LOG.Debug("Got state: " + boost::lexical_cast<std::string>((int)client_state));
  182.     }
  183. }
  184.  
  185. Value Console::Export_PromptRequest(const v8::Arguments& args)
  186. {
  187.     v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
  188.    
  189.     //LOG.Debug(std::string(__FUNCTION__) + " called!");
  190.    
  191.     if (args.Length() < 2)
  192.     {
  193.         LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
  194.         return v8::Boolean::New(false);
  195.     }
  196.    
  197.     v8::String::AsciiValue prompt(args[1]);
  198.    
  199.     std::string packet = "PROM";
  200.     packet += common::PadNumber(prompt.length() + 1, 4);
  201.     packet += *prompt;
  202.    
  203.     net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
  204.     return v8::Boolean::New(true);
  205. }
  206.  
  207. Value Console::Export_AutoCompleteResponse(const v8::Arguments& args)
  208. {
  209.     v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
  210.    
  211.     //LOG.Debug(std::string(__FUNCTION__) + " called!");
  212.    
  213.     if (args.Length() < 2)
  214.     {
  215.         LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
  216.         return v8::Boolean::New(false);
  217.     }
  218.    
  219.     v8::String::AsciiValue result(args[1]);
  220.    
  221.     std::string packet = "COMP";
  222.     packet += common::PadNumber(result.length() + 1, 4);
  223.     packet += *result;
  224.    
  225.     net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
  226.     return v8::Boolean::New(true);
  227. }
  228.  
  229. Value Console::Export_LogToClient(const v8::Arguments& args)
  230. {
  231.     v8::Context::Scope context_scope(vm::Manager::Instance()->GetContext());
  232.    
  233.     //LOG.Debug(std::string(__FUNCTION__) + " called!");
  234.    
  235.     if (args.Length() < 2)
  236.     {
  237.         LOG.Error(std::string(__FUNCTION__) + ": To few arguments.");
  238.         return v8::Boolean::New(false);
  239.     }
  240.    
  241.     v8::String::AsciiValue text(args[1]);
  242.    
  243.     std::string line = *text;
  244.    
  245.     std::string packet = "TEXT";
  246.     packet += common::PadNumber(line.length() + 1, 4);
  247.     packet += line;
  248.    
  249.     net::Manager::Instance()->SendTo(args[0]->Uint32Value(), packet);
  250.     return v8::Boolean::New(true);
  251. }
  252.  
  253. }; // namespace plugin
  254. }; // namespace vm
  255. }; // namespace atom
  256.