blob: 67305f2270603299dc805b2d057c436163de4b4e [file] [log] [blame]
Yingdi Yud45777b2014-10-16 23:54:11 -07001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
2/*
Junxiao Shid5798f22016-08-22 02:33:26 +00003 * Copyright (c) 2013-2016, Regents of the University of California
4 * Yingdi Yu
Yingdi Yud45777b2014-10-16 23:54:11 -07005 *
6 * BSD license, See the LICENSE file for more information
7 *
8 * Author: Yingdi Yu <yingdi@cs.ucla.edu>
Yingdi Yuf3401182015-02-02 20:21:07 -08009 * Qiuhan Ding <qiuhanding@cs.ucla.edu>
Yingdi Yud45777b2014-10-16 23:54:11 -070010 */
11
12#include "chat-dialog-backend.hpp"
13
Yingdi Yu45da92a2015-02-02 13:17:03 -080014#include <QFile>
15
Yingdi Yud45777b2014-10-16 23:54:11 -070016#ifndef Q_MOC_RUN
Junxiao Shid5798f22016-08-22 02:33:26 +000017#include <boost/iostreams/stream.hpp>
Yingdi Yud45777b2014-10-16 23:54:11 -070018#include <ndn-cxx/util/io.hpp>
Yingdi Yu45da92a2015-02-02 13:17:03 -080019#include <ndn-cxx/security/validator-regex.hpp>
Yingdi Yud45777b2014-10-16 23:54:11 -070020#include "logging.h"
21#endif
22
23
24INIT_LOGGER("ChatDialogBackend");
25
Yingdi Yueb692ac2015-02-10 18:46:18 -080026namespace chronochat {
Yingdi Yud45777b2014-10-16 23:54:11 -070027
28static const time::milliseconds FRESHNESS_PERIOD(60000);
29static const time::seconds HELLO_INTERVAL(60);
Qiuhan Dingba3e57a2015-01-08 19:07:39 -080030static const ndn::Name::Component ROUTING_HINT_SEPARATOR =
31 ndn::name::Component::fromEscapedString("%F0%2E");
Qiuhan Ding43c8e162015-02-02 15:16:48 -080032static const int IDENTITY_OFFSET = -3;
Yingdi Yuf3401182015-02-02 20:21:07 -080033static const int CONNECTION_RETRY_TIMER = 3;
Yingdi Yud45777b2014-10-16 23:54:11 -070034
35ChatDialogBackend::ChatDialogBackend(const Name& chatroomPrefix,
36 const Name& userChatPrefix,
37 const Name& routingPrefix,
38 const std::string& chatroomName,
39 const std::string& nick,
Yingdi Yu45da92a2015-02-02 13:17:03 -080040 const Name& signingId,
Yingdi Yud45777b2014-10-16 23:54:11 -070041 QObject* parent)
42 : QThread(parent)
Yingdi Yuf3401182015-02-02 20:21:07 -080043 , m_shouldResume(false)
Yingdi Yud45777b2014-10-16 23:54:11 -070044 , m_localRoutingPrefix(routingPrefix)
45 , m_chatroomPrefix(chatroomPrefix)
46 , m_userChatPrefix(userChatPrefix)
47 , m_chatroomName(chatroomName)
48 , m_nick(nick)
Yingdi Yu45da92a2015-02-02 13:17:03 -080049 , m_signingId(signingId)
Yingdi Yud45777b2014-10-16 23:54:11 -070050{
51 updatePrefixes();
52}
53
54
55ChatDialogBackend::~ChatDialogBackend()
56{
57}
58
59// protected methods:
60void
61ChatDialogBackend::run()
62{
Yingdi Yu4647f022015-02-01 00:26:38 -080063 bool shouldResume = false;
64 do {
65 initializeSync();
Yingdi Yud45777b2014-10-16 23:54:11 -070066
Yingdi Yu4647f022015-02-01 00:26:38 -080067 if (m_face == nullptr)
68 break;
69
Yingdi Yuf3401182015-02-02 20:21:07 -080070 try {
71 m_face->getIoService().run();
72 }
73 catch (std::runtime_error& e) {
74 {
75 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
76 m_isNfdConnected = false;
77 }
78 emit nfdError();
79 {
80 std::lock_guard<std::mutex>lock(m_resumeMutex);
81 m_shouldResume = true;
82 }
83#ifdef BOOST_THREAD_USES_CHRONO
84 time::seconds reconnectTimer = time::seconds(CONNECTION_RETRY_TIMER);
85#else
86 boost::posix_time::time_duration reconnectTimer;
87 reconnectTimer = boost::posix_time::seconds(CONNECTION_RETRY_TIMER);
88#endif
89 while (!m_isNfdConnected) {
90#ifdef BOOST_THREAD_USES_CHRONO
91 boost::this_thread::sleep_for(reconnectTimer);
92#else
93 boost::this_thread::sleep(reconnectTimer);
94#endif
95 }
96 emit refreshChatDialog(m_routableUserChatPrefix);
97 }
Qiuhan Dingf22c41b2015-03-11 13:19:01 -070098 {
Yingdi Yuf3401182015-02-02 20:21:07 -080099 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700100 shouldResume = m_shouldResume;
101 m_shouldResume = false;
102 }
Yingdi Yuf3401182015-02-02 20:21:07 -0800103 close();
Yingdi Yu4647f022015-02-01 00:26:38 -0800104
105 } while (shouldResume);
Yingdi Yud45777b2014-10-16 23:54:11 -0700106
107 std::cerr << "Bye!" << std::endl;
108}
109
110// private methods:
111void
112ChatDialogBackend::initializeSync()
113{
Yingdi Yu4647f022015-02-01 00:26:38 -0800114 BOOST_ASSERT(m_sock == nullptr);
Yingdi Yud45777b2014-10-16 23:54:11 -0700115
Yingdi Yu45da92a2015-02-02 13:17:03 -0800116 m_face = make_shared<ndn::Face>();
Yingdi Yu4647f022015-02-01 00:26:38 -0800117 m_scheduler = unique_ptr<ndn::Scheduler>(new ndn::Scheduler(m_face->getIoService()));
Yingdi Yud45777b2014-10-16 23:54:11 -0700118
Yingdi Yu45da92a2015-02-02 13:17:03 -0800119 // initialize validator
120 shared_ptr<ndn::IdentityCertificate> anchor = loadTrustAnchor();
121
122 if (static_cast<bool>(anchor)) {
123 shared_ptr<ndn::ValidatorRegex> validator =
124 make_shared<ndn::ValidatorRegex>(m_face.get()); // TODO: Change to Face*
125 validator->addDataVerificationRule(
126 make_shared<ndn::SecRuleRelative>("^<>*<%F0.>(<>*)$",
127 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
128 ">", "\\1", "\\1\\2", true));
129 validator->addDataVerificationRule(
130 make_shared<ndn::SecRuleRelative>("(<>*)$",
131 "^([^<KEY>]*)<KEY>(<>*)<ksk-.*><ID-CERT>$",
132 ">", "\\1", "\\1\\2", true));
133 validator->addTrustAnchor(anchor);
134
135 m_validator = validator;
136 }
137 else
138 m_validator = shared_ptr<ndn::Validator>();
139
140
Yingdi Yud45777b2014-10-16 23:54:11 -0700141 // create a new SyncSocket
142 m_sock = make_shared<chronosync::Socket>(m_chatroomPrefix,
143 m_routableUserChatPrefix,
Yingdi Yu4647f022015-02-01 00:26:38 -0800144 ref(*m_face),
Yingdi Yu45da92a2015-02-02 13:17:03 -0800145 bind(&ChatDialogBackend::processSyncUpdate, this, _1),
146 m_signingId,
147 m_validator);
Yingdi Yud45777b2014-10-16 23:54:11 -0700148
149 // schedule a new join event
Yingdi Yu4647f022015-02-01 00:26:38 -0800150 m_scheduler->scheduleEvent(time::milliseconds(600),
151 bind(&ChatDialogBackend::sendJoin, this));
Yingdi Yud45777b2014-10-16 23:54:11 -0700152
153 // cancel existing hello event if it exists
Yingdi Yu4647f022015-02-01 00:26:38 -0800154 if (m_helloEventId != nullptr) {
155 m_scheduler->cancelEvent(m_helloEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700156 m_helloEventId.reset();
157 }
158}
159
Yingdi Yu45da92a2015-02-02 13:17:03 -0800160class IoDeviceSource
161{
162public:
163 typedef char char_type;
164 typedef boost::iostreams::source_tag category;
165
166 explicit
167 IoDeviceSource(QIODevice& source)
168 : m_source(source)
169 {
170 }
171
172 std::streamsize
173 read(char* buffer, std::streamsize n)
174 {
175 return m_source.read(buffer, n);
176 }
177private:
178 QIODevice& m_source;
179};
180
181shared_ptr<ndn::IdentityCertificate>
182ChatDialogBackend::loadTrustAnchor()
183{
184 QFile anchorFile(":/security/anchor.cert");
185
186 if (!anchorFile.open(QIODevice::ReadOnly)) {
187 return {};
188 }
189
190 boost::iostreams::stream<IoDeviceSource> anchorFileStream(anchorFile);
191 return ndn::io::load<ndn::IdentityCertificate>(anchorFileStream);
192}
193
Yingdi Yud45777b2014-10-16 23:54:11 -0700194void
Yingdi Yuf3401182015-02-02 20:21:07 -0800195ChatDialogBackend::exitChatroom() {
Yingdi Yu4647f022015-02-01 00:26:38 -0800196 if (m_joined)
197 sendLeave();
198
199 usleep(100000);
Yingdi Yuf3401182015-02-02 20:21:07 -0800200}
Yingdi Yu4647f022015-02-01 00:26:38 -0800201
Yingdi Yuf3401182015-02-02 20:21:07 -0800202void
203ChatDialogBackend::close()
204{
Yingdi Yu4647f022015-02-01 00:26:38 -0800205 m_scheduler->cancelAllEvents();
206 m_helloEventId.reset();
207 m_roster.clear();
Yingdi Yu45da92a2015-02-02 13:17:03 -0800208 m_validator.reset();
Yingdi Yu4647f022015-02-01 00:26:38 -0800209 m_sock.reset();
210}
211
212void
Yingdi Yud45777b2014-10-16 23:54:11 -0700213ChatDialogBackend::processSyncUpdate(const std::vector<chronosync::MissingDataInfo>& updates)
214{
215 _LOG_DEBUG("<<< processing Tree Update");
216
217 if (updates.empty()) {
218 return;
219 }
220
221 std::vector<NodeInfo> nodeInfos;
222
223
Yingdi Yu1cc45d92015-02-09 14:19:54 -0800224 for (size_t i = 0; i < updates.size(); i++) {
Yingdi Yud45777b2014-10-16 23:54:11 -0700225 // update roster
226 if (m_roster.find(updates[i].session) == m_roster.end()) {
227 m_roster[updates[i].session].sessionPrefix = updates[i].session;
228 m_roster[updates[i].session].hasNick = false;
229 }
230
231 // fetch missing chat data
232 if (updates[i].high - updates[i].low < 3) {
233 for (chronosync::SeqNo seq = updates[i].low; seq <= updates[i].high; ++seq) {
234 m_sock->fetchData(updates[i].session, seq,
Yingdi Yu45da92a2015-02-02 13:17:03 -0800235 [this] (const shared_ptr<const ndn::Data>& data) {
236 this->processChatData(data, true, true);
237 },
238 [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
239 this->processChatData(data, true, false);
240 },
241 ndn::OnTimeout(),
Yingdi Yud45777b2014-10-16 23:54:11 -0700242 2);
243 _LOG_DEBUG("<<< Fetching " << updates[i].session << "/" << seq);
244 }
245 }
246 else {
247 // There are too many msgs to fetch, let's just fetch the latest one
248 m_sock->fetchData(updates[i].session, updates[i].high,
Yingdi Yu45da92a2015-02-02 13:17:03 -0800249 [this] (const shared_ptr<const ndn::Data>& data) {
250 this->processChatData(data, false, true);
251 },
252 [this] (const shared_ptr<const ndn::Data>& data, const std::string& msg) {
253 this->processChatData(data, false, false);
254 },
255 ndn::OnTimeout(),
Yingdi Yud45777b2014-10-16 23:54:11 -0700256 2);
257 }
258
Yingdi Yud45777b2014-10-16 23:54:11 -0700259 }
260
261 // reflect the changes on GUI
262 emit syncTreeUpdated(nodeInfos,
263 QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
264}
265
266void
Yingdi Yu45da92a2015-02-02 13:17:03 -0800267ChatDialogBackend::processChatData(const ndn::shared_ptr<const ndn::Data>& data,
268 bool needDisplay,
269 bool isValidated)
Yingdi Yud45777b2014-10-16 23:54:11 -0700270{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800271 ChatMessage msg;
Yingdi Yud45777b2014-10-16 23:54:11 -0700272
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800273 try {
274 msg.wireDecode(data->getContent().blockFromValue());
275 }
276 catch (tlv::Error) {
Yingdi Yud45777b2014-10-16 23:54:11 -0700277 _LOG_DEBUG("Errrrr.. Can not parse msg with name: " <<
278 data->getName() << ". what is happening?");
279 // nasty stuff: as a remedy, we'll form some standard msg for inparsable msgs
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800280 msg.setNick("inconnu");
281 msg.setMsgType(ChatMessage::OTHER);
Yingdi Yud45777b2014-10-16 23:54:11 -0700282 return;
283 }
284
285 Name remoteSessionPrefix = data->getName().getPrefix(-1);
286
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800287 if (msg.getMsgType() == ChatMessage::LEAVE) {
Yingdi Yud45777b2014-10-16 23:54:11 -0700288 BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
289
290 if (it != m_roster.end()) {
291 // cancel timeout event
292 if (static_cast<bool>(it->second.timeoutEventId))
Yingdi Yu4647f022015-02-01 00:26:38 -0800293 m_scheduler->cancelEvent(it->second.timeoutEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700294
295 // notify frontend to remove the remote session (node)
296 emit sessionRemoved(QString::fromStdString(remoteSessionPrefix.toUri()),
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800297 QString::fromStdString(msg.getNick()),
298 msg.getTimestamp());
Yingdi Yud45777b2014-10-16 23:54:11 -0700299
300 // remove roster entry
301 m_roster.erase(remoteSessionPrefix);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800302
303 emit eraseInRoster(remoteSessionPrefix.getPrefix(IDENTITY_OFFSET),
304 Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700305 }
306 }
307 else {
308 BackendRoster::iterator it = m_roster.find(remoteSessionPrefix);
309
310 if (it == m_roster.end()) {
311 // Should not happen
312 BOOST_ASSERT(false);
313 }
314
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800315 uint64_t seqNo = data->getName().get(-1).toNumber();
Yingdi Yud45777b2014-10-16 23:54:11 -0700316
317 // If a timeout event has been scheduled, cancel it.
318 if (static_cast<bool>(it->second.timeoutEventId))
Yingdi Yu4647f022015-02-01 00:26:38 -0800319 m_scheduler->cancelEvent(it->second.timeoutEventId);
Yingdi Yud45777b2014-10-16 23:54:11 -0700320
321 // (Re)schedule another timeout event after 3 HELLO_INTERVAL;
322 it->second.timeoutEventId =
Yingdi Yu4647f022015-02-01 00:26:38 -0800323 m_scheduler->scheduleEvent(HELLO_INTERVAL * 3,
324 bind(&ChatDialogBackend::remoteSessionTimeout,
325 this, remoteSessionPrefix));
Yingdi Yud45777b2014-10-16 23:54:11 -0700326
327 // If chat message, notify the frontend
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800328 if (msg.getMsgType() == ChatMessage::CHAT) {
Yingdi Yu45da92a2015-02-02 13:17:03 -0800329 if (isValidated)
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800330 emit chatMessageReceived(QString::fromStdString(msg.getNick()),
331 QString::fromStdString(msg.getData()),
332 msg.getTimestamp());
Yingdi Yu45da92a2015-02-02 13:17:03 -0800333 else
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800334 emit chatMessageReceived(QString::fromStdString(msg.getNick() + " (Unverified)"),
335 QString::fromStdString(msg.getData()),
336 msg.getTimestamp());
Yingdi Yu45da92a2015-02-02 13:17:03 -0800337 }
Yingdi Yud45777b2014-10-16 23:54:11 -0700338
339 // Notify frontend to plot notification on DigestTree.
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800340
341 // If we haven't got any message from this session yet.
342 if (m_roster[remoteSessionPrefix].hasNick == false) {
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800343 m_roster[remoteSessionPrefix].userNick = msg.getNick();
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800344 m_roster[remoteSessionPrefix].hasNick = true;
345
346 emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()),
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800347 QString::fromStdString(msg.getNick()),
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800348 seqNo,
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800349 msg.getTimestamp(),
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800350 true);
351
352 emit addInRoster(remoteSessionPrefix.getPrefix(IDENTITY_OFFSET),
353 Name::Component(m_chatroomName));
354 }
355 else
356 emit messageReceived(QString::fromStdString(remoteSessionPrefix.toUri()),
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800357 QString::fromStdString(msg.getNick()),
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800358 seqNo,
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800359 msg.getTimestamp(),
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800360 false);
Yingdi Yud45777b2014-10-16 23:54:11 -0700361 }
362}
363
364void
365ChatDialogBackend::remoteSessionTimeout(const Name& sessionPrefix)
366{
367 time_t timestamp =
368 static_cast<time_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
369
370 // notify frontend
371 emit sessionRemoved(QString::fromStdString(sessionPrefix.toUri()),
372 QString::fromStdString(m_roster[sessionPrefix].userNick),
373 timestamp);
374
375 // remove roster entry
376 m_roster.erase(sessionPrefix);
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800377
378 emit eraseInRoster(sessionPrefix.getPrefix(IDENTITY_OFFSET),
379 Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700380}
381
382void
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800383ChatDialogBackend::sendMsg(ChatMessage& msg)
Yingdi Yud45777b2014-10-16 23:54:11 -0700384{
385 // send msg
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800386 ndn::Block buf = msg.wireEncode();
Yingdi Yud45777b2014-10-16 23:54:11 -0700387
388 uint64_t nextSequence = m_sock->getLogic().getSeqNo() + 1;
389
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800390 m_sock->publishData(buf.wire(), buf.size(), FRESHNESS_PERIOD);
Yingdi Yud45777b2014-10-16 23:54:11 -0700391
392 std::vector<NodeInfo> nodeInfos;
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800393 Name sessionName = m_sock->getLogic().getSessionName();
394 NodeInfo nodeInfo = {QString::fromStdString(sessionName.toUri()),
Yingdi Yud45777b2014-10-16 23:54:11 -0700395 nextSequence};
396 nodeInfos.push_back(nodeInfo);
397
398 emit syncTreeUpdated(nodeInfos,
399 QString::fromStdString(getHexEncodedDigest(m_sock->getRootDigest())));
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800400
401 emit messageReceived(QString::fromStdString(sessionName.toUri()),
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800402 QString::fromStdString(msg.getNick()),
Qiuhan Ding7a4e7ef2015-02-03 20:25:50 -0800403 nextSequence,
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800404 msg.getTimestamp(),
405 msg.getMsgType() == ChatMessage::JOIN);
Yingdi Yud45777b2014-10-16 23:54:11 -0700406}
407
408void
409ChatDialogBackend::sendJoin()
410{
411 m_joined = true;
412
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800413 ChatMessage msg;
414 prepareControlMessage(msg, ChatMessage::JOIN);
Yingdi Yud45777b2014-10-16 23:54:11 -0700415 sendMsg(msg);
416
Yingdi Yu4647f022015-02-01 00:26:38 -0800417 m_helloEventId = m_scheduler->scheduleEvent(HELLO_INTERVAL,
418 bind(&ChatDialogBackend::sendHello, this));
Yingdi Yuf3401182015-02-02 20:21:07 -0800419 emit newChatroomForDiscovery(Name::Component(m_chatroomName));
Yingdi Yud45777b2014-10-16 23:54:11 -0700420}
421
422void
423ChatDialogBackend::sendHello()
424{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800425 ChatMessage msg;
426 prepareControlMessage(msg, ChatMessage::HELLO);
Yingdi Yud45777b2014-10-16 23:54:11 -0700427 sendMsg(msg);
428
Yingdi Yu4647f022015-02-01 00:26:38 -0800429 m_helloEventId = m_scheduler->scheduleEvent(HELLO_INTERVAL,
430 bind(&ChatDialogBackend::sendHello, this));
Yingdi Yud45777b2014-10-16 23:54:11 -0700431}
432
433void
434ChatDialogBackend::sendLeave()
435{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800436 ChatMessage msg;
437 prepareControlMessage(msg, ChatMessage::LEAVE);
Yingdi Yud45777b2014-10-16 23:54:11 -0700438 sendMsg(msg);
439
Qiuhan Ding43c8e162015-02-02 15:16:48 -0800440 // get my own identity with routable prefix by getPrefix(-2)
441 emit eraseInRoster(m_routableUserChatPrefix.getPrefix(-2),
442 Name::Component(m_chatroomName));
443
Yingdi Yud45777b2014-10-16 23:54:11 -0700444 usleep(5000);
445 m_joined = false;
446}
447
448void
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800449ChatDialogBackend::prepareControlMessage(ChatMessage& msg,
450 ChatMessage::ChatMessageType type)
Yingdi Yud45777b2014-10-16 23:54:11 -0700451{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800452 msg.setNick(m_nick);
453 msg.setChatroomName(m_chatroomName);
Yingdi Yud45777b2014-10-16 23:54:11 -0700454 int32_t seconds =
455 static_cast<int32_t>(time::toUnixTimestamp(time::system_clock::now()).count() / 1000);
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800456 msg.setTimestamp(seconds);
457 msg.setMsgType(type);
Yingdi Yud45777b2014-10-16 23:54:11 -0700458}
459
460void
461ChatDialogBackend::prepareChatMessage(const QString& text,
462 time_t timestamp,
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800463 ChatMessage &msg)
Yingdi Yud45777b2014-10-16 23:54:11 -0700464{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800465 msg.setNick(m_nick);
466 msg.setChatroomName(m_chatroomName);
467 msg.setData(text.toStdString());
468 msg.setTimestamp(timestamp);
469 msg.setMsgType(ChatMessage::CHAT);
Yingdi Yud45777b2014-10-16 23:54:11 -0700470}
471
472void
473ChatDialogBackend::updatePrefixes()
474{
475 m_routableUserChatPrefix.clear();
476
477 if (m_localRoutingPrefix.isPrefixOf(m_userChatPrefix))
478 m_routableUserChatPrefix = m_userChatPrefix;
479 else
480 m_routableUserChatPrefix.append(m_localRoutingPrefix)
Qiuhan Dingba3e57a2015-01-08 19:07:39 -0800481 .append(ROUTING_HINT_SEPARATOR)
Yingdi Yud45777b2014-10-16 23:54:11 -0700482 .append(m_userChatPrefix);
483
484 emit chatPrefixChanged(m_routableUserChatPrefix);
485}
486
487std::string
488ChatDialogBackend::getHexEncodedDigest(ndn::ConstBufferPtr digest)
489{
490 std::stringstream os;
491
492 CryptoPP::StringSource(digest->buf(), digest->size(), true,
493 new CryptoPP::HexEncoder(new CryptoPP::FileSink(os), false));
494 return os.str();
495}
496
497
498// public slots:
499void
500ChatDialogBackend::sendChatMessage(QString text, time_t timestamp)
501{
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800502 ChatMessage msg;
Yingdi Yud45777b2014-10-16 23:54:11 -0700503 prepareChatMessage(text, timestamp, msg);
504 sendMsg(msg);
505
Qiuhan Ding0cfc1512015-02-17 17:44:11 -0800506 emit chatMessageReceived(QString::fromStdString(msg.getNick()),
507 QString::fromStdString(msg.getData()),
508 msg.getTimestamp());
Yingdi Yud45777b2014-10-16 23:54:11 -0700509}
510
511void
512ChatDialogBackend::updateRoutingPrefix(const QString& localRoutingPrefix)
513{
514 Name newLocalRoutingPrefix(localRoutingPrefix.toStdString());
515
516 if (!newLocalRoutingPrefix.empty() && newLocalRoutingPrefix != m_localRoutingPrefix) {
517 // Update localPrefix
518 m_localRoutingPrefix = newLocalRoutingPrefix;
519
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700520 {
Yingdi Yuf3401182015-02-02 20:21:07 -0800521 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700522 m_shouldResume = true;
523 }
Yingdi Yu4647f022015-02-01 00:26:38 -0800524
Yingdi Yuf3401182015-02-02 20:21:07 -0800525 exitChatroom();
Yingdi Yu4647f022015-02-01 00:26:38 -0800526
Qiuhan Ding112ee482015-03-11 11:54:11 -0700527 updatePrefixes();
528
Yingdi Yu4647f022015-02-01 00:26:38 -0800529 m_face->getIoService().stop();
Yingdi Yud45777b2014-10-16 23:54:11 -0700530 }
531}
532
533void
534ChatDialogBackend::shutdown()
535{
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700536 {
Yingdi Yuf3401182015-02-02 20:21:07 -0800537 std::lock_guard<std::mutex>lock(m_resumeMutex);
Qiuhan Dingf22c41b2015-03-11 13:19:01 -0700538 m_shouldResume = false;
539 }
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700540
Yingdi Yuf3401182015-02-02 20:21:07 -0800541 {
542 // In this case, we just stop checking the nfd connection and exit
543 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
544 m_isNfdConnected = true;
545 }
546
547 exitChatroom();
Yingdi Yu2c9e7712014-10-20 11:55:05 -0700548
Yingdi Yu4647f022015-02-01 00:26:38 -0800549 m_face->getIoService().stop();
Yingdi Yud45777b2014-10-16 23:54:11 -0700550}
551
Yingdi Yuf3401182015-02-02 20:21:07 -0800552void
553ChatDialogBackend::onNfdReconnect()
554{
555 std::lock_guard<std::mutex>lock(m_nfdConnectionMutex);
556 m_isNfdConnected = true;
557}
558
Yingdi Yueb692ac2015-02-10 18:46:18 -0800559} // namespace chronochat
Yingdi Yud45777b2014-10-16 23:54:11 -0700560
561#if WAF
562#include "chat-dialog-backend.moc"
563// #include "chat-dialog-backend.cpp.moc"
564#endif