1 //
2 // client.hpp
3 // ~~~~~~~~~~~~~~~
4 //
5 // Copyright (c) 2003-2018 Christopher M. Kohlhoff (chris at kohlhoff dot com)
6 //
7 // Distributed under the Boost Software License, Version 1.0. (See accompanying
8 // file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
9 //
10
11 #ifndef CHAT_CLIENT_HPP
12 #define CHAT_CLIENT_HPP
13
14 #include <deque>
15 #include "asio.hpp"
16 #include "chat_message.hpp"
17
18 typedef std::deque<chat_message> chat_message_queue;
19
20 class chat_client
21 {
22 public:
chat_client(asio::io_context & io_context,const asio::ip::tcp::resolver::results_type & endpoints)23 chat_client(asio::io_context& io_context,
24 const asio::ip::tcp::resolver::results_type& endpoints)
25 : io_context_(io_context),
26 socket_(io_context)
27 {
28 do_connect(endpoints);
29 }
30
write(const chat_message & msg)31 void write(const chat_message& msg)
32 {
33 asio::post(io_context_,
34 [this, msg]()
35 {
36 bool write_in_progress = !write_msgs_.empty();
37 write_msgs_.push_back(msg);
38 if (!write_in_progress)
39 {
40 do_write();
41 }
42 });
43 }
44
close()45 void close()
46 {
47 asio::post(io_context_, [this]() { socket_.close(); });
48 }
49
50 private:
do_connect(const asio::ip::tcp::resolver::results_type & endpoints)51 void do_connect(const asio::ip::tcp::resolver::results_type& endpoints)
52 {
53 asio::async_connect(socket_, endpoints,
54 [this](std::error_code ec, asio::ip::tcp::endpoint)
55 {
56 if (!ec)
57 {
58 do_read_header();
59 }
60 });
61 }
62
do_read_header()63 void do_read_header()
64 {
65 asio::async_read(socket_,
66 asio::buffer(read_msg_.data(), chat_message::header_length),
67 [this](std::error_code ec, std::size_t /*length*/)
68 {
69 if (!ec && read_msg_.decode_header())
70 {
71 do_read_body();
72 }
73 else
74 {
75 socket_.close();
76 }
77 });
78 }
79
do_read_body()80 void do_read_body()
81 {
82 asio::async_read(socket_,
83 asio::buffer(read_msg_.body(), read_msg_.body_length()),
84 [this](std::error_code ec, std::size_t /*length*/)
85 {
86 if (!ec)
87 {
88 do_read_header();
89 }
90 else
91 {
92 socket_.close();
93 }
94 });
95 }
96
do_write()97 void do_write()
98 {
99 asio::async_write(socket_,
100 asio::buffer(write_msgs_.front().data(),
101 write_msgs_.front().length()),
102 [this](std::error_code ec, std::size_t /*length*/)
103 {
104 if (!ec)
105 {
106 write_msgs_.pop_front();
107 if (!write_msgs_.empty())
108 {
109 do_write();
110 }
111 }
112 else
113 {
114 socket_.close();
115 }
116 });
117 }
118
119 private:
120 asio::io_context& io_context_;
121 asio::ip::tcp::socket socket_;
122 chat_message read_msg_;
123 chat_message_queue write_msgs_;
124 };
125
126 #endif // CHAT_CLIENT_HPP
127