Console: Add log support to network client (every client is a log target)
[senf.git] / Console / Server.cc
index 5790d83..eb1fac1 100644 (file)
@@ -32,6 +32,7 @@
 #include <boost/algorithm/string/trim.hpp>
 #include <boost/iostreams/device/file_descriptor.hpp>
 #include <boost/iostreams/stream.hpp>
+#include <boost/bind.hpp>
 #include "../Utils/senfassert.hh"
 #include "../Utils/membind.hh"
 #include "../Utils/Logger/SenfLog.hh"
@@ -101,11 +102,13 @@ prefix_ void senf::console::Server::removeClient(Client & client)
 // senf::console::Client
 
 prefix_ senf::console::Client::Client(ClientHandle handle, std::string const & name)
-    : handle_ (handle), name_ (name), out_(::dup(handle.fd()))
+    : out_t(::dup(handle.fd())), senf::log::IOStreamTarget(out_t::member),
+      handle_ (handle), name_ (name), promptLen_(0)
 {
-    out_ << name_ << "# " << std::flush;
+    showPrompt();
     ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
                                         senf::membind(&Client::clientData, this) );
+    route< senf::SenfLog, senf::log::NOTICE >();
 }
 
 prefix_ senf::console::Client::~Client()
@@ -119,38 +122,58 @@ prefix_ void senf::console::Client::stopClient()
 
 prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr helper)
 {
+    promptLen_ = 0;
     if (helper->error() || handle_.eof()) {
         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
         stopClient();
         return;
     }
 
-#   warning fix Client::clientData implementation
-    // Remove the 'dup' needed here so we don't close the same fd twice (see Client constructor)
-    // Make output non-blocking
-    // Don't register a new ReadHelper every round
-
     std::string data (tail_ + helper->data());
     tail_ = helper->tail();
     boost::trim(data); // Gets rid of superfluous  \r or \n characters
 
-    if (data == "exit") {
+    try {
+        if (! parser_.parse(data, boost::bind<void>(boost::ref(executor_), _1, 
+                                                    boost::ref(out_t::member))))
+            out_t::member << "syntax error" << std::endl;
+    }
+    catch (Executor::ExitException &) {
         // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
         stopClient();
         return;
     }
-        
-    ParseCommandInfo command;
-    if (parser_.parseCommand(data, command))
-        executor_(command, out_);
-    else 
-        out_ << "syntax error" << std::endl;
-
-    out_ << name_ << "# " << std::flush;
+    catch (std::exception & ex) {
+        out_t::member << ex.what() << std::endl;
+    }
+    catch (...) {
+        out_t::member << "unidentified error (unknown exception thrown)" << std::endl;
+    }
+
+    showPrompt();
     ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
                                         senf::membind(&Client::clientData, this) );
 }
 
+prefix_ void senf::console::Client::showPrompt()
+{
+    std::string path (executor_.cwd().path());
+    out_t::member << name_ << ":" << path << "# " << std::flush;
+    promptLen_ = name_.size() + 1 + path.size() + 1;
+}
+
+prefix_ void senf::console::Client::v_write(boost::posix_time::ptime timestamp,
+                                            std::string const & stream,
+                                            std::string const & area, unsigned level,
+                                            std::string const & message)
+{
+    if (promptLen_)
+        out_t::member << '\r' << std::string(' ', promptLen_) << '\r';
+    IOStreamTarget::v_write(timestamp, stream, area, level, message);
+    if (promptLen_)
+        showPrompt();
+}
+
 ///////////////////////////////cc.e////////////////////////////////////////
 #undef prefix_
 //#include "Server.mpp"