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