Samchon Framework for CPP  1.0.0
IWebClientBase.cpp
1 #include <samchon/protocol/IWebClientBase.hpp>
2 
3 #include <memory>
4 #include <mutex>
5 #include <boost/asio.hpp>
6 
7 #include <samchon/ByteArray.hpp>
8 #include <samchon/WeakString.hpp>
9 #include <samchon/library/XML.hpp>
10 #include <samchon/protocol/Invoke.hpp>
11 
12 using namespace std;
13 using namespace samchon;
14 using namespace samchon::library;
15 using namespace samchon::protocol;
16 
17 /* -----------------------------------------------------------------------
18  CONSTRUCTORS
19 ----------------------------------------------------------------------- */
20 IWebClientBase::IWebClientBase()
21  : super()
22 {
23 }
24 
25 /* -----------------------------------------------------------------------
26  LISTEN MESSAGE
27 ----------------------------------------------------------------------- */
29 {
30  shared_ptr<Invoke> binaryInvoke;
31 
32  // CLIENT ADDS MASK
33  unsigned char mask = DIRECTION() == SERVER ? 128 : 0;
34 
35  while (true)
36  {
37  ByteArray piece;
38  boost::system::error_code error;
39 
40  piece.assign(BUFFER_SIZE(), NULL);
41  socket->read_some(boost::asio::buffer(piece), error);
42 
43  while (piece.getPosition() != piece.size())
44  {
45  if (error)
46  return;
47 
48  // GET TYPE
49  unsigned char typeHeader = piece.read<unsigned char>();
50  if (piece.leftSize() == 0)
51  continue;
52 
53  // GET SIZE TYPE
54  unsigned char sizeHeader = piece.read<unsigned char>() - mask;
55  if (piece.leftSize() == 0)
56  continue;
57 
58  // GET SIZE
59  size_t size = 125;
60  if (sizeHeader == 126)
61  {
62  if (piece.leftSize() < sizeof(unsigned short))
63  listenMoreBytes(piece, error);
64 
65  if (error)
66  break;
67 
68  size = (size_t)piece.readReversely<unsigned short>();
69  }
70  else if (sizeHeader == 127)
71  {
72  if (piece.leftSize() < sizeof(unsigned long long))
73  listenMoreBytes(piece, error);
74 
75  if (error)
76  break;
77 
78  size = (size_t)piece.readReversely<unsigned long long>();
79  }
80 
81  // GET DATA FOLLOWING TYPE
82  if (typeHeader == (unsigned char)129)
83  binaryInvoke = listenString(size, piece, error);
84  else if (typeHeader == (unsigned char)130 && binaryInvoke != nullptr)
85  listenBinary(size, piece, binaryInvoke, error);
86  else
87  break;
88  }
89  }
90 }
91 auto IWebClientBase::listenString(size_t size, ByteArray &piece, boost::system::error_code &error) -> shared_ptr<Invoke>
92 {
93  string data;
94 
95  data.reserve(size);
96  data.append(piece.read<string>());
97 
98  //LISTEN UNTIL TO MEET THE CAPACITY
99  while (data.size() < size)
100  {
101  piece.assign(BUFFER_SIZE(), NULL);
102  socket->read_some(boost::asio::buffer(piece), error);
103 
104  data.append(piece.read<string>());
105  }
106 
107  // CONSTRUCT INVOKE MESSAGES
108  size_t start = data.find("<invoke listener=");
109  size_t end = data.rfind("</invoke>");
110  if (start == string::npos || end == string::npos)
111  return nullptr;
112 
113  WeakString wstr(&data[0], &data[end + string("</invoke").size()]);
114  shared_ptr<XML> xml(new XML(wstr));
115 
116  shared_ptr<Invoke> invoke(new Invoke());
117  invoke->construct(xml);
118 
119  for (size_t i = 0; i < invoke->size(); i++)
120  if (invoke->at(i)->getType() == "ByteArray")
121  return invoke;
122 
123  _replyData(invoke);
124  return nullptr;
125 }
126 void IWebClientBase::listenBinary(size_t size, ByteArray &piece, shared_ptr<Invoke> invoke, boost::system::error_code &error)
127 {
128  ByteArray *data = nullptr;
129  size_t paramIndex;
130 
131  for (paramIndex = 0; paramIndex < invoke->size(); paramIndex++)
132  if (invoke->at(paramIndex)->getType() == "ByteArray")
133  {
134  const ByteArray &byteArray = invoke->at(paramIndex)->referValue<ByteArray>();
135  if (byteArray.size() == 0 && byteArray.capacity() == size)
136  {
137  data = (ByteArray*)&byteArray;
138  break;
139  }
140  }
141 
142  if (data == nullptr)
143  return;
144 
145  data->insert
146  (
147  data->end(),
148  piece.begin(),
149  piece.begin() + std::min(piece.size(), size)
150  );
151 
152  while (data->size() < size)
153  {
154  piece.assign(BUFFER_SIZE(), NULL);
155  socket->read_some(boost::asio::buffer(piece), error);
156 
157  data->insert
158  (
159  data->end(),
160  piece.begin(),
161  piece.begin() + std::min(piece.size(), size - data->size())
162  );
163  }
164 
165  for(size_t i = paramIndex + 1; i < invoke->size(); i++)
166  if(invoke->at(i)->getType() == "ByteArray")
167  return;
168 
169  _replyData(invoke);
170 }
171 
172 void IWebClientBase::listenMoreBytes(ByteArray &piece, boost::system::error_code &error)
173 {
174  ByteArray myPiece;
175  myPiece.assign(BUFFER_SIZE(), NULL);
176 
177  socket->read_some(boost::asio::buffer(piece), error);
178  if (error)
179  return;
180 
181  piece.write(myPiece);
182 }
183 
184 void IWebClientBase::sendData(shared_ptr<Invoke> invoke)
185 {
186  unique_lock<mutex> uk(*sendMtx);
187  boost::system::error_code error;
188 
189  sendString(invoke->toXML()->toString(), error);
190 
191  if (error)
192  return;
193 
194  for (size_t i = 0; i < invoke->size(); i++)
195  if (invoke->at(i)->getType() == "ByteArray")
196  {
197  sendBinary(invoke->at(i)->referValue<ByteArray>(), error);
198 
199  if (error)
200  return;
201  }
202 }
203 
204 /* -----------------------------------------------------------------------
205  SEND MESSAGE
206 ----------------------------------------------------------------------- */
207 void IWebClientBase::sendSizeHeader(unsigned char type, size_t size, boost::system::error_code &error)
208 {
209  ByteArray header;
210  header.write(type); //1000 0001
211 
212  unsigned char mask = (DIRECTION() == CLIENT) ? 128 : 0;
213 
214  if (size < 126)
215  {
216  header.write((unsigned char)size + mask);
217  }
218  else if (size <= 66535)
219  {
220  header.write((unsigned char)126 + mask);
221  header.writeReversely((unsigned short)size);
222  }
223  else
224  {
225  header.write((unsigned char)127 + mask);
226  header.writeReversely((unsigned long long)size);
227  }
228 
229  socket->write_some(boost::asio::buffer(header), error);
230 }
231 
232 void IWebClientBase::sendString(const string &data, boost::system::error_code &error)
233 {
234  sendSizeHeader(TEXT_HEADER, data.size(), error);
235 
236  if (error)
237  return;
238 
239  socket->write_some(boost::asio::buffer(data), error); if (error) return;
240 }
241 void IWebClientBase::sendBinary(const ByteArray &data, boost::system::error_code &error)
242 {
243  sendSizeHeader(BINARY_HEADER, data.size(), error);
244 
245  if (error)
246  return;
247 
248  socket->write_some(boost::asio::buffer(data), error); if (error) return;
249 }
auto getPosition() const -> size_t
Get position.
Definition: ByteArray.cpp:46
virtual void sendData(std::shared_ptr< Invoke >) override
Sends message to a related system.
Definition: RWMutex.hpp:4
Package of libraries.
Definition: library.hpp:84
virtual void listen() override
Listens message from a related system.
auto read() const -> T
Read data.
Definition: ByteArray.hpp:121
void writeReversely(const T &val)
Write a data.
Definition: ByteArray.hpp:193
std::mutex * sendMtx
A mutex for sending message.
Definition: IClient.hpp:65
Package of network protocol and libraries.
Definition: protocol.hpp:185
An interface for a client.
Definition: IClient.hpp:53
Standard message of network I/O.
Definition: Invoke.hpp:47
Binary data class.
Definition: ByteArray.hpp:30
Socket * socket
Socket for network I/O.
Definition: IClient.hpp:60
virtual void _replyData(std::shared_ptr< Invoke >)
A method for pre-processing replied Invoke message.
Definition: IClient.cpp:333
XML is a class representing xml object.
Definition: XML.hpp:72
auto readReversely() const -> T
Read a reversed data.
Definition: ByteArray.hpp:152
virtual auto BUFFER_SIZE() const -> size_t
Buffer size of network I/O.
Definition: IClient.cpp:25
Top level namespace of products built from samchon.
Definition: ByteArray.hpp:7
void write(const T &val)
Write a data.
Definition: ByteArray.hpp:168
A string class only references characeters, reference only.
Definition: WeakString.hpp:32