X-Git-Url: http://g0dil.de/git?a=blobdiff_plain;f=Console%2FServer.cc;h=856a67c6b6dded059659a26fd8ce7a80c649c1b5;hb=bf1d8ba5ce6fc6a169a938183f8d01c8bdbccf32;hp=4e37e68c403709ed6e4bbbf92b53716ccfeba385;hpb=9c0078ac0054789badff2a987364ed0448b080ef;p=senf.git diff --git a/Console/Server.cc b/Console/Server.cc index 4e37e68..856a67c 100644 --- a/Console/Server.cc +++ b/Console/Server.cc @@ -24,7 +24,7 @@ \brief Server non-inline non-template implementation */ #include "Server.hh" -//#include "Server.ih" +#include "Server.ih" // Custom includes #include @@ -41,6 +41,25 @@ #define prefix_ ///////////////////////////////cc.p//////////////////////////////////////// +/////////////////////////////////////////////////////////////////////////// +// senf::console::detail::NonBlockingSocketSink + +prefix_ std::streamsize senf::console::detail::NonblockingSocketSink::write(const char * s, + std::streamsize n) +{ + try { + if (handle_.writeable()) + handle_.write(s, s+n); + } + catch (SystemException & ex) { + ; + } + return n; +} + +/////////////////////////////////////////////////////////////////////////// +// senf::console::Server + prefix_ senf::console::Server & senf::console::Server::start(senf::INet4SocketAddress const & address) { @@ -48,7 +67,7 @@ senf::console::Server::start(senf::INet4SocketAddress const & address) senf::console::Server::start(handle); SENF_LOG((Server::SENFLogArea)(log::NOTICE)( "Console server started at " << address )); - return *instance_; + return instance(); } prefix_ senf::console::Server & @@ -58,18 +77,31 @@ senf::console::Server::start(senf::INet6SocketAddress const & address) senf::console::Server::start(handle); SENF_LOG((Server::SENFLogArea)(log::NOTICE)( "Console server started at " << address )); - return *instance_; + return instance(); } -/////////////////////////////////////////////////////////////////////////// -// senf::console::Server +prefix_ senf::console::Server & senf::console::Server::instance() +{ + SENF_ASSERT( instancePtr() ); + return *instancePtr(); +} -boost::scoped_ptr senf::console::Server::instance_; +prefix_ boost::scoped_ptr & senf::console::Server::instancePtr() +{ + // We cannot make 'instance' a global or class-static variable, since it will then be destructed + // at an unknown time which may fail if the scheduler or the file-handle pool allocators have + // already been destructed. + static boost::scoped_ptr instance; + return instance; +} prefix_ void senf::console::Server::start(ServerHandle handle) { - SENF_ASSERT( ! instance_ ); - instance_.reset(new Server(handle)); + // Uah .... ensure the scheduler is created before the instance pointer so it get's destructed + // AFTER it. + (void) senf::Scheduler::instance(); + SENF_ASSERT( ! instancePtr() ); + instancePtr().reset(new Server(handle)); } prefix_ senf::console::Server::Server(ServerHandle handle) @@ -102,11 +134,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(handle), senf::log::IOStreamTarget(out_t::member), + handle_ (handle), name_ (name), promptLen_(0) { showPrompt(); ReadHelper::dispatch( handle_, 16384u, ReadUntil("\n"), senf::membind(&Client::clientData, this) ); + route< senf::SenfLog, senf::log::NOTICE >(); } prefix_ senf::console::Client::~Client() @@ -115,11 +149,12 @@ prefix_ senf::console::Client::~Client() prefix_ void senf::console::Client::stopClient() { // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS - Server::instance_->removeClient(*this); + Server::instance().removeClient(*this); } prefix_ void senf::console::Client::clientData(ReadHelper::ptr helper) { + promptLen_ = 0; if (helper->error() || handle_.eof()) { // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS stopClient(); @@ -130,9 +165,16 @@ prefix_ void senf::console::Client::clientData(ReadHelper::ptr hel tail_ = helper->tail(); boost::trim(data); // Gets rid of superfluous \r or \n characters + if (data.empty()) + data = lastCommand_; + else + lastCommand_ = data; + try { - if (! parser_.parse(data, boost::bind(boost::ref(executor_), _1, boost::ref(out_)))) - out_ << "syntax error" << std::endl; + if (! parser_.parse(data, boost::bind( boost::ref(executor_), + boost::ref(out_t::member), + _1 )) ) + out_t::member << "syntax error" << std::endl; } catch (Executor::ExitException &) { // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS @@ -140,10 +182,10 @@ prefix_ void senf::console::Client::clientData(ReadHelper::ptr hel return; } catch (std::exception & ex) { - out_ << ex.what() << std::endl; + out_t::member << ex.what() << std::endl; } catch (...) { - out_ << "unidentified error (unknown exception thrown)" << std::endl; + out_t::member << "unidentified error (unknown exception thrown)" << std::endl; } showPrompt(); @@ -153,7 +195,21 @@ prefix_ void senf::console::Client::clientData(ReadHelper::ptr hel prefix_ void senf::console::Client::showPrompt() { - out_ << name_ << ":" << executor_.cwd().path() << "# " << std::flush; + 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////////////////////////////////////////