Ring Daemon
Loading...
Searching...
No Matches
typers.cpp
Go to the documentation of this file.
1/*
2 * Copyright (C) 2004-2026 Savoir-faire Linux Inc.
3 *
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, either version 3 of the License, or
7 * (at your option) any later version.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
13 *
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <https://www.gnu.org/licenses/>.
16 */
17
18#include "typers.h"
19#include "manager.h"
20#include "jamidht/jamiaccount.h"
21
22static constexpr std::chrono::steady_clock::duration COMPOSING_TIMEOUT {std::chrono::seconds(12)};
23
24namespace jami {
25
26Typers::Typers(const std::shared_ptr<JamiAccount>& acc, const std::string& convId)
27 : ioContext_(Manager::instance().ioContext())
28 , acc_(acc)
29 , accountId_(acc->getAccountID())
30 , convId_(convId)
31 , selfUri_(acc->getUsername())
32{}
33
35{
36 for (auto& watcher : watcher_) {
37 watcher.second.cancel();
38 }
39 watcher_.clear();
40}
41
42std::string
43getIsComposing(const std::string& conversationId, bool isWriting)
44{
45 // implementing https://tools.ietf.org/rfc/rfc3994.txt
46 return fmt::format("<?xml version=\"1.0\" encoding=\"utf-8\" ?>\n"
47 "<isComposing><state>{}</state>{}</isComposing>",
48 isWriting ? "active"sv : "idle"sv,
49 conversationId.empty() ? "" : "<conversation>" + conversationId + "</conversation>");
50}
51
52void
53Typers::addTyper(const std::string& typer, bool sendMessage)
54{
55 auto acc = acc_.lock();
56 if (!acc || !acc->isComposingEnabled())
57 return;
58 auto [it, res] = watcher_.emplace(typer, asio::steady_timer {*ioContext_});
59 if (res) {
60 auto& watcher = it->second;
61 // Check next member
62 watcher.expires_at(std::chrono::steady_clock::now() + COMPOSING_TIMEOUT);
63 watcher.async_wait(std::bind(&Typers::onTyperTimeout, shared_from_this(), std::placeholders::_1, typer));
64
65 if (typer != selfUri_)
67 }
68 if (sendMessage) {
69 // In this case we should emit for remote to update the timer
70 acc->sendInstantMessage(convId_, {{MIME_TYPE_IM_COMPOSING, getIsComposing(convId_, true)}});
71 }
72}
73
74void
75Typers::removeTyper(const std::string& typer, bool sendMessage)
76{
77 auto acc = acc_.lock();
78 if (!acc || !acc->isComposingEnabled())
79 return;
80 if (watcher_.erase(typer)) {
81 if (sendMessage) {
82 acc->sendInstantMessage(convId_, {{MIME_TYPE_IM_COMPOSING, getIsComposing(convId_, false)}});
83 }
84 if (typer != selfUri_) {
86 }
87 }
88}
89
90void
91Typers::onTyperTimeout(const asio::error_code& ec, const std::string& typer)
92{
93 if (ec == asio::error::operation_aborted)
94 return;
96}
97
98} // namespace jami
Manager (controller) of daemon.
Definition manager.h:66
void removeTyper(const std::string &typer, bool sendMessage=false)
Definition typers.cpp:75
void addTyper(const std::string &typer, bool sendMessage=false)
Add typer to the list of typers.
Definition typers.cpp:53
Typers(const std::shared_ptr< JamiAccount > &acc, const std::string &convId)
Definition typers.cpp:26
void emitSignal(Args... args)
Definition jami_signal.h:64
static constexpr const char MIME_TYPE_IM_COMPOSING[]
Definition jamiaccount.h:87
std::string getIsComposing(const std::string &conversationId, bool isWriting)
Definition typers.cpp:43
static constexpr std::chrono::steady_clock::duration COMPOSING_TIMEOUT
Definition typers.cpp:22