Line data Source code
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 : #pragma once
18 :
19 : #include <string>
20 : #include <map>
21 : #include <chrono>
22 : #include <mutex>
23 : #include <cstdint>
24 : #include <filesystem>
25 :
26 : #include <msgpack.hpp>
27 : #include <asio/steady_timer.hpp>
28 :
29 : namespace jami {
30 :
31 : class SIPAccountBase;
32 :
33 : namespace im {
34 :
35 : using MessageToken = uint64_t;
36 :
37 : enum class MessageStatus : std::int8_t { UNKNOWN = 0, IDLE, SENDING, SENT, FAILURE };
38 :
39 : class MessageEngine
40 : {
41 : public:
42 : MessageEngine(SIPAccountBase&, const std::filesystem::path& path);
43 :
44 : /**
45 : * Add a message to the engine and try to send it
46 : * @param to Uri of the peer
47 : * @param deviceId (Optional) if we want to send to a specific device
48 : * @param payloads The message
49 : * @param refreshToken The token of the message
50 : */
51 : MessageToken sendMessage(const std::string& to,
52 : const std::string& deviceId,
53 : const std::map<std::string, std::string>& payloads,
54 : uint64_t refreshToken);
55 :
56 : MessageStatus getStatus(MessageToken t) const;
57 :
58 : void onMessageSent(const std::string& peer, MessageToken t, bool success, const std::string& deviceId = {});
59 :
60 : /**
61 : * @TODO change MessageEngine by a queue,
62 : * @NOTE retryOnTimeout is used for failing SIP messages (jamiAccount::sendTextMessage)
63 : */
64 : void onPeerOnline(const std::string& peer, const std::string& deviceId = {}, bool retryOnTimeout = true);
65 :
66 : /**
67 : * Load persisted messages
68 : */
69 : void load();
70 :
71 : /**
72 : * Persist messages
73 : */
74 : void save() const;
75 :
76 : private:
77 : static const constexpr unsigned MAX_RETRIES = 20;
78 : using clock = std::chrono::system_clock;
79 :
80 : void retrySend(const std::string& peer, const std::string& deviceId, bool retryOnTimeout);
81 :
82 : void save_() const;
83 : void scheduleSave();
84 :
85 : struct Message
86 : {
87 : MessageToken token {};
88 : std::string to {};
89 : std::map<std::string, std::string> payloads {};
90 : MessageStatus status {MessageStatus::IDLE};
91 : unsigned retried {0};
92 : clock::time_point last_op {};
93 :
94 119 : MSGPACK_DEFINE_MAP(token, to, payloads, status, retried, last_op)
95 : };
96 :
97 : SIPAccountBase& account_;
98 : const std::filesystem::path savePath_;
99 : std::shared_ptr<asio::io_context> ioContext_;
100 : asio::steady_timer saveTimer_;
101 :
102 : std::map<std::string, std::list<Message>> messages_;
103 : std::map<std::string, std::list<Message>> messagesDevices_;
104 :
105 : mutable std::mutex messagesMutex_ {};
106 : };
107 :
108 : } // namespace im
109 : } // namespace jami
110 :
111 119 : MSGPACK_ADD_ENUM(jami::im::MessageStatus);
|