OrcaSlicer latest
OrcaSlicer
Loading...
Searching...
No Matches
Slic3r::CloudPluginService Class Reference

#include </home/runner/work/OrcaSlicer/OrcaSlicer/src/slic3r/plugin/CloudPluginService.hpp>

Collaboration diagram for Slic3r::CloudPluginService:

Public Member Functions

void set_cloud_agent (std::shared_ptr< OrcaCloudServiceAgent > agent)
std::shared_ptr< OrcaCloudServiceAgent > get_cloud_agent () const
bool can_fetch_cloud_plugins () const
bool fetch_manifests_into_descriptors (std::vector< PluginDescriptor > &descriptors, std::vector< std::string > &not_found, std::vector< std::string > &unauthorized) const
bool request_cloud_subscribe (const std::string &plugin_uuid, std::string &error) const
bool request_cloud_unsubscribe (const PluginDescriptor &plugin, std::string &error) const
bool download_cloud_plugin (PluginDescriptor &entry, const std::string &requested_version, CloudPluginDownload &download, std::string &error) const
bool fetch_plugin_changelog (const PluginDescriptor &descriptor, std::vector< PluginChangelog > &changelog, std::string &error) const
bool fetch_plugin_changelog (const std::vector< PluginDescriptor > &descriptors, std::unordered_map< std::string, std::vector< PluginChangelog > > &changelog, std::string &error) const

Private Attributes

std::shared_ptr< OrcaCloudServiceAgent > m_orca_agent = nullptr

Detailed Description

Member Function Documentation

◆ can_fetch_cloud_plugins()

bool Slic3r::CloudPluginService::can_fetch_cloud_plugins ( ) const
30{
31 if (!m_orca_agent) {
32 BOOST_LOG_TRIVIAL(warning) << "Orca service agent is null";
33 return false;
34 }
35
36 if (!m_orca_agent->is_user_login() || m_orca_agent->get_user_id().empty()) {
37 BOOST_LOG_TRIVIAL(info) << "User not logged in, no cloud directory";
38 return false;
39 }
40
41 return true;
42}
std::shared_ptr< OrcaCloudServiceAgent > m_orca_agent
Definition CloudPluginService.hpp:44

References m_orca_agent.

◆ download_cloud_plugin()

bool Slic3r::CloudPluginService::download_cloud_plugin ( PluginDescriptor & entry,
const std::string & requested_version,
CloudPluginDownload & download,
std::string & error ) const
133{
134 namespace fs = boost::filesystem;
135
136 error.clear();
137 download = {};
138
139 // Look up the cloud plugin metadata in the catalog.
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
148 if (!m_orca_agent) {
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 // TRN %1% is the numeric result code returned by the cloud service.
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 // TRN %1% is the reason reported by the cloud service, in English.
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 // Download the plugin package.
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
207 Http http = Http::get(download_url);
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()) {
223 error = GUI::format(_u8L("Failed to download plugin: %1%"), error);
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 // Detect file format from content: PK magic bytes = zip/wheel, otherwise .py.
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

References _u8L, Slic3r::PluginDescriptor::cloud, Slic3r::PluginDescriptor::cloud_uuid(), Slic3r::GUI::format(), Slic3r::Http::get(), Slic3r::http, Slic3r::PluginDescriptor::is_cloud_plugin(), m_orca_agent, and Slic3r::CloudPluginDownload::package_path.

Here is the call graph for this function:

◆ fetch_manifests_into_descriptors()

bool Slic3r::CloudPluginService::fetch_manifests_into_descriptors ( std::vector< PluginDescriptor > & descriptors,
std::vector< std::string > & not_found,
std::vector< std::string > & unauthorized ) const
47{
48 descriptors.clear();
49 not_found.clear();
50 unauthorized.clear();
51
52 if (m_orca_agent) {
53 // Refresh the token once, then run both requests in parallel.
54 m_orca_agent->ensure_token_fresh("fetch_plugin_manifests");
55 std::vector<PluginDescriptor> mine_descriptors;
56 auto mine = std::async(std::launch::async, [agent = m_orca_agent, &mine_descriptors] {
57 return agent->fetch_mine_manifests_into_descriptors(mine_descriptors);
58 });
59
60 int ret = m_orca_agent->fetch_subscribed_manifests_into_descriptors(descriptors, not_found, unauthorized);
61 const int mine_ret = mine.get();
62
63 if (ret != 0) {
64 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": Failed to get subscribed plugins.";
65 return false;
66 }
67
68 ret = mine_ret;
69
70 if (ret != 0) {
71 BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << ": Failed to get owned plugins.";
72 return false;
73 }
74
75 descriptors.insert(descriptors.end(), mine_descriptors.begin(), mine_descriptors.end());
76 }
77
78 return true;
79}

References m_orca_agent.

◆ fetch_plugin_changelog() [1/2]

bool Slic3r::CloudPluginService::fetch_plugin_changelog ( const PluginDescriptor & descriptor,
std::vector< PluginChangelog > & changelog,
std::string & error ) const
265{
266 error.clear();
267 changelog.clear();
268
269 std::string plugin_uuid = descriptor.cloud_uuid();
270 std::vector<PluginDescriptor> descriptors{descriptor};
271 std::unordered_map<std::string, std::vector<PluginChangelog>> changelogs;
272
273 bool result = fetch_plugin_changelog(descriptors, changelogs, error);
274
275 bool found_changelog = changelogs.find(plugin_uuid) != changelogs.end();
276
277 if (changelogs.empty() || !found_changelog) {
278 if (!error.empty())
279 return false;
280 error = "Failed to fetch changelogs for plugin " + descriptor.cloud_uuid();
281 return false;
282 }
283
284 changelog = std::move(changelogs[plugin_uuid]);
285
286 return result;
287}
bool fetch_plugin_changelog(const PluginDescriptor &descriptor, std::vector< PluginChangelog > &changelog, std::string &error) const
Definition CloudPluginService.cpp:262

References Slic3r::PluginDescriptor::cloud_uuid(), and fetch_plugin_changelog().

Referenced by fetch_plugin_changelog().

Here is the call graph for this function:
Here is the caller graph for this function:

◆ fetch_plugin_changelog() [2/2]

bool Slic3r::CloudPluginService::fetch_plugin_changelog ( const std::vector< PluginDescriptor > & descriptors,
std::unordered_map< std::string, std::vector< PluginChangelog > > & changelog,
std::string & error ) const
292{
293 error.clear();
294 changelog.clear();
295
296 if (!m_orca_agent) {
297 error = "Cloud service agent is null.";
298 return false;
299 }
300
301 size_t descriptor_count = descriptors.size();
302
303 if (descriptor_count <= 0) {
304 return true;
305 }
306
307 std::vector<std::string> uuids;
308 uuids.reserve(descriptor_count);
309 for (const PluginDescriptor& descriptor : descriptors) {
310 const std::string uuid = descriptor.cloud_uuid();
311 if (!uuid.empty())
312 uuids.push_back(uuid);
313 }
314
315 if (uuids.empty())
316 return true;
317
318 int result = m_orca_agent->fetch_plugin_changelogs(uuids, changelog);
319
320 if (result != 0) {
321 error = "Failed to fetch one or more plugin changelogs. result=" + std::to_string(result);
322 BOOST_LOG_TRIVIAL(warning) << error;
323 return false;
324 }
325
326 return true;
327}

References m_orca_agent.

◆ get_cloud_agent()

std::shared_ptr< OrcaCloudServiceAgent > Slic3r::CloudPluginService::get_cloud_agent ( ) const
27{ return m_orca_agent; }

References m_orca_agent.

◆ request_cloud_subscribe()

bool Slic3r::CloudPluginService::request_cloud_subscribe ( const std::string & plugin_uuid,
std::string & error ) const
82{
83 error.clear();
84 if (!m_orca_agent) {
85 error = "No cloud agent.";
86 return false;
87 }
88 if (plugin_uuid.empty()) {
89 error = _u8L("Cloud plugin key is missing UUID.");
90 return false;
91 }
92
93 if (m_orca_agent->subscribe_plugin(plugin_uuid) != 0) {
94 error = _u8L("Failed to subscribe to cloud plugin, see logs for more info.");
95 return false;
96 }
97
98 return true;
99}

References _u8L, and m_orca_agent.

◆ request_cloud_unsubscribe()

bool Slic3r::CloudPluginService::request_cloud_unsubscribe ( const PluginDescriptor & plugin,
std::string & error ) const
102{
103 if (!m_orca_agent) {
104 error = "No cloud agent.";
105 return false;
106 }
107
108 if (!plugin.is_cloud_plugin()) {
109 error = _u8L("Only cloud plugins can be unsubscribed.");
110 return false;
111 }
112
113 const std::string cloud_uuid = plugin.cloud_uuid();
114 if (cloud_uuid.empty()) {
115 error = _u8L("Cloud plugin key is missing UUID.");
116 return false;
117 }
118
119 int result = m_orca_agent->unsubscribe_plugins({cloud_uuid});
120
121 if (result != 0) {
122 error = _u8L("Failed to unsubscribe plugin, see logs for more info.");
123 return false;
124 }
125
126 return true;
127}

References _u8L, Slic3r::PluginDescriptor::cloud_uuid(), Slic3r::PluginDescriptor::is_cloud_plugin(), and m_orca_agent.

Here is the call graph for this function:

◆ set_cloud_agent()

void Slic3r::CloudPluginService::set_cloud_agent ( std::shared_ptr< OrcaCloudServiceAgent > agent)
25{ m_orca_agent = std::move(agent); }

References m_orca_agent.

Member Data Documentation

◆ m_orca_agent


The documentation for this class was generated from the following files: