aboutsummaryrefslogtreecommitdiffstatshomepage
path: root/server/session.cpp
diff options
context:
space:
mode:
authorEgor Tensin <Egor.Tensin@gmail.com>2019-11-30 01:38:08 +0300
committerEgor Tensin <Egor.Tensin@gmail.com>2019-12-01 05:23:11 +0300
commit90bd600c5025ede4db99122f13dfb07b27de46ae (patch)
tree0b581b43e5fcb54114c6c373352ed6ab5fcd61dc /server/session.cpp
downloadmath-server-90bd600c5025ede4db99122f13dfb07b27de46ae.tar.gz
math-server-90bd600c5025ede4db99122f13dfb07b27de46ae.zip
initial commit
Diffstat (limited to '')
-rw-r--r--server/session.cpp113
1 files changed, 113 insertions, 0 deletions
diff --git a/server/session.cpp b/server/session.cpp
new file mode 100644
index 0000000..409ca5a
--- /dev/null
+++ b/server/session.cpp
@@ -0,0 +1,113 @@
+#include "error.hpp"
+#include "log.hpp"
+#include "parser.hpp"
+#include "session.hpp"
+#include "session_manager.hpp"
+
+#include <boost/asio.hpp>
+#include <boost/lexical_cast.hpp>
+#include <boost/system/error_code.hpp>
+#include <boost/system/system_error.hpp>
+
+#include <cstddef>
+
+#include <exception>
+#include <string>
+#include <utility>
+
+namespace math::server {
+namespace {
+
+std::string reply_to_string(double result) {
+ return boost::lexical_cast<std::string>(result);
+}
+
+std::string calc_reply(const std::string& input) {
+ std::string reply;
+ try {
+ reply = reply_to_string(Parser{input}.exec());
+ } catch (const std::exception& e) {
+ reply = e.what();
+ }
+ return reply;
+}
+
+}
+
+Session::Session(SessionManager& mgr, boost::asio::io_context& io_context)
+ : m_session_mgr{mgr}, m_strand{io_context}, m_socket{io_context}
+{ }
+
+boost::asio::ip::tcp::socket& Session::socket() {
+ return m_socket;
+}
+
+void Session::start() {
+ read();
+}
+
+void Session::stop() {
+ close();
+}
+
+void Session::close() {
+ try {
+ m_socket.shutdown(boost::asio::ip::tcp::socket::shutdown_both);
+ m_socket.close();
+ } catch (const boost::system::system_error& e) {
+ throw Error{e.what()};
+ }
+}
+
+void Session::read() {
+ const auto self = shared_from_this();
+
+ // Stop at LF
+ boost::asio::async_read_until(m_socket, m_buffer, '\n', boost::asio::bind_executor(m_strand,
+ [this, self] (const boost::system::error_code& ec, std::size_t bytes) {
+ handle_read(ec, bytes);
+ }));
+}
+
+void Session::handle_read(const boost::system::error_code& ec, std::size_t bytes) {
+ if (ec) {
+ log::error("%1%: %2%", __func__, ec.message());
+ m_session_mgr.stop(shared_from_this());
+ return;
+ }
+
+ write(calc_reply(consume_input(bytes)));
+}
+
+std::string Session::consume_input(std::size_t bytes) {
+ const auto data = boost::asio::buffer_cast<const char*>(m_buffer.data());
+ const std::string input{data, bytes - 1};
+ m_buffer.consume(bytes);
+ return input;
+}
+
+void Session::write(std::string output) {
+ const auto self = shared_from_this();
+
+ // Include CR (so that Windows' telnet client works)
+ output += "\r\n";
+
+ boost::asio::const_buffer buffer{output.c_str(), output.length()};
+
+ boost::asio::async_write(m_socket, std::move(buffer), boost::asio::bind_executor(m_strand,
+ [this, self] (const boost::system::error_code& ec, std::size_t bytes) {
+ handle_write(ec, bytes);
+ }));
+}
+
+void Session::handle_write(const boost::system::error_code& ec, std::size_t bytes) {
+ if (ec) {
+ log::error("%1%: %2%", __func__, ec.message());
+ m_session_mgr.stop(shared_from_this());
+ return;
+ }
+
+ read();
+}
+
+}