#include "Server.ih"
// Custom includes
-#include <unistd.h>
#include <iostream>
#include <boost/algorithm/string/trim.hpp>
#include <boost/iostreams/device/file_descriptor.hpp>
#include "../Utils/senfassert.hh"
#include "../Utils/membind.hh"
#include "../Utils/Logger/SenfLog.hh"
+#include "Readline.hh"
//#include "Server.mpp"
#define prefix_
std::streamsize n)
{
try {
- if (handle_.writeable())
- handle_.write(s, s+n);
+ if (client_.handle().writeable()) {
+ std::string data (s, n);
+ client_.translate(data);
+ client_.handle().write( data );
+ }
}
catch (SystemException & ex) {
;
}
///////////////////////////////////////////////////////////////////////////
-// senf::console::Client
+// senf::console::detail::DumbClientReader
-prefix_ senf::console::Client::Client(Server & server, ClientHandle handle,
- std::string const & name)
- : out_t(handle), senf::log::IOStreamTarget(out_t::member), server_ (server),
- handle_ (handle), name_ (name), promptLen_(0)
+prefix_ senf::console::detail::DumbClientReader::DumbClientReader(Client & client)
+ : ClientReader(client), promptLen_ (0), promptActive_ (false)
{
showPrompt();
- ReadHelper<ClientHandle>::dispatch( handle_, 16384u, ReadUntil("\n"),
- senf::membind(&Client::clientData, this) );
- route< senf::SenfLog, senf::log::NOTICE >();
-}
-
-prefix_ senf::console::Client::~Client()
-{}
-
-prefix_ void senf::console::Client::stopClient()
-{
- // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER removeClient RETURNS
- server_.removeClient(*this);
+ ReadHelper<ClientHandle>::dispatch( handle(), 16384u, ReadUntil("\n"),
+ senf::membind(&DumbClientReader::clientData, this) );
}
-prefix_ void senf::console::Client::clientData(ReadHelper<ClientHandle>::ptr helper)
+prefix_ void
+senf::console::detail::DumbClientReader::clientData(senf::ReadHelper<ClientHandle>::ptr helper)
{
- promptLen_ = 0;
- if (helper->error() || handle_.eof()) {
+ if (helper->error() || handle().eof()) {
// THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
stopClient();
return;
}
+
+ promptLen_ = 0;
+ promptActive_ = false;
std::string data (tail_ + helper->data());
tail_ = helper->tail();
- boost::trim(data); // Gets rid of superfluous \r or \n characters
+ boost::trim(data); // Gets rid of superfluous \r or \n characters
+ handleInput(data);
+
+ showPrompt();
+ ReadHelper<ClientHandle>::dispatch( handle(), 16384u, ReadUntil("\n"),
+ senf::membind(&DumbClientReader::clientData, this) );
+}
+
+prefix_ void senf::console::detail::DumbClientReader::showPrompt()
+{
+ std::string prompt (promptString());
+
+ stream() << std::flush;
+ handle().write(prompt);
+ promptLen_ = prompt.size();
+ promptActive_ = true;
+}
+
+prefix_ void senf::console::detail::DumbClientReader::v_disablePrompt()
+{
+ if (promptActive_ && promptLen_ > 0) {
+ stream() << '\r' << std::string(' ', promptLen_) << '\r';
+ promptLen_ = 0;
+ }
+}
+
+prefix_ void senf::console::detail::DumbClientReader::v_enablePrompt()
+{
+ if (promptActive_ && ! promptLen_)
+ showPrompt();
+}
+
+prefix_ void senf::console::detail::DumbClientReader::v_translate(std::string & data)
+{}
+
+///////////////////////////////////////////////////////////////////////////
+// senf::console::Client
+
+prefix_ senf::console::Client::Client(Server & server, ClientHandle handle,
+ std::string const & name)
+ : out_t(boost::ref(*this)), senf::log::IOStreamTarget(out_t::member), server_ (server),
+ handle_ (handle), name_ (name), reader_ (new detail::SafeReadlineClientReader (*this))
+{
+ executor_.autocd(true).autocomplete(true);
+ handle_.facet<senf::TCPSocketProtocol>().nodelay();
+ // route< senf::SenfLog, senf::log::NOTICE >();
+}
+
+prefix_ void senf::console::Client::translate(std::string & data)
+{
+ reader_->translate(data);
+}
+
+prefix_ void senf::console::Client::handleInput(std::string data)
+{
if (data.empty())
data = lastCommand_;
else
try {
if (! parser_.parse(data, boost::bind<void>( boost::ref(executor_),
- boost::ref(out_t::member),
+ boost::ref(stream()),
_1 )) )
- out_t::member << "syntax error" << std::endl;
+ stream() << "syntax error" << std::endl;
}
catch (Executor::ExitException &) {
- // THIS COMMITS SUICIDE. THE INSTANCE IS GONE AFTER stopClient RETURNS
- stopClient();
+ // This generates an EOF condition on the Handle. This EOF condition is expected
+ // to be handled gracefully by the ClientReader. We cannot call stop() here, since we
+ // are called from the client reader callback and that will continue executing even if we
+ // call stop here ...
+ handle_.facet<senf::TCPSocketProtocol>().shutdown(senf::TCPSocketProtocol::ShutRD);
return;
}
catch (std::exception & ex) {
- out_t::member << ex.what() << std::endl;
+ stream() << ex.what() << std::endl;
}
catch (...) {
- out_t::member << "unidentified error (unknown exception thrown)" << std::endl;
+ stream() << "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,
+prefix_ void senf::console::Client::v_write(senf::log::time_type 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';
+ reader_->disablePrompt();
IOStreamTarget::v_write(timestamp, stream, area, level, message);
- if (promptLen_)
- showPrompt();
+ out_t::member << std::flush;
+ reader_->enablePrompt();
+}
+
+prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client const & client)
+{
+ typedef ClientSocketHandle< MakeSocketPolicy<
+ INet4AddressingPolicy,ConnectedCommunicationPolicy>::policy > V4Socket;
+ typedef ClientSocketHandle< MakeSocketPolicy<
+ INet6AddressingPolicy,ConnectedCommunicationPolicy>::policy > V6Socket;
+
+ if (check_socket_cast<V4Socket>(client.handle()))
+ os << dynamic_socket_cast<V4Socket>(client.handle()).peer();
+ else if (check_socket_cast<V6Socket>(client.handle()))
+ os << dynamic_socket_cast<V6Socket>(client.handle()).peer();
+ else
+ os << static_cast<void const *>(&client);
+
+ return os;
+}
+
+prefix_ std::ostream & senf::console::operator<<(std::ostream & os, Client * client)
+{
+ return os << *client;
}
///////////////////////////////cc.e////////////////////////////////////////