Subversion Repositories HomeAutomation

Rev

Rev 1609 | 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 <string>
  22. #include <vector>
  23.  
  24. #include <signal.h>
  25. #include <stdio.h>
  26. #include <stdlib.h>
  27.  
  28. #include <boost/lexical_cast.hpp>
  29. #include <boost/thread/mutex.hpp>
  30. #include <boost/thread/condition.hpp>
  31. #include <boost/thread/locks.hpp>
  32. #include <boost/algorithm/string.hpp>
  33.  
  34. #include "net/Manager.h"
  35. #include "net/Subscriber.h"
  36. #include "net/types.h"
  37.  
  38. #include "type/common.h"
  39.  
  40. #include <readline/readline.h>
  41. #include <readline/history.h>
  42.  
  43. using namespace atom;
  44.  
  45.  
  46. void Handler(int status);
  47. void CleanUp();
  48.  
  49. char* AutoCompleteGet(const char* text, int state);
  50. static char** AutoComplete(const char* text, int start, int end);
  51.  
  52. type::StringList autocomplete_list;
  53. char* buffer = NULL;
  54. bool waiting_for_autocomplete = false;
  55. boost::condition on_message_condition;
  56. boost::mutex guard_mutex;
  57.  
  58. class ConsoleClient : public net::Subscriber
  59. {
  60. public:
  61.     typedef boost::shared_ptr<ConsoleClient> Pointer;
  62.    
  63.     ConsoleClient(std::string address, unsigned int port)
  64.     {
  65.         this->client_id_ = net::Manager::Instance()->Connect(net::PROTOCOL_TCP, address, port);
  66.     }
  67.    
  68.     virtual ~ConsoleClient()
  69.     {
  70.         net::Manager::Instance()->Disconnect(this->client_id_);
  71.  
  72.         this->io_service_.stop();
  73.     }
  74.    
  75.     void Send(std::string data)
  76.     {
  77.         net::Manager::Instance()->SendTo(this->client_id_, data);
  78.     }
  79.    
  80.     bool IsConnected()
  81.     {
  82.         return this->client_id_ != 0;
  83.     }
  84.    
  85. private:
  86.     net::ClientId client_id_;
  87.    
  88.     void SlotOnNewStateHandler(net::ClientId client_id, net::ServerId server_id, net::ClientState client_state)
  89.     {
  90.         if (client_state == net::CLIENT_STATE_CONNECTED)
  91.         {
  92.             printf("Connected to Atom Daemon!\n");
  93.         }
  94.         else
  95.         {
  96.             printf("\nDisconnected!\n");
  97.             this->client_id_ = 0;
  98.            
  99.             kill(getpid(), SIGABRT);
  100.         }
  101.     }
  102.    
  103.     void SlotOnNewDataHandler(net::ClientId client_id, net::ServerId server_id, type::Byteset data)
  104.     {
  105.         std::string s(data.ToCharString());
  106.        
  107.         if (waiting_for_autocomplete)
  108.         {
  109.             autocomplete_list.clear();
  110.             boost::algorithm::split(autocomplete_list, s, boost::is_any_of("\n"), boost::algorithm::token_compress_on);
  111.         }
  112.         else
  113.         {
  114.             if (s[s.length()-1] != '\n')
  115.             {
  116.                 s += "\n";
  117.             }
  118.            
  119.             printf("%s", s.data());
  120.         }
  121.          
  122.         on_message_condition.notify_all();
  123.     }
  124. };
  125.  
  126. ConsoleClient::Pointer cc;
  127. struct termios original_flags;
  128.  
  129. int main(int argc, char **argv)
  130. {
  131.     signal(SIGTERM, Handler);
  132.     signal(SIGINT, Handler);
  133.     signal(SIGQUIT, Handler);
  134.     signal(SIGABRT, Handler);
  135.     signal(SIGPIPE, Handler);
  136.    
  137.     tcgetattr(fileno(stdin), &original_flags);
  138.        
  139.     printf("Atom Interactive Console, version 1.5.0 starting...\n");
  140.     printf("Written by Mattias Runge 2010.\n");
  141.     printf("Released under GPL version 2.\n");
  142.    
  143.     net::Manager::Create();
  144.    
  145.     std::string address = "localhost";
  146.     unsigned int port = 1202;
  147.    
  148.     printf("Connecting to %s:%d...", address.data(), port);
  149.    
  150.     try
  151.     {
  152.         cc = ConsoleClient::Pointer(new ConsoleClient(address, port));
  153.     }
  154.     catch (std::runtime_error& e)
  155.     {
  156.         printf("%s\n", e.what());
  157.         CleanUp();
  158.        
  159.         return EXIT_FAILURE;
  160.     }
  161.    
  162.     printf("success!\n");
  163.    
  164.     std::string prompt = address + ":" + boost::lexical_cast<std::string>(port) + "] ";
  165.    
  166.    
  167.    
  168.     rl_attempted_completion_function = AutoComplete;
  169.    
  170.     while ((buffer = readline(prompt.data())) != NULL)
  171.     {
  172.         if (strlen(buffer) == 0)
  173.         {
  174.             continue;
  175.         }
  176.        
  177.         if (strcmp(buffer, "quit") == 0)
  178.         {
  179.             break;
  180.         }
  181.        
  182.         waiting_for_autocomplete = false;
  183.        
  184.         cc->Send("E;" + std::string(buffer));
  185.        
  186.         boost::mutex::scoped_lock guard(guard_mutex);
  187.         on_message_condition.wait(guard);    
  188.        
  189.         add_history(buffer);
  190.     }
  191.    
  192.     CleanUp();
  193.    
  194.     return EXIT_SUCCESS;
  195. }
  196.  
  197. static char** AutoComplete(const char* text, int start, int end)
  198. {
  199.     unsigned int count = 0;
  200.    
  201.     for (unsigned int n = 0; n < start; n++)
  202.     {
  203.         if (text[n] == ' ')
  204.         {
  205.             count++;
  206.         }
  207.     }
  208.    
  209.     waiting_for_autocomplete = true;
  210.    
  211.     //printf("Sending request\n");
  212.    
  213.     cc->Send("A;"+ boost::lexical_cast<std::string>(count) + ";" + std::string(text));
  214.    
  215.     boost::mutex::scoped_lock guard(guard_mutex);
  216.     on_message_condition.wait(guard);    
  217.    
  218.     //printf("processing response\n");
  219.    
  220.     return rl_completion_matches(text, &AutoCompleteGet);
  221. }
  222.  
  223. char* AutoCompleteGet(const char* text, int state)
  224. {
  225.     static int index = 0;
  226.     int length = strlen(text);
  227.     std::string name;
  228.    
  229.     //printf("run, %s, %d, %d\n", text, state, autocomplete_list.size());
  230.    
  231.     if (!state) // First run
  232.     {
  233.         index = 0;
  234.     }
  235.    
  236.     while (autocomplete_list.size() > index)
  237.     {
  238.         name = autocomplete_list[index];
  239.         //printf("testing name = %s\n", name.data());
  240.        
  241.         index++;
  242.        
  243.         if (strncmp(name.data(), text, length) == 0)
  244.         {
  245.             char *result = (char*)malloc(name.size() + 1);
  246.             strcpy(result, name.data());
  247.            
  248.             return result;
  249.         }
  250.     }
  251.    
  252.     return NULL;
  253. }
  254.  
  255. void CleanUp()
  256. {
  257.     printf("Cleaning up...\n");
  258.    
  259.     cc.reset();
  260.    
  261.     net::Manager::Delete();
  262.    
  263.     if (buffer != NULL)
  264.     {
  265.         free(buffer);
  266.     }
  267.    
  268.     printf("Thank you for using Atom. Goodbye!\n");
  269.    
  270.     tcsetattr(fileno(stdin), TCSANOW, &original_flags); // Restore
  271. }
  272.  
  273. void Handler(int status)
  274. {
  275.     std::string signal_name = "Unknown";
  276.    
  277.     switch (status)
  278.     {
  279.         case SIGTERM:
  280.         {
  281.             signal_name = "Terminate";
  282.             break;
  283.         }  
  284.         case SIGINT:
  285.         {
  286.             signal_name = "Interupt";
  287.             break;
  288.         }  
  289.         case SIGQUIT:
  290.         {
  291.             signal_name = "Quit";
  292.             break;
  293.         }  
  294.         case SIGABRT:
  295.         {
  296.             signal_name = "Abort";
  297.             break;
  298.         }  
  299.         case SIGIO:
  300.         {
  301.             signal_name = "I/O";
  302.             break;
  303.         }  
  304.         case SIGPIPE:
  305.         {
  306.             signal_name = "Pipe";
  307.             break;
  308.         }
  309.     }
  310.    
  311.    
  312.     if (status != SIGPIPE)
  313.     {
  314.         CleanUp();
  315.         exit(0);
  316.         //on_message_condition.notify_all();
  317.     }
  318. }