133{
134 namespace fs = boost::filesystem;
135
136 error.clear();
137 download = {};
138
139
140 std::string download_url;
141 if (!entry.is_cloud_plugin()) {
142 error = "Plugin is not a cloud plugin";
143 return false;
144 }
145
146 const std::string entry_uuid = entry.cloud_uuid();
147
149 error = "Cloud service agent is null";
150 return false;
151 }
152
153 std::vector<PluginDownloadData> data;
154 std::vector<PluginDownloadNotFound> not_found;
155 std::vector<std::string> unauthorized;
156
157 int result =
m_orca_agent->get_plugin_download_url(entry_uuid, requested_version, data, not_found, unauthorized);
158 if (result != 0) {
159
160 error =
GUI::format(
_u8L(
"Failed to fetch the plugin download URL (result %1%)."), result);
161 return false;
162 }
163
164 for (const std::string& plugin_uuid : unauthorized) {
165 if (plugin_uuid == entry_uuid) {
166 error =
_u8L(
"You are not authorized to download this cloud plugin.");
167 return false;
168 }
169 }
170
171 for (const PluginDownloadNotFound& item : not_found) {
172 if (item.id == entry_uuid) {
173 if (item.reason == "requested os not found")
174 error =
_u8L(
"No plugin package is available for this operating system.");
175 else if (item.reason == "requested version not found")
176 error = requested_version.empty() ?
_u8L(
"The selected plugin version was not found.") :
177 GUI::
format(
_u8L(
"Plugin version %1% was not found."), requested_version);
178 else if (item.reason == "requested plugin not found")
179 error =
_u8L(
"Cloud plugin was not found.");
180 else if (!item.reason.empty())
181
182 error =
GUI::format(
_u8L(
"Cloud plugin download was not found: %1%."), item.reason);
183 else
184 error =
_u8L(
"Cloud plugin download was not found.");
185 return false;
186 }
187 }
188
189 for (const PluginDownloadData& item : data) {
190 if (item.plugin_id == entry_uuid) {
191 download_url = item.download_link;
192 break;
193 }
194 }
195
196 if (download_url.empty()) {
197 error =
_u8L(
"No download URL is available for this plugin. Please check the logs for errors.");
198 return false;
199 }
200
201
202 BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << "Downloading cloud plugin " << entry_uuid << " from " << download_url;
203
204 std::string body;
205 unsigned http_status = 0;
206
208 http.timeout_connect(30)
209 .timeout_max(300)
210 .tls_verify(true)
211 .on_complete([&body, &http_status](std::string response_body, unsigned status) {
212 body = std::move(response_body);
213 http_status = status;
214 })
215 .on_error([&error](std::string response_body, std::string err, unsigned status) {
216 error = std::move(err);
217 if (!response_body.empty())
218 error += " — " + response_body;
219 })
220 .perform_sync();
221
222 if (!error.empty()) {
224 return false;
225 }
226
227 if (http_status >= 400) {
228 error =
GUI::format(
_u8L(
"Plugin download failed with HTTP status %1%."), http_status);
229 return false;
230 }
231
232 if (body.empty()) {
233 error =
_u8L(
"Plugin download returned empty data.");
234 return false;
235 }
236
237
238 const bool is_wheel = (body.size() >= 4 && body[0] == 'P' && body[1] == 'K' && body[2] == '\x03' && body[3] == '\x04');
239 const std::string ext = is_wheel ? ".whl" : ".py";
240
241 const fs::path tmp_path = fs::temp_directory_path() / (fs::unique_path("cloud_plugin-%%%%-%%%%-%%%%-%%%%%%%").string() + ext);
242 {
243 boost::nowide::ofstream file(tmp_path.string(), std::ios::binary | std::ios::trunc);
244 if (!file) {
245 error =
_u8L(
"Failed to create temporary file for plugin download.");
246 return false;
247 }
248 file.write(body.data(), body.size());
249 if (!file) {
250 error =
_u8L(
"Failed to write plugin data to temporary file.");
251 return false;
252 }
253 }
254
255 download.package_path = tmp_path;
256
257 if (entry.cloud.has_value())
258 entry.cloud->update_available = false;
259 return true;
260}
static Http get(std::string url)
Definition Http.cpp:886
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:36
@ http
Definition IPrinterAgent.hpp:64
@ Http
Definition PluginAuditManager.hpp:49
std::string format(const char *fmt, TArgs &&... args)
Definition format.hpp:45
#define _u8L(s)
Definition I18N.hpp:11