Samchon Framework for CPP  1.0.0
IClient.cpp
1 #include <samchon/protocol/IClient.hpp>
2 
3 #include <iostream>
4 #include <mutex>
5 #include <list>
6 
7 #include <boost/asio.hpp>
8 #include <samchon/ByteArray.hpp>
9 #include <samchon/WeakString.hpp>
10 
11 #include <samchon/protocol/Invoke.hpp>
12 #include <samchon/library/XML.hpp>
13 
14 using namespace samchon;
15 using namespace samchon::library;
16 using namespace samchon::protocol;
17 
18 using namespace std;
19 using namespace boost::asio;
20 using namespace boost::asio::ip;
21 
22 /* -----------------------------------------------------------------------------------
23  SEMI STATIC GETTER
24 ----------------------------------------------------------------------------------- */
25 auto IClient::BUFFER_SIZE() const -> size_t { return 10000; }
26 
27 /* -----------------------------------------------------------------------------------
28  CONSTRUCTORS
29 ----------------------------------------------------------------------------------- */
30 IClient::IClient()
31 {
32  socket = nullptr;
33  sendMtx = new mutex();
34 }
35 IClient::~IClient()
36 {
37  if (socket != nullptr)
38  socket->close();
39  delete sendMtx;
40 }
41 
42 /* -----------------------------------------------------------------------------------
43  LISTENERS
44 ----------------------------------------------------------------------------------- */
45 void IClient::listen()
46 {
47  //BASIC DATA
48  string str = "";
49  std::shared_ptr<Invoke> ba_invoke(nullptr);
50 
51  while (true)
52  {
53  ByteArray piece;
54  boost::system::error_code error;
55 
56  piece.assign(BUFFER_SIZE(), NULL);
57  size_t size = socket->read_some(boost::asio::buffer(piece), error);
58 
59  if (error)
60  break;
61 
62  if(ba_invoke == nullptr)
63  handleString(piece, str, ba_invoke, size);
64  else
65  handleBinary(piece, str, ba_invoke, size);
66  }
67 }
68 void IClient::handleString(ByteArray &piece, string &str, shared_ptr<Invoke> &baInvoke, size_t size)
69 {
70  static size_t CLOSED_PARENTHESIS = string("</invoke>").size();
71 
72  if (piece.getPosition() >= size)
73  return;
74 
75  // LIST OF INVOKE MESSAGES
76  list<shared_ptr<Invoke>> invokeList;
77 
78  // READ STRING
79  string &pieceString = piece.read<string>();
80  str.append(pieceString);
81 
82  WeakString wstr = str;
83  vector<WeakString> &wstrArray = wstr.betweens("<invoke ", "</invoke>");
84 
85  for (size_t i = 0; i < wstrArray.size(); i++)
86  {
87  string &message = "<invoke " + wstrArray[i].str() + "</invoke>";
88 
89  shared_ptr<Invoke> invoke( new Invoke() );
90  invoke->construct(make_shared<XML>(message));
91 
92  invokeList.push_back(invoke);
93  }
94 
95  /*list<shared_ptr<Invoke>> invokeList;
96  pair<size_t, size_t> posPair = {-1, -1};
97  pair<size_t, size_t> sizePair = {0, 0};
98  pair<size_t, size_t> indexPair = {0, 0};
99 
100  size_t endIndex = -1;
101 
102  while (true)
103  {
104  // FIND WORDS
105  pair<size_t, size_t> myPair =
106  {
107  str.find("<invoke ", indexPair.first),
108  str.find("</invoke>", indexPair.second)
109  };
110 
111  // COUNTS
112  if (myPair.first != -1)
113  {
114  sizePair.first++;
115  indexPair.first = myPair.first + string("<invoke ").size();
116  }
117  if (myPair.second != -1)
118  {
119  sizePair.second++;
120  indexPair.second = myPair.second + string("</invoke>").size();
121  }
122 
123  // IF AN INVOKE MESSAGE HAS FOUND
124  if (sizePair.first == sizePair.second && sizePair.first != 0)
125  {
126  if (posPair.first == -1 && posPair.second == -1)
127  posPair = myPair;
128  else
129  posPair.second = myPair.second;
130 
131  endIndex = posPair.second + string("</invoke>").size();
132 
133  WeakString wstr(str.data() + posPair.first, str.data() + endIndex);
134  shared_ptr<XML> xml(new XML(wstr));
135  shared_ptr<Invoke> invoke(new Invoke());
136 
137  invoke->construct(xml);
138 
139  cout << invoke->toXML()->toString() << endl;
140 
141  invokeList.push_back(invoke);
142 
143  posPair = { -1, -1 };
144  }
145  else if (myPair.first != -1 && posPair.first == -1)
146  posPair.first = myPair.first;
147  }*/
148 
149  //BASIC DATA
150  /*list<shared_ptr<Invoke>> invokeList;
151  unique_ptr<pair<size_t, size_t>> indexPair(nullptr);
152  pair<size_t, size_t> sizePair = {0, 0};
153  size_t startIndex = 0;
154  size_t endIndex = 0;
155 
156  while (true)
157  {
158  //FIND WORDS
159  pair<size_t, size_t> iPair =
160  {
161  str.find("<invoke ", startIndex),
162  str.find("</invoke>", endIndex)
163  };
164 
165  //COUNTS
166  if (iPair.first != -1) sizePair.first++;
167  if (iPair.second != -1) sizePair.second++;
168 
169  //IF IT MEANS THE START,
170  if (indexPair.get() != nullptr && sizePair.first == 0)
171  {
172  //SPECIFY THE STARTING INDEX
173  indexPair.reset(new pair<size_t, size_t>(iPair.first, string::npos));
174  }
175 
176  //FAILED TO FIND NOTHING
177  if(iPair.first == string::npos || iPair.second == string::npos)
178  break;
179 
180  //AN INVOKE HAS FOUND
181  if(indexPair.get() != nullptr && sizePair.first == sizePair.second)
182  {
183  //INDEX
184  size_t start = indexPair->first;
185  size_t end = indexPair->second + string("</invoke>").size();
186 
187  //CONSTRUCT INVOKE
188  shared_ptr<XML> xml(new XML(str.substr(start, end - start)));
189  shared_ptr<Invoke> invoke(new Invoke());
190  invoke->construct(xml);
191 
192  invokeList.push_back(invoke);
193 
194  //CLEAR CURRENT INEX PAIR
195  endIndex = end;
196  indexPair.reset(nullptr);
197  }
198 
199  //ADJUST INDEX
200  startIndex = (iPair.second == string::npos) ?
201  iPair.first + 1 : iPair.second + 1;
202  }
203 
204  //ERASE USED CHARACTERS
205  if (endIndex != string::npos)
206  str = str.substr(endIndex);*/
207 
208  if (invokeList.empty() == true)
209  return;
210 
211  /*str = str.substr(endIndex);
212  cout << "#" << invokeList.size() << endl;*/
213 
214  // CUT USED STRING
215  str = move(str.substr(str.rfind("</invoke>") + CLOSED_PARENTHESIS));
216 
217  //CALL REPLY_DATA
218  auto last_it = --invokeList.end();
219  for (auto it = invokeList.begin(); it != last_it; it++)
220  _replyData(*it);
221 
222  //TEST WHETHER THE LAST CONTAINS BINARY DATA
223  shared_ptr<Invoke> &lastInvoke = *last_it;
224  for (size_t i = 0; i < lastInvoke->size(); i++)
225  {
226  //IF HAS, TO HANDLE_BINARY
227  if (lastInvoke->at(i)->getType() == "ByteArray")
228  {
229  baInvoke = lastInvoke;
230 
231  piece.setPosition
232  (
233  piece.getPosition() -
234  (pieceString.size() - (pieceString.rfind("</invoke>") + CLOSED_PARENTHESIS))
235  );
236 
237  //HANDLING LEFT BINARY PIECE
238  handleBinary(piece, str, baInvoke, size);
239  return;
240  }
241  }
242 
243  //ELSE, DOES NOT HAVE, CALL REPLY_DATA
244  _replyData(lastInvoke);
245 }
246 void IClient::handleBinary(ByteArray &piece, string &str, shared_ptr<Invoke> &invoke, size_t size)
247 {
248  if (piece.getPosition() >= size)
249  return;
250 
251  ByteArray *byteArray = nullptr;
252  size_t position = piece.getPosition();
253  size_t param_index = 0;
254 
255  //FIND WHICH PARAMETER IS BINARY
256  for (size_t i = 0; i < invoke->size(); i++)
257  if (invoke->at(i)->getType() == "ByteArray")
258  {
259  const ByteArray &ba = invoke->at(i)->referValue<ByteArray>();
260 
261  if (ba.size() < ba.capacity())
262  {
263  param_index = i;
264  byteArray = (ByteArray*)&ba;
265 
266  break;
267  }
268  }
269 
270  //IF THERE'S NOT BINARY TYPE
271  if(byteArray == nullptr)
272  return;
273 
274  //CALCULATE SIZE
275  size_t totalSize = byteArray->capacity();
276  size_t leftSize = totalSize - byteArray->size();
277  size_t writeSize = std::min(size - position, leftSize);
278 
279  //AND WRITES
280  byteArray->insert
281  (
282  byteArray->end(),
283  piece.begin() + position, piece.begin() + (position + writeSize)
284  );
285  piece.setPosition( position + writeSize );
286 
287  // IF NOT FULFILLED, RETURNS
288  if (byteArray->size() < byteArray->capacity())
289  return;
290 
291  //IF LAST BINARY
292  for(size_t i = param_index + 1; i < invoke->size(); i++)
293  if(invoke->at(i)->getType() == "ByteArray")
294  return;
295 
296  // SHIFTS
297  _replyData(invoke);
298 
299  //IS LAST BINARY, THEN CLEAR
300  invoke.reset();
301 
302  //IF BYTES ARE LEFT, CALL HANDLE_STRING
303  handleString(piece, str, invoke, size);
304 }
305 
306 /* -----------------------------------------------------------------------------------
307  CHAIN OF INVOKE MESSAGE
308 ----------------------------------------------------------------------------------- */
309 void IClient::sendData(shared_ptr<Invoke> invoke)
310 {
311  string &data = invoke->toXML()->toString();
312  boost::system::error_code error;
313 
314  unique_lock<mutex> uk(*sendMtx);
315  socket->write_some(boost::asio::buffer(data), error);
316 
317  if (error)
318  {
319  cout << error.message() << endl;
320  return;
321  }
322 
323  for (size_t i = 0; i < invoke->size(); i++)
324  if (invoke->at(i)->getType() == "ByteArray")
325  {
326  const ByteArray &byteArray = invoke->at(i)->referValue<ByteArray>();
327  socket->write_some(boost::asio::buffer(byteArray), error);
328 
329  if (error)
330  return;
331  }
332 }
333 void IClient::_replyData(shared_ptr<Invoke> invoke)
334 {
335  replyData(invoke);
336 }
auto getPosition() const -> size_t
Get position.
Definition: ByteArray.cpp:46
Definition: RWMutex.hpp:4
Package of libraries.
Definition: library.hpp:84
auto read() const -> T
Read data.
Definition: ByteArray.hpp:121
Package of network protocol and libraries.
Definition: protocol.hpp:185
Standard message of network I/O.
Definition: Invoke.hpp:47
Binary data class.
Definition: ByteArray.hpp:30
void setPosition(size_t)
Set poisition.
Definition: ByteArray.cpp:50
auto betweens(const WeakString &start={}, const WeakString &end={}) const -> std::vector< WeakString >
Generates substrings.
Definition: WeakString.cpp:237
Top level namespace of products built from samchon.
Definition: ByteArray.hpp:7
A string class only references characeters, reference only.
Definition: WeakString.hpp:32