Samchon Framework for CPP  1.0.0
Server.hpp
1 #pragma once
2 #include <samchon/API.hpp>
3 
4 #include <samchon/protocol/WebServer.hpp>
5 #include <samchon/protocol/IProtocol.hpp>
6 
7 #include <samchon/templates/service/User.hpp>
8 
9 #include <thread>
10 #include <samchon/HashMap.hpp>
11 #include <samchon/library/RWMutex.hpp>
12 
13 namespace samchon
14 {
15 namespace templates
16 {
17 
24 namespace service
25 {
26  class User;
27  class Client;
28 
51  class Server
52  : public protocol::WebServer,
53  public virtual protocol::IProtocol
54  {
55  friend class User;
56 
57  private:
58  typedef WebServer super;
59 
62 
63  library::RWMutex session_map_mtx;
64  library::RWMutex account_map_mtx;
65 
66  public:
67  /* ---------------------------------------------------------
68  CONSTRUCTORS
69  --------------------------------------------------------- */
74  : super()
75  {
76  };
77 
81  virtual ~Server() = default;
82 
83  protected:
89  virtual auto createUser() -> User* = 0;
90 
91  public:
92  /* ---------------------------------------------------------
93  ACCESSORS
94  --------------------------------------------------------- */
101  auto has(const std::string &accountID) const -> bool
102  {
103  return account_map.has(accountID);
104  };
105 
112  auto get(const std::string &accountID) const -> std::shared_ptr<User>
113  {
114  return account_map.get(accountID);
115  };
116 
117  /* ---------------------------------------------------------
118  MESSAGE CHAIN
119  --------------------------------------------------------- */
142  virtual void sendData(std::shared_ptr<protocol::Invoke> invoke) override
143  {
144  std::vector<std::thread> threadArray;
145  library::UniqueReadLock uk(session_map_mtx);
146 
147  threadArray.reserve(session_map.size());
148  for (auto it = session_map.begin(); it != session_map.end(); it++)
149  threadArray.emplace_back(&User::sendData, it->second.get(), invoke);
150 
151  uk.unlock();
152  for (auto it = threadArray.begin(); it != threadArray.end(); it++)
153  it->join();
154  };
155 
165  virtual void replyData(std::shared_ptr<protocol::Invoke>) = 0;
166 
167  private:
168  /* ---------------------------------------------------------
169  CLIENT I/O
170  --------------------------------------------------------- */
190  virtual void addClient(std::shared_ptr<protocol::ClientDriver> driver) final
191  {
192  std::shared_ptr<protocol::WebClientDriver> web_driver = std::dynamic_pointer_cast<protocol::WebClientDriver>(driver);
193 
194  // IDENTIFIERS
195  const std::string &session_id = web_driver->getSessionID(); // SESSION_ID -> USER
196  const std::string &path = web_driver->getPath(); // PATH -> SERVICE
197 
199  // CONSTRUCT USER
201  std::shared_ptr<User> user;
203  {
204  library::UniqueReadLock uk(session_map_mtx);
205  it = session_map.find(session_id);
206  }
207 
208  if (it == session_map.end())
209  {
210  // CREATE USER
211  user.reset(this->createUser());
212  user->my_weak_ptr = user;
213 
214  // REGISTER TO THIS SERVER
215  library::UniqueWriteLock uk(session_map_mtx);
216  session_map.insert({ session_id, user });
217  }
218  else
219  user = it->second; // FETCH ORDINARY USER
220 
221  user->account_map = &account_map;
222  user->account_map_mtx = &account_map_mtx;
223  user->erase_user_function = std::bind(&Server::erase_user, this, user.get());
224 
226  // CREATE CLIENT
228  std::shared_ptr<Client> client(user->createClient());
229  client->user_weak_ptr = user;
230  client->my_weak_ptr = client;
231 
232  // REGISTER TO USER
233  {
234  library::UniqueWriteLock uk(user->mtx);
235 
236  client->no = ++user->sequence;
237  user->insert({ client->no, client });
238  }
239 
241  // CREATE SERVICE
243  Service *service = client->createService(path);
244  service->client = client.get();
245  service->path = path;
246 
247  service->user_weak_ptr = user;
248  service->client_weak_ptr = client;
249 
250  // REGISTER TO CLIENT
251  client->service.reset(service);
252 
254  // BEGINS COMMUNICATION
256  client->driver->listen(client.get());
257 
258  // DISCONNECTED - ERASE CLIENT.
259  // IF THE USER HAS NO CLIENT LEFT, THEN THE USER WILL ALSO BE ERASED.
260  user->erase(client->no);
261  user->check_empty();
262  };
263 
264  void erase_user(User *user)
265  {
266  // USER DOESN'T BE ERASED AT THAT TIME
267  // IT WAITS UNTIL 30 SECONDS TO KEEP SESSION
268  std::this_thread::sleep_for(std::chrono::seconds(30));
269 
270  if (user->empty() == false)
271  {
272  // ERASE FROM ACCOUNT_MAP
273  if (user->account.empty() == false)
274  {
275  library::UniqueWriteLock w_uk(account_map_mtx);
276  account_map.erase(user->account);
277  }
278 
279  // ERASE FROM SESSION_MAP
280  {
281  library::UniqueWriteLock w_uk(session_map_mtx);
282  session_map.erase(user->session_id);
283  }
284  }
285  };
286  };
287 };
288 };
289 };
virtual void sendData(std::shared_ptr< protocol::Invoke > invoke) override
Definition: Server.hpp:142
virtual void replyData(std::shared_ptr< protocol::Invoke >)=0
auto has(const Key &key) const -> bool
Whether have the item or not.
Definition: HashMap.hpp:125
auto getSessionID() const -> std::string
auto has(const std::string &accountID) const -> bool
Definition: Server.hpp:101
virtual void addClient(std::shared_ptr< protocol::ClientDriver > driver) final
Definition: Server.hpp:190
auto get(const Key &key) -> T &
Get element.
Definition: HashMap.hpp:144
void unlock() const
Unlock of read.
virtual auto createUser() -> User *=0
Unique lock for reading.
Unique lock for writing.
Customized std::unordered_map.
Definition: HashMap.hpp:103
virtual void sendData(std::shared_ptr< protocol::Invoke > invoke) override
Definition: User.hpp:229