Line data Source code
1 : /* 2 : * Copyright (C) 2004-2024 Savoir-faire Linux Inc. 3 : * 4 : * Author: Adrien BĂ©raud <adrien.beraud@savoirfairelinux.com> 5 : * 6 : * This program is free software; you can redistribute it and/or modify 7 : * it under the terms of the GNU General Public License as published by 8 : * the Free Software Foundation; either version 3 of the License, or 9 : * (at your option) any later version. 10 : * 11 : * This program is distributed in the hope that it will be useful, 12 : * but WITHOUT ANY WARRANTY; without even the implied warranty of 13 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14 : * GNU General Public License for more details. 15 : * 16 : * You should have received a copy of the GNU General Public License 17 : * along with this program. If not, see <http://www.gnu.org/licenses/>. 18 : */ 19 : 20 : #pragma once 21 : 22 : #include <string> 23 : #include <map> 24 : #include <set> 25 : #include <chrono> 26 : #include <mutex> 27 : #include <cstdint> 28 : #include <filesystem> 29 : 30 : #include <msgpack.hpp> 31 : #include <asio/steady_timer.hpp> 32 : 33 : namespace jami { 34 : 35 : class SIPAccountBase; 36 : 37 : namespace im { 38 : 39 : using MessageToken = uint64_t; 40 : 41 : enum class MessageStatus { UNKNOWN=0, IDLE, SENDING, SENT, FAILURE }; 42 : 43 : class MessageEngine 44 : { 45 : public: 46 : MessageEngine(SIPAccountBase&, const std::filesystem::path& path); 47 : 48 : /** 49 : * Add a message to the engine and try to send it 50 : * @param to Uri of the peer 51 : * @param deviceId (Optional) if we want to send to a specific device 52 : * @param payloads The message 53 : * @param refreshToken The token of the message 54 : */ 55 : MessageToken sendMessage(const std::string& to, 56 : const std::string& deviceId, 57 : const std::map<std::string, std::string>& payloads, 58 : uint64_t refreshToken); 59 : 60 : MessageStatus getStatus(MessageToken t) const; 61 : 62 : void onMessageSent(const std::string& peer, 63 : MessageToken t, 64 : bool success, 65 : const std::string& deviceId = {}); 66 : 67 : /** 68 : * @TODO change MessageEngine by a queue, 69 : * @NOTE retryOnTimeout is used for failing SIP messages (jamiAccount::sendTextMessage) 70 : */ 71 : void onPeerOnline(const std::string& peer, 72 : const std::string& deviceId = {}, 73 : bool retryOnTimeout = true); 74 : 75 : /** 76 : * Load persisted messages 77 : */ 78 : void load(); 79 : 80 : /** 81 : * Persist messages 82 : */ 83 : void save() const; 84 : 85 : private: 86 : static const constexpr unsigned MAX_RETRIES = 20; 87 : using clock = std::chrono::system_clock; 88 : 89 : void retrySend(const std::string& peer, 90 : const std::string& deviceId, 91 : bool retryOnTimeout); 92 : 93 : void save_() const; 94 : void scheduleSave(); 95 : 96 : struct Message 97 : { 98 : MessageToken token; 99 : std::string to; 100 : std::map<std::string, std::string> payloads; 101 : MessageStatus status {MessageStatus::IDLE}; 102 : unsigned retried {0}; 103 : clock::time_point last_op; 104 : 105 21776 : MSGPACK_DEFINE_MAP(token, to, payloads, status, retried, last_op) 106 : }; 107 : 108 : SIPAccountBase& account_; 109 : const std::filesystem::path savePath_; 110 : std::shared_ptr<asio::io_context> ioContext_; 111 : asio::steady_timer saveTimer_; 112 : 113 : std::map<std::string, std::list<Message>> messages_; 114 : std::map<std::string, std::list<Message>> messagesDevices_; 115 : 116 : mutable std::mutex messagesMutex_ {}; 117 : }; 118 : 119 : } // namespace im 120 : } // namespace jami 121 : 122 21776 : MSGPACK_ADD_ENUM(jami::im::MessageStatus);