Line data Source code
1 : /*
2 : * Copyright (C) 2004-2024 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 "jami/datatransfer_interface.h"
20 : #include "noncopyable.h"
21 :
22 : #include <dhtnet/multiplexed_socket.h>
23 :
24 : #include <fstream>
25 : #include <functional>
26 : #include <memory>
27 : #include <optional>
28 : #include <string>
29 :
30 : namespace jami {
31 :
32 : libjami::DataTransferId generateUID(std::mt19937_64& engine);
33 :
34 : class Stream;
35 :
36 : struct IncomingFileInfo
37 : {
38 : libjami::DataTransferId id;
39 : std::shared_ptr<Stream> stream;
40 : };
41 :
42 : struct WaitingRequest
43 : {
44 : std::string fileId;
45 : std::string interactionId;
46 : std::string sha3sum;
47 : std::string path;
48 : std::size_t totalSize;
49 11 : MSGPACK_DEFINE(fileId, interactionId, sha3sum, path, totalSize)
50 : };
51 :
52 : typedef std::function<void(const std::string&)> InternalCompletionCb;
53 : typedef std::function<void()> OnFinishedCb;
54 :
55 : class FileInfo
56 : {
57 : public:
58 : FileInfo(const std::shared_ptr<dhtnet::ChannelSocket>& channel,
59 : const std::string& fileId,
60 : const std::string& interactionId,
61 : const libjami::DataTransferInfo& info);
62 127 : virtual ~FileInfo() {}
63 : virtual void process() = 0;
64 : std::shared_ptr<dhtnet::ChannelSocket> channel() const { return channel_; }
65 0 : libjami::DataTransferInfo info() const { return info_; }
66 : virtual void cancel() = 0;
67 127 : void onFinished(std::function<void(uint32_t)>&& cb) { finishedCb_ = std::move(cb); }
68 : void emit(libjami::DataTransferEventCode code);
69 :
70 : protected:
71 : std::atomic_bool isUserCancelled_ {false};
72 : std::string fileId_ {};
73 : std::string interactionId_ {};
74 : libjami::DataTransferInfo info_ {};
75 : std::shared_ptr<dhtnet::ChannelSocket> channel_ {};
76 : std::function<void(uint32_t)> finishedCb_ {};
77 : };
78 :
79 : class IncomingFile : public FileInfo, public std::enable_shared_from_this<IncomingFile>
80 : {
81 : public:
82 : IncomingFile(const std::shared_ptr<dhtnet::ChannelSocket>& channel,
83 : const libjami::DataTransferInfo& info,
84 : const std::string& fileId,
85 : const std::string& interactionId,
86 : const std::string& sha3Sum);
87 : ~IncomingFile();
88 : void process() override;
89 : void cancel() override;
90 :
91 : private:
92 : std::mutex streamMtx_;
93 : std::ofstream stream_;
94 : std::string sha3Sum_ {};
95 : std::filesystem::path path_;
96 : };
97 :
98 : class OutgoingFile : public FileInfo
99 : {
100 : public:
101 : OutgoingFile(const std::shared_ptr<dhtnet::ChannelSocket>& channel,
102 : const std::string& fileId,
103 : const std::string& interactionId,
104 : const libjami::DataTransferInfo& info,
105 : size_t start = 0,
106 : size_t end = 0);
107 : ~OutgoingFile();
108 : void process() override;
109 : void cancel() override;
110 :
111 : private:
112 : std::ifstream stream_;
113 : size_t start_ {0};
114 : size_t end_ {0};
115 : };
116 :
117 : class TransferManager : public std::enable_shared_from_this<TransferManager>
118 : {
119 : public:
120 : TransferManager(const std::string& accountId, const std::string& accountUri, const std::string& to, const std::mt19937_64& rand);
121 : ~TransferManager();
122 :
123 : /**
124 : * Send a file to a channel
125 : * @param channel channel to use
126 : * @param fileId fileId of the transfer
127 : * @param interactionId interactionId of the transfer
128 : * @param path path of the file
129 : * @param start start offset
130 : * @param end end
131 : */
132 : void transferFile(const std::shared_ptr<dhtnet::ChannelSocket>& channel,
133 : const std::string& fileId,
134 : const std::string& interactionId,
135 : const std::string& path,
136 : size_t start = 0,
137 : size_t end = 0,
138 : OnFinishedCb onFinished = {});
139 :
140 : /**
141 : * Refuse a transfer
142 : * @param id of the transfer
143 : */
144 : bool cancel(const std::string& fileId);
145 :
146 : /**
147 : * Get current transfer info
148 : * @param id of the transfer
149 : * @param total size
150 : * @param path path of the file
151 : * @param progress current progress
152 : * @return if found
153 : */
154 : bool info(const std::string& fileId,
155 : std::string& path,
156 : int64_t& total,
157 : int64_t& progress) const noexcept;
158 :
159 : /**
160 : * Inform the transfer manager that a transfer is waited (and will be automatically accepted)
161 : * @param id of the transfer
162 : * @param interactionId linked interaction
163 : * @param sha3sum attended sha3sum
164 : * @param path where the file will be downloaded
165 : * @param total total size of the file
166 : */
167 : void waitForTransfer(const std::string& fileId,
168 : const std::string& interactionId,
169 : const std::string& sha3sum,
170 : const std::string& path,
171 : std::size_t total);
172 :
173 : /**
174 : * Handle incoming transfer
175 : * @param id Related id
176 : * @param channel Related channel
177 : */
178 : void onIncomingFileTransfer(const std::string& fileId,
179 : const std::shared_ptr<dhtnet::ChannelSocket>& channel);
180 :
181 : /**
182 : * Retrieve path of a file
183 : * @param id
184 : */
185 : std::filesystem::path path(const std::string& fileId) const;
186 :
187 : /**
188 : * Retrieve waiting files
189 : * @return waiting list
190 : */
191 : std::vector<WaitingRequest> waitingRequests() const;
192 : bool isWaiting(const std::string& fileId) const;
193 : void onIncomingProfile(const std::shared_ptr<dhtnet::ChannelSocket>& channel, const std::string& sha3Sum = "");
194 :
195 : /**
196 : * @param contactId contact's id
197 : * @return where profile.vcf is stored
198 : */
199 : std::filesystem::path profilePath(const std::string& contactId) const;
200 :
201 : private:
202 127 : std::weak_ptr<TransferManager> weak()
203 : {
204 127 : return std::static_pointer_cast<TransferManager>(shared_from_this());
205 : }
206 : NON_COPYABLE(TransferManager);
207 : class Impl;
208 : std::unique_ptr<Impl> pimpl_;
209 : };
210 :
211 : } // namespace jami
|