Console: Implement autocomplete
[senf.git] / Console / Server.hh
index 7bca747..e33be2c 100644 (file)
@@ -56,6 +56,17 @@ namespace console {
 
         \todo Add readline support
         \todo Add interactivity detection using timeout
+        \idea To support blocking commands, we could give the Client 'suspend()' and 'resume()'
+            members. suspend() would probably throw some kind of exception to transfer control back
+            to the Client instance. on resume(), the command would be called again, maybe setting
+            some flag or something. Example for use: Host name resolution: Here we can just built
+            our own little host-name cache. When the name is not found, we ask the resolver to
+            resolve it and call 'resume' when the name is found. Since it is in the cache now, the
+            command will now complete.
+        
+        \implementation We do \e not provide an \c instance() member so we can easily later extend
+            the server to allow registering more than one instance, e.g. with each instance on a
+            differently firewalled port and with different security restrictions.
       */
     class Server
         : boost::noncopyable
@@ -65,10 +76,8 @@ namespace console {
     public:
         ///////////////////////////////////////////////////////////////////////////
         // Types
-
-        typedef senf::ServerSocketHandle<
-            senf::MakeSocketPolicy< senf::TCPv4SocketProtocol::Policy, 
-                                    senf::UnspecifiedAddressingPolicy>::policy > ServerHandle;
+        
+        typedef detail::ServerHandle ServerHandle;
 
         ~Server();
 
@@ -76,16 +85,19 @@ namespace console {
                                         ///< Start server on given IPv4 address/port
         static Server & start(senf::INet6SocketAddress const & address);
                                         ///< Start server on given IPv6 address/port
-
-        void name(std::string const & name); ///< Set server name
+        Server & name(std::string const & name); ///< Set server name
                                         /**< This information is used in the prompt string. */
-
+        
+        void stop();                    ///< Stop the server
+                                        /**< All clients will be closed */
+        
     protected:
 
     private:
         Server(ServerHandle handle);
 
-        static void start(ServerHandle handle);
+        static Server & start(ServerHandle handle);
+        static boost::scoped_ptr<Server> & instancePtr();
 
         void newClient(Scheduler::EventId event);
         void removeClient(Client & client);
@@ -96,8 +108,6 @@ namespace console {
         Clients clients_;
         std::string name_;
         
-        static boost::scoped_ptr<Server> instance_;
-        
         friend class Client;
     };
     
@@ -106,11 +116,6 @@ namespace console {
         Whenever a new client connects, a new instance of this class is created. This class shows a
         command prompt, receives the commands, parses them and then passes (using a CommandParser)
         and passes the commands to an Executor instance.
-
-        \fixme Fix Client::clientData implementation
-        \fixme Don't register a new ReadHelper every round
-        \fixme Ensure, that output errors (or any errors) in the console don't terminate the
-            application
      */
     class Client
         : public senf::intrusive_refcount, 
@@ -121,35 +126,44 @@ namespace console {
 
         SENF_LOG_CLASS_AREA();
         SENF_LOG_DEFAULT_LEVEL( senf::log::NOTICE );
+
     public:
         typedef Server::ServerHandle::ClientSocketHandle ClientHandle;
 
         ~Client();
 
-        void stopClient();              ///< Stop the client
+        void stop();                    ///< Stop the client
                                         /**< This will close the client socket. */
 
+        std::string const & name() const;
+        ClientHandle handle() const;
+        std::ostream & stream();
+        std::string promptString() const;
+
+        static Client & get(std::ostream & os);
+
     protected:
         
     private:
-        Client(ClientHandle handle, std::string const & name);
-
-        void clientData(ReadHelper<ClientHandle>::ptr helper);
-        void showPrompt();
+        Client(Server & server, ClientHandle handle, std::string const & name);
 
+        void translate(std::string & data);
+        void handleInput(std::string input);
         virtual void v_write(boost::posix_time::ptime timestamp, std::string const & stream, 
                              std::string const & area, unsigned level, 
                              std::string const & message);
         
+        Server & server_;
         ClientHandle handle_;
-        std::string tail_;
         CommandParser parser_;
         Executor executor_;
         std::string name_;
-        unsigned promptLen_;
         std::string lastCommand_;
+        boost::scoped_ptr<detail::ClientReader> reader_;
 
         friend class Server;
+        friend class detail::ClientReader;
+        friend class detail::NonblockingSocketSink;
     };
 
 }}