mirror of
https://github.com/SoftFever/OrcaSlicer.git
synced 2025-10-19 23:01:22 -06:00
Add the full source of BambuStudio
using version 1.0.10
This commit is contained in:
parent
30bcadab3e
commit
1555904bef
3771 changed files with 1251328 additions and 0 deletions
1957
src/slic3r/Utils/ASCIIFolding.cpp
Normal file
1957
src/slic3r/Utils/ASCIIFolding.cpp
Normal file
File diff suppressed because it is too large
Load diff
19
src/slic3r/Utils/ASCIIFolding.hpp
Normal file
19
src/slic3r/Utils/ASCIIFolding.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef slic3r_ASCIIFolding_hpp_
|
||||
#define slic3r_ASCIIFolding_hpp_
|
||||
|
||||
#include <string>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// If possible, remove accents from accented latin characters.
|
||||
// This function is useful for generating file names to be processed by legacy firmwares.
|
||||
extern std::string fold_utf8_to_ascii(const std::string &src);
|
||||
|
||||
// Convert the input UNICODE character to a string of maximum 4 output ASCII characters.
|
||||
// Return the end of the string written to the output.
|
||||
// The output buffer must be at least 4 characters long.
|
||||
extern wchar_t* fold_to_ascii(wchar_t c, wchar_t *out);
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_ASCIIFolding_hpp_ */
|
806
src/slic3r/Utils/Bonjour.cpp
Normal file
806
src/slic3r/Utils/Bonjour.cpp
Normal file
|
@ -0,0 +1,806 @@
|
|||
#include "Bonjour.hpp"
|
||||
|
||||
#include <cstdint>
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <map>
|
||||
#include <thread>
|
||||
#include <boost/optional.hpp>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/endian/conversion.hpp>
|
||||
#include <boost/asio.hpp>
|
||||
#include <boost/date_time/posix_time/posix_time_duration.hpp>
|
||||
#include <boost/format.hpp>
|
||||
|
||||
using boost::optional;
|
||||
using boost::system::error_code;
|
||||
namespace endian = boost::endian;
|
||||
namespace asio = boost::asio;
|
||||
using boost::asio::ip::udp;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
// Minimal implementation of a MDNS/DNS-SD client
|
||||
// This implementation is extremely simple, only the bits that are useful
|
||||
// for basic MDNS discovery of OctoPi devices are present.
|
||||
// However, the bits that are present are implemented with security in mind.
|
||||
// Only fully correct DNS replies are allowed through.
|
||||
// While decoding the decoder will bail the moment it encounters anything fishy.
|
||||
// At least that's the idea. To help prove this is actually the case,
|
||||
// the implementations has been tested with AFL.
|
||||
|
||||
|
||||
// Relevant RFCs:
|
||||
// https://tools.ietf.org/html/rfc6762.txt
|
||||
// https://tools.ietf.org/html/rfc6763.txt
|
||||
|
||||
|
||||
struct DnsName: public std::string
|
||||
{
|
||||
enum
|
||||
{
|
||||
MAX_RECURSION = 10, // Keep this low
|
||||
};
|
||||
|
||||
static optional<DnsName> decode(const std::vector<char> &buffer, size_t &offset, unsigned depth = 0)
|
||||
{
|
||||
// Check offset sanity:
|
||||
if (offset + 1 >= buffer.size()) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
// Check for recursion depth to prevent parsing names that are nested too deeply or end up cyclic:
|
||||
if (depth >= MAX_RECURSION) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsName res;
|
||||
const size_t bsize = buffer.size();
|
||||
|
||||
while (true) {
|
||||
const char* ptr = buffer.data() + offset;
|
||||
unsigned len = static_cast<unsigned char>(*ptr);
|
||||
if (len & 0xc0) {
|
||||
// This is a recursive label
|
||||
unsigned len_2 = static_cast<unsigned char>(ptr[1]);
|
||||
size_t pointer = (len & 0x3f) << 8 | len_2;
|
||||
const auto nested = decode(buffer, pointer, depth + 1);
|
||||
if (!nested) {
|
||||
return boost::none;
|
||||
} else {
|
||||
if (res.size() > 0) {
|
||||
res.push_back('.');
|
||||
}
|
||||
res.append(*nested);
|
||||
offset += 2;
|
||||
return std::move(res);
|
||||
}
|
||||
} else if (len == 0) {
|
||||
// This is a name terminator
|
||||
offset++;
|
||||
break;
|
||||
} else {
|
||||
// This is a regular label
|
||||
len &= 0x3f;
|
||||
if (len + offset + 1 >= bsize) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
res.reserve(len);
|
||||
if (res.size() > 0) {
|
||||
res.push_back('.');
|
||||
}
|
||||
|
||||
ptr++;
|
||||
for (const auto end = ptr + len; ptr < end; ptr++) {
|
||||
char c = *ptr;
|
||||
if (c >= 0x20 && c <= 0x7f) {
|
||||
res.push_back(c);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
|
||||
offset += len + 1;
|
||||
}
|
||||
}
|
||||
|
||||
if (res.size() > 0) {
|
||||
return std::move(res);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsHeader
|
||||
{
|
||||
uint16_t id;
|
||||
uint16_t flags;
|
||||
uint16_t qdcount;
|
||||
uint16_t ancount;
|
||||
uint16_t nscount;
|
||||
uint16_t arcount;
|
||||
|
||||
enum
|
||||
{
|
||||
SIZE = 12,
|
||||
};
|
||||
|
||||
static DnsHeader decode(const std::vector<char> &buffer) {
|
||||
DnsHeader res;
|
||||
const uint16_t *data_16 = reinterpret_cast<const uint16_t*>(buffer.data());
|
||||
res.id = endian::big_to_native(data_16[0]);
|
||||
res.flags = endian::big_to_native(data_16[1]);
|
||||
res.qdcount = endian::big_to_native(data_16[2]);
|
||||
res.ancount = endian::big_to_native(data_16[3]);
|
||||
res.nscount = endian::big_to_native(data_16[4]);
|
||||
res.arcount = endian::big_to_native(data_16[5]);
|
||||
return res;
|
||||
}
|
||||
|
||||
uint32_t rrcount() const {
|
||||
return ancount + nscount + arcount;
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsQuestion
|
||||
{
|
||||
enum
|
||||
{
|
||||
MIN_SIZE = 5,
|
||||
};
|
||||
|
||||
DnsName name;
|
||||
uint16_t type;
|
||||
uint16_t qclass;
|
||||
|
||||
DnsQuestion()
|
||||
: type(0)
|
||||
, qclass(0)
|
||||
{}
|
||||
|
||||
static optional<DnsQuestion> decode(const std::vector<char> &buffer, size_t &offset)
|
||||
{
|
||||
auto qname = DnsName::decode(buffer, offset);
|
||||
if (!qname) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsQuestion res;
|
||||
res.name = std::move(*qname);
|
||||
const uint16_t *data_16 = reinterpret_cast<const uint16_t*>(buffer.data() + offset);
|
||||
res.type = endian::big_to_native(data_16[0]);
|
||||
res.qclass = endian::big_to_native(data_16[1]);
|
||||
|
||||
offset += 4;
|
||||
return std::move(res);
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsResource
|
||||
{
|
||||
DnsName name;
|
||||
uint16_t type;
|
||||
uint16_t rclass;
|
||||
uint32_t ttl;
|
||||
std::vector<char> data;
|
||||
|
||||
DnsResource()
|
||||
: type(0)
|
||||
, rclass(0)
|
||||
, ttl(0)
|
||||
{}
|
||||
|
||||
static optional<DnsResource> decode(const std::vector<char> &buffer, size_t &offset, size_t &dataoffset)
|
||||
{
|
||||
const size_t bsize = buffer.size();
|
||||
if (offset + 1 >= bsize) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
auto rname = DnsName::decode(buffer, offset);
|
||||
if (!rname) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
if (offset + 10 >= bsize) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsResource res;
|
||||
res.name = std::move(*rname);
|
||||
const uint16_t *data_16 = reinterpret_cast<const uint16_t*>(buffer.data() + offset);
|
||||
res.type = endian::big_to_native(data_16[0]);
|
||||
res.rclass = endian::big_to_native(data_16[1]);
|
||||
res.ttl = endian::big_to_native(*reinterpret_cast<const uint32_t*>(data_16 + 2));
|
||||
uint16_t rdlength = endian::big_to_native(data_16[4]);
|
||||
|
||||
offset += 10;
|
||||
if (offset + rdlength > bsize) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
dataoffset = offset;
|
||||
res.data = std::vector<char>(buffer.begin() + offset, buffer.begin() + offset + rdlength);
|
||||
offset += rdlength;
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsRR_A
|
||||
{
|
||||
enum { TAG = 0x1 };
|
||||
|
||||
asio::ip::address_v4 ip;
|
||||
|
||||
static void decode(optional<DnsRR_A> &result, const DnsResource &rr)
|
||||
{
|
||||
if (rr.data.size() == 4) {
|
||||
DnsRR_A res;
|
||||
const uint32_t ip = endian::big_to_native(*reinterpret_cast<const uint32_t*>(rr.data.data()));
|
||||
res.ip = asio::ip::address_v4(ip);
|
||||
result = std::move(res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsRR_AAAA
|
||||
{
|
||||
enum { TAG = 0x1c };
|
||||
|
||||
asio::ip::address_v6 ip;
|
||||
|
||||
static void decode(optional<DnsRR_AAAA> &result, const DnsResource &rr)
|
||||
{
|
||||
if (rr.data.size() == 16) {
|
||||
DnsRR_AAAA res;
|
||||
std::array<unsigned char, 16> ip;
|
||||
std::copy_n(rr.data.begin(), 16, ip.begin());
|
||||
res.ip = asio::ip::address_v6(ip);
|
||||
result = std::move(res);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsRR_SRV
|
||||
{
|
||||
enum
|
||||
{
|
||||
TAG = 0x21,
|
||||
MIN_SIZE = 8,
|
||||
};
|
||||
|
||||
uint16_t priority;
|
||||
uint16_t weight;
|
||||
uint16_t port;
|
||||
DnsName hostname;
|
||||
|
||||
static optional<DnsRR_SRV> decode(const std::vector<char> &buffer, const DnsResource &rr, size_t dataoffset)
|
||||
{
|
||||
if (rr.data.size() < MIN_SIZE) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsRR_SRV res;
|
||||
|
||||
const uint16_t *data_16 = reinterpret_cast<const uint16_t*>(rr.data.data());
|
||||
res.priority = endian::big_to_native(data_16[0]);
|
||||
res.weight = endian::big_to_native(data_16[1]);
|
||||
res.port = endian::big_to_native(data_16[2]);
|
||||
|
||||
size_t offset = dataoffset + 6;
|
||||
auto hostname = DnsName::decode(buffer, offset);
|
||||
|
||||
if (hostname) {
|
||||
res.hostname = std::move(*hostname);
|
||||
return std::move(res);
|
||||
} else {
|
||||
return boost::none;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsRR_TXT
|
||||
{
|
||||
enum
|
||||
{
|
||||
TAG = 0x10,
|
||||
};
|
||||
|
||||
BonjourReply::TxtData data;
|
||||
|
||||
static optional<DnsRR_TXT> decode(const DnsResource &rr, const Bonjour::TxtKeys &txt_keys)
|
||||
{
|
||||
const size_t size = rr.data.size();
|
||||
if (size < 2) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsRR_TXT res;
|
||||
|
||||
for (auto it = rr.data.begin(); it != rr.data.end(); ) {
|
||||
unsigned val_size = static_cast<unsigned char>(*it);
|
||||
if (val_size == 0 || it + val_size >= rr.data.end()) {
|
||||
return boost::none;
|
||||
}
|
||||
++it;
|
||||
|
||||
const auto it_end = it + val_size;
|
||||
const auto it_eq = std::find(it, it_end, '=');
|
||||
if (it_eq > it && it_eq < it_end - 1) {
|
||||
std::string key(it_eq - it, ' ');
|
||||
std::copy(it, it_eq, key.begin());
|
||||
|
||||
if (txt_keys.find(key) != txt_keys.end() || key == "path") {
|
||||
// This key-value has been requested for
|
||||
std::string value(it_end - it_eq - 1, ' ');
|
||||
std::copy(it_eq + 1, it_end, value.begin());
|
||||
res.data.insert(std::make_pair(std::move(key), std::move(value)));
|
||||
}
|
||||
}
|
||||
|
||||
it = it_end;
|
||||
}
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsSDPair
|
||||
{
|
||||
optional<DnsRR_SRV> srv;
|
||||
optional<DnsRR_TXT> txt;
|
||||
};
|
||||
|
||||
struct DnsSDMap : public std::map<std::string, DnsSDPair>
|
||||
{
|
||||
void insert_srv(std::string &&name, DnsRR_SRV &&srv)
|
||||
{
|
||||
auto hit = this->find(name);
|
||||
if (hit != this->end()) {
|
||||
hit->second.srv = std::move(srv);
|
||||
} else {
|
||||
DnsSDPair pair;
|
||||
pair.srv = std::move(srv);
|
||||
this->insert(std::make_pair(std::move(name), std::move(pair)));
|
||||
}
|
||||
}
|
||||
|
||||
void insert_txt(std::string &&name, DnsRR_TXT &&txt)
|
||||
{
|
||||
auto hit = this->find(name);
|
||||
if (hit != this->end()) {
|
||||
hit->second.txt = std::move(txt);
|
||||
} else {
|
||||
DnsSDPair pair;
|
||||
pair.txt = std::move(txt);
|
||||
this->insert(std::make_pair(std::move(name), std::move(pair)));
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct DnsMessage
|
||||
{
|
||||
enum
|
||||
{
|
||||
MAX_SIZE = 4096,
|
||||
MAX_ANS = 30,
|
||||
};
|
||||
|
||||
DnsHeader header;
|
||||
optional<DnsQuestion> question;
|
||||
|
||||
optional<DnsRR_A> rr_a;
|
||||
optional<DnsRR_AAAA> rr_aaaa;
|
||||
std::vector<DnsRR_SRV> rr_srv;
|
||||
|
||||
DnsSDMap sdmap;
|
||||
|
||||
static optional<DnsMessage> decode(const std::vector<char> &buffer, const Bonjour::TxtKeys &txt_keys)
|
||||
{
|
||||
const auto size = buffer.size();
|
||||
if (size < DnsHeader::SIZE + DnsQuestion::MIN_SIZE || size > MAX_SIZE) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
DnsMessage res;
|
||||
res.header = DnsHeader::decode(buffer);
|
||||
|
||||
if (res.header.qdcount > 1 || res.header.ancount > MAX_ANS) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
size_t offset = DnsHeader::SIZE;
|
||||
if (res.header.qdcount == 1) {
|
||||
res.question = DnsQuestion::decode(buffer, offset);
|
||||
}
|
||||
|
||||
for (unsigned i = 0; i < res.header.rrcount(); i++) {
|
||||
size_t dataoffset = 0;
|
||||
auto rr = DnsResource::decode(buffer, offset, dataoffset);
|
||||
if (!rr) {
|
||||
return boost::none;
|
||||
} else {
|
||||
res.parse_rr(buffer, std::move(*rr), dataoffset, txt_keys);
|
||||
}
|
||||
}
|
||||
|
||||
return std::move(res);
|
||||
}
|
||||
|
||||
private:
|
||||
void parse_rr(const std::vector<char> &buffer, DnsResource &&rr, size_t dataoffset, const Bonjour::TxtKeys &txt_keys)
|
||||
{
|
||||
switch (rr.type) {
|
||||
case DnsRR_A::TAG: DnsRR_A::decode(this->rr_a, rr); break;
|
||||
case DnsRR_AAAA::TAG: DnsRR_AAAA::decode(this->rr_aaaa, rr); break;
|
||||
case DnsRR_SRV::TAG: {
|
||||
auto srv = DnsRR_SRV::decode(buffer, rr, dataoffset);
|
||||
if (srv) { this->sdmap.insert_srv(std::move(rr.name), std::move(*srv)); }
|
||||
break;
|
||||
}
|
||||
case DnsRR_TXT::TAG: {
|
||||
auto txt = DnsRR_TXT::decode(rr, txt_keys);
|
||||
if (txt) { this->sdmap.insert_txt(std::move(rr.name), std::move(*txt)); }
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const DnsMessage &msg)
|
||||
{
|
||||
os << boost::format("DnsMessage(ID: %1%, Q: %2%, A: %3%, AAAA: %4%, services: [")
|
||||
% msg.header.id
|
||||
% (msg.question ? msg.question->name.c_str() : "none")
|
||||
% (msg.rr_a ? msg.rr_a->ip.to_string() : "none")
|
||||
% (msg.rr_aaaa ? msg.rr_aaaa->ip.to_string() : "none");
|
||||
|
||||
enum { SRV_PRINT_MAX = 3 };
|
||||
unsigned i = 0;
|
||||
for (const auto &sdpair : msg.sdmap) {
|
||||
if (i > 0) { os << ", "; }
|
||||
|
||||
if (i < SRV_PRINT_MAX) {
|
||||
os << sdpair.first;
|
||||
} else {
|
||||
os << "...";
|
||||
break;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
|
||||
return os << "])";
|
||||
}
|
||||
|
||||
|
||||
struct BonjourRequest
|
||||
{
|
||||
static const asio::ip::address_v4 MCAST_IP4;
|
||||
static const uint16_t MCAST_PORT;
|
||||
|
||||
std::vector<char> data;
|
||||
|
||||
static optional<BonjourRequest> make(const std::string &service, const std::string &protocol);
|
||||
|
||||
private:
|
||||
BonjourRequest(std::vector<char> &&data) : data(std::move(data)) {}
|
||||
};
|
||||
|
||||
const asio::ip::address_v4 BonjourRequest::MCAST_IP4{0xe00000fb};
|
||||
const uint16_t BonjourRequest::MCAST_PORT = 5353;
|
||||
|
||||
optional<BonjourRequest> BonjourRequest::make(const std::string &service, const std::string &protocol)
|
||||
{
|
||||
if (service.size() > 15 || protocol.size() > 15) {
|
||||
return boost::none;
|
||||
}
|
||||
|
||||
std::vector<char> data;
|
||||
data.reserve(service.size() + 18);
|
||||
|
||||
// Add metadata
|
||||
static const unsigned char rq_meta[] = {
|
||||
0x00, 0x00, // Query ID (zero for mDNS)
|
||||
0x00, 0x00, // Flags
|
||||
0x00, 0x01, // One query
|
||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00 // Zero Answer, Authority, and Additional RRs
|
||||
};
|
||||
std::copy(rq_meta, rq_meta + sizeof(rq_meta), std::back_inserter(data));
|
||||
|
||||
// Add PTR query name
|
||||
data.push_back(service.size() + 1);
|
||||
data.push_back('_');
|
||||
data.insert(data.end(), service.begin(), service.end());
|
||||
data.push_back(protocol.size() + 1);
|
||||
data.push_back('_');
|
||||
data.insert(data.end(), protocol.begin(), protocol.end());
|
||||
|
||||
// Add the rest of PTR record
|
||||
static const unsigned char ptr_tail[] = {
|
||||
0x05, // length of "label"
|
||||
0x6c, 0x6f, 0x63, 0x61, 0x6c, 0x00, // "label" string and terminator
|
||||
0x00, 0x0c, // Type PTR
|
||||
0x00, 0xff, // Class ANY
|
||||
};
|
||||
std::copy(ptr_tail, ptr_tail + sizeof(ptr_tail), std::back_inserter(data));
|
||||
|
||||
return BonjourRequest(std::move(data));
|
||||
}
|
||||
|
||||
|
||||
// API - private part
|
||||
|
||||
struct Bonjour::priv
|
||||
{
|
||||
const std::string service;
|
||||
std::string protocol;
|
||||
std::string service_dn;
|
||||
TxtKeys txt_keys;
|
||||
unsigned timeout;
|
||||
unsigned retries;
|
||||
|
||||
std::vector<char> buffer;
|
||||
std::thread io_thread;
|
||||
Bonjour::ReplyFn replyfn;
|
||||
Bonjour::CompleteFn completefn;
|
||||
|
||||
priv(std::string &&service);
|
||||
|
||||
std::string strip_service_dn(const std::string &service_name) const;
|
||||
void udp_receive(udp::endpoint from, size_t bytes);
|
||||
void lookup_perform();
|
||||
};
|
||||
|
||||
Bonjour::priv::priv(std::string &&service)
|
||||
: service(std::move(service))
|
||||
, protocol("tcp")
|
||||
, timeout(10)
|
||||
, retries(1)
|
||||
{
|
||||
buffer.resize(DnsMessage::MAX_SIZE);
|
||||
}
|
||||
|
||||
std::string Bonjour::priv::strip_service_dn(const std::string &service_name) const
|
||||
{
|
||||
if (service_name.size() <= service_dn.size()) {
|
||||
return service_name;
|
||||
}
|
||||
|
||||
auto needle = service_name.rfind(service_dn);
|
||||
if (needle == service_name.size() - service_dn.size()) {
|
||||
return service_name.substr(0, needle - 1);
|
||||
} else {
|
||||
return service_name;
|
||||
}
|
||||
}
|
||||
|
||||
void Bonjour::priv::udp_receive(udp::endpoint from, size_t bytes)
|
||||
{
|
||||
if (bytes == 0 || !replyfn) {
|
||||
return;
|
||||
}
|
||||
|
||||
buffer.resize(bytes);
|
||||
auto dns_msg = DnsMessage::decode(buffer, txt_keys);
|
||||
if (dns_msg) {
|
||||
asio::ip::address ip = from.address();
|
||||
if (dns_msg->rr_a) { ip = dns_msg->rr_a->ip; }
|
||||
else if (dns_msg->rr_aaaa) { ip = dns_msg->rr_aaaa->ip; }
|
||||
|
||||
for (auto &sdpair : dns_msg->sdmap) {
|
||||
if (! sdpair.second.srv) {
|
||||
continue;
|
||||
}
|
||||
|
||||
const auto &srv = *sdpair.second.srv;
|
||||
auto service_name = strip_service_dn(sdpair.first);
|
||||
|
||||
std::string path;
|
||||
std::string version;
|
||||
|
||||
BonjourReply::TxtData txt_data;
|
||||
if (sdpair.second.txt) {
|
||||
txt_data = std::move(sdpair.second.txt->data);
|
||||
}
|
||||
|
||||
BonjourReply reply(ip, srv.port, std::move(service_name), srv.hostname, std::move(txt_data));
|
||||
replyfn(std::move(reply));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void Bonjour::priv::lookup_perform()
|
||||
{
|
||||
service_dn = (boost::format("_%1%._%2%.local") % service % protocol).str();
|
||||
|
||||
const auto brq = BonjourRequest::make(service, protocol);
|
||||
if (!brq) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto self = this;
|
||||
|
||||
try {
|
||||
boost::asio::io_service io_service;
|
||||
udp::socket socket(io_service);
|
||||
socket.open(udp::v4());
|
||||
socket.set_option(udp::socket::reuse_address(true));
|
||||
udp::endpoint mcast(BonjourRequest::MCAST_IP4, BonjourRequest::MCAST_PORT);
|
||||
socket.send_to(asio::buffer(brq->data), mcast);
|
||||
|
||||
bool expired = false;
|
||||
bool retry = false;
|
||||
asio::deadline_timer timer(io_service);
|
||||
retries--;
|
||||
std::function<void(const error_code &)> timer_handler = [&](const error_code &error) {
|
||||
if (retries == 0 || error) {
|
||||
expired = true;
|
||||
if (self->completefn) {
|
||||
self->completefn();
|
||||
}
|
||||
} else {
|
||||
retry = true;
|
||||
retries--;
|
||||
timer.expires_from_now(boost::posix_time::seconds(timeout));
|
||||
timer.async_wait(timer_handler);
|
||||
}
|
||||
};
|
||||
|
||||
timer.expires_from_now(boost::posix_time::seconds(timeout));
|
||||
timer.async_wait(timer_handler);
|
||||
|
||||
udp::endpoint recv_from;
|
||||
const auto recv_handler = [&](const error_code &error, size_t bytes) {
|
||||
if (!error) { self->udp_receive(recv_from, bytes); }
|
||||
};
|
||||
socket.async_receive_from(asio::buffer(buffer, buffer.size()), recv_from, recv_handler);
|
||||
|
||||
while (io_service.run_one()) {
|
||||
if (expired) {
|
||||
socket.cancel();
|
||||
} else if (retry) {
|
||||
retry = false;
|
||||
socket.send_to(asio::buffer(brq->data), mcast);
|
||||
} else {
|
||||
buffer.resize(DnsMessage::MAX_SIZE);
|
||||
socket.async_receive_from(asio::buffer(buffer, buffer.size()), recv_from, recv_handler);
|
||||
}
|
||||
}
|
||||
} catch (std::exception& /* e */) {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// API - public part
|
||||
|
||||
BonjourReply::BonjourReply(boost::asio::ip::address ip, uint16_t port, std::string service_name, std::string hostname, BonjourReply::TxtData txt_data)
|
||||
: ip(std::move(ip))
|
||||
, port(port)
|
||||
, service_name(std::move(service_name))
|
||||
, hostname(std::move(hostname))
|
||||
, txt_data(std::move(txt_data))
|
||||
{
|
||||
std::string proto;
|
||||
std::string port_suffix;
|
||||
if (port == 443) { proto = "https://"; }
|
||||
if (port != 443 && port != 80) { port_suffix = std::to_string(port).insert(0, 1, ':'); }
|
||||
|
||||
std::string path = this->path();
|
||||
if (path[0] != '/') { path.insert(0, 1, '/'); }
|
||||
full_address = proto + ip.to_string() + port_suffix;
|
||||
if (path != "/") { full_address += path; }
|
||||
txt_data["path"] = std::move(path);
|
||||
}
|
||||
|
||||
std::string BonjourReply::path() const
|
||||
{
|
||||
const auto it = txt_data.find("path");
|
||||
return it != txt_data.end() ? it->second : std::string("/");
|
||||
}
|
||||
|
||||
bool BonjourReply::operator==(const BonjourReply &other) const
|
||||
{
|
||||
return this->full_address == other.full_address
|
||||
&& this->service_name == other.service_name;
|
||||
}
|
||||
|
||||
bool BonjourReply::operator<(const BonjourReply &other) const
|
||||
{
|
||||
if (this->ip != other.ip) {
|
||||
// So that the common case doesn't involve string comparison
|
||||
return this->ip < other.ip;
|
||||
} else {
|
||||
auto cmp = this->full_address.compare(other.full_address);
|
||||
return cmp != 0 ? cmp < 0 : this->service_name < other.service_name;
|
||||
}
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const BonjourReply &reply)
|
||||
{
|
||||
os << boost::format("BonjourReply(%1%, %2%, %3%, %4%")
|
||||
% reply.ip.to_string()
|
||||
% reply.service_name
|
||||
% reply.hostname
|
||||
% reply.full_address;
|
||||
|
||||
for (const auto &kv : reply.txt_data) {
|
||||
os << boost::format(", %1%=%2%") % kv.first % kv.second;
|
||||
}
|
||||
|
||||
return os << ')';
|
||||
}
|
||||
|
||||
|
||||
Bonjour::Bonjour(std::string service)
|
||||
: p(new priv(std::move(service)))
|
||||
{}
|
||||
|
||||
Bonjour::Bonjour(Bonjour &&other) : p(std::move(other.p)) {}
|
||||
|
||||
Bonjour::~Bonjour()
|
||||
{
|
||||
if (p && p->io_thread.joinable()) {
|
||||
p->io_thread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::set_protocol(std::string protocol)
|
||||
{
|
||||
if (p) { p->protocol = std::move(protocol); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::set_txt_keys(TxtKeys txt_keys)
|
||||
{
|
||||
if (p) { p->txt_keys = std::move(txt_keys); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::set_timeout(unsigned timeout)
|
||||
{
|
||||
if (p) { p->timeout = timeout; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::set_retries(unsigned retries)
|
||||
{
|
||||
if (p && retries > 0) { p->retries = retries; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::on_reply(ReplyFn fn)
|
||||
{
|
||||
if (p) { p->replyfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour& Bonjour::on_complete(CompleteFn fn)
|
||||
{
|
||||
if (p) { p->completefn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Bonjour::Ptr Bonjour::lookup()
|
||||
{
|
||||
auto self = std::make_shared<Bonjour>(std::move(*this));
|
||||
|
||||
if (self->p) {
|
||||
auto io_thread = std::thread([self]() {
|
||||
self->p->lookup_perform();
|
||||
});
|
||||
self->p->io_thread = std::move(io_thread);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
|
||||
}
|
80
src/slic3r/Utils/Bonjour.hpp
Normal file
80
src/slic3r/Utils/Bonjour.hpp
Normal file
|
@ -0,0 +1,80 @@
|
|||
#ifndef slic3r_Bonjour_hpp_
|
||||
#define slic3r_Bonjour_hpp_
|
||||
|
||||
#include <cstdint>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <set>
|
||||
#include <unordered_map>
|
||||
#include <functional>
|
||||
#include <boost/asio/ip/address.hpp>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
struct BonjourReply
|
||||
{
|
||||
typedef std::unordered_map<std::string, std::string> TxtData;
|
||||
|
||||
boost::asio::ip::address ip;
|
||||
uint16_t port;
|
||||
std::string service_name;
|
||||
std::string hostname;
|
||||
std::string full_address;
|
||||
|
||||
TxtData txt_data;
|
||||
|
||||
BonjourReply() = delete;
|
||||
BonjourReply(boost::asio::ip::address ip,
|
||||
uint16_t port,
|
||||
std::string service_name,
|
||||
std::string hostname,
|
||||
TxtData txt_data);
|
||||
|
||||
std::string path() const;
|
||||
|
||||
bool operator==(const BonjourReply &other) const;
|
||||
bool operator<(const BonjourReply &other) const;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &, const BonjourReply &);
|
||||
|
||||
|
||||
/// Bonjour lookup performer
|
||||
class Bonjour : public std::enable_shared_from_this<Bonjour> {
|
||||
private:
|
||||
struct priv;
|
||||
public:
|
||||
typedef std::shared_ptr<Bonjour> Ptr;
|
||||
typedef std::function<void(BonjourReply &&)> ReplyFn;
|
||||
typedef std::function<void()> CompleteFn;
|
||||
typedef std::set<std::string> TxtKeys;
|
||||
|
||||
Bonjour(std::string service);
|
||||
Bonjour(Bonjour &&other);
|
||||
~Bonjour();
|
||||
|
||||
// Set requested service protocol, "tcp" by default
|
||||
Bonjour& set_protocol(std::string protocol);
|
||||
// Set which TXT key-values should be collected
|
||||
// Note that "path" is always collected
|
||||
Bonjour& set_txt_keys(TxtKeys txt_keys);
|
||||
Bonjour& set_timeout(unsigned timeout);
|
||||
Bonjour& set_retries(unsigned retries);
|
||||
// ^ Note: By default there is 1 retry (meaning 1 broadcast is sent).
|
||||
// Timeout is per one retry, ie. total time spent listening = retries * timeout.
|
||||
// If retries > 1, then care needs to be taken as more than one reply from the same service may be received.
|
||||
|
||||
Bonjour& on_reply(ReplyFn fn);
|
||||
Bonjour& on_complete(CompleteFn fn);
|
||||
|
||||
Ptr lookup();
|
||||
private:
|
||||
std::unique_ptr<priv> p;
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
235
src/slic3r/Utils/ColorSpaceConvert.cpp
Normal file
235
src/slic3r/Utils/ColorSpaceConvert.cpp
Normal file
|
@ -0,0 +1,235 @@
|
|||
#include "ColorSpaceConvert.hpp"
|
||||
|
||||
#include <algorithm>
|
||||
|
||||
const static float param_13 = 1.0f / 3.0f;
|
||||
const static float param_16116 = 16.0f / 116.0f;
|
||||
const static float Xn = 0.950456f;
|
||||
const static float Yn = 1.0f;
|
||||
const static float Zn = 1.088754f;
|
||||
|
||||
std::tuple<int, int, int> rgb_to_yuv(float r, float g, float b)
|
||||
{
|
||||
int y = (int)(0.2126 * r + 0.7152 * g + 0.0722 * b);
|
||||
int u = (int)(-0.09991 * r - 0.33609 * g + 0.436 * b);
|
||||
int v = (int)(0.615 * r - 0.55861 * g - 0.05639 * b);
|
||||
return std::make_tuple(y, u, v);
|
||||
}
|
||||
|
||||
double PivotRGB(double n)
|
||||
{
|
||||
return (n > 0.04045 ? std::pow((n + 0.055) / 1.055, 2.4) : n / 12.92) * 100.0;
|
||||
}
|
||||
|
||||
double PivotXYZ(double n)
|
||||
{
|
||||
double i = std::cbrt(n);
|
||||
return n > 0.008856 ? i : 7.787 * n + 16.0 / 116.0;
|
||||
}
|
||||
|
||||
void XYZ2RGB(float X, float Y, float Z, float* R, float* G, float* B)
|
||||
{
|
||||
float RR, GG, BB;
|
||||
RR = 3.240479f * X - 1.537150f * Y - 0.498535f * Z;
|
||||
GG = -0.969256f * X + 1.875992f * Y + 0.041556f * Z;
|
||||
BB = 0.055648f * X - 0.204043f * Y + 1.057311f * Z;
|
||||
|
||||
*R = (float)std::clamp(RR, 0.f, 255.f);
|
||||
*G = (float)std::clamp(GG, 0.f, 255.f);
|
||||
*B = (float)std::clamp(BB, 0.f, 255.f);
|
||||
}
|
||||
|
||||
void Lab2XYZ(float L, float a, float b, float* X, float* Y, float* Z)
|
||||
{
|
||||
float fX, fY, fZ;
|
||||
|
||||
fY = (L + 16.0f) / 116.0f;
|
||||
if (fY > 0.206893f)
|
||||
*Y = fY * fY * fY;
|
||||
else
|
||||
*Y = (fY - param_16116) / 7.787f;
|
||||
|
||||
fX = a / 500.0f + fY;
|
||||
if (fX > 0.206893f)
|
||||
*X = fX * fX * fX;
|
||||
else
|
||||
*X = (fX - param_16116) / 7.787f;
|
||||
|
||||
fZ = fY - b / 200.0f;
|
||||
if (fZ > 0.206893f)
|
||||
*Z = fZ * fZ * fZ;
|
||||
else
|
||||
*Z = (fZ - param_16116) / 7.787f;
|
||||
|
||||
(*X) *= Xn;
|
||||
(*Y) *= Yn;
|
||||
(*Z) *= Zn;
|
||||
}
|
||||
|
||||
void Lab2RGB(float L, float a, float b, float* R, float* G, float* B)
|
||||
{
|
||||
float X = 0.0f, Y = 0.0f, Z = 0.0f;
|
||||
Lab2XYZ(L, a, b, &X, &Y, &Z);
|
||||
XYZ2RGB(X, Y, Z, R, G, B);
|
||||
}
|
||||
|
||||
void RGB2XYZ(float R, float G, float B, float* X, float* Y, float* Z)
|
||||
{
|
||||
R = PivotRGB(R);
|
||||
G = PivotRGB(G);
|
||||
B = PivotRGB(B);
|
||||
|
||||
*X = 0.412453f * R + 0.357580f * G + 0.180423f * B;
|
||||
*Y = 0.212671f * R + 0.715160f * G + 0.072169f * B;
|
||||
*Z = 0.019334f * R + 0.119193f * G + 0.950227f * B;
|
||||
}
|
||||
|
||||
void XYZ2Lab(float X, float Y, float Z, float* L, float* a, float* b)
|
||||
{
|
||||
double REF_X = 95.047;
|
||||
double REF_Y = 100.000;
|
||||
double REF_Z = 108.883;
|
||||
|
||||
double x = PivotXYZ(X / REF_X);
|
||||
double y = PivotXYZ(Y / REF_Y);
|
||||
double z = PivotXYZ(Z / REF_Z);
|
||||
|
||||
*L = 116.0 * y - 16.0;
|
||||
*a = 500.0 * (x - y);
|
||||
*b = 200.0 * (y - z);
|
||||
}
|
||||
|
||||
void RGB2Lab(float R, float G, float B, float* L, float* a, float* b)
|
||||
{
|
||||
float X = 0.0f, Y = 0.0f, Z = 0.0f;
|
||||
RGB2XYZ(R, G, B, &X, &Y, &Z);
|
||||
XYZ2Lab(X, Y, Z, L, a, b);
|
||||
}
|
||||
|
||||
// The input r, g, b values should be in range [0, 1]. The output h is in range [0, 360], s is in range [0, 1] and v is in range [0, 1].
|
||||
void RGB2HSV(float r, float g, float b, float* h, float* s, float* v)
|
||||
{
|
||||
float Cmax = std::max(std::max(r, g), b);
|
||||
float Cmin = std::min(std::min(r, g), b);
|
||||
float delta = Cmax - Cmin;
|
||||
|
||||
if (std::abs(delta) < 0.001) {
|
||||
*h = 0.f;
|
||||
}
|
||||
else if (Cmax == r) {
|
||||
*h = 60.f * fmod((g - b) / delta, 6.f);
|
||||
}
|
||||
else if (Cmax == g) {
|
||||
*h = 60.f * ((b - r) / delta + 2);
|
||||
}
|
||||
else {
|
||||
*h = 60.f * ((r - g) / delta + 4);
|
||||
}
|
||||
|
||||
if (std::abs(Cmax) < 0.001) {
|
||||
*s = 0.f;
|
||||
}
|
||||
else {
|
||||
*s = delta / Cmax;
|
||||
}
|
||||
|
||||
*v = Cmax;
|
||||
}
|
||||
|
||||
float DeltaE00(float l1, float a1, float b1, float l2, float a2, float b2)
|
||||
{
|
||||
auto rad2deg = [](float rad) {
|
||||
return 360.0 * rad / (2.0 * M_PI);
|
||||
};
|
||||
|
||||
auto deg2rad = [](float deg) {
|
||||
return (2.0 * M_PI * deg) / 360.0;
|
||||
};
|
||||
|
||||
float avgL = (l1 + l2) / 2.0;
|
||||
float c1 = std::sqrt(std::pow(a1, 2) + std::pow(b1, 2));
|
||||
float c2 = std::sqrt(std::pow(a2, 2) + std::pow(b2, 2));
|
||||
float avgC = (c1 + c2) / 2.0;
|
||||
float g = (1.0 - std::sqrt(std::pow(avgC, 7) / (std::pow(avgC, 7) + std::pow(25.0, 7)))) / 2.0;
|
||||
|
||||
float a1p = a1 * (1.0 + g);
|
||||
float a2p = a2 * (1.0 + g);
|
||||
|
||||
float c1p = std::sqrt(std::pow(a1p, 2) + std::pow(b1, 2));
|
||||
float c2p = std::sqrt(std::pow(a2p, 2) + std::pow(b2, 2));
|
||||
|
||||
float avgCp = (c1p + c2p) / 2.0;
|
||||
|
||||
float h1p = rad2deg(std::atan2(b1, a1p));
|
||||
if (h1p < 0.0) {
|
||||
h1p = h1p + 360.0;
|
||||
}
|
||||
|
||||
float h2p = rad2deg(std::atan2(b2, a2p));
|
||||
if (h2p < 0.0) {
|
||||
h2p = h2p + 360;
|
||||
}
|
||||
|
||||
float avghp = std::abs(h1p - h2p) > 180.0 ? (h1p + h2p + 360.0) / 2.0 : (h1p + h2p) / 2.0;
|
||||
|
||||
float t = 1.0 - 0.17 * std::cos(deg2rad(avghp - 30.0)) + 0.24 * std::cos(deg2rad(2.0 * avghp)) + 0.32 * std::cos(deg2rad(3.0 * avghp + 6.0)) - 0.2 * std::cos(deg2rad(4.0 * avghp - 63.0));
|
||||
|
||||
float deltahp = h2p - h1p;
|
||||
if (std::abs(deltahp) > 180.0) {
|
||||
if (h2p <= h1p) {
|
||||
deltahp += 360.0;
|
||||
}
|
||||
else {
|
||||
deltahp -= 360.0;
|
||||
}
|
||||
}
|
||||
|
||||
float deltalp = l2 - l1;
|
||||
float deltacp = c2p - c1p;
|
||||
|
||||
deltahp = 2.0 * std::sqrt(c1p * c2p) * std::sin(deg2rad(deltahp) / 2.0);
|
||||
|
||||
float sl = 1.0 + ((0.015 * std::pow(avgL - 50.0, 2)) / std::sqrt(20.0 + std::pow(avgL - 50.0, 2)));
|
||||
float sc = 1.0 + 0.045 * avgCp;
|
||||
float sh = 1.0 + 0.015 * avgCp * t;
|
||||
|
||||
float deltaro = 30.0 * std::exp(-(std::pow((avghp - 275.0) / 25.0, 2)));
|
||||
float rc = 2.0 * std::sqrt(std::pow(avgCp, 7) / (std::pow(avgCp, 7) + std::pow(25.0, 7)));
|
||||
float rt = -rc * std::sin(2.0 * deg2rad(deltaro));
|
||||
|
||||
float kl = 1;
|
||||
float kc = 1;
|
||||
float kh = 1;
|
||||
|
||||
float delta_e00 = std::sqrt(std::pow(deltalp / (kl * sl), 2) + std::pow(deltacp / (kc * sc), 2) + std::pow(deltahp / (kh * sh), 2) + rt * (deltacp / (kc * sc)) * (deltahp / (kh * sh)));
|
||||
return delta_e00;
|
||||
}
|
||||
|
||||
float DeltaE94(float l1, float a1, float b1, float l2, float a2, float b2)
|
||||
{
|
||||
float k_L = 1;
|
||||
float k_C = 1;
|
||||
float k_H = 1;
|
||||
float K1 = 0.045;
|
||||
float K2 = 0.015;
|
||||
|
||||
float delta_l = l1 - l2;
|
||||
float C1 = std::sqrt(a1 * a1 + b1 * b1);
|
||||
float C2 = std::sqrt(a2 * a2 + b2 * b2);
|
||||
float delta_c = C1 - C2;
|
||||
float delta_a = a1 - a2;
|
||||
float delta_b = b1 - b2;
|
||||
float delta_h = std::sqrt(delta_a * delta_a + delta_b * delta_b - delta_c * delta_c);
|
||||
float SL = 1.0;
|
||||
float SC = 1 + K1 * C1;
|
||||
float SH = 1 + K2 * C1;
|
||||
|
||||
float delta_e94 = std::sqrt(std::pow(delta_l / (k_L * SL), 2) + std::pow(delta_c / (k_C * SC), 2) + std::pow(delta_h / (k_H / k_C * SH), 2));
|
||||
return delta_e94;
|
||||
}
|
||||
|
||||
float DeltaE76(float l1, float a1, float b1, float l2, float a2, float b2)
|
||||
{
|
||||
return std::sqrt(std::pow((l1 - l2), 2) + std::pow((a1 - a2), 2) + std::pow((b1 - b2), 2));
|
||||
}
|
||||
|
19
src/slic3r/Utils/ColorSpaceConvert.hpp
Normal file
19
src/slic3r/Utils/ColorSpaceConvert.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef slic3r_Utils_ColorSpaceConvert_hpp_
|
||||
#define slic3r_Utils_ColorSpaceConvert_hpp_
|
||||
|
||||
std::tuple<int, int, int> rgb_to_yuv(float r, float g, float b);
|
||||
double PivotRGB(double n);
|
||||
double PivotXYZ(double n);
|
||||
void XYZ2RGB(float X, float Y, float Z, float* R, float* G, float* B);
|
||||
void Lab2XYZ(float L, float a, float b, float* X, float* Y, float* Z);
|
||||
void Lab2RGB(float L, float a, float b, float* R, float* G, float* B);
|
||||
void RGB2XYZ(float R, float G, float B, float* X, float* Y, float* Z);
|
||||
void XYZ2Lab(float X, float Y, float Z, float* L, float* a, float* b);
|
||||
void RGB2Lab(float R, float G, float B, float* L, float* a, float* b);
|
||||
void RGB2HSV(float r, float g, float b, float* h, float* s, float* v);
|
||||
|
||||
float DeltaE00(float l1, float a1, float b1, float l2, float a2, float b2);
|
||||
float DeltaE94(float l1, float a1, float b1, float l2, float a2, float b2);
|
||||
float DeltaE76(float l1, float a1, float b1, float l2, float a2, float b2);
|
||||
|
||||
#endif /* slic3r_Utils_ColorSpaceConvert_hpp_ */
|
446
src/slic3r/Utils/FixModelByWin10.cpp
Normal file
446
src/slic3r/Utils/FixModelByWin10.cpp
Normal file
|
@ -0,0 +1,446 @@
|
|||
#ifdef HAS_WIN10SDK
|
||||
|
||||
#ifndef NOMINMAX
|
||||
# define NOMINMAX
|
||||
#endif
|
||||
|
||||
// Windows Runtime
|
||||
#include <roapi.h>
|
||||
// for ComPtr
|
||||
#include <wrl/client.h>
|
||||
|
||||
// from C:/Program Files (x86)/Windows Kits/10/Include/10.0.17134.0/
|
||||
#include <winrt/robuffer.h>
|
||||
#include <winrt/windows.storage.provider.h>
|
||||
#include <winrt/windows.graphics.printing3d.h>
|
||||
|
||||
#include "FixModelByWin10.hpp"
|
||||
|
||||
#include <atomic>
|
||||
#include <chrono>
|
||||
#include <cstdint>
|
||||
#include <condition_variable>
|
||||
#include <exception>
|
||||
#include <string>
|
||||
#include <thread>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/nowide/convert.hpp>
|
||||
#include <boost/nowide/cstdio.hpp>
|
||||
#include <boost/thread.hpp>
|
||||
|
||||
#include "libslic3r/Model.hpp"
|
||||
#include "libslic3r/Print.hpp"
|
||||
#include "libslic3r/PresetBundle.hpp"
|
||||
#include "libslic3r/Format/3mf.hpp"
|
||||
#include "../GUI/GUI.hpp"
|
||||
#include "../GUI/I18N.hpp"
|
||||
#include "../GUI/MsgDialog.hpp"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <wx/progdlg.h>
|
||||
|
||||
extern "C"{
|
||||
// from rapi.h
|
||||
typedef HRESULT (__stdcall* FunctionRoInitialize)(int);
|
||||
typedef HRESULT (__stdcall* FunctionRoUninitialize)();
|
||||
typedef HRESULT (__stdcall* FunctionRoActivateInstance)(HSTRING activatableClassId, IInspectable **instance);
|
||||
typedef HRESULT (__stdcall* FunctionRoGetActivationFactory)(HSTRING activatableClassId, REFIID iid, void **factory);
|
||||
// from winstring.h
|
||||
typedef HRESULT (__stdcall* FunctionWindowsCreateString)(LPCWSTR sourceString, UINT32 length, HSTRING *string);
|
||||
typedef HRESULT (__stdcall* FunctionWindowsDelteString)(HSTRING string);
|
||||
}
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
static std::string saving_failed_str = L("Saving objects into the 3mf failed.");
|
||||
|
||||
HMODULE s_hRuntimeObjectLibrary = nullptr;
|
||||
FunctionRoInitialize s_RoInitialize = nullptr;
|
||||
FunctionRoUninitialize s_RoUninitialize = nullptr;
|
||||
FunctionRoActivateInstance s_RoActivateInstance = nullptr;
|
||||
FunctionRoGetActivationFactory s_RoGetActivationFactory = nullptr;
|
||||
FunctionWindowsCreateString s_WindowsCreateString = nullptr;
|
||||
FunctionWindowsDelteString s_WindowsDeleteString = nullptr;
|
||||
|
||||
bool winrt_load_runtime_object_library()
|
||||
{
|
||||
if (s_hRuntimeObjectLibrary == nullptr)
|
||||
s_hRuntimeObjectLibrary = LoadLibrary(L"ComBase.dll");
|
||||
if (s_hRuntimeObjectLibrary != nullptr) {
|
||||
s_RoInitialize = (FunctionRoInitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoInitialize");
|
||||
s_RoUninitialize = (FunctionRoUninitialize) GetProcAddress(s_hRuntimeObjectLibrary, "RoUninitialize");
|
||||
s_RoActivateInstance = (FunctionRoActivateInstance) GetProcAddress(s_hRuntimeObjectLibrary, "RoActivateInstance");
|
||||
s_RoGetActivationFactory = (FunctionRoGetActivationFactory) GetProcAddress(s_hRuntimeObjectLibrary, "RoGetActivationFactory");
|
||||
s_WindowsCreateString = (FunctionWindowsCreateString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsCreateString");
|
||||
s_WindowsDeleteString = (FunctionWindowsDelteString) GetProcAddress(s_hRuntimeObjectLibrary, "WindowsDeleteString");
|
||||
}
|
||||
return s_RoInitialize && s_RoUninitialize && s_RoActivateInstance && s_WindowsCreateString && s_WindowsDeleteString;
|
||||
}
|
||||
|
||||
static HRESULT winrt_activate_instance(const std::wstring &class_name, IInspectable **pinst)
|
||||
{
|
||||
HSTRING hClassName;
|
||||
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = (*s_RoActivateInstance)(hClassName, pinst);
|
||||
(*s_WindowsDeleteString)(hClassName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
static HRESULT winrt_activate_instance(const std::wstring &class_name, TYPE **pinst)
|
||||
{
|
||||
IInspectable *pinspectable = nullptr;
|
||||
HRESULT hr = winrt_activate_instance(class_name, &pinspectable);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = pinspectable->QueryInterface(__uuidof(TYPE), (void**)pinst);
|
||||
pinspectable->Release();
|
||||
return hr;
|
||||
}
|
||||
|
||||
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, REFIID iid, void **pinst)
|
||||
{
|
||||
HSTRING hClassName;
|
||||
HRESULT hr = (*s_WindowsCreateString)(class_name.c_str(), class_name.size(), &hClassName);
|
||||
if (S_OK != hr)
|
||||
return hr;
|
||||
hr = (*s_RoGetActivationFactory)(hClassName, iid, pinst);
|
||||
(*s_WindowsDeleteString)(hClassName);
|
||||
return hr;
|
||||
}
|
||||
|
||||
template<typename TYPE>
|
||||
static HRESULT winrt_get_activation_factory(const std::wstring &class_name, TYPE **pinst)
|
||||
{
|
||||
return winrt_get_activation_factory(class_name, __uuidof(TYPE), reinterpret_cast<void**>(pinst));
|
||||
}
|
||||
|
||||
// To be called often to test whether to cancel the operation.
|
||||
typedef std::function<void ()> ThrowOnCancelFn;
|
||||
|
||||
template<typename T>
|
||||
static AsyncStatus winrt_async_await(const Microsoft::WRL::ComPtr<T> &asyncAction, ThrowOnCancelFn throw_on_cancel, int blocking_tick_ms = 100)
|
||||
{
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
asyncAction.As(&asyncInfo);
|
||||
AsyncStatus status;
|
||||
// Ugly blocking loop until the RepairAsync call finishes.
|
||||
//FIXME replace with a callback.
|
||||
// https://social.msdn.microsoft.com/Forums/en-US/a5038fb4-b7b7-4504-969d-c102faa389fb/trying-to-block-an-async-operation-and-wait-for-a-particular-time?forum=vclanguage
|
||||
for (;;) {
|
||||
asyncInfo->get_Status(&status);
|
||||
if (status != AsyncStatus::Started)
|
||||
return status;
|
||||
throw_on_cancel();
|
||||
::Sleep(blocking_tick_ms);
|
||||
}
|
||||
}
|
||||
|
||||
static HRESULT winrt_open_file_stream(
|
||||
const std::wstring &path,
|
||||
ABI::Windows::Storage::FileAccessMode mode,
|
||||
ABI::Windows::Storage::Streams::IRandomAccessStream **fileStream,
|
||||
ThrowOnCancelFn throw_on_cancel)
|
||||
{
|
||||
// Get the file factory.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFileStatics> fileFactory;
|
||||
HRESULT hr = winrt_get_activation_factory(L"Windows.Storage.StorageFile", fileFactory.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
// Open the file asynchronously.
|
||||
HSTRING hstr_path;
|
||||
hr = (*s_WindowsCreateString)(path.c_str(), path.size(), &hstr_path);
|
||||
if (FAILED(hr)) return hr;
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::StorageFile*>> fileOpenAsync;
|
||||
hr = fileFactory->GetFileFromPathAsync(hstr_path, fileOpenAsync.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
(*s_WindowsDeleteString)(hstr_path);
|
||||
|
||||
// Wait until the file gets open, get the actual file.
|
||||
AsyncStatus status = winrt_async_await(fileOpenAsync, throw_on_cancel);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::IStorageFile> storageFile;
|
||||
if (status == AsyncStatus::Completed) {
|
||||
hr = fileOpenAsync->GetResults(storageFile.GetAddressOf());
|
||||
} else {
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = fileOpenAsync.As(&asyncInfo);
|
||||
if (FAILED(hr)) return hr;
|
||||
HRESULT err;
|
||||
hr = asyncInfo->get_ErrorCode(&err);
|
||||
return FAILED(hr) ? hr : err;
|
||||
}
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> fileStreamAsync;
|
||||
hr = storageFile->OpenAsync(mode, fileStreamAsync.GetAddressOf());
|
||||
if (FAILED(hr)) return hr;
|
||||
|
||||
status = winrt_async_await(fileStreamAsync, throw_on_cancel);
|
||||
if (status == AsyncStatus::Completed) {
|
||||
hr = fileStreamAsync->GetResults(fileStream);
|
||||
} else {
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncInfo> asyncInfo;
|
||||
hr = fileStreamAsync.As(&asyncInfo);
|
||||
if (FAILED(hr)) return hr;
|
||||
HRESULT err;
|
||||
hr = asyncInfo->get_ErrorCode(&err);
|
||||
if (!FAILED(hr))
|
||||
hr = err;
|
||||
}
|
||||
return hr;
|
||||
}
|
||||
|
||||
bool is_windows10()
|
||||
{
|
||||
HKEY hKey;
|
||||
LONG lRes = RegOpenKeyExW(HKEY_LOCAL_MACHINE, L"SOFTWARE\\Microsoft\\Windows NT\\CurrentVersion", 0, KEY_READ, &hKey);
|
||||
if (lRes == ERROR_SUCCESS) {
|
||||
WCHAR szBuffer[512];
|
||||
DWORD dwBufferSize = sizeof(szBuffer);
|
||||
lRes = RegQueryValueExW(hKey, L"ProductName", 0, nullptr, (LPBYTE)szBuffer, &dwBufferSize);
|
||||
if (lRes == ERROR_SUCCESS)
|
||||
return wcsncmp(szBuffer, L"Windows 10", 10) == 0;
|
||||
RegCloseKey(hKey);
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
// Progress function, to be called regularly to update the progress.
|
||||
typedef std::function<void (const char * /* message */, unsigned /* progress */)> ProgressFn;
|
||||
|
||||
void fix_model_by_win10_sdk(const std::string &path_src, const std::string &path_dst, ProgressFn on_progress, ThrowOnCancelFn throw_on_cancel)
|
||||
{
|
||||
if (! is_windows10())
|
||||
throw Slic3r::RuntimeError(L("Only Windows 10 is supported."));
|
||||
|
||||
if (! winrt_load_runtime_object_library())
|
||||
throw Slic3r::RuntimeError(L("Failed to initialize the WinRT library."));
|
||||
|
||||
HRESULT hr = (*s_RoInitialize)(RO_INIT_MULTITHREADED);
|
||||
{
|
||||
on_progress(L("Exporting objects"), 20);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> fileStream;
|
||||
hr = winrt_open_file_stream(boost::nowide::widen(path_src), ABI::Windows::Storage::FileAccessMode::FileAccessMode_Read, fileStream.GetAddressOf(), throw_on_cancel);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3D3MFPackage> printing3d3mfpackage;
|
||||
hr = winrt_activate_instance(L"Windows.Graphics.Printing3D.Printing3D3MFPackage", printing3d3mfpackage.GetAddressOf());
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Graphics::Printing3D::Printing3DModel*>> modelAsync;
|
||||
hr = printing3d3mfpackage->LoadModelFromPackageAsync(fileStream.Get(), modelAsync.GetAddressOf());
|
||||
|
||||
AsyncStatus status = winrt_async_await(modelAsync, throw_on_cancel);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Graphics::Printing3D::IPrinting3DModel> model;
|
||||
if (status == AsyncStatus::Completed)
|
||||
hr = modelAsync->GetResults(model.GetAddressOf());
|
||||
else
|
||||
throw Slic3r::RuntimeError(L("Failed loading objects."));
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::Collections::IVector<ABI::Windows::Graphics::Printing3D::Printing3DMesh*>> meshes;
|
||||
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||
unsigned num_meshes = 0;
|
||||
hr = meshes->get_Size(&num_meshes);
|
||||
on_progress(L("Repairing object by Windows service"), 40);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> repairAsync;
|
||||
hr = model->RepairAsync(repairAsync.GetAddressOf());
|
||||
status = winrt_async_await(repairAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(L("Repair failed."));
|
||||
repairAsync->GetResults();
|
||||
|
||||
on_progress(L("Loading repaired objects"), 60);
|
||||
|
||||
// Verify the number of meshes returned after the repair action.
|
||||
meshes.Reset();
|
||||
hr = model->get_Meshes(meshes.GetAddressOf());
|
||||
hr = meshes->get_Size(&num_meshes);
|
||||
|
||||
// Save model to this class' Printing3D3MFPackage.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncAction> saveToPackageAsync;
|
||||
hr = printing3d3mfpackage->SaveModelToPackageAsync(model.Get(), saveToPackageAsync.GetAddressOf());
|
||||
status = winrt_async_await(saveToPackageAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
hr = saveToPackageAsync->GetResults();
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperation<ABI::Windows::Storage::Streams::IRandomAccessStream*>> generatorStreamAsync;
|
||||
hr = printing3d3mfpackage->SaveAsync(generatorStreamAsync.GetAddressOf());
|
||||
status = winrt_async_await(generatorStreamAsync, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IRandomAccessStream> generatorStream;
|
||||
hr = generatorStreamAsync->GetResults(generatorStream.GetAddressOf());
|
||||
|
||||
// Go to the beginning of the stream.
|
||||
generatorStream->Seek(0);
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IInputStream> inputStream;
|
||||
hr = generatorStream.As(&inputStream);
|
||||
|
||||
// Get the buffer factory.
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBufferFactory> bufferFactory;
|
||||
hr = winrt_get_activation_factory(L"Windows.Storage.Streams.Buffer", bufferFactory.GetAddressOf());
|
||||
|
||||
// Open the destination file.
|
||||
FILE *fout = boost::nowide::fopen(path_dst.c_str(), "wb");
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Storage::Streams::IBuffer> buffer;
|
||||
byte *buffer_ptr;
|
||||
bufferFactory->Create(65536 * 2048, buffer.GetAddressOf());
|
||||
{
|
||||
Microsoft::WRL::ComPtr<Windows::Storage::Streams::IBufferByteAccess> bufferByteAccess;
|
||||
buffer.As(&bufferByteAccess);
|
||||
hr = bufferByteAccess->Buffer(&buffer_ptr);
|
||||
}
|
||||
uint32_t length;
|
||||
hr = buffer->get_Length(&length);
|
||||
|
||||
Microsoft::WRL::ComPtr<ABI::Windows::Foundation::IAsyncOperationWithProgress<ABI::Windows::Storage::Streams::IBuffer*, UINT32>> asyncRead;
|
||||
for (;;) {
|
||||
hr = inputStream->ReadAsync(buffer.Get(), 65536 * 2048, ABI::Windows::Storage::Streams::InputStreamOptions_ReadAhead, asyncRead.GetAddressOf());
|
||||
status = winrt_async_await(asyncRead, throw_on_cancel);
|
||||
if (status != AsyncStatus::Completed)
|
||||
throw Slic3r::RuntimeError(saving_failed_str);
|
||||
hr = buffer->get_Length(&length);
|
||||
if (length == 0)
|
||||
break;
|
||||
fwrite(buffer_ptr, length, 1, fout);
|
||||
}
|
||||
fclose(fout);
|
||||
// Here all the COM objects will be released through the ComPtr destructors.
|
||||
}
|
||||
(*s_RoUninitialize)();
|
||||
}
|
||||
|
||||
class RepairCanceledException : public std::exception {
|
||||
public:
|
||||
const char* what() const throw() { return "Model repair has been canceled"; }
|
||||
};
|
||||
|
||||
// returt FALSE, if fixing was canceled
|
||||
// fix_result is empty, if fixing finished successfully
|
||||
// fix_result containes a message if fixing failed
|
||||
bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx, GUI::ProgressDialog& progress_dialog, const wxString& msg_header, std::string& fix_result)
|
||||
{
|
||||
std::mutex mutex;
|
||||
std::condition_variable condition;
|
||||
std::unique_lock<std::mutex> lock(mutex);
|
||||
struct Progress {
|
||||
std::string message;
|
||||
int percent = 0;
|
||||
bool updated = false;
|
||||
} progress;
|
||||
std::atomic<bool> canceled = false;
|
||||
std::atomic<bool> finished = false;
|
||||
|
||||
std::vector<ModelVolume*> volumes;
|
||||
if (volume_idx == -1)
|
||||
volumes = model_object.volumes;
|
||||
else
|
||||
volumes.emplace_back(model_object.volumes[volume_idx]);
|
||||
|
||||
// Executing the calculation in a background thread, so that the COM context could be created with its own threading model.
|
||||
// (It seems like wxWidgets initialize the COM contex as single threaded and we need a multi-threaded context).
|
||||
bool success = false;
|
||||
size_t ivolume = 0;
|
||||
auto on_progress = [&mutex, &condition, &ivolume, &volumes, &progress](const char *msg, unsigned prcnt) {
|
||||
std::lock_guard<std::mutex> lk(mutex);
|
||||
progress.message = msg;
|
||||
progress.percent = (int)floor((float(prcnt) + float(ivolume) * 100.f) / float(volumes.size()));
|
||||
progress.updated = true;
|
||||
condition.notify_all();
|
||||
};
|
||||
auto worker_thread = boost::thread([&model_object, &volumes, &ivolume, on_progress, &success, &canceled, &finished]() {
|
||||
try {
|
||||
std::vector<TriangleMesh> meshes_repaired;
|
||||
meshes_repaired.reserve(volumes.size());
|
||||
for (; ivolume < volumes.size(); ++ ivolume) {
|
||||
on_progress(L("Exporting objects"), 0);
|
||||
boost::filesystem::path path_src = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_src += ".3mf";
|
||||
Model model;
|
||||
ModelObject *mo = model.add_object();
|
||||
mo->add_volume(*volumes[ivolume]);
|
||||
|
||||
// We are about to save a 3mf, fix it by netfabb and load the fixed 3mf back.
|
||||
// store_3mf currently bakes the volume transformation into the mesh itself.
|
||||
// If we then loaded the repaired 3mf and pushed the mesh into the original ModelVolume
|
||||
// (which remembers the matrix the whole time), the transformation would be used twice.
|
||||
// We will therefore set the volume transform on the dummy ModelVolume to identity.
|
||||
mo->volumes.back()->set_transformation(Geometry::Transformation());
|
||||
|
||||
mo->add_instance();
|
||||
if (!Slic3r::store_3mf(path_src.string().c_str(), &model, nullptr, false, nullptr, false)) {
|
||||
boost::filesystem::remove(path_src);
|
||||
throw Slic3r::RuntimeError(L("Exporting 3mf file failed"));
|
||||
}
|
||||
model.clear_objects();
|
||||
model.clear_materials();
|
||||
boost::filesystem::path path_dst = boost::filesystem::temp_directory_path() / boost::filesystem::unique_path();
|
||||
path_dst += ".3mf";
|
||||
fix_model_by_win10_sdk(path_src.string().c_str(), path_dst.string(), on_progress,
|
||||
[&canceled]() { if (canceled) throw RepairCanceledException(); });
|
||||
boost::filesystem::remove(path_src);
|
||||
// PresetBundle bundle;
|
||||
on_progress(L("Loading repaired objects"), 80);
|
||||
DynamicPrintConfig config;
|
||||
ConfigSubstitutionContext config_substitutions{ ForwardCompatibilitySubstitutionRule::EnableSilent };
|
||||
bool loaded = Slic3r::load_3mf(path_dst.string().c_str(), config, config_substitutions, &model, false);
|
||||
boost::filesystem::remove(path_dst);
|
||||
if (! loaded)
|
||||
throw Slic3r::RuntimeError(L("Import 3mf file failed"));
|
||||
if (model.objects.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3mf file does not contain any object"));
|
||||
if (model.objects.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3mf file contains more than one object"));
|
||||
if (model.objects.front()->volumes.size() == 0)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3mf file does not contain any volume"));
|
||||
if (model.objects.front()->volumes.size() > 1)
|
||||
throw Slic3r::RuntimeError(L("Repaired 3mf file contains more than one volume"));
|
||||
meshes_repaired.emplace_back(std::move(model.objects.front()->volumes.front()->mesh()));
|
||||
}
|
||||
for (size_t i = 0; i < volumes.size(); ++ i) {
|
||||
volumes[i]->set_mesh(std::move(meshes_repaired[i]));
|
||||
volumes[i]->calculate_convex_hull();
|
||||
volumes[i]->set_new_unique_id();
|
||||
}
|
||||
model_object.invalidate_bounding_box();
|
||||
-- ivolume;
|
||||
on_progress(L("Repair finished"), 100);
|
||||
success = true;
|
||||
finished = true;
|
||||
} catch (RepairCanceledException & /* ex */) {
|
||||
canceled = true;
|
||||
finished = true;
|
||||
on_progress(L("Repair canceled"), 100);
|
||||
} catch (std::exception &ex) {
|
||||
success = false;
|
||||
finished = true;
|
||||
on_progress(ex.what(), 100);
|
||||
}
|
||||
});
|
||||
while (! finished) {
|
||||
condition.wait_for(lock, std::chrono::milliseconds(250), [&progress]{ return progress.updated; });
|
||||
// decrease progress.percent value to avoid closing of the progress dialog
|
||||
if (!progress_dialog.Update(progress.percent-1, msg_header + _(progress.message)))
|
||||
canceled = true;
|
||||
else
|
||||
progress_dialog.Fit();
|
||||
progress.updated = false;
|
||||
}
|
||||
|
||||
if (canceled) {
|
||||
// Nothing to show.
|
||||
} else if (success) {
|
||||
fix_result = "";
|
||||
} else {
|
||||
fix_result = progress.message;
|
||||
}
|
||||
worker_thread.join();
|
||||
return !canceled;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* HAS_WIN10SDK */
|
31
src/slic3r/Utils/FixModelByWin10.hpp
Normal file
31
src/slic3r/Utils/FixModelByWin10.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||
#define slic3r_GUI_Utils_FixModelByWin10_hpp_
|
||||
|
||||
#include <string>
|
||||
#include "../GUI/Widgets/ProgressDialog.hpp"
|
||||
|
||||
class ProgressDialog;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
class ModelObject;
|
||||
class Print;
|
||||
|
||||
#ifdef HAS_WIN10SDK
|
||||
|
||||
extern bool is_windows10();
|
||||
// returt false, if fixing was canceled
|
||||
extern bool fix_model_by_win10_sdk_gui(ModelObject &model_object, int volume_idx,GUI::ProgressDialog &progress_dlg, const wxString &msg_header, std::string &fix_result);
|
||||
|
||||
#else /* HAS_WIN10SDK */
|
||||
|
||||
inline bool is_windows10() { return false; }
|
||||
// returt false, if fixing was canceled
|
||||
inline bool fix_model_by_win10_sdk_gui(ModelObject &, int, GUI::ProgressDialog &, const wxString &, std::string &) { return false; }
|
||||
|
||||
#endif /* HAS_WIN10SDK */
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_GUI_Utils_FixModelByWin10_hpp_ */
|
108
src/slic3r/Utils/HexFile.cpp
Normal file
108
src/slic3r/Utils/HexFile.cpp
Normal file
|
@ -0,0 +1,108 @@
|
|||
#include "HexFile.hpp"
|
||||
|
||||
#include <sstream>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/property_tree/ptree.hpp>
|
||||
#include <boost/property_tree/ini_parser.hpp>
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
namespace pt = boost::property_tree;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
static HexFile::DeviceKind parse_device_kind(const std::string &str)
|
||||
{
|
||||
if (str == "mk2") { return HexFile::DEV_MK2; }
|
||||
else if (str == "mk3") { return HexFile::DEV_MK3; }
|
||||
else if (str == "mm-control") { return HexFile::DEV_MM_CONTROL; }
|
||||
else if (str == "cw1") { return HexFile::DEV_CW1; }
|
||||
else if (str == "cw1s") { return HexFile::DEV_CW1S; }
|
||||
else { return HexFile::DEV_GENERIC; }
|
||||
}
|
||||
|
||||
static size_t hex_num_sections(fs::ifstream &file)
|
||||
{
|
||||
file.seekg(0);
|
||||
if (! file.good()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const char *hex_terminator = ":00000001FF\r";
|
||||
size_t res = 0;
|
||||
std::string line;
|
||||
while (getline(file, line, '\n').good()) {
|
||||
// Account for LF vs CRLF
|
||||
if (!line.empty() && line.back() != '\r') {
|
||||
line.push_back('\r');
|
||||
}
|
||||
|
||||
if (line == hex_terminator) {
|
||||
res++;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
HexFile::HexFile(fs::path path) :
|
||||
path(std::move(path))
|
||||
{
|
||||
fs::ifstream file(this->path);
|
||||
if (! file.good()) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string line;
|
||||
std::stringstream header_ini;
|
||||
while (std::getline(file, line, '\n').good()) {
|
||||
if (line.empty()) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Account for LF vs CRLF
|
||||
if (!line.empty() && line.back() == '\r') {
|
||||
line.pop_back();
|
||||
}
|
||||
|
||||
if (line.front() == ';') {
|
||||
line.front() = ' ';
|
||||
header_ini << line << std::endl;
|
||||
} else if (line.front() == ':') {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
pt::ptree ptree;
|
||||
try {
|
||||
pt::read_ini(header_ini, ptree);
|
||||
} catch (std::exception & /* e */) {
|
||||
return;
|
||||
}
|
||||
|
||||
bool has_device_meta = false;
|
||||
const auto device = ptree.find("device");
|
||||
if (device != ptree.not_found()) {
|
||||
this->device = parse_device_kind(device->second.data());
|
||||
has_device_meta = true;
|
||||
}
|
||||
|
||||
const auto model_id = ptree.find("model_id");
|
||||
if (model_id != ptree.not_found()) {
|
||||
this->model_id = model_id->second.data();
|
||||
}
|
||||
|
||||
if (! has_device_meta) {
|
||||
// No device metadata, look at the number of 'sections'
|
||||
if (hex_num_sections(file) == 2) {
|
||||
// Looks like a pre-metadata l10n firmware for the MK3, assume that's the case
|
||||
this->device = DEV_MK3;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
35
src/slic3r/Utils/HexFile.hpp
Normal file
35
src/slic3r/Utils/HexFile.hpp
Normal file
|
@ -0,0 +1,35 @@
|
|||
#ifndef slic3r_Hex_hpp_
|
||||
#define slic3r_Hex_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
|
||||
struct HexFile
|
||||
{
|
||||
enum DeviceKind {
|
||||
DEV_GENERIC,
|
||||
DEV_MK2,
|
||||
DEV_MK3,
|
||||
DEV_MM_CONTROL,
|
||||
DEV_CW1,
|
||||
DEV_CW1S,
|
||||
};
|
||||
|
||||
boost::filesystem::path path;
|
||||
DeviceKind device = DEV_GENERIC;
|
||||
std::string model_id;
|
||||
|
||||
HexFile() {}
|
||||
HexFile(boost::filesystem::path path);
|
||||
};
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
#endif
|
804
src/slic3r/Utils/Http.cpp
Normal file
804
src/slic3r/Utils/Http.cpp
Normal file
|
@ -0,0 +1,804 @@
|
|||
#include "Http.hpp"
|
||||
|
||||
#include <cstdlib>
|
||||
#include <functional>
|
||||
#include <thread>
|
||||
#include <deque>
|
||||
#include <sstream>
|
||||
#include <exception>
|
||||
#include <boost/filesystem/fstream.hpp>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
#include <curl/curl.h>
|
||||
|
||||
#ifdef OPENSSL_CERT_OVERRIDE
|
||||
#include <openssl/x509.h>
|
||||
#endif
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
// Private
|
||||
|
||||
struct CurlGlobalInit
|
||||
{
|
||||
static std::unique_ptr<CurlGlobalInit> instance;
|
||||
std::string message;
|
||||
|
||||
CurlGlobalInit()
|
||||
{
|
||||
#ifdef OPENSSL_CERT_OVERRIDE // defined if SLIC3R_STATIC=ON
|
||||
|
||||
// Look for a set of distro specific directories. Don't change the
|
||||
// order: https://bugzilla.redhat.com/show_bug.cgi?id=1053882
|
||||
static const char * CA_BUNDLES[] = {
|
||||
"/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
|
||||
"/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
|
||||
"/usr/share/ssl/certs/ca-bundle.crt",
|
||||
"/usr/local/share/certs/ca-root-nss.crt", // FreeBSD
|
||||
"/etc/ssl/cert.pem",
|
||||
"/etc/ssl/ca-bundle.pem" // OpenSUSE Tumbleweed
|
||||
};
|
||||
|
||||
namespace fs = boost::filesystem;
|
||||
// Env var name for the OpenSSL CA bundle (SSL_CERT_FILE nomally)
|
||||
const char *const SSL_CA_FILE = X509_get_default_cert_file_env();
|
||||
const char * ssl_cafile = ::getenv(SSL_CA_FILE);
|
||||
|
||||
if (!ssl_cafile)
|
||||
ssl_cafile = X509_get_default_cert_file();
|
||||
|
||||
int replace = true;
|
||||
if (!ssl_cafile || !fs::exists(fs::path(ssl_cafile))) {
|
||||
const char * bundle = nullptr;
|
||||
for (const char * b : CA_BUNDLES) {
|
||||
if (fs::exists(fs::path(b))) {
|
||||
::setenv(SSL_CA_FILE, bundle = b, replace);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (!bundle)
|
||||
message = "Unable to get system certificate.";
|
||||
else
|
||||
message = (boost::format("use system SSL certificate: %1%") % bundle).str();
|
||||
|
||||
message += "\n" + (boost::format("To manually specify the system certificate store, "
|
||||
"set the %1% environment variable to the correct CA and restart the application") % SSL_CA_FILE).str();
|
||||
}
|
||||
#endif // OPENSSL_CERT_OVERRIDE
|
||||
|
||||
if (CURLcode ec = ::curl_global_init(CURL_GLOBAL_DEFAULT)) {
|
||||
message += "CURL initialization failed. See the log for additional details.";
|
||||
BOOST_LOG_TRIVIAL(error) << ::curl_easy_strerror(ec);
|
||||
}
|
||||
}
|
||||
|
||||
~CurlGlobalInit() { ::curl_global_cleanup(); }
|
||||
};
|
||||
|
||||
std::unique_ptr<CurlGlobalInit> CurlGlobalInit::instance;
|
||||
|
||||
struct Http::priv
|
||||
{
|
||||
enum {
|
||||
DEFAULT_TIMEOUT_CONNECT = 10,
|
||||
DEFAULT_TIMEOUT_MAX = 0,
|
||||
DEFAULT_SIZE_LIMIT = 1024 * 1024 * 1024,
|
||||
};
|
||||
|
||||
::CURL *curl;
|
||||
::curl_httppost *form;
|
||||
::curl_httppost *form_end;
|
||||
::curl_mime* mime;
|
||||
::curl_slist *headerlist;
|
||||
// Used for reading the body
|
||||
std::string buffer;
|
||||
// Used for storing file streams added as multipart form parts
|
||||
// Using a deque here because unlike vector it doesn't ivalidate pointers on insertion
|
||||
std::deque<fs::ifstream> form_files;
|
||||
std::string postfields;
|
||||
std::string error_buffer; // Used for CURLOPT_ERRORBUFFER
|
||||
std::string headers;
|
||||
size_t limit;
|
||||
bool cancel;
|
||||
std::unique_ptr<fs::ifstream> putFile;
|
||||
|
||||
std::thread io_thread;
|
||||
Http::CompleteFn completefn;
|
||||
Http::ErrorFn errorfn;
|
||||
Http::ProgressFn progressfn;
|
||||
Http::IPResolveFn ipresolvefn;
|
||||
Http::HeaderCallbackFn headerfn;
|
||||
|
||||
priv(const std::string &url);
|
||||
~priv();
|
||||
|
||||
static bool ca_file_supported(::CURL *curl);
|
||||
static size_t writecb(void *data, size_t size, size_t nmemb, void *userp);
|
||||
static int xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow);
|
||||
static int xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow);
|
||||
static size_t form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp);
|
||||
static size_t headers_cb(char *buffer, size_t size, size_t nitems, void *userp);
|
||||
|
||||
void set_timeout_connect(long timeout);
|
||||
void set_timeout_max(long timeout);
|
||||
void form_add_file(const char *name, const fs::path &path, const char* filename);
|
||||
/* mime */
|
||||
void mime_form_add_text(const char* name, const char* value);
|
||||
void mime_form_add_file(const char* name, const char* path);
|
||||
void set_post_body(const fs::path &path);
|
||||
void set_post_body(const std::string &body);
|
||||
void set_put_body(const fs::path &path);
|
||||
void set_del_body(const std::string& body);
|
||||
|
||||
std::string curl_error(CURLcode curlcode);
|
||||
std::string body_size_error();
|
||||
void http_perform();
|
||||
};
|
||||
|
||||
Http::priv::priv(const std::string &url)
|
||||
: curl(::curl_easy_init())
|
||||
, form(nullptr)
|
||||
, form_end(nullptr)
|
||||
, mime(nullptr)
|
||||
, headerlist(nullptr)
|
||||
, error_buffer(CURL_ERROR_SIZE + 1, '\0')
|
||||
, limit(0)
|
||||
, cancel(false)
|
||||
{
|
||||
Http::tls_global_init();
|
||||
|
||||
if (curl == nullptr) {
|
||||
throw Slic3r::RuntimeError(std::string("Could not construct Curl object"));
|
||||
}
|
||||
|
||||
set_timeout_connect(DEFAULT_TIMEOUT_CONNECT);
|
||||
set_timeout_max(DEFAULT_TIMEOUT_MAX);
|
||||
::curl_easy_setopt(curl, CURLOPT_URL, url.c_str()); // curl makes a copy internally
|
||||
::curl_easy_setopt(curl, CURLOPT_USERAGENT, SLIC3R_APP_NAME "/" SLIC3R_VERSION);
|
||||
::curl_easy_setopt(curl, CURLOPT_ERRORBUFFER, &error_buffer.front());
|
||||
|
||||
::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0L);
|
||||
::curl_easy_setopt(curl, CURLOPT_SSL_VERIFYHOST, 0L);
|
||||
}
|
||||
|
||||
Http::priv::~priv()
|
||||
{
|
||||
::curl_easy_cleanup(curl);
|
||||
::curl_formfree(form);
|
||||
::curl_mime_free(mime);
|
||||
::curl_slist_free_all(headerlist);
|
||||
}
|
||||
|
||||
bool Http::priv::ca_file_supported(::CURL *curl)
|
||||
{
|
||||
//BBS support set ca file by default
|
||||
bool res = true;
|
||||
|
||||
if (curl == nullptr) { return res; }
|
||||
|
||||
#if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 48
|
||||
::curl_tlssessioninfo *tls;
|
||||
if (::curl_easy_getinfo(curl, CURLINFO_TLS_SSL_PTR, &tls) == CURLE_OK) {
|
||||
if (tls->backend == CURLSSLBACKEND_SCHANNEL || tls->backend == CURLSSLBACKEND_DARWINSSL) {
|
||||
// With Windows and OS X native SSL support, cert files cannot be set
|
||||
res = false;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
size_t Http::priv::writecb(void *data, size_t size, size_t nmemb, void *userp)
|
||||
{
|
||||
auto self = static_cast<priv*>(userp);
|
||||
const char *cdata = static_cast<char*>(data);
|
||||
const size_t realsize = size * nmemb;
|
||||
|
||||
const size_t limit = self->limit > 0 ? self->limit : DEFAULT_SIZE_LIMIT;
|
||||
if (self->buffer.size() + realsize > limit) {
|
||||
// This makes curl_easy_perform return CURLE_WRITE_ERROR
|
||||
return 0;
|
||||
}
|
||||
|
||||
self->buffer.append(cdata, realsize);
|
||||
|
||||
return realsize;
|
||||
}
|
||||
|
||||
int Http::priv::xfercb(void *userp, curl_off_t dltotal, curl_off_t dlnow, curl_off_t ultotal, curl_off_t ulnow)
|
||||
{
|
||||
auto self = static_cast<priv*>(userp);
|
||||
bool cb_cancel = false;
|
||||
|
||||
if (self->progressfn) {
|
||||
double speed;
|
||||
curl_easy_getinfo(self->curl, CURLINFO_SPEED_UPLOAD, &speed);
|
||||
if (speed > 0.01)
|
||||
speed = speed;
|
||||
Progress progress(dltotal, dlnow, ultotal, ulnow, speed);
|
||||
self->progressfn(progress, cb_cancel);
|
||||
}
|
||||
|
||||
if (cb_cancel) { self->cancel = true; }
|
||||
|
||||
return self->cancel;
|
||||
}
|
||||
|
||||
int Http::priv::xfercb_legacy(void *userp, double dltotal, double dlnow, double ultotal, double ulnow)
|
||||
{
|
||||
return xfercb(userp, dltotal, dlnow, ultotal, ulnow);
|
||||
}
|
||||
|
||||
size_t Http::priv::form_file_read_cb(char *buffer, size_t size, size_t nitems, void *userp)
|
||||
{
|
||||
auto stream = reinterpret_cast<fs::ifstream*>(userp);
|
||||
|
||||
try {
|
||||
stream->read(buffer, size * nitems);
|
||||
} catch (const std::exception &) {
|
||||
return CURL_READFUNC_ABORT;
|
||||
}
|
||||
|
||||
return stream->gcount();
|
||||
}
|
||||
|
||||
size_t Http::priv::headers_cb(char *buffer, size_t size, size_t nitems, void *userp)
|
||||
{
|
||||
auto self = static_cast<priv*>(userp);
|
||||
|
||||
if (self->headerfn) {
|
||||
self->headers.append(buffer, nitems * size);
|
||||
self->headerfn(self->headers);
|
||||
}
|
||||
return nitems * size;
|
||||
}
|
||||
|
||||
void Http::priv::set_timeout_connect(long timeout)
|
||||
{
|
||||
::curl_easy_setopt(curl, CURLOPT_CONNECTTIMEOUT, timeout);
|
||||
}
|
||||
|
||||
void Http::priv::set_timeout_max(long timeout)
|
||||
{
|
||||
::curl_easy_setopt(curl, CURLOPT_TIMEOUT, timeout);
|
||||
}
|
||||
|
||||
void Http::priv::form_add_file(const char *name, const fs::path &path, const char* filename)
|
||||
{
|
||||
// We can't use CURLFORM_FILECONTENT, because curl doesn't support Unicode filenames on Windows
|
||||
// and so we use CURLFORM_STREAM with boost ifstream to read the file.
|
||||
|
||||
if (filename == nullptr) {
|
||||
filename = path.string().c_str();
|
||||
}
|
||||
|
||||
form_files.emplace_back(path, std::ios::in | std::ios::binary);
|
||||
auto &stream = form_files.back();
|
||||
stream.seekg(0, std::ios::end);
|
||||
size_t size = stream.tellg();
|
||||
stream.seekg(0);
|
||||
|
||||
if (filename != nullptr) {
|
||||
::curl_formadd(&form, &form_end,
|
||||
CURLFORM_COPYNAME, name,
|
||||
CURLFORM_FILENAME, filename,
|
||||
CURLFORM_CONTENTTYPE, "application/octet-stream",
|
||||
CURLFORM_STREAM, static_cast<void*>(&stream),
|
||||
CURLFORM_CONTENTSLENGTH, static_cast<long>(size),
|
||||
CURLFORM_END
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::priv::mime_form_add_text(const char* name, const char* value)
|
||||
{
|
||||
if (!mime) {
|
||||
mime = curl_mime_init(curl);
|
||||
}
|
||||
|
||||
curl_mimepart *part;
|
||||
part = curl_mime_addpart(mime);
|
||||
curl_mime_name(part, name);
|
||||
curl_mime_type(part, "multipart/form-data");
|
||||
curl_mime_data(part, value, CURL_ZERO_TERMINATED);
|
||||
}
|
||||
|
||||
void Http::priv::mime_form_add_file(const char* name, const char* path)
|
||||
{
|
||||
if (!mime) {
|
||||
mime = curl_mime_init(curl);
|
||||
}
|
||||
|
||||
curl_mimepart* part;
|
||||
part = curl_mime_addpart(mime);
|
||||
curl_mime_name(part, "file");
|
||||
curl_mime_type(part, "multipart/form-data");
|
||||
curl_mime_filedata(part, path);
|
||||
// BBS specify filename after filedata
|
||||
curl_mime_filename(part, name);
|
||||
}
|
||||
|
||||
//FIXME may throw! Is the caller aware of it?
|
||||
void Http::priv::set_post_body(const fs::path &path)
|
||||
{
|
||||
std::ifstream file(path.string());
|
||||
std::string file_content { std::istreambuf_iterator<char>(file), std::istreambuf_iterator<char>() };
|
||||
postfields = std::move(file_content);
|
||||
}
|
||||
|
||||
void Http::priv::set_post_body(const std::string &body)
|
||||
{
|
||||
postfields = body;
|
||||
}
|
||||
|
||||
void Http::priv::set_put_body(const fs::path &path)
|
||||
{
|
||||
boost::system::error_code ec;
|
||||
boost::uintmax_t filesize = file_size(path, ec);
|
||||
if (!ec) {
|
||||
putFile = std::make_unique<fs::ifstream>(path, std::ios_base::binary |std::ios_base::in);
|
||||
::curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L);
|
||||
::curl_easy_setopt(curl, CURLOPT_READDATA, (void *) (putFile.get()));
|
||||
::curl_easy_setopt(curl, CURLOPT_INFILESIZE, filesize);
|
||||
}
|
||||
}
|
||||
|
||||
void Http::priv::set_del_body(const std::string& body)
|
||||
{
|
||||
postfields = body;
|
||||
}
|
||||
|
||||
std::string Http::priv::curl_error(CURLcode curlcode)
|
||||
{
|
||||
return (boost::format("curl:%1%:\n%2%\n[Error %3%]")
|
||||
% ::curl_easy_strerror(curlcode)
|
||||
% error_buffer.c_str()
|
||||
% curlcode
|
||||
).str();
|
||||
}
|
||||
|
||||
std::string Http::priv::body_size_error()
|
||||
{
|
||||
return (boost::format("HTTP body data size exceeded limit (%1% bytes)") % limit).str();
|
||||
}
|
||||
|
||||
void Http::priv::http_perform()
|
||||
{
|
||||
::curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
|
||||
::curl_easy_setopt(curl, CURLOPT_POSTREDIR, CURL_REDIR_POST_ALL);
|
||||
::curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, writecb);
|
||||
::curl_easy_setopt(curl, CURLOPT_WRITEDATA, static_cast<void*>(this));
|
||||
::curl_easy_setopt(curl, CURLOPT_READFUNCTION, form_file_read_cb);
|
||||
//BBS set header functions
|
||||
::curl_easy_setopt(curl, CURLOPT_HEADERDATA, static_cast<void *>(this));
|
||||
::curl_easy_setopt(curl, CURLOPT_HEADERFUNCTION, headers_cb);
|
||||
|
||||
::curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
|
||||
#if LIBCURL_VERSION_MAJOR >= 7 && LIBCURL_VERSION_MINOR >= 32
|
||||
::curl_easy_setopt(curl, CURLOPT_XFERINFOFUNCTION, xfercb);
|
||||
::curl_easy_setopt(curl, CURLOPT_XFERINFODATA, static_cast<void*>(this));
|
||||
#ifndef _WIN32
|
||||
(void)xfercb_legacy; // prevent unused function warning
|
||||
#endif
|
||||
#else
|
||||
::curl_easy_setopt(curl, CURLOPT_PROGRESSFUNCTION, xfercb);
|
||||
::curl_easy_setopt(curl, CURLOPT_PROGRESSDATA, static_cast<void*>(this));
|
||||
#endif
|
||||
|
||||
::curl_easy_setopt(curl, CURLOPT_VERBOSE, 1L);
|
||||
|
||||
if (headerlist != nullptr) {
|
||||
::curl_easy_setopt(curl, CURLOPT_HTTPHEADER, headerlist);
|
||||
}
|
||||
|
||||
if (form != nullptr) {
|
||||
::curl_easy_setopt(curl, CURLOPT_HTTPPOST, form);
|
||||
}
|
||||
|
||||
if (mime != nullptr) {
|
||||
::curl_easy_setopt(curl, CURLOPT_MIMEPOST, mime);
|
||||
}
|
||||
|
||||
if (!postfields.empty()) {
|
||||
::curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postfields.c_str());
|
||||
::curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE_LARGE, postfields.size());
|
||||
}
|
||||
|
||||
CURLcode res = ::curl_easy_perform(curl);
|
||||
|
||||
putFile.reset();
|
||||
|
||||
if (res != CURLE_OK) {
|
||||
if (res == CURLE_ABORTED_BY_CALLBACK) {
|
||||
if (cancel) {
|
||||
// The abort comes from the request being cancelled programatically
|
||||
Progress dummyprogress(0, 0, 0, 0);
|
||||
bool cancel = true;
|
||||
if (progressfn) { progressfn(dummyprogress, cancel); }
|
||||
} else {
|
||||
// The abort comes from the CURLOPT_READFUNCTION callback, which means reading file failed
|
||||
if (errorfn) { errorfn(std::move(buffer), "Error reading file for file upload", 0); }
|
||||
}
|
||||
}
|
||||
else if (res == CURLE_WRITE_ERROR) {
|
||||
if (errorfn) { errorfn(std::move(buffer), body_size_error(), 0); }
|
||||
} else {
|
||||
if (errorfn) { errorfn(std::move(buffer), curl_error(res), 0); }
|
||||
};
|
||||
} else {
|
||||
long http_status = 0;
|
||||
::curl_easy_getinfo(curl, CURLINFO_RESPONSE_CODE, &http_status);
|
||||
|
||||
//BBS check success http status code
|
||||
if (http_status >= 200 && http_status < 300) {
|
||||
if (completefn) { completefn(std::move(buffer), http_status); }
|
||||
if (ipresolvefn) {
|
||||
char* ct;
|
||||
res = curl_easy_getinfo(curl, CURLINFO_PRIMARY_IP, &ct);
|
||||
if ((CURLE_OK == res) && ct) {
|
||||
ipresolvefn(ct);
|
||||
}
|
||||
}
|
||||
}
|
||||
//BBS check error http status code
|
||||
else if (http_status >= 400) {
|
||||
if (errorfn) { errorfn(std::move(buffer), std::string(), http_status); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Http::Http(const std::string &url) : p(new priv(url))
|
||||
{
|
||||
;
|
||||
}
|
||||
|
||||
|
||||
// Public
|
||||
|
||||
Http::Http(Http &&other) : p(std::move(other.p)) {}
|
||||
|
||||
Http::~Http()
|
||||
{
|
||||
assert(! p || ! p->putFile);
|
||||
if (p && p->io_thread.joinable()) {
|
||||
p->io_thread.detach();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Http& Http::timeout_connect(long timeout)
|
||||
{
|
||||
if (timeout < 1) { timeout = priv::DEFAULT_TIMEOUT_CONNECT; }
|
||||
if (p) { p->set_timeout_connect(timeout); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::timeout_max(long timeout)
|
||||
{
|
||||
if (timeout < 1) { timeout = priv::DEFAULT_TIMEOUT_MAX; }
|
||||
if (p) { p->set_timeout_max(timeout); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::size_limit(size_t sizeLimit)
|
||||
{
|
||||
if (p) { p->limit = sizeLimit; }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::header(std::string name, const std::string &value)
|
||||
{
|
||||
if (!p) { return * this; }
|
||||
|
||||
if (name.size() > 0) {
|
||||
name.append(": ").append(value);
|
||||
} else {
|
||||
name.push_back(':');
|
||||
}
|
||||
p->headerlist = curl_slist_append(p->headerlist, name.c_str());
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::remove_header(std::string name)
|
||||
{
|
||||
if (p) {
|
||||
name.push_back(':');
|
||||
p->headerlist = curl_slist_append(p->headerlist, name.c_str());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
// Authorization by HTTP digest, based on RFC2617.
|
||||
Http& Http::auth_digest(const std::string &user, const std::string &password)
|
||||
{
|
||||
curl_easy_setopt(p->curl, CURLOPT_USERNAME, user.c_str());
|
||||
curl_easy_setopt(p->curl, CURLOPT_PASSWORD, password.c_str());
|
||||
curl_easy_setopt(p->curl, CURLOPT_HTTPAUTH, CURLAUTH_DIGEST);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::auth_basic(const std::string &user, const std::string &password)
|
||||
{
|
||||
curl_easy_setopt(p->curl, CURLOPT_USERNAME, user.c_str());
|
||||
curl_easy_setopt(p->curl, CURLOPT_PASSWORD, password.c_str());
|
||||
curl_easy_setopt(p->curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::ca_file(const std::string &name)
|
||||
{
|
||||
if (p && priv::ca_file_supported(p->curl)) {
|
||||
::curl_easy_setopt(p->curl, CURLOPT_CAINFO, name.c_str());
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Http& Http::form_add(const std::string &name, const std::string &contents)
|
||||
{
|
||||
if (p) {
|
||||
::curl_formadd(&p->form, &p->form_end,
|
||||
CURLFORM_COPYNAME, name.c_str(),
|
||||
CURLFORM_COPYCONTENTS, contents.c_str(),
|
||||
CURLFORM_END
|
||||
);
|
||||
}
|
||||
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::form_add_file(const std::string &name, const fs::path &path)
|
||||
{
|
||||
if (p) { p->form_add_file(name.c_str(), path.c_str(), nullptr); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Http& Http::mime_form_add_text(std::string &name, std::string &value)
|
||||
{
|
||||
if (p) { p->mime_form_add_text(name.c_str(), value.c_str()); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::mime_form_add_file(std::string &name, const char* path)
|
||||
{
|
||||
if (p) { p->mime_form_add_file(name.c_str(), path); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
Http& Http::form_add_file(const std::wstring& name, const fs::path& path)
|
||||
{
|
||||
if (p) { p->form_add_file((char*)name.c_str(), path.c_str(), nullptr); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::form_add_file(const std::string &name, const fs::path &path, const std::string &filename)
|
||||
{
|
||||
if (p) { p->form_add_file(name.c_str(), path.c_str(), filename.c_str()); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
#ifdef WIN32
|
||||
// Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present.
|
||||
// This option is only supported for Schannel (the native Windows SSL library).
|
||||
Http& Http::ssl_revoke_best_effort(bool set)
|
||||
{
|
||||
// BBS
|
||||
#if 0
|
||||
if(p && set){
|
||||
::curl_easy_setopt(p->curl, CURLOPT_SSL_OPTIONS, CURLSSLOPT_REVOKE_BEST_EFFORT);
|
||||
}
|
||||
#endif
|
||||
return *this;
|
||||
}
|
||||
#endif // WIN32
|
||||
|
||||
Http& Http::set_post_body(const fs::path &path)
|
||||
{
|
||||
if (p) { p->set_post_body(path);}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::set_post_body(const std::string &body)
|
||||
{
|
||||
if (p) { p->set_post_body(body); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::set_put_body(const fs::path &path)
|
||||
{
|
||||
if (p) { p->set_put_body(path);}
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::set_del_body(const std::string &body)
|
||||
{
|
||||
if (p) { p->set_del_body(body); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_complete(CompleteFn fn)
|
||||
{
|
||||
if (p) { p->completefn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_error(ErrorFn fn)
|
||||
{
|
||||
if (p) { p->errorfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_progress(ProgressFn fn)
|
||||
{
|
||||
if (p) { p->progressfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http& Http::on_ip_resolve(IPResolveFn fn)
|
||||
{
|
||||
if (p) { p->ipresolvefn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http &Http::on_header_callback(HeaderCallbackFn fn)
|
||||
{
|
||||
if (p) { p->headerfn = std::move(fn); }
|
||||
return *this;
|
||||
}
|
||||
|
||||
Http::Ptr Http::perform()
|
||||
{
|
||||
auto self = std::make_shared<Http>(std::move(*this));
|
||||
|
||||
if (self->p) {
|
||||
auto io_thread = std::thread([self](){
|
||||
self->p->http_perform();
|
||||
});
|
||||
self->p->io_thread = std::move(io_thread);
|
||||
}
|
||||
|
||||
return self;
|
||||
}
|
||||
|
||||
void Http::perform_sync()
|
||||
{
|
||||
if (p) { p->http_perform(); }
|
||||
}
|
||||
|
||||
void Http::cancel()
|
||||
{
|
||||
if (p) { p->cancel = true; }
|
||||
}
|
||||
|
||||
Http Http::get(std::string url)
|
||||
{
|
||||
return Http{std::move(url)};
|
||||
}
|
||||
|
||||
Http Http::post(std::string url)
|
||||
{
|
||||
Http http{std::move(url)};
|
||||
curl_easy_setopt(http.p->curl, CURLOPT_POST, 1L);
|
||||
return http;
|
||||
}
|
||||
|
||||
Http Http::put(std::string url)
|
||||
{
|
||||
Http http{std::move(url)};
|
||||
curl_easy_setopt(http.p->curl, CURLOPT_UPLOAD, 1L);
|
||||
return http;
|
||||
}
|
||||
|
||||
Http Http::put2(std::string url)
|
||||
{
|
||||
Http http{ std::move(url) };
|
||||
curl_easy_setopt(http.p->curl, CURLOPT_CUSTOMREQUEST, "PUT");
|
||||
return http;
|
||||
}
|
||||
|
||||
Http Http::patch(std::string url)
|
||||
{
|
||||
Http http{ std::move(url) };
|
||||
curl_easy_setopt(http.p->curl, CURLOPT_CUSTOMREQUEST, "PATCH");
|
||||
return http;
|
||||
}
|
||||
|
||||
Http Http::del(std::string url)
|
||||
{
|
||||
Http http{ std::move(url) };
|
||||
curl_easy_setopt(http.p->curl, CURLOPT_CUSTOMREQUEST, "DELETE");
|
||||
return http;
|
||||
}
|
||||
|
||||
bool Http::ca_file_supported()
|
||||
{
|
||||
::CURL *curl = ::curl_easy_init();
|
||||
bool res = priv::ca_file_supported(curl);
|
||||
if (curl != nullptr) { ::curl_easy_cleanup(curl); }
|
||||
return res;
|
||||
}
|
||||
|
||||
std::string Http::tls_global_init()
|
||||
{
|
||||
if (!CurlGlobalInit::instance)
|
||||
CurlGlobalInit::instance = std::make_unique<CurlGlobalInit>();
|
||||
|
||||
return CurlGlobalInit::instance->message;
|
||||
}
|
||||
|
||||
std::string Http::tls_system_cert_store()
|
||||
{
|
||||
std::string ret;
|
||||
|
||||
#ifdef OPENSSL_CERT_OVERRIDE
|
||||
ret = ::getenv(X509_get_default_cert_file_env());
|
||||
#endif
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string Http::url_encode(const std::string &str)
|
||||
{
|
||||
::CURL *curl = ::curl_easy_init();
|
||||
if (curl == nullptr) {
|
||||
return str;
|
||||
}
|
||||
char *ce = ::curl_easy_escape(curl, str.c_str(), str.length());
|
||||
std::string encoded = std::string(ce);
|
||||
|
||||
::curl_free(ce);
|
||||
::curl_easy_cleanup(curl);
|
||||
|
||||
return encoded;
|
||||
}
|
||||
|
||||
std::string Http::url_decode(const std::string &str)
|
||||
{
|
||||
::CURL *curl = ::curl_easy_init();
|
||||
if (curl == nullptr) { return str; }
|
||||
int outlen = 0;
|
||||
char *ce = ::curl_easy_unescape(curl, str.c_str(), str.length(), &outlen);
|
||||
std::string dencoded = std::string(ce, outlen);
|
||||
|
||||
::curl_free(ce);
|
||||
::curl_easy_cleanup(curl);
|
||||
|
||||
return dencoded;
|
||||
}
|
||||
|
||||
std::string Http::get_filename_from_url(const std::string &url)
|
||||
{
|
||||
int end_pos = url.find_first_of('?');
|
||||
if (end_pos <= 0) return "";
|
||||
std::string path_url = url.substr(0, end_pos);
|
||||
int start_pos = path_url.find_last_of("/");
|
||||
if (start_pos < 0) return "";
|
||||
return path_url.substr(start_pos + 1, path_url.length() - start_pos - 1);
|
||||
}
|
||||
|
||||
std::ostream& operator<<(std::ostream &os, const Http::Progress &progress)
|
||||
{
|
||||
os << "Http::Progress("
|
||||
<< "dltotal = " << progress.dltotal
|
||||
<< ", dlnow = " << progress.dlnow
|
||||
<< ", ultotal = " << progress.ultotal
|
||||
<< ", ulnow = " << progress.ulnow
|
||||
<< ")";
|
||||
return os;
|
||||
}
|
||||
|
||||
|
||||
}
|
179
src/slic3r/Utils/Http.hpp
Normal file
179
src/slic3r/Utils/Http.hpp
Normal file
|
@ -0,0 +1,179 @@
|
|||
#ifndef __Http_hpp__
|
||||
#define __Http_hpp__
|
||||
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <functional>
|
||||
#include <boost/filesystem/path.hpp>
|
||||
|
||||
#define MAX_SIZE_TO_FILE 3*1024
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
/// Represetns a Http request
|
||||
class Http : public std::enable_shared_from_this<Http> {
|
||||
private:
|
||||
struct priv;
|
||||
public:
|
||||
struct Progress
|
||||
{
|
||||
size_t dltotal; // Total bytes to download
|
||||
size_t dlnow; // Bytes downloaded so far
|
||||
size_t ultotal; // Total bytes to upload
|
||||
size_t ulnow; // Bytes uploaded so far
|
||||
double upload_spd{0.0f};
|
||||
|
||||
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow) :
|
||||
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow)
|
||||
{}
|
||||
|
||||
Progress(size_t dltotal, size_t dlnow, size_t ultotal, size_t ulnow, double ulspd) :
|
||||
dltotal(dltotal), dlnow(dlnow), ultotal(ultotal), ulnow(ulnow), upload_spd(ulspd)
|
||||
{}
|
||||
};
|
||||
|
||||
typedef std::shared_ptr<Http> Ptr;
|
||||
typedef std::function<void(std::string /* body */, unsigned /* http_status */)> CompleteFn;
|
||||
|
||||
// A HTTP request may fail at various stages of completeness (URL parsing, DNS lookup, TCP connection, ...).
|
||||
// If the HTTP request could not be made or failed before completion, the `error` arg contains a description
|
||||
// of the error and `http_status` is zero.
|
||||
// If the HTTP request was completed but the response HTTP code is >= 400, `error` is empty and `http_status` contains the response code.
|
||||
// In either case there may or may not be a body.
|
||||
typedef std::function<void(std::string /* body */, std::string /* error */, unsigned /* http_status */)> ErrorFn;
|
||||
|
||||
// See the Progress struct above.
|
||||
// Writing true to the `cancel` reference cancels the request in progress.
|
||||
typedef std::function<void(Progress, bool& /* cancel */)> ProgressFn;
|
||||
|
||||
typedef std::function<void(std::string/* address */)> IPResolveFn;
|
||||
|
||||
typedef std::function<void(std::string headers)> HeaderCallbackFn;
|
||||
|
||||
Http(Http &&other);
|
||||
|
||||
// Note: strings are expected to be UTF-8-encoded
|
||||
|
||||
// These are the primary constructors that create a HTTP object
|
||||
// for a GET and a POST request respectively.
|
||||
static Http get(std::string url);
|
||||
static Http post(std::string url);
|
||||
static Http put(std::string url);
|
||||
static Http del(std::string url);
|
||||
|
||||
//BBS
|
||||
static Http put2(std::string url);
|
||||
static Http patch(std::string url);
|
||||
|
||||
~Http();
|
||||
|
||||
Http(const Http &) = delete;
|
||||
Http& operator=(const Http &) = delete;
|
||||
Http& operator=(Http &&) = delete;
|
||||
|
||||
// Sets a maximum connection timeout in seconds
|
||||
Http& timeout_connect(long timeout);
|
||||
// Sets a maximum total request timeout in seconds
|
||||
Http& timeout_max(long timeout);
|
||||
// Sets a maximum size of the data that can be received.
|
||||
// A value of zero sets the default limit, which is is 5MB.
|
||||
Http& size_limit(size_t sizeLimit);
|
||||
// Sets a HTTP header field.
|
||||
Http& header(std::string name, const std::string &value);
|
||||
// Removes a header field.
|
||||
Http& remove_header(std::string name);
|
||||
// Authorization by HTTP digest, based on RFC2617.
|
||||
Http& auth_digest(const std::string &user, const std::string &password);
|
||||
// Basic HTTP authorization
|
||||
Http& auth_basic(const std::string &user, const std::string &password);
|
||||
// Sets a CA certificate file for usage with HTTPS. This is only supported on some backends,
|
||||
// specifically, this is supported with OpenSSL and NOT supported with Windows and OS X native certificate store.
|
||||
// See also ca_file_supported().
|
||||
Http& ca_file(const std::string &filename);
|
||||
|
||||
// Add a HTTP multipart form field
|
||||
Http& form_add(const std::string &name, const std::string &contents);
|
||||
// Add a HTTP multipart form file data contents, `name` is the name of the part
|
||||
Http& form_add_file(const std::string &name, const boost::filesystem::path &path);
|
||||
// Add a HTTP mime form field
|
||||
Http& mime_form_add_text(std::string& name, std::string& value);
|
||||
// Add a HTTP mime form file
|
||||
Http& mime_form_add_file(std::string& name, const char* path);
|
||||
// Same as above except also override the file's filename with a wstring type
|
||||
Http& form_add_file(const std::wstring& name, const boost::filesystem::path& path);
|
||||
// Same as above except also override the file's filename with a custom one
|
||||
Http& form_add_file(const std::string &name, const boost::filesystem::path &path, const std::string &filename);
|
||||
|
||||
#ifdef WIN32
|
||||
// Tells libcurl to ignore certificate revocation checks in case of missing or offline distribution points for those SSL backends where such behavior is present.
|
||||
// This option is only supported for Schannel (the native Windows SSL library).
|
||||
Http& ssl_revoke_best_effort(bool set);
|
||||
#endif // WIN32
|
||||
|
||||
// Set the file contents as a POST request body.
|
||||
// The data is used verbatim, it is not additionally encoded in any way.
|
||||
// This can be used for hosts which do not support multipart requests.
|
||||
Http& set_post_body(const boost::filesystem::path &path);
|
||||
|
||||
// Set the POST request body.
|
||||
// The data is used verbatim, it is not additionally encoded in any way.
|
||||
// This can be used for hosts which do not support multipart requests.
|
||||
Http& set_post_body(const std::string &body);
|
||||
|
||||
// Set the file contents as a PUT request body.
|
||||
// The data is used verbatim, it is not additionally encoded in any way.
|
||||
// This can be used for hosts which do not support multipart requests.
|
||||
Http& set_put_body(const boost::filesystem::path &path);
|
||||
|
||||
// Set the file contents as a DELETE request body.
|
||||
// The data is used verbatim, it is not additionally encoded in any way.
|
||||
// This can be used for hosts which do not support multipart requests.
|
||||
Http& set_del_body(const std::string& body);
|
||||
|
||||
// Callback called on HTTP request complete
|
||||
Http& on_complete(CompleteFn fn);
|
||||
// Callback called on an error occuring at any stage of the requests: Url parsing, DNS lookup,
|
||||
// TCP connection, HTTP transfer, and finally also when the response indicates an error (status >= 400).
|
||||
// Therefore, a response body may or may not be present.
|
||||
Http& on_error(ErrorFn fn);
|
||||
// Callback called on data download/upload prorgess (called fairly frequently).
|
||||
// See the `Progress` structure for description of the data passed.
|
||||
// Writing a true-ish value into the cancel reference parameter cancels the request.
|
||||
Http& on_progress(ProgressFn fn);
|
||||
// Callback called after succesful HTTP request (after on_complete callback)
|
||||
// Called if curl_easy_getinfo resolved just used IP address.
|
||||
Http& on_ip_resolve(IPResolveFn fn);
|
||||
// Callback called when response header is received
|
||||
Http& on_header_callback(HeaderCallbackFn fn);
|
||||
|
||||
// Starts performing the request in a background thread
|
||||
Ptr perform();
|
||||
// Starts performing the request on the current thread
|
||||
void perform_sync();
|
||||
// Cancels a request in progress
|
||||
void cancel();
|
||||
|
||||
// Tells whether current backend supports seting up a CA file using ca_file()
|
||||
static bool ca_file_supported();
|
||||
|
||||
// Return empty string on success or error message on fail.
|
||||
static std::string tls_global_init();
|
||||
static std::string tls_system_cert_store();
|
||||
|
||||
// converts the given string to an url_encoded_string
|
||||
static std::string url_encode(const std::string &str);
|
||||
static std::string url_decode(const std::string &str);
|
||||
|
||||
static std::string get_filename_from_url(const std::string &url);
|
||||
private:
|
||||
Http(const std::string &url);
|
||||
|
||||
std::unique_ptr<priv> p;
|
||||
};
|
||||
|
||||
std::ostream& operator<<(std::ostream &, const Http::Progress &);
|
||||
|
||||
|
||||
}
|
||||
|
||||
#endif
|
17
src/slic3r/Utils/MacDarkMode.hpp
Normal file
17
src/slic3r/Utils/MacDarkMode.hpp
Normal file
|
@ -0,0 +1,17 @@
|
|||
#ifndef slic3r_MacDarkMode_hpp_
|
||||
#define slic3r_MacDarkMode_hpp_
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
#if __APPLE__
|
||||
extern bool mac_dark_mode();
|
||||
extern double mac_max_scaling_factor();
|
||||
extern void set_miniaturizable(void * window);
|
||||
#endif
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // MacDarkMode_h
|
99
src/slic3r/Utils/MacDarkMode.mm
Normal file
99
src/slic3r/Utils/MacDarkMode.mm
Normal file
|
@ -0,0 +1,99 @@
|
|||
#import "MacDarkMode.hpp"
|
||||
|
||||
#import <algorithm>
|
||||
|
||||
#import <Cocoa/Cocoa.h>
|
||||
#import <Foundation/Foundation.h>
|
||||
#import <AppKit/NSScreen.h>
|
||||
|
||||
@interface MacDarkMode : NSObject {}
|
||||
@end
|
||||
|
||||
@implementation MacDarkMode
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
bool mac_dark_mode()
|
||||
{
|
||||
NSString *style = [[NSUserDefaults standardUserDefaults] stringForKey:@"AppleInterfaceStyle"];
|
||||
return style && [style isEqualToString:@"Dark"];
|
||||
|
||||
}
|
||||
|
||||
double mac_max_scaling_factor()
|
||||
{
|
||||
double scaling = 1.;
|
||||
// if ([NSScreen screens] == nil) {
|
||||
// scaling = [[NSScreen mainScreen] backingScaleFactor];
|
||||
// } else {
|
||||
// for (int i = 0; i < [[NSScreen screens] count]; ++ i)
|
||||
// scaling = std::max<double>(scaling, [[[NSScreen screens] objectAtIndex:0] backingScaleFactor]);
|
||||
// }
|
||||
return scaling;
|
||||
}
|
||||
|
||||
void set_miniaturizable(void * window)
|
||||
{
|
||||
[(NSView*) window window].styleMask |= NSMiniaturizableWindowMask;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
/* textColor for NSButton */
|
||||
|
||||
@implementation NSButton (NSButton_Extended)
|
||||
|
||||
- (NSColor *)textColor
|
||||
{
|
||||
NSAttributedString *attrTitle = [self attributedTitle];
|
||||
int len = [attrTitle length];
|
||||
NSRange range = NSMakeRange(0, MIN(len, 1)); // get the font attributes from the first character
|
||||
NSDictionary *attrs = [attrTitle fontAttributesInRange:range];
|
||||
NSColor *textColor = [NSColor controlTextColor];
|
||||
if (attrs)
|
||||
{
|
||||
textColor = [attrs objectForKey:NSForegroundColorAttributeName];
|
||||
}
|
||||
|
||||
return textColor;
|
||||
}
|
||||
|
||||
- (void)setTextColor:(NSColor *)textColor
|
||||
{
|
||||
NSMutableAttributedString *attrTitle =
|
||||
[[NSMutableAttributedString alloc] initWithAttributedString:[self attributedTitle]];
|
||||
int len = [attrTitle length];
|
||||
NSRange range = NSMakeRange(0, len);
|
||||
[attrTitle addAttribute:NSForegroundColorAttributeName value:textColor range:range];
|
||||
[attrTitle fixAttributesInRange:range];
|
||||
[self setAttributedTitle:attrTitle];
|
||||
[attrTitle release];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#include <wx/dataview.h>
|
||||
#include <wx/osx/cocoa/dataview.h>
|
||||
#include <wx/osx/dataview.h>
|
||||
|
||||
@implementation wxCocoaOutlineView (Edit)
|
||||
|
||||
- (BOOL)outlineView: (NSOutlineView*) view shouldEditTableColumn:(nullable NSTableColumn *)tableColumn item:(nonnull id)item
|
||||
{
|
||||
wxDataViewColumn* const col((wxDataViewColumn *)[tableColumn getColumnPointer]);
|
||||
wxDataViewItem item2([static_cast<wxPointerObject *>(item) pointer]);
|
||||
|
||||
wxDataViewCtrl* const dvc = implementation->GetDataViewCtrl();
|
||||
// Before doing anything we send an event asking if editing of this item is really wanted.
|
||||
wxDataViewEvent event(wxEVT_DATAVIEW_ITEM_EDITING_STARTED, dvc, col, item2);
|
||||
dvc->GetEventHandler()->ProcessEvent( event );
|
||||
if( !event.IsAllowed() )
|
||||
return NO;
|
||||
return YES;
|
||||
}
|
||||
|
||||
@end
|
822
src/slic3r/Utils/NetworkAgent.cpp
Normal file
822
src/slic3r/Utils/NetworkAgent.cpp
Normal file
|
@ -0,0 +1,822 @@
|
|||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
#include <Windows.h>
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#endif
|
||||
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include "libslic3r/Utils.hpp"
|
||||
#include "NetworkAgent.hpp"
|
||||
|
||||
|
||||
using namespace BBL;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
static HMODULE netwoking_module = NULL;
|
||||
#else
|
||||
static void* netwoking_module = NULL;
|
||||
#endif
|
||||
|
||||
func_create_agent NetworkAgent::create_agent_ptr = nullptr;
|
||||
func_destroy_agent NetworkAgent::destroy_agent_ptr = nullptr;
|
||||
func_init_log NetworkAgent::init_log_ptr = nullptr;
|
||||
func_set_config_dir NetworkAgent::set_config_dir_ptr = nullptr;
|
||||
func_set_cert_file NetworkAgent::set_cert_file_ptr = nullptr;
|
||||
func_set_country_code NetworkAgent::set_country_code_ptr = nullptr;
|
||||
func_start NetworkAgent::start_ptr = nullptr;
|
||||
func_set_on_ssdp_msg_fn NetworkAgent::set_on_ssdp_msg_fn_ptr = nullptr;
|
||||
func_set_on_user_login_fn NetworkAgent::set_on_user_login_fn_ptr = nullptr;
|
||||
func_set_on_printer_connected_fn NetworkAgent::set_on_printer_connected_fn_ptr = nullptr;
|
||||
func_set_on_server_connected_fn NetworkAgent::set_on_server_connected_fn_ptr = nullptr;
|
||||
func_set_on_http_error_fn NetworkAgent::set_on_http_error_fn_ptr = nullptr;
|
||||
func_set_get_country_code_fn NetworkAgent::set_get_country_code_fn_ptr = nullptr;
|
||||
func_set_on_message_fn NetworkAgent::set_on_message_fn_ptr = nullptr;
|
||||
func_set_on_local_connect_fn NetworkAgent::set_on_local_connect_fn_ptr = nullptr;
|
||||
func_set_on_local_message_fn NetworkAgent::set_on_local_message_fn_ptr = nullptr;
|
||||
func_connect_server NetworkAgent::connect_server_ptr = nullptr;
|
||||
func_is_server_connected NetworkAgent::is_server_connected_ptr = nullptr;
|
||||
func_refresh_connection NetworkAgent::refresh_connection_ptr = nullptr;
|
||||
func_start_subscribe NetworkAgent::start_subscribe_ptr = nullptr;
|
||||
func_stop_subscribe NetworkAgent::stop_subscribe_ptr = nullptr;
|
||||
func_send_message NetworkAgent::send_message_ptr = nullptr;
|
||||
func_connect_printer NetworkAgent::connect_printer_ptr = nullptr;
|
||||
func_disconnect_printer NetworkAgent::disconnect_printer_ptr = nullptr;
|
||||
func_send_message_to_printer NetworkAgent::send_message_to_printer_ptr = nullptr;
|
||||
func_start_discovery NetworkAgent::start_discovery_ptr = nullptr;
|
||||
func_change_user NetworkAgent::change_user_ptr = nullptr;
|
||||
func_is_user_login NetworkAgent::is_user_login_ptr = nullptr;
|
||||
func_user_logout NetworkAgent::user_logout_ptr = nullptr;
|
||||
func_get_user_id NetworkAgent::get_user_id_ptr = nullptr;
|
||||
func_get_user_name NetworkAgent::get_user_name_ptr = nullptr;
|
||||
func_get_user_avatar NetworkAgent::get_user_avatar_ptr = nullptr;
|
||||
func_get_user_nickanme NetworkAgent::get_user_nickanme_ptr = nullptr;
|
||||
func_build_login_cmd NetworkAgent::build_login_cmd_ptr = nullptr;
|
||||
func_build_logout_cmd NetworkAgent::build_logout_cmd_ptr = nullptr;
|
||||
func_build_login_info NetworkAgent::build_login_info_ptr = nullptr;
|
||||
func_bind NetworkAgent::bind_ptr = nullptr;
|
||||
func_unbind NetworkAgent::unbind_ptr = nullptr;
|
||||
func_get_bambulab_host NetworkAgent::get_bambulab_host_ptr = nullptr;
|
||||
func_get_user_selected_machine NetworkAgent::get_user_selected_machine_ptr = nullptr;
|
||||
func_set_user_selected_machine NetworkAgent::set_user_selected_machine_ptr = nullptr;
|
||||
func_start_print NetworkAgent::start_print_ptr = nullptr;
|
||||
func_start_local_print_with_record NetworkAgent::start_local_print_with_record_ptr = nullptr;
|
||||
func_start_local_print NetworkAgent::start_local_print_ptr = nullptr;
|
||||
func_get_user_presets NetworkAgent::get_user_presets_ptr = nullptr;
|
||||
func_request_setting_id NetworkAgent::request_setting_id_ptr = nullptr;
|
||||
func_put_setting NetworkAgent::put_setting_ptr = nullptr;
|
||||
func_get_setting_list NetworkAgent::get_setting_list_ptr = nullptr;
|
||||
func_delete_setting NetworkAgent::delete_setting_ptr = nullptr;
|
||||
func_get_studio_info_url NetworkAgent::get_studio_info_url_ptr = nullptr;
|
||||
func_set_extra_http_header NetworkAgent::set_extra_http_header_ptr = nullptr;
|
||||
func_check_user_task_report NetworkAgent::check_user_task_report_ptr = nullptr;
|
||||
func_get_user_print_info NetworkAgent::get_user_print_info_ptr = nullptr;
|
||||
func_get_printer_firmware NetworkAgent::get_printer_firmware_ptr = nullptr;
|
||||
func_get_task_plate_index NetworkAgent::get_task_plate_index_ptr = nullptr;
|
||||
func_get_slice_info NetworkAgent::get_slice_info_ptr = nullptr;
|
||||
func_query_bind_status NetworkAgent::query_bind_status_ptr = nullptr;
|
||||
func_modify_printer_name NetworkAgent::modify_printer_name_ptr = nullptr;
|
||||
func_get_camera_url NetworkAgent::get_camera_url_ptr = nullptr;
|
||||
|
||||
|
||||
NetworkAgent::NetworkAgent()
|
||||
{
|
||||
if (create_agent_ptr) {
|
||||
network_agent = create_agent_ptr();
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", this %1%, network_agent=%2%, create_agent_ptr=%3%")%this %network_agent %create_agent_ptr;
|
||||
}
|
||||
|
||||
NetworkAgent::~NetworkAgent()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && destroy_agent_ptr) {
|
||||
ret = destroy_agent_ptr(network_agent);
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", this %1%, network_agent=%2%, destroy_agent_ptr=%3%, ret %4%")%this %network_agent %destroy_agent_ptr %ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::initialize_network_module()
|
||||
{
|
||||
//int ret = -1;
|
||||
std::string library;
|
||||
|
||||
//first load the library
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
library = std::string(BAMBU_NETWORK_LIBRARY) + ".dll";
|
||||
wchar_t lib_wstr[128];
|
||||
memset(lib_wstr, 0, sizeof(lib_wstr));
|
||||
::MultiByteToWideChar(CP_UTF8, NULL, library.c_str(), strlen(library.c_str())+1, lib_wstr, sizeof(lib_wstr) / sizeof(lib_wstr[0]));
|
||||
netwoking_module = LoadLibrary(lib_wstr);
|
||||
#elif defined(__WXMAC__)
|
||||
std::string resource_dir = resources_dir();
|
||||
library = resource_dir + "/../Library/"+ std::string("lib") + BAMBU_NETWORK_LIBRARY + ".dylib";
|
||||
printf("loading network module at %s\n", library.c_str());
|
||||
netwoking_module = dlopen( library.c_str(), RTLD_LAZY);
|
||||
if (!netwoking_module) {
|
||||
library = std::string("lib") + BAMBU_NETWORK_LIBRARY + ".dylib";
|
||||
netwoking_module = dlopen( library.c_str(), RTLD_LAZY);
|
||||
}
|
||||
printf("after dlopen, network_module is %p\n", netwoking_module);
|
||||
#else
|
||||
library = std::string("lib") + BAMBU_NETWORK_LIBRARY + ".so";
|
||||
netwoking_module = dlopen( library.c_str(), RTLD_LAZY);
|
||||
#endif
|
||||
|
||||
if (!netwoking_module) {
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", can not Load Library for %1%")%library;
|
||||
return -1;
|
||||
}
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(", successfully loaded library %1%")%library;
|
||||
|
||||
//load the functions
|
||||
create_agent_ptr = reinterpret_cast<func_create_agent>(get_network_function("bambu_network_create_agent"));
|
||||
destroy_agent_ptr = reinterpret_cast<func_destroy_agent>(get_network_function("bambu_network_destroy_agent"));
|
||||
init_log_ptr = reinterpret_cast<func_init_log>(get_network_function("bambu_network_init_log"));
|
||||
set_config_dir_ptr = reinterpret_cast<func_set_config_dir>(get_network_function("bambu_network_set_config_dir"));
|
||||
set_cert_file_ptr = reinterpret_cast<func_set_cert_file>(get_network_function("bambu_network_set_cert_file"));
|
||||
set_country_code_ptr = reinterpret_cast<func_set_country_code>(get_network_function("bambu_network_set_country_code"));
|
||||
start_ptr = reinterpret_cast<func_start>(get_network_function("bambu_network_start"));
|
||||
set_on_ssdp_msg_fn_ptr = reinterpret_cast<func_set_on_ssdp_msg_fn>(get_network_function("bambu_network_set_on_ssdp_msg_fn"));
|
||||
set_on_user_login_fn_ptr = reinterpret_cast<func_set_on_user_login_fn>(get_network_function("bambu_network_set_on_user_login_fn"));
|
||||
set_on_printer_connected_fn_ptr = reinterpret_cast<func_set_on_printer_connected_fn>(get_network_function("bambu_network_set_on_printer_connected_fn"));
|
||||
set_on_server_connected_fn_ptr = reinterpret_cast<func_set_on_server_connected_fn>(get_network_function("bambu_network_set_on_server_connected_fn"));
|
||||
set_on_http_error_fn_ptr = reinterpret_cast<func_set_on_http_error_fn>(get_network_function("bambu_network_set_on_http_error_fn"));
|
||||
set_get_country_code_fn_ptr = reinterpret_cast<func_set_get_country_code_fn>(get_network_function("bambu_network_set_get_country_code_fn"));
|
||||
set_on_message_fn_ptr = reinterpret_cast<func_set_on_message_fn>(get_network_function("bambu_network_set_on_message_fn"));
|
||||
set_on_local_connect_fn_ptr = reinterpret_cast<func_set_on_local_connect_fn>(get_network_function("bambu_network_set_on_local_connect_fn"));
|
||||
set_on_local_message_fn_ptr = reinterpret_cast<func_set_on_local_message_fn>(get_network_function("bambu_network_set_on_local_message_fn"));
|
||||
connect_server_ptr = reinterpret_cast<func_connect_server>(get_network_function("bambu_network_connect_server"));
|
||||
is_server_connected_ptr = reinterpret_cast<func_is_server_connected>(get_network_function("bambu_network_is_server_connected"));
|
||||
refresh_connection_ptr = reinterpret_cast<func_refresh_connection>(get_network_function("bambu_network_refresh_connection"));
|
||||
start_subscribe_ptr = reinterpret_cast<func_start_subscribe>(get_network_function("bambu_network_start_subscribe"));
|
||||
stop_subscribe_ptr = reinterpret_cast<func_stop_subscribe>(get_network_function("bambu_network_stop_subscribe"));
|
||||
send_message_ptr = reinterpret_cast<func_send_message>(get_network_function("bambu_network_send_message"));
|
||||
connect_printer_ptr = reinterpret_cast<func_connect_printer>(get_network_function("bambu_network_connect_printer"));
|
||||
disconnect_printer_ptr = reinterpret_cast<func_disconnect_printer>(get_network_function("bambu_network_disconnect_printer"));
|
||||
send_message_to_printer_ptr = reinterpret_cast<func_send_message_to_printer>(get_network_function("bambu_network_send_message_to_printer"));
|
||||
start_discovery_ptr = reinterpret_cast<func_start_discovery>(get_network_function("bambu_network_start_discovery"));
|
||||
change_user_ptr = reinterpret_cast<func_change_user>(get_network_function("bambu_network_change_user"));
|
||||
is_user_login_ptr = reinterpret_cast<func_is_user_login>(get_network_function("bambu_network_is_user_login"));
|
||||
user_logout_ptr = reinterpret_cast<func_user_logout>(get_network_function("bambu_network_user_logout"));
|
||||
get_user_id_ptr = reinterpret_cast<func_get_user_id>(get_network_function("bambu_network_get_user_id"));
|
||||
get_user_name_ptr = reinterpret_cast<func_get_user_name>(get_network_function("bambu_network_get_user_name"));
|
||||
get_user_avatar_ptr = reinterpret_cast<func_get_user_avatar>(get_network_function("bambu_network_get_user_avatar"));
|
||||
get_user_nickanme_ptr = reinterpret_cast<func_get_user_nickanme>(get_network_function("bambu_network_get_user_nickanme"));
|
||||
build_login_cmd_ptr = reinterpret_cast<func_build_login_cmd>(get_network_function("bambu_network_build_login_cmd"));
|
||||
build_logout_cmd_ptr = reinterpret_cast<func_build_logout_cmd>(get_network_function("bambu_network_build_logout_cmd"));
|
||||
build_login_info_ptr = reinterpret_cast<func_build_login_info>(get_network_function("bambu_network_build_login_info"));
|
||||
bind_ptr = reinterpret_cast<func_bind>(get_network_function("bambu_network_bind"));
|
||||
unbind_ptr = reinterpret_cast<func_unbind>(get_network_function("bambu_network_unbind"));
|
||||
get_bambulab_host_ptr = reinterpret_cast<func_get_bambulab_host>(get_network_function("bambu_network_get_bambulab_host"));
|
||||
get_user_selected_machine_ptr = reinterpret_cast<func_get_user_selected_machine>(get_network_function("bambu_network_get_user_selected_machine"));
|
||||
set_user_selected_machine_ptr = reinterpret_cast<func_set_user_selected_machine>(get_network_function("bambu_network_set_user_selected_machine"));
|
||||
start_print_ptr = reinterpret_cast<func_start_print>(get_network_function("bambu_network_start_print"));
|
||||
start_local_print_with_record_ptr = reinterpret_cast<func_start_local_print_with_record>(get_network_function("bambu_network_start_local_print_with_record"));
|
||||
start_local_print_ptr = reinterpret_cast<func_start_local_print>(get_network_function("bambu_network_start_local_print"));
|
||||
get_user_presets_ptr = reinterpret_cast<func_get_user_presets>(get_network_function("bambu_network_get_user_presets"));
|
||||
request_setting_id_ptr = reinterpret_cast<func_request_setting_id>(get_network_function("bambu_network_request_setting_id"));
|
||||
put_setting_ptr = reinterpret_cast<func_put_setting>(get_network_function("bambu_network_put_setting"));
|
||||
get_setting_list_ptr = reinterpret_cast<func_get_setting_list>(get_network_function("bambu_network_get_setting_list"));
|
||||
delete_setting_ptr = reinterpret_cast<func_delete_setting>(get_network_function("bambu_network_delete_setting"));
|
||||
get_studio_info_url_ptr = reinterpret_cast<func_get_studio_info_url>(get_network_function("bambu_network_get_studio_info_url"));
|
||||
set_extra_http_header_ptr = reinterpret_cast<func_set_extra_http_header>(get_network_function("bambu_network_set_extra_http_header"));
|
||||
check_user_task_report_ptr = reinterpret_cast<func_check_user_task_report>(get_network_function("bambu_network_check_user_task_report"));
|
||||
get_user_print_info_ptr = reinterpret_cast<func_get_user_print_info>(get_network_function("bambu_network_get_user_print_info"));
|
||||
get_printer_firmware_ptr = reinterpret_cast<func_get_printer_firmware>(get_network_function("bambu_network_get_printer_firmware"));
|
||||
get_task_plate_index_ptr = reinterpret_cast<func_get_task_plate_index>(get_network_function("bambu_network_get_task_plate_index"));
|
||||
get_slice_info_ptr = reinterpret_cast<func_get_slice_info>(get_network_function("bambu_network_get_slice_info"));
|
||||
query_bind_status_ptr = reinterpret_cast<func_query_bind_status>(get_network_function("bambu_network_query_bind_status"));
|
||||
modify_printer_name_ptr = reinterpret_cast<func_modify_printer_name>(get_network_function("bambu_network_modify_printer_name"));
|
||||
get_camera_url_ptr = reinterpret_cast<func_get_camera_url>(get_network_function("bambu_network_get_camera_url"));
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
void* NetworkAgent::get_network_function(const char* name)
|
||||
{
|
||||
void* function = nullptr;
|
||||
|
||||
if (!netwoking_module)
|
||||
return function;
|
||||
|
||||
#if defined(_MSC_VER) || defined(_WIN32)
|
||||
function = GetProcAddress(netwoking_module, name);
|
||||
#else
|
||||
function = dlsym(netwoking_module, name);
|
||||
#endif
|
||||
|
||||
if (!function) {
|
||||
BOOST_LOG_TRIVIAL(warning) << __FUNCTION__ << boost::format(", can not find function %1%")%name;
|
||||
}
|
||||
return function;
|
||||
}
|
||||
|
||||
int NetworkAgent::init_log()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && init_log_ptr) {
|
||||
ret = init_log_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_config_dir(std::string config_dir)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_config_dir_ptr) {
|
||||
ret = set_config_dir_ptr(network_agent, config_dir);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, config_dir=%3%")%network_agent %ret %config_dir ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_cert_file(std::string folder, std::string filename)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_cert_file_ptr) {
|
||||
ret = set_cert_file_ptr(network_agent, folder, filename);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, folder=%3%, filename=%4%")%network_agent %ret %folder %filename;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_country_code(std::string country_code)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_country_code_ptr) {
|
||||
ret = set_country_code_ptr(network_agent, country_code);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, country_code=%3%")%network_agent %ret %country_code ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::start()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && start_ptr) {
|
||||
ret = start_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_ssdp_msg_fn(OnMsgArrivedFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_ssdp_msg_fn_ptr) {
|
||||
ret = set_on_ssdp_msg_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_user_login_fn(OnUserLoginFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_user_login_fn_ptr) {
|
||||
ret = set_on_user_login_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_printer_connected_fn(OnPrinterConnectedFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_printer_connected_fn_ptr) {
|
||||
ret = set_on_printer_connected_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_server_connected_fn(OnServerConnectedFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_server_connected_fn_ptr) {
|
||||
ret = set_on_server_connected_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_http_error_fn(OnHttpErrorFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_http_error_fn_ptr) {
|
||||
ret = set_on_http_error_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_get_country_code_fn(GetCountryCodeFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_get_country_code_fn_ptr) {
|
||||
ret = set_get_country_code_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_message_fn(OnMessageFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_message_fn_ptr) {
|
||||
ret = set_on_message_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_local_connect_fn(OnLocalConnectedFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_local_connect_fn_ptr) {
|
||||
ret = set_on_local_connect_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_on_local_message_fn(OnMessageFn fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_on_local_message_fn_ptr) {
|
||||
ret = set_on_local_message_fn_ptr(network_agent, fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::connect_server()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && connect_server_ptr) {
|
||||
ret = connect_server_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool NetworkAgent::is_server_connected()
|
||||
{
|
||||
bool ret = false;
|
||||
if (network_agent && is_server_connected_ptr) {
|
||||
ret = is_server_connected_ptr(network_agent);
|
||||
//BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::refresh_connection()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && refresh_connection_ptr) {
|
||||
ret = refresh_connection_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::start_subscribe(std::string module)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && start_subscribe_ptr) {
|
||||
ret = start_subscribe_ptr(network_agent, module);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, module=%3%")%network_agent %ret %module ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::stop_subscribe(std::string module)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && stop_subscribe_ptr) {
|
||||
ret = stop_subscribe_ptr(network_agent, module);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, module=%3%")%network_agent %ret %module ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::send_message(std::string dev_id, std::string json_str, int qos)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && send_message_ptr) {
|
||||
ret = send_message_ptr(network_agent, dev_id, json_str, qos);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%, json_str=%4%, qos=%5%")%network_agent %ret %dev_id %json_str %qos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && connect_printer_ptr) {
|
||||
ret = connect_printer_ptr(network_agent, dev_id, dev_ip, username, password);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%, dev_ip=%4%, username=%5%, password=%6%")
|
||||
%network_agent %ret %dev_id %dev_ip %username %password;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::disconnect_printer()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && disconnect_printer_ptr) {
|
||||
ret = disconnect_printer_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::send_message_to_printer(std::string dev_id, std::string json_str, int qos)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && send_message_to_printer_ptr) {
|
||||
ret = send_message_to_printer_ptr(network_agent, dev_id, json_str, qos);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%, json_str=%4%, qos=%5%")
|
||||
%network_agent %ret %dev_id %json_str %qos;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool NetworkAgent::start_discovery(bool start, bool sending)
|
||||
{
|
||||
bool ret = false;
|
||||
if (network_agent && start_discovery_ptr) {
|
||||
ret = start_discovery_ptr(network_agent, start, sending);
|
||||
//BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, start=%3%, sending=%4%")%network_agent %ret %start %sending;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::change_user(std::string user_info)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && change_user_ptr) {
|
||||
ret = change_user_ptr(network_agent, user_info);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, user_info=%3%")%network_agent %ret %user_info ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
bool NetworkAgent::is_user_login()
|
||||
{
|
||||
bool ret = false;
|
||||
if (network_agent && is_user_login_ptr) {
|
||||
ret = is_user_login_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::user_logout()
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && user_logout_ptr) {
|
||||
ret = user_logout_ptr(network_agent);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%")%network_agent %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_user_id()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_user_id_ptr) {
|
||||
ret = get_user_id_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_user_name()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_user_name_ptr) {
|
||||
ret = get_user_name_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_user_avatar()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_user_avatar_ptr) {
|
||||
ret = get_user_avatar_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_user_nickanme()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_user_nickanme_ptr) {
|
||||
ret = get_user_nickanme_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::build_login_cmd()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && build_login_cmd_ptr) {
|
||||
ret = build_login_cmd_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::build_logout_cmd()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && build_logout_cmd_ptr) {
|
||||
ret = build_logout_cmd_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::build_login_info()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && build_login_info_ptr) {
|
||||
ret = build_login_info_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::bind(std::string dev_ip, std::string timezone, OnUpdateStatusFn update_fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && bind_ptr) {
|
||||
ret = bind_ptr(network_agent, dev_ip, timezone, update_fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_ip=%3%, timezone=%4%")
|
||||
%network_agent %ret %dev_ip %timezone;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::unbind(std::string dev_id)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && unbind_ptr) {
|
||||
ret = unbind_ptr(network_agent, dev_id);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, user_info=%3%")%network_agent %ret %dev_id ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_bambulab_host()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_bambulab_host_ptr) {
|
||||
ret = get_bambulab_host_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_user_selected_machine()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_user_selected_machine_ptr) {
|
||||
ret = get_user_selected_machine_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_user_selected_machine(std::string dev_id)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_user_selected_machine_ptr) {
|
||||
ret = set_user_selected_machine_ptr(network_agent, dev_id);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, user_info=%3%")%network_agent %ret %dev_id ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::start_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && start_print_ptr) {
|
||||
ret = start_print_ptr(network_agent, params, update_fn, cancel_fn);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%")
|
||||
%network_agent %ret %params.dev_id %params.task_name %params.project_name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::start_local_print_with_record(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && start_local_print_with_record_ptr) {
|
||||
ret = start_local_print_with_record_ptr(network_agent, params, update_fn, cancel_fn);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%")
|
||||
%network_agent %ret %params.dev_id %params.task_name %params.project_name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && start_local_print_ptr) {
|
||||
ret = start_local_print_ptr(network_agent, params, update_fn, cancel_fn);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, task_name=%4%, project_name=%5%")
|
||||
%network_agent %ret %params.dev_id %params.task_name %params.project_name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_user_presets(std::map<std::string, std::map<std::string, std::string>>* user_presets)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_user_presets_ptr) {
|
||||
ret = get_user_presets_ptr(network_agent, user_presets);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, setting_id count=%3%")%network_agent %ret %user_presets->size() ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::request_setting_id(std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code)
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && request_setting_id_ptr) {
|
||||
ret = request_setting_id_ptr(network_agent, name, values_map, http_code);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, name=%2%, http_code=%3%, ret.setting_id=%4%")
|
||||
%network_agent %name %(*http_code) %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::put_setting(std::string setting_id, std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code)
|
||||
{
|
||||
int ret;
|
||||
if (network_agent && put_setting_ptr) {
|
||||
ret = put_setting_ptr(network_agent, setting_id, name, values_map, http_code);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, setting_id=%2%, name=%3%, http_code=%4%, ret=%5%")
|
||||
%network_agent %setting_id %name %(*http_code) %ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_setting_list(std::string bundle_version, ProgressFn pro_fn, WasCancelledFn cancel_fn)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_setting_list_ptr) {
|
||||
ret = get_setting_list_ptr(network_agent, bundle_version, pro_fn, cancel_fn);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, bundle_version=%3%")%network_agent %ret %bundle_version ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::delete_setting(std::string setting_id)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && delete_setting_ptr) {
|
||||
ret = delete_setting_ptr(network_agent, setting_id);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, setting_id=%3%")%network_agent %ret %setting_id ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
std::string NetworkAgent::get_studio_info_url()
|
||||
{
|
||||
std::string ret;
|
||||
if (network_agent && get_studio_info_url_ptr) {
|
||||
ret = get_studio_info_url_ptr(network_agent);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::set_extra_http_header(std::map<std::string, std::string> extra_headers)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && set_extra_http_header_ptr) {
|
||||
ret = set_extra_http_header_ptr(network_agent, extra_headers);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, extra_headers count=%3%")%network_agent %ret %extra_headers.size() ;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::check_user_task_report(int* task_id, bool* printable)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && check_user_task_report_ptr) {
|
||||
ret = check_user_task_report_ptr(network_agent, task_id, printable);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, task_id=%3%, printable=%4%")%network_agent %ret %(*task_id) %(*printable);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_user_print_info(unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_user_print_info_ptr) {
|
||||
ret = get_user_print_info_ptr(network_agent, http_code, http_body);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, http_code=%3%, http_body=%4%")%network_agent %ret %(*http_code) %(*http_body);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_printer_firmware(std::string dev_id, unsigned* http_code, std::string* http_body)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_printer_firmware_ptr) {
|
||||
ret = get_printer_firmware_ptr(network_agent, dev_id, http_code, http_body);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, http_code=%4%, http_body=%5%")
|
||||
%network_agent %ret %dev_id %(*http_code) %(*http_body);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_task_plate_index(std::string task_id, int* plate_index)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_task_plate_index_ptr) {
|
||||
ret = get_task_plate_index_ptr(network_agent, task_id, plate_index);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, task_id=%3%")%network_agent %ret %task_id;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_slice_info(std::string project_id, std::string profile_id, int plate_index, std::string* slice_json)
|
||||
{
|
||||
int ret;
|
||||
if (network_agent && get_slice_info_ptr) {
|
||||
ret = get_slice_info_ptr(network_agent, project_id, profile_id, plate_index, slice_json);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, project_id=%2%, profile_id=%3%, plate_index=%4%, slice_json=%5%")
|
||||
%network_agent %project_id %profile_id %plate_index %(*slice_json);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::query_bind_status(std::vector<std::string> query_list, unsigned int* http_code, std::string* http_body)
|
||||
{
|
||||
int ret;
|
||||
if (network_agent && query_bind_status_ptr) {
|
||||
ret = query_bind_status_ptr(network_agent, query_list, http_code, http_body);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, http_code=%3%, http_body=%4%")
|
||||
%network_agent %ret%(*http_code) %(*http_body);
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::modify_printer_name(std::string dev_id, std::string dev_name)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && modify_printer_name_ptr) {
|
||||
ret = modify_printer_name_ptr(network_agent, dev_id, dev_name);
|
||||
BOOST_LOG_TRIVIAL(info) << __FUNCTION__ << boost::format(" : network_agent=%1%, ret=%2%, dev_id=%3%, dev_name=%4%")%network_agent %ret %dev_id %dev_name;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
int NetworkAgent::get_camera_url(std::string dev_id, std::function<void(std::string)> callback)
|
||||
{
|
||||
int ret = 0;
|
||||
if (network_agent && get_camera_url_ptr) {
|
||||
ret = get_camera_url_ptr(network_agent, dev_id, callback);
|
||||
if (ret)
|
||||
BOOST_LOG_TRIVIAL(error) << __FUNCTION__ << boost::format(" error: network_agent=%1%, ret=%2%, dev_id=%3%")%network_agent %ret %dev_id;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
} //namespace
|
208
src/slic3r/Utils/NetworkAgent.hpp
Normal file
208
src/slic3r/Utils/NetworkAgent.hpp
Normal file
|
@ -0,0 +1,208 @@
|
|||
#ifndef __NETWORK_Agent_HPP__
|
||||
#define __NETWORK_Agent_HPP__
|
||||
|
||||
#include "bambu_networking.hpp"
|
||||
|
||||
using namespace BBL;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
typedef void* (*func_create_agent)(void);
|
||||
typedef int (*func_destroy_agent)(void *agent);
|
||||
typedef int (*func_init_log)(void *agent);
|
||||
typedef int (*func_set_config_dir)(void *agent, std::string config_dir);
|
||||
typedef int (*func_set_cert_file)(void *agent, std::string folder, std::string filename);
|
||||
typedef int (*func_set_country_code)(void *agent, std::string country_code);
|
||||
typedef int (*func_start)(void *agent);
|
||||
typedef int (*func_set_on_ssdp_msg_fn)(void *agent, OnMsgArrivedFn fn);
|
||||
typedef int (*func_set_on_user_login_fn)(void *agent, OnUserLoginFn fn);
|
||||
typedef int (*func_set_on_printer_connected_fn)(void *agent, OnPrinterConnectedFn fn);
|
||||
typedef int (*func_set_on_server_connected_fn)(void *agent, OnServerConnectedFn fn);
|
||||
typedef int (*func_set_on_http_error_fn)(void *agent, OnHttpErrorFn fn);
|
||||
typedef int (*func_set_get_country_code_fn)(void *agent, GetCountryCodeFn fn);
|
||||
typedef int (*func_set_on_message_fn)(void *agent, OnMessageFn fn);
|
||||
typedef int (*func_set_on_local_connect_fn)(void *agent, OnLocalConnectedFn fn);
|
||||
typedef int (*func_set_on_local_message_fn)(void *agent, OnMessageFn fn);
|
||||
typedef int (*func_connect_server)(void *agent);
|
||||
typedef bool (*func_is_server_connected)(void *agent);
|
||||
typedef int (*func_refresh_connection)(void *agent);
|
||||
typedef int (*func_start_subscribe)(void *agent, std::string module);
|
||||
typedef int (*func_stop_subscribe)(void *agent, std::string module);
|
||||
typedef int (*func_send_message)(void *agent, std::string dev_id, std::string json_str, int qos);
|
||||
typedef int (*func_connect_printer)(void *agent, std::string dev_id, std::string dev_ip, std::string username, std::string password);
|
||||
typedef int (*func_disconnect_printer)(void *agent);
|
||||
typedef int (*func_send_message_to_printer)(void *agent, std::string dev_id, std::string json_str, int qos);
|
||||
typedef bool (*func_start_discovery)(void *agent, bool start, bool sending);
|
||||
typedef int (*func_change_user)(void *agent, std::string user_info);
|
||||
typedef bool (*func_is_user_login)(void *agent);
|
||||
typedef int (*func_user_logout)(void *agent);
|
||||
typedef std::string (*func_get_user_id)(void *agent);
|
||||
typedef std::string (*func_get_user_name)(void *agent);
|
||||
typedef std::string (*func_get_user_avatar)(void *agent);
|
||||
typedef std::string (*func_get_user_nickanme)(void *agent);
|
||||
typedef std::string (*func_build_login_cmd)(void *agent);
|
||||
typedef std::string (*func_build_logout_cmd)(void *agent);
|
||||
typedef std::string (*func_build_login_info)(void *agent);
|
||||
typedef int (*func_bind)(void *agent, std::string dev_ip, std::string timezone, OnUpdateStatusFn update_fn);
|
||||
typedef int (*func_unbind)(void *agent, std::string dev_id);
|
||||
typedef std::string (*func_get_bambulab_host)(void *agent);
|
||||
typedef std::string (*func_get_user_selected_machine)(void *agent);
|
||||
typedef int (*func_set_user_selected_machine)(void *agent, std::string dev_id);
|
||||
typedef int (*func_start_print)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
typedef int (*func_start_local_print_with_record)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
typedef int (*func_start_local_print)(void *agent, PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
typedef int (*func_get_user_presets)(void *agent, std::map<std::string, std::map<std::string, std::string>>* user_presets);
|
||||
typedef std::string (*func_request_setting_id)(void *agent, std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code);
|
||||
typedef int (*func_put_setting)(void *agent, std::string setting_id, std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code);
|
||||
typedef int (*func_get_setting_list)(void *agent, std::string bundle_version, ProgressFn pro_fn, WasCancelledFn cancel_fn);
|
||||
typedef int (*func_delete_setting)(void *agent, std::string setting_id);
|
||||
typedef std::string (*func_get_studio_info_url)(void *agent);
|
||||
typedef int (*func_set_extra_http_header)(void *agent, std::map<std::string, std::string> extra_headers);
|
||||
typedef int (*func_check_user_task_report)(void *agent, int* task_id, bool* printable);
|
||||
typedef int (*func_get_user_print_info)(void *agent, unsigned int* http_code, std::string* http_body);
|
||||
typedef int (*func_get_printer_firmware)(void *agent, std::string dev_id, unsigned* http_code, std::string* http_body);
|
||||
typedef int (*func_get_task_plate_index)(void *agent, std::string task_id, int* plate_index);
|
||||
typedef int (*func_get_slice_info)(void *agent, std::string project_id, std::string profile_id, int plate_index, std::string* slice_json);
|
||||
typedef int (*func_query_bind_status)(void *agent, std::vector<std::string> query_list, unsigned int* http_code, std::string* http_body);
|
||||
typedef int (*func_modify_printer_name)(void *agent, std::string dev_id, std::string dev_name);
|
||||
typedef int (*func_get_camera_url)(void *agent, std::string dev_id, std::function<void(std::string)> callback);
|
||||
|
||||
|
||||
|
||||
//the NetworkAgent class
|
||||
class NetworkAgent
|
||||
{
|
||||
|
||||
public:
|
||||
static int initialize_network_module();
|
||||
static void* get_network_function(const char* name);
|
||||
NetworkAgent();
|
||||
~NetworkAgent();
|
||||
|
||||
int init_log();
|
||||
int set_config_dir(std::string config_dir);
|
||||
int set_cert_file(std::string folder, std::string filename);
|
||||
int set_country_code(std::string country_code);
|
||||
int start();
|
||||
int set_on_ssdp_msg_fn(OnMsgArrivedFn fn);
|
||||
int set_on_user_login_fn(OnUserLoginFn fn);
|
||||
int set_on_printer_connected_fn(OnPrinterConnectedFn fn);
|
||||
int set_on_server_connected_fn(OnServerConnectedFn fn);
|
||||
int set_on_http_error_fn(OnHttpErrorFn fn);
|
||||
int set_get_country_code_fn(GetCountryCodeFn fn);
|
||||
int set_on_message_fn(OnMessageFn fn);
|
||||
int set_on_local_connect_fn(OnLocalConnectedFn fn);
|
||||
int set_on_local_message_fn(OnMessageFn fn);
|
||||
int connect_server();
|
||||
bool is_server_connected();
|
||||
int refresh_connection();
|
||||
int start_subscribe(std::string module);
|
||||
int stop_subscribe(std::string module);
|
||||
int send_message(std::string dev_id, std::string json_str, int qos);
|
||||
int connect_printer(std::string dev_id, std::string dev_ip, std::string username, std::string password);
|
||||
int disconnect_printer();
|
||||
int send_message_to_printer(std::string dev_id, std::string json_str, int qos);
|
||||
bool start_discovery(bool start, bool sending);
|
||||
int change_user(std::string user_info);
|
||||
bool is_user_login();
|
||||
int user_logout();
|
||||
std::string get_user_id();
|
||||
std::string get_user_name();
|
||||
std::string get_user_avatar();
|
||||
std::string get_user_nickanme();
|
||||
std::string build_login_cmd();
|
||||
std::string build_logout_cmd();
|
||||
std::string build_login_info();
|
||||
int bind(std::string dev_ip, std::string timezone, OnUpdateStatusFn update_fn);
|
||||
int unbind(std::string dev_id);
|
||||
std::string get_bambulab_host();
|
||||
std::string get_user_selected_machine();
|
||||
int set_user_selected_machine(std::string dev_id);
|
||||
int start_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
int start_local_print_with_record(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
int start_local_print(PrintParams params, OnUpdateStatusFn update_fn, WasCancelledFn cancel_fn);
|
||||
int get_user_presets(std::map<std::string, std::map<std::string, std::string>>* user_presets);
|
||||
std::string request_setting_id(std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code);
|
||||
int put_setting(std::string setting_id, std::string name, std::map<std::string, std::string>* values_map, unsigned int* http_code);
|
||||
int get_setting_list(std::string bundle_version, ProgressFn pro_fn = nullptr, WasCancelledFn cancel_fn = nullptr);
|
||||
int delete_setting(std::string setting_id);
|
||||
std::string get_studio_info_url();
|
||||
int set_extra_http_header(std::map<std::string, std::string> extra_headers);
|
||||
int check_user_task_report(int* task_id, bool* printable);
|
||||
int get_user_print_info(unsigned int* http_code, std::string* http_body);
|
||||
int get_printer_firmware(std::string dev_id, unsigned* http_code, std::string* http_body);
|
||||
int get_task_plate_index(std::string task_id, int* plate_index);
|
||||
int get_slice_info(std::string project_id, std::string profile_id, int plate_index, std::string* slice_json);
|
||||
int query_bind_status(std::vector<std::string> query_list, unsigned int* http_code, std::string* http_body);
|
||||
int modify_printer_name(std::string dev_id, std::string dev_name);
|
||||
int get_camera_url(std::string dev_id, std::function<void(std::string)> callback);
|
||||
|
||||
private:
|
||||
|
||||
void* network_agent { nullptr };
|
||||
|
||||
static func_create_agent create_agent_ptr;
|
||||
static func_destroy_agent destroy_agent_ptr;
|
||||
static func_init_log init_log_ptr;
|
||||
static func_set_config_dir set_config_dir_ptr;
|
||||
static func_set_cert_file set_cert_file_ptr;
|
||||
static func_set_country_code set_country_code_ptr;
|
||||
static func_start start_ptr;
|
||||
static func_set_on_ssdp_msg_fn set_on_ssdp_msg_fn_ptr;
|
||||
static func_set_on_user_login_fn set_on_user_login_fn_ptr;
|
||||
static func_set_on_printer_connected_fn set_on_printer_connected_fn_ptr;
|
||||
static func_set_on_server_connected_fn set_on_server_connected_fn_ptr;
|
||||
static func_set_on_http_error_fn set_on_http_error_fn_ptr;
|
||||
static func_set_get_country_code_fn set_get_country_code_fn_ptr;
|
||||
static func_set_on_message_fn set_on_message_fn_ptr;
|
||||
static func_set_on_local_connect_fn set_on_local_connect_fn_ptr;
|
||||
static func_set_on_local_message_fn set_on_local_message_fn_ptr;
|
||||
static func_connect_server connect_server_ptr;
|
||||
static func_is_server_connected is_server_connected_ptr;
|
||||
static func_refresh_connection refresh_connection_ptr;
|
||||
static func_start_subscribe start_subscribe_ptr;
|
||||
static func_stop_subscribe stop_subscribe_ptr;
|
||||
static func_send_message send_message_ptr;
|
||||
static func_connect_printer connect_printer_ptr;
|
||||
static func_disconnect_printer disconnect_printer_ptr;
|
||||
static func_send_message_to_printer send_message_to_printer_ptr;
|
||||
static func_start_discovery start_discovery_ptr;
|
||||
static func_change_user change_user_ptr;
|
||||
static func_is_user_login is_user_login_ptr;
|
||||
static func_user_logout user_logout_ptr;
|
||||
static func_get_user_id get_user_id_ptr;
|
||||
static func_get_user_name get_user_name_ptr;
|
||||
static func_get_user_avatar get_user_avatar_ptr;
|
||||
static func_get_user_nickanme get_user_nickanme_ptr;
|
||||
static func_build_login_cmd build_login_cmd_ptr;
|
||||
static func_build_logout_cmd build_logout_cmd_ptr;
|
||||
static func_build_login_info build_login_info_ptr;
|
||||
static func_bind bind_ptr;
|
||||
static func_unbind unbind_ptr;
|
||||
static func_get_bambulab_host get_bambulab_host_ptr;
|
||||
static func_get_user_selected_machine get_user_selected_machine_ptr;
|
||||
static func_set_user_selected_machine set_user_selected_machine_ptr;
|
||||
static func_start_print start_print_ptr;
|
||||
static func_start_local_print_with_record start_local_print_with_record_ptr;
|
||||
static func_start_local_print start_local_print_ptr;
|
||||
static func_get_user_presets get_user_presets_ptr;
|
||||
static func_request_setting_id request_setting_id_ptr;
|
||||
static func_put_setting put_setting_ptr;
|
||||
static func_get_setting_list get_setting_list_ptr;
|
||||
static func_delete_setting delete_setting_ptr;
|
||||
static func_get_studio_info_url get_studio_info_url_ptr;
|
||||
static func_set_extra_http_header set_extra_http_header_ptr;
|
||||
static func_check_user_task_report check_user_task_report_ptr;
|
||||
static func_get_user_print_info get_user_print_info_ptr;
|
||||
static func_get_printer_firmware get_printer_firmware_ptr;
|
||||
static func_get_task_plate_index get_task_plate_index_ptr;
|
||||
static func_get_slice_info get_slice_info_ptr;
|
||||
static func_query_bind_status query_bind_status_ptr;
|
||||
static func_modify_printer_name modify_printer_name_ptr;
|
||||
static func_get_camera_url get_camera_url_ptr;
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
||||
|
1270
src/slic3r/Utils/PresetUpdater.cpp
Normal file
1270
src/slic3r/Utils/PresetUpdater.cpp
Normal file
File diff suppressed because it is too large
Load diff
72
src/slic3r/Utils/PresetUpdater.hpp
Normal file
72
src/slic3r/Utils/PresetUpdater.hpp
Normal file
|
@ -0,0 +1,72 @@
|
|||
#ifndef slic3r_PresetUpdate_hpp_
|
||||
#define slic3r_PresetUpdate_hpp_
|
||||
|
||||
#include <memory>
|
||||
#include <vector>
|
||||
|
||||
#include <wx/event.h>
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
|
||||
class AppConfig;
|
||||
class PresetBundle;
|
||||
class Semver;
|
||||
|
||||
static constexpr const int SLIC3R_VERSION_BODY_MAX = 256;
|
||||
|
||||
class PresetUpdater
|
||||
{
|
||||
public:
|
||||
PresetUpdater();
|
||||
PresetUpdater(PresetUpdater &&) = delete;
|
||||
PresetUpdater(const PresetUpdater &) = delete;
|
||||
PresetUpdater &operator=(PresetUpdater &&) = delete;
|
||||
PresetUpdater &operator=(const PresetUpdater &) = delete;
|
||||
~PresetUpdater();
|
||||
|
||||
// If either version check or config updating is enabled, get the appropriate data in the background and cache it.
|
||||
void sync(PresetBundle *preset_bundle);
|
||||
|
||||
// If version check is enabled, check if chaced online slic3r version is newer, notify if so.
|
||||
void slic3r_update_notify();
|
||||
|
||||
enum UpdateResult {
|
||||
R_NOOP,
|
||||
R_INCOMPAT_EXIT,
|
||||
R_INCOMPAT_CONFIGURED,
|
||||
R_UPDATE_INSTALLED,
|
||||
R_UPDATE_REJECT,
|
||||
R_UPDATE_NOTIFICATION,
|
||||
R_ALL_CANCELED
|
||||
};
|
||||
|
||||
enum class UpdateParams {
|
||||
SHOW_TEXT_BOX, // force modal textbox
|
||||
SHOW_NOTIFICATION, // only shows notification
|
||||
FORCED_BEFORE_WIZARD // indicates that check of updated is forced before ConfigWizard opening
|
||||
};
|
||||
|
||||
// If updating is enabled, check if updates are available in cache, if so, ask about installation.
|
||||
// A false return value implies Slic3r should exit due to incompatibility of configuration.
|
||||
// Providing old slic3r version upgrade profiles on upgrade of an application even in case
|
||||
// that the config index installed from the Internet is equal to the index contained in the installation package.
|
||||
UpdateResult config_update(const Semver &old_slic3r_version, UpdateParams params) const;
|
||||
|
||||
// "Update" a list of bundles from resources (behaves like an online update).
|
||||
bool install_bundles_rsrc(std::vector<std::string> bundles, bool snapshot = true) const;
|
||||
|
||||
void on_update_notification_confirm();
|
||||
|
||||
bool version_check_enabled() const;
|
||||
|
||||
private:
|
||||
struct priv;
|
||||
std::unique_ptr<priv> p;
|
||||
};
|
||||
|
||||
wxDECLARE_EVENT(EVT_SLIC3R_VERSION_ONLINE, wxCommandEvent);
|
||||
wxDECLARE_EVENT(EVT_SLIC3R_EXPERIMENTAL_VERSION_ONLINE, wxCommandEvent);
|
||||
wxDECLARE_EVENT(EVT_ENTER_FORCE_UPGRADE, wxCommandEvent);
|
||||
}
|
||||
#endif
|
157
src/slic3r/Utils/Process.cpp
Normal file
157
src/slic3r/Utils/Process.cpp
Normal file
|
@ -0,0 +1,157 @@
|
|||
#include "Process.hpp"
|
||||
|
||||
#include <libslic3r/AppConfig.hpp>
|
||||
|
||||
#include "../GUI/GUI.hpp"
|
||||
// for file_wildcards()
|
||||
#include "../GUI/GUI_App.hpp"
|
||||
// localization
|
||||
#include "../GUI/I18N.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <fstream>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
|
||||
// For starting another BambuStudio instance on OSX.
|
||||
// Fails to compile on Windows on the build server.
|
||||
#ifdef __APPLE__
|
||||
#include <boost/process/spawn.hpp>
|
||||
#include <boost/process/args.hpp>
|
||||
#endif
|
||||
|
||||
#include <wx/stdpaths.h>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
enum class NewSlicerInstanceType {
|
||||
Slicer,
|
||||
GCodeViewer
|
||||
};
|
||||
|
||||
// Start a new Slicer process instance either in a Slicer mode or in a G-code mode.
|
||||
// Optionally load a 3MF, STL or a G-code on start.
|
||||
static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const std::vector<wxString> paths_to_open, bool single_instance)
|
||||
{
|
||||
#ifdef _WIN32
|
||||
wxString path;
|
||||
wxFileName::SplitPath(wxStandardPaths::Get().GetExecutablePath(), &path, nullptr, nullptr, wxPATH_NATIVE);
|
||||
path += "\\";
|
||||
path += (instance_type == NewSlicerInstanceType::Slicer) ? "bambu-studio.exe" : "bambu-gcodeviewer.exe";
|
||||
std::vector<const wchar_t*> args;
|
||||
args.reserve(4);
|
||||
args.emplace_back(path.wc_str());
|
||||
if (!paths_to_open.empty()) {
|
||||
for (const auto& file : paths_to_open)
|
||||
args.emplace_back(file);
|
||||
}
|
||||
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
|
||||
args.emplace_back(L"--single-instance");
|
||||
args.emplace_back(nullptr);
|
||||
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << into_u8(path) << "\"";
|
||||
// Don't call with wxEXEC_HIDE_CONSOLE, BambuStudio in GUI mode would just show the splash screen. It would not open the main window though, it would
|
||||
// just hang in the background.
|
||||
if (wxExecute(const_cast<wchar_t**>(args.data()), wxEXEC_ASYNC) <= 0)
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << into_u8(path);
|
||||
#else
|
||||
// Own executable path.
|
||||
boost::filesystem::path bin_path = into_path(wxStandardPaths::Get().GetExecutablePath());
|
||||
#if defined(__APPLE__)
|
||||
{
|
||||
bin_path = bin_path.parent_path() / "BambuStudio";
|
||||
// On Apple the wxExecute fails, thus we use boost::process instead.
|
||||
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << bin_path.string() << "\"";
|
||||
try {
|
||||
std::vector<std::string> args;
|
||||
if (instance_type == NewSlicerInstanceType::GCodeViewer)
|
||||
args.emplace_back("--gcodeviewer");
|
||||
if (!paths_to_open.empty()) {
|
||||
for (const auto& file : paths_to_open)
|
||||
args.emplace_back(into_u8(file));
|
||||
}
|
||||
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
|
||||
args.emplace_back("--single-instance");
|
||||
boost::process::spawn(bin_path, args);
|
||||
}
|
||||
catch (const std::exception& ex) {
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << bin_path.string() << "\": " << ex.what();
|
||||
}
|
||||
}
|
||||
#else // Linux or Unix
|
||||
{
|
||||
std::vector<const char*> args;
|
||||
args.reserve(3);
|
||||
#ifdef __linux__
|
||||
static const char* gcodeviewer_param = "--gcodeviewer";
|
||||
{
|
||||
// If executed by an AppImage, start the AppImage, not the main process.
|
||||
// see https://docs.appimage.org/packaging-guide/environment-variables.html#id2
|
||||
const char* appimage_binary = std::getenv("APPIMAGE");
|
||||
if (appimage_binary) {
|
||||
args.emplace_back(appimage_binary);
|
||||
if (instance_type == NewSlicerInstanceType::GCodeViewer)
|
||||
args.emplace_back(gcodeviewer_param);
|
||||
}
|
||||
}
|
||||
#endif // __linux__
|
||||
std::string my_path;
|
||||
if (args.empty()) {
|
||||
// Binary path was not set to the AppImage in the Linux specific block above, call the application directly.
|
||||
my_path = (bin_path.parent_path() / ((instance_type == NewSlicerInstanceType::Slicer) ? "bambu-studio" : "bambu-gcodeviewer")).string();
|
||||
args.emplace_back(my_path.c_str());
|
||||
}
|
||||
std::string to_open;
|
||||
if (!paths_to_open.empty()) {
|
||||
for (const auto& file : paths_to_open) {
|
||||
to_open = into_u8(file);
|
||||
args.emplace_back(to_open.c_str());
|
||||
}
|
||||
}
|
||||
if (instance_type == NewSlicerInstanceType::Slicer && single_instance)
|
||||
args.emplace_back("--single-instance");
|
||||
args.emplace_back(nullptr);
|
||||
BOOST_LOG_TRIVIAL(info) << "Trying to spawn a new slicer \"" << args[0] << "\"";
|
||||
if (wxExecute(const_cast<char**>(args.data()), wxEXEC_ASYNC | wxEXEC_MAKE_GROUP_LEADER) <= 0)
|
||||
BOOST_LOG_TRIVIAL(error) << "Failed to spawn a new slicer \"" << args[0];
|
||||
}
|
||||
#endif // Linux or Unix
|
||||
#endif // Win32
|
||||
}
|
||||
static void start_new_slicer_or_gcodeviewer(const NewSlicerInstanceType instance_type, const wxString* path_to_open, bool single_instance)
|
||||
{
|
||||
std::vector<wxString> paths;
|
||||
if (path_to_open != nullptr)
|
||||
paths.emplace_back(path_to_open->wc_str());
|
||||
start_new_slicer_or_gcodeviewer(instance_type, paths, single_instance);
|
||||
}
|
||||
|
||||
void start_new_slicer(const wxString *path_to_open, bool single_instance)
|
||||
{
|
||||
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, path_to_open, single_instance);
|
||||
}
|
||||
void start_new_slicer(const std::vector<wxString>& files, bool single_instance)
|
||||
{
|
||||
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::Slicer, files, single_instance);
|
||||
}
|
||||
|
||||
void start_new_gcodeviewer(const wxString *path_to_open)
|
||||
{
|
||||
start_new_slicer_or_gcodeviewer(NewSlicerInstanceType::GCodeViewer, path_to_open, false);
|
||||
}
|
||||
|
||||
void start_new_gcodeviewer_open_file(wxWindow *parent)
|
||||
{
|
||||
wxFileDialog dialog(parent ? parent : wxGetApp().GetTopWindow(),
|
||||
_L("Open G-code file:"),
|
||||
from_u8(wxGetApp().app_config->get_last_dir()), wxString(),
|
||||
file_wildcards(FT_GCODE), wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
if (dialog.ShowModal() == wxID_OK) {
|
||||
wxString path = dialog.GetPath();
|
||||
start_new_gcodeviewer(&path);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
25
src/slic3r/Utils/Process.hpp
Normal file
25
src/slic3r/Utils/Process.hpp
Normal file
|
@ -0,0 +1,25 @@
|
|||
#ifndef GUI_PROCESS_HPP
|
||||
#define GUI_PROCESS_HPP
|
||||
|
||||
#include <vector>
|
||||
|
||||
|
||||
class wxWindow;
|
||||
class wxString;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
// Start a new slicer instance, optionally with a file to open.
|
||||
void start_new_slicer(const wxString *path_to_open = nullptr, bool single_instance = false);
|
||||
void start_new_slicer(const std::vector<wxString>& files, bool single_instance = false);
|
||||
|
||||
// Start a new G-code viewer instance, optionally with a file to open.
|
||||
void start_new_gcodeviewer(const wxString *path_to_open = nullptr);
|
||||
// Open a file dialog, ask the user to select a new G-code to open, start a new G-code viewer.
|
||||
void start_new_gcodeviewer_open_file(wxWindow *parent = nullptr);
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // GUI_PROCESS_HPP
|
19
src/slic3r/Utils/Profile.hpp
Normal file
19
src/slic3r/Utils/Profile.hpp
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef slic3r_GUI_Profile_hpp_
|
||||
#define slic3r_GUI_Profile_hpp_
|
||||
|
||||
// Profiling support using the Shiny intrusive profiler
|
||||
//#define SLIC3R_PROFILE_GUI
|
||||
#if defined(SLIC3R_PROFILE) && defined(SLIC3R_PROFILE_GUI)
|
||||
#include <Shiny/Shiny.h>
|
||||
#define SLIC3R_GUI_PROFILE_FUNC() PROFILE_FUNC()
|
||||
#define SLIC3R_GUI_PROFILE_BLOCK(name) PROFILE_BLOCK(name)
|
||||
#define SLIC3R_GUI_PROFILE_UPDATE() PROFILE_UPDATE()
|
||||
#define SLIC3R_GUI_PROFILE_OUTPUT(x) PROFILE_OUTPUT(x)
|
||||
#else
|
||||
#define SLIC3R_GUI_PROFILE_FUNC()
|
||||
#define SLIC3R_GUI_PROFILE_BLOCK(name)
|
||||
#define SLIC3R_GUI_PROFILE_UPDATE()
|
||||
#define SLIC3R_GUI_PROFILE_OUTPUT(x)
|
||||
#endif
|
||||
|
||||
#endif // slic3r_GUI_Profile_hpp_
|
31
src/slic3r/Utils/RetinaHelper.hpp
Normal file
31
src/slic3r/Utils/RetinaHelper.hpp
Normal file
|
@ -0,0 +1,31 @@
|
|||
#ifndef slic3r_RetinaHelper_hpp_
|
||||
#define slic3r_RetinaHelper_hpp_
|
||||
|
||||
class wxWindow;
|
||||
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
class RetinaHelper
|
||||
{
|
||||
public:
|
||||
RetinaHelper(wxWindow* window);
|
||||
~RetinaHelper();
|
||||
|
||||
void set_use_retina(bool value);
|
||||
bool get_use_retina();
|
||||
float get_scale_factor();
|
||||
|
||||
private:
|
||||
#ifdef __WXGTK3__
|
||||
wxWindow* m_window;
|
||||
#endif // __WXGTK3__
|
||||
void* m_self;
|
||||
};
|
||||
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // RetinaHelper_h
|
15
src/slic3r/Utils/RetinaHelperImpl.hmm
Normal file
15
src/slic3r/Utils/RetinaHelperImpl.hmm
Normal file
|
@ -0,0 +1,15 @@
|
|||
#import <Cocoa/Cocoa.h>
|
||||
|
||||
class wxEvtHandler;
|
||||
|
||||
@interface RetinaHelperImpl : NSObject
|
||||
{
|
||||
NSView *view;
|
||||
wxEvtHandler* handler;
|
||||
}
|
||||
|
||||
-(id)initWithView:(NSView *)view handler:(wxEvtHandler *)handler;
|
||||
-(void)setViewWantsBestResolutionOpenGLSurface:(BOOL)value;
|
||||
-(BOOL)getViewWantsBestResolutionOpenGLSurface;
|
||||
-(float)getBackingScaleFactor;
|
||||
@end
|
110
src/slic3r/Utils/RetinaHelperImpl.mm
Normal file
110
src/slic3r/Utils/RetinaHelperImpl.mm
Normal file
|
@ -0,0 +1,110 @@
|
|||
// The RetinaHelper was originally written by Andreas Stahl, 2013
|
||||
|
||||
#import "RetinaHelper.hpp"
|
||||
#import "RetinaHelperImpl.hmm"
|
||||
#import <OpenGL/OpenGL.h>
|
||||
|
||||
#import "wx/window.h"
|
||||
|
||||
@implementation RetinaHelperImpl
|
||||
|
||||
namespace Slic3r {
|
||||
namespace GUI {
|
||||
|
||||
RetinaHelper::RetinaHelper(wxWindow *window)
|
||||
{
|
||||
m_self = nullptr;
|
||||
m_self = [[RetinaHelperImpl alloc] initWithView:window->GetHandle() handler:window->GetEventHandler()];
|
||||
}
|
||||
|
||||
RetinaHelper::~RetinaHelper()
|
||||
{
|
||||
[(id)m_self release];
|
||||
}
|
||||
|
||||
void RetinaHelper::set_use_retina(bool aValue)
|
||||
{
|
||||
[(id)m_self setViewWantsBestResolutionOpenGLSurface:aValue];
|
||||
}
|
||||
|
||||
bool RetinaHelper::get_use_retina()
|
||||
{
|
||||
return [(id)m_self getViewWantsBestResolutionOpenGLSurface];
|
||||
}
|
||||
|
||||
float RetinaHelper::get_scale_factor()
|
||||
{
|
||||
return [(id)m_self getViewWantsBestResolutionOpenGLSurface] ? [(id)m_self getBackingScaleFactor] : 1.0f;
|
||||
}
|
||||
|
||||
} // namespace GUI
|
||||
} // namespace Slic3r
|
||||
|
||||
|
||||
-(id)initWithView:(NSView *)aView handler:(wxEvtHandler *)aHandler
|
||||
{
|
||||
self = [super init];
|
||||
if (self) {
|
||||
handler = aHandler;
|
||||
view = aView;
|
||||
// register for backing change notifications
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
if (nc) {
|
||||
[nc addObserver:self selector:@selector(windowDidChangeBackingProperties:)
|
||||
name:NSWindowDidChangeBackingPropertiesNotification object:nil];
|
||||
}
|
||||
}
|
||||
return self;
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
// unregister from all notifications
|
||||
NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
|
||||
if (nc) {
|
||||
[nc removeObserver:self];
|
||||
}
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
-(void)setViewWantsBestResolutionOpenGLSurface:(BOOL)value
|
||||
{
|
||||
[view setWantsBestResolutionOpenGLSurface:value];
|
||||
}
|
||||
|
||||
-(BOOL)getViewWantsBestResolutionOpenGLSurface
|
||||
{
|
||||
return [view wantsBestResolutionOpenGLSurface];
|
||||
}
|
||||
|
||||
-(float)getBackingScaleFactor
|
||||
{
|
||||
return [[view window] backingScaleFactor];
|
||||
}
|
||||
|
||||
- (void)windowDidChangeBackingProperties:(NSNotification *)notification
|
||||
{
|
||||
NSWindow *theWindow = (NSWindow *)[notification object];
|
||||
|
||||
if (theWindow == [view window]) {
|
||||
CGFloat newBackingScaleFactor = [theWindow backingScaleFactor];
|
||||
CGFloat oldBackingScaleFactor = [[[notification userInfo]
|
||||
objectForKey:@"NSBackingPropertyOldScaleFactorKey"]
|
||||
doubleValue];
|
||||
|
||||
if (newBackingScaleFactor != oldBackingScaleFactor) {
|
||||
// generate a wx resize event and pass it to the handler's queue
|
||||
wxSizeEvent *event = new wxSizeEvent();
|
||||
// use the following line if this resize event should have the physical pixel resolution
|
||||
// but that is not recommended, because ordinary resize events won't do so either
|
||||
// which would necessitate a case-by-case switch in the resize handler method.
|
||||
// NSRect nsrect = [view convertRectToBacking:[view bounds]];
|
||||
NSRect nsrect = [view bounds];
|
||||
wxRect rect = wxRect(nsrect.origin.x, nsrect.origin.y, nsrect.size.width, nsrect.size.height);
|
||||
event->SetRect(rect);
|
||||
event->SetSize(rect.GetSize());
|
||||
handler->QueueEvent(event);
|
||||
}
|
||||
}
|
||||
}
|
||||
@end
|
205
src/slic3r/Utils/TCPConsole.cpp
Normal file
205
src/slic3r/Utils/TCPConsole.cpp
Normal file
|
@ -0,0 +1,205 @@
|
|||
#include <boost/asio/buffer.hpp>
|
||||
#include <boost/asio/io_context.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/read_until.hpp>
|
||||
#include <boost/asio/steady_timer.hpp>
|
||||
#include <boost/asio/write.hpp>
|
||||
#include <boost/bind.hpp>
|
||||
#include <boost/format.hpp>
|
||||
#include <boost/log/trivial.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
|
||||
#include "TCPConsole.hpp"
|
||||
|
||||
using boost::asio::steady_timer;
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
void TCPConsole::transmit_next_command()
|
||||
{
|
||||
if (m_cmd_queue.empty()) {
|
||||
m_io_context.stop();
|
||||
return;
|
||||
}
|
||||
|
||||
std::string cmd = m_cmd_queue.front();
|
||||
m_cmd_queue.pop_front();
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: transmitting '%3%' to %1%:%2%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% cmd;
|
||||
|
||||
m_send_buffer = cmd + m_newline;
|
||||
|
||||
set_deadline_in(m_write_timeout);
|
||||
boost::asio::async_write(
|
||||
m_socket,
|
||||
boost::asio::buffer(m_send_buffer),
|
||||
boost::bind(&TCPConsole::handle_write, this, _1, _2)
|
||||
);
|
||||
}
|
||||
|
||||
void TCPConsole::wait_next_line()
|
||||
{
|
||||
set_deadline_in(m_read_timeout);
|
||||
boost::asio::async_read_until(
|
||||
m_socket,
|
||||
m_recv_buffer,
|
||||
m_newline,
|
||||
boost::bind(&TCPConsole::handle_read, this, _1, _2)
|
||||
);
|
||||
}
|
||||
|
||||
// TODO: Use std::optional here
|
||||
std::string TCPConsole::extract_next_line()
|
||||
{
|
||||
char linebuf[1024];
|
||||
std::istream is(&m_recv_buffer);
|
||||
is.getline(linebuf, sizeof(linebuf));
|
||||
return is.good() ? linebuf : std::string{};
|
||||
}
|
||||
|
||||
void TCPConsole::handle_read(
|
||||
const boost::system::error_code& ec,
|
||||
std::size_t bytes_transferred)
|
||||
{
|
||||
m_error_code = ec;
|
||||
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't read from %1%:%2%: %3%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% ec.message();
|
||||
|
||||
m_io_context.stop();
|
||||
}
|
||||
else {
|
||||
std::string line = extract_next_line();
|
||||
boost::trim(line);
|
||||
|
||||
BOOST_LOG_TRIVIAL(debug) << boost::format("TCPConsole: received '%3%' from %1%:%2%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% line;
|
||||
|
||||
boost::to_lower(line);
|
||||
|
||||
if (line == m_done_string)
|
||||
transmit_next_command();
|
||||
else
|
||||
wait_next_line();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPConsole::handle_write(
|
||||
const boost::system::error_code& ec,
|
||||
std::size_t)
|
||||
{
|
||||
m_error_code = ec;
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't write to %1%:%2%: %3%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% ec.message();
|
||||
|
||||
m_io_context.stop();
|
||||
}
|
||||
else {
|
||||
wait_next_line();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPConsole::handle_connect(const boost::system::error_code& ec)
|
||||
{
|
||||
m_error_code = ec;
|
||||
|
||||
if (ec) {
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Can't connect to %1%:%2%: %3%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% ec.message();
|
||||
|
||||
m_io_context.stop();
|
||||
}
|
||||
else {
|
||||
m_is_connected = true;
|
||||
BOOST_LOG_TRIVIAL(info) << boost::format("TCPConsole: connected to %1%:%2%")
|
||||
% m_host_name
|
||||
% m_port_name;
|
||||
|
||||
transmit_next_command();
|
||||
}
|
||||
}
|
||||
|
||||
void TCPConsole::set_deadline_in(std::chrono::steady_clock::duration d)
|
||||
{
|
||||
m_deadline = std::chrono::steady_clock::now() + d;
|
||||
}
|
||||
bool TCPConsole::is_deadline_over() const
|
||||
{
|
||||
return m_deadline < std::chrono::steady_clock::now();
|
||||
}
|
||||
|
||||
bool TCPConsole::run_queue()
|
||||
{
|
||||
try {
|
||||
// TODO: Add more resets and initializations after previous run (reset() method?..)
|
||||
set_deadline_in(m_connect_timeout);
|
||||
m_is_connected = false;
|
||||
m_io_context.restart();
|
||||
|
||||
auto endpoints = m_resolver.resolve(m_host_name, m_port_name);
|
||||
|
||||
m_socket.async_connect(endpoints->endpoint(),
|
||||
boost::bind(&TCPConsole::handle_connect, this, _1)
|
||||
);
|
||||
|
||||
// Loop until we get any reasonable result. Negative result is also result.
|
||||
// TODO: Rewrite to more graceful way using deadlime_timer
|
||||
bool timeout = false;
|
||||
while (!(timeout = is_deadline_over()) && !m_io_context.stopped()) {
|
||||
if (m_error_code) {
|
||||
m_io_context.stop();
|
||||
}
|
||||
m_io_context.run_for(boost::asio::chrono::milliseconds(100));
|
||||
}
|
||||
|
||||
// Override error message if timeout is set
|
||||
if (timeout)
|
||||
m_error_code = make_error_code(boost::asio::error::timed_out);
|
||||
|
||||
// Socket is not closed automatically by boost
|
||||
m_socket.close();
|
||||
|
||||
if (m_error_code) {
|
||||
// We expect that message is logged in handler
|
||||
return false;
|
||||
}
|
||||
|
||||
// It's expected to have empty queue after successful exchange
|
||||
if (!m_cmd_queue.empty()) {
|
||||
BOOST_LOG_TRIVIAL(error) << "TCPConsole: command queue is not empty after end of exchange";
|
||||
return false;
|
||||
}
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(error) << boost::format("TCPConsole: Exception while talking with %1%:%2%: %3%")
|
||||
% m_host_name
|
||||
% m_port_name
|
||||
% e.what();
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
} // namespace Utils
|
||||
} // namespace Slic3r
|
93
src/slic3r/Utils/TCPConsole.hpp
Normal file
93
src/slic3r/Utils/TCPConsole.hpp
Normal file
|
@ -0,0 +1,93 @@
|
|||
#ifndef slic3r_Utils_TCPConsole_hpp_
|
||||
#define slic3r_Utils_TCPConsole_hpp_
|
||||
|
||||
#include <string>
|
||||
#include <deque>
|
||||
#include <boost/system/error_code.hpp>
|
||||
#include <boost/system/system_error.hpp>
|
||||
#include <boost/asio/ip/tcp.hpp>
|
||||
#include <boost/asio/streambuf.hpp>
|
||||
|
||||
namespace Slic3r {
|
||||
namespace Utils {
|
||||
|
||||
using boost::asio::ip::tcp;
|
||||
|
||||
// Generic command / response TCP telnet like console class.
|
||||
// Used by the MKS host to send G-code commands to test connection ("M105") and to start printing ("M23 filename", "M24").
|
||||
class TCPConsole
|
||||
{
|
||||
public:
|
||||
TCPConsole() : m_resolver(m_io_context), m_socket(m_io_context) { set_defaults(); }
|
||||
TCPConsole(const std::string& host_name, const std::string& port_name) : m_resolver(m_io_context), m_socket(m_io_context)
|
||||
{ set_defaults(); set_remote(host_name, port_name); }
|
||||
~TCPConsole() = default;
|
||||
|
||||
void set_defaults()
|
||||
{
|
||||
m_newline = "\n";
|
||||
m_done_string = "ok";
|
||||
m_connect_timeout = std::chrono::milliseconds(5000);
|
||||
m_write_timeout = std::chrono::milliseconds(10000);
|
||||
m_read_timeout = std::chrono::milliseconds(10000);
|
||||
}
|
||||
|
||||
void set_line_delimiter(const std::string& newline) {
|
||||
m_newline = newline;
|
||||
}
|
||||
void set_command_done_string(const std::string& done_string) {
|
||||
m_done_string = done_string;
|
||||
}
|
||||
|
||||
void set_remote(const std::string& host_name, const std::string& port_name)
|
||||
{
|
||||
m_host_name = host_name;
|
||||
m_port_name = port_name;
|
||||
}
|
||||
|
||||
bool enqueue_cmd(const std::string& cmd) {
|
||||
// TODO: Add multithread protection to queue
|
||||
m_cmd_queue.push_back(cmd);
|
||||
return true;
|
||||
}
|
||||
|
||||
bool run_queue();
|
||||
std::string error_message() const { return m_error_code.message(); }
|
||||
|
||||
private:
|
||||
void handle_connect(const boost::system::error_code& ec);
|
||||
void handle_read(const boost::system::error_code& ec, std::size_t bytes_transferred);
|
||||
void handle_write(const boost::system::error_code& ec, std::size_t bytes_transferred);
|
||||
|
||||
void transmit_next_command();
|
||||
void wait_next_line();
|
||||
std::string extract_next_line();
|
||||
|
||||
void set_deadline_in(std::chrono::steady_clock::duration);
|
||||
bool is_deadline_over() const;
|
||||
|
||||
std::string m_host_name;
|
||||
std::string m_port_name;
|
||||
std::string m_newline;
|
||||
std::string m_done_string;
|
||||
std::chrono::steady_clock::duration m_connect_timeout;
|
||||
std::chrono::steady_clock::duration m_write_timeout;
|
||||
std::chrono::steady_clock::duration m_read_timeout;
|
||||
|
||||
std::deque<std::string> m_cmd_queue;
|
||||
|
||||
boost::asio::io_context m_io_context;
|
||||
tcp::resolver m_resolver;
|
||||
tcp::socket m_socket;
|
||||
boost::asio::streambuf m_recv_buffer;
|
||||
std::string m_send_buffer;
|
||||
|
||||
bool m_is_connected;
|
||||
boost::system::error_code m_error_code;
|
||||
std::chrono::steady_clock::time_point m_deadline;
|
||||
};
|
||||
|
||||
} // Utils
|
||||
} // Slic3r
|
||||
|
||||
#endif
|
1367
src/slic3r/Utils/UndoRedo.cpp
Normal file
1367
src/slic3r/Utils/UndoRedo.cpp
Normal file
File diff suppressed because it is too large
Load diff
193
src/slic3r/Utils/UndoRedo.hpp
Normal file
193
src/slic3r/Utils/UndoRedo.hpp
Normal file
|
@ -0,0 +1,193 @@
|
|||
#ifndef slic3r_Utils_UndoRedo_hpp_
|
||||
#define slic3r_Utils_UndoRedo_hpp_
|
||||
|
||||
#include <algorithm>
|
||||
#include <memory>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
|
||||
#include <libslic3r/ObjectID.hpp>
|
||||
#include <libslic3r/Config.hpp>
|
||||
|
||||
typedef double coordf_t;
|
||||
typedef std::pair<coordf_t, coordf_t> t_layer_height_range;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
class Model;
|
||||
|
||||
namespace GUI {
|
||||
class Selection;
|
||||
class GLGizmosManager;
|
||||
class PartPlateList;
|
||||
class PartPlate;
|
||||
} // namespace GUI
|
||||
|
||||
namespace UndoRedo {
|
||||
|
||||
enum class SnapshotType : unsigned char {
|
||||
// Some action modifying project state, outside any EnteringGizmo / LeavingGizmo interval.
|
||||
Action,
|
||||
// Some action modifying project state, inside some EnteringGizmo / LeavingGizmo interval.
|
||||
GizmoAction,
|
||||
// Selection change at the Plater.
|
||||
Selection,
|
||||
// New project, Reset project, Load project ...
|
||||
ProjectSeparator,
|
||||
// Entering a Gizmo, which opens a secondary Undo / Redo stack.
|
||||
EnteringGizmo,
|
||||
// Leaving a Gizmo, which closes a secondary Undo / Redo stack.
|
||||
// No action modifying a project state was done between EnteringGizmo / LeavingGizmo.
|
||||
LeavingGizmoNoAction,
|
||||
// Leaving a Gizmo, which closes a secondary Undo / Redo stack.
|
||||
// Some action modifying a project state was done between EnteringGizmo / LeavingGizmo.
|
||||
LeavingGizmoWithAction,
|
||||
};
|
||||
|
||||
// Data structure to be stored with each snapshot.
|
||||
// Storing short data (bit masks, ints) with each snapshot instead of being serialized into the Undo / Redo stack
|
||||
// is likely cheaper in term of both the runtime and memory allocation.
|
||||
// Also the SnapshotData is available without having to deserialize the snapshot from the Undo / Redo stack,
|
||||
// which may be handy sometimes.
|
||||
struct SnapshotData
|
||||
{
|
||||
SnapshotType snapshot_type;
|
||||
PrinterTechnology printer_technology { ptUnknown };
|
||||
// Bitmap of Flags (see the Flags enum).
|
||||
unsigned int flags { 0 };
|
||||
int layer_range_idx { -1 };
|
||||
|
||||
// Bitmask of various binary flags to be stored with the snapshot.
|
||||
enum Flags {
|
||||
VARIABLE_LAYER_EDITING_ACTIVE = 1,
|
||||
SELECTED_SETTINGS_ON_SIDEBAR = 2,
|
||||
SELECTED_LAYERROOT_ON_SIDEBAR = 4,
|
||||
SELECTED_LAYER_ON_SIDEBAR = 8,
|
||||
RECALCULATE_SLA_SUPPORTS = 16
|
||||
};
|
||||
};
|
||||
|
||||
struct Snapshot
|
||||
{
|
||||
Snapshot(size_t timestamp) : timestamp(timestamp) {}
|
||||
Snapshot(const std::string &name, size_t timestamp, size_t model_id, const SnapshotData &snapshot_data) :
|
||||
name(name), timestamp(timestamp), model_id(model_id), snapshot_data(snapshot_data) {}
|
||||
|
||||
std::string name;
|
||||
size_t timestamp;
|
||||
size_t model_id;
|
||||
SnapshotData snapshot_data;
|
||||
|
||||
bool operator< (const Snapshot &rhs) const { return this->timestamp < rhs.timestamp; }
|
||||
bool operator==(const Snapshot &rhs) const { return this->timestamp == rhs.timestamp; }
|
||||
|
||||
// The topmost snapshot represents the current state when going forward.
|
||||
bool is_topmost() const;
|
||||
// The topmost snapshot is not being serialized to the Undo / Redo stack until going back in time,
|
||||
// when the top most state is being serialized, so we can redo back to the top most state.
|
||||
bool is_topmost_captured() const { assert(this->is_topmost()); return model_id > 0; }
|
||||
|
||||
};
|
||||
|
||||
// BBS: moved from UndoRedo.cpp
|
||||
// If a snapshot modifies the snapshot type,
|
||||
inline bool snapshot_modifies_project(SnapshotType type)
|
||||
{
|
||||
return type == SnapshotType::Action || type == SnapshotType::GizmoAction || type == SnapshotType::ProjectSeparator;
|
||||
}
|
||||
|
||||
inline bool snapshot_modifies_project(const Snapshot &snapshot)
|
||||
{
|
||||
return snapshot_modifies_project(snapshot.snapshot_data.snapshot_type) && (snapshot.name.empty() || snapshot.name.back() != '!');
|
||||
}
|
||||
|
||||
// Excerpt of Slic3r::GUI::Selection for serialization onto the Undo / Redo stack.
|
||||
struct Selection : public Slic3r::ObjectBase {
|
||||
void clear() { mode = 0; volumes_and_instances.clear(); }
|
||||
unsigned char mode = 0;
|
||||
std::vector<std::pair<size_t, size_t>> volumes_and_instances;
|
||||
template<class Archive> void serialize(Archive &ar) { ar(mode, volumes_and_instances); }
|
||||
};
|
||||
|
||||
class StackImpl;
|
||||
|
||||
class Stack
|
||||
{
|
||||
public:
|
||||
// Stack needs to be initialized. An empty stack is not valid, there must be a "New Project" status stored at the beginning.
|
||||
// The first "New Project" snapshot shall not be removed.
|
||||
Stack();
|
||||
~Stack();
|
||||
|
||||
void clear();
|
||||
bool empty() const;
|
||||
|
||||
// Set maximum memory threshold. If the threshold is exceeded, least recently used snapshots are released.
|
||||
void set_memory_limit(size_t memsize);
|
||||
size_t get_memory_limit() const;
|
||||
|
||||
// Estimate size of the RAM consumed by the Undo / Redo stack.
|
||||
size_t memsize() const;
|
||||
|
||||
// Release least recently used snapshots up to the memory limit set above.
|
||||
void release_least_recently_used();
|
||||
|
||||
// Store the current application state onto the Undo / Redo stack, remove all snapshots after m_active_snapshot_time.
|
||||
void take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, const SnapshotData &snapshot_data);
|
||||
|
||||
void take_snapshot(const std::string& snapshot_name, const Slic3r::Model& model, const Slic3r::GUI::Selection& selection, const Slic3r::GUI::GLGizmosManager& gizmos, const Slic3r::GUI::PartPlateList& plate_list, const SnapshotData& snapshot_data);
|
||||
|
||||
// To be called just after take_snapshot() when leaving a gizmo, inside which small edits like support point add / remove events or paiting actions were allowed.
|
||||
// Remove all but the last edit between the gizmo enter / leave snapshots.
|
||||
void reduce_noisy_snapshots(const std::string& new_name);
|
||||
|
||||
// To be queried to enable / disable the Undo / Redo buttons at the UI.
|
||||
bool has_undo_snapshot() const;
|
||||
bool has_redo_snapshot() const;
|
||||
// To query whether one can undo to a snapshot. Useful for notifications, that want to Undo a specific operation.
|
||||
bool has_undo_snapshot(size_t time_to_load) const;
|
||||
|
||||
// Roll back the time. If time_to_load is SIZE_MAX, the previous snapshot is activated.
|
||||
// Undoing an action may need to take a snapshot of the current application state, so that redo to the current state is possible.
|
||||
bool undo(Slic3r::Model& model, const Slic3r::GUI::Selection& selection, Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::GUI::PartPlateList& plate_list, const SnapshotData &snapshot_data, size_t time_to_load = SIZE_MAX);
|
||||
|
||||
// Jump forward in time. If time_to_load is SIZE_MAX, the next snapshot is activated.
|
||||
bool redo(Slic3r::Model& model, Slic3r::GUI::GLGizmosManager& gizmos, Slic3r::GUI::PartPlateList& plate_list, size_t time_to_load = SIZE_MAX);
|
||||
|
||||
// Snapshot history (names with timestamps).
|
||||
// Each snapshot indicates start of an interval in which this operation is performed.
|
||||
// There is one additional snapshot taken at the very end, which indicates the current unnamed state.
|
||||
|
||||
const std::vector<Snapshot>& snapshots() const;
|
||||
const Snapshot& snapshot(size_t time) const;
|
||||
|
||||
// Timestamp of the active snapshot. One of the snapshots of this->snapshots() shall have Snapshot::timestamp equal to this->active_snapshot_time().
|
||||
// The active snapshot may be a special placeholder "@@@ Topmost @@@" indicating an uncaptured current state,
|
||||
// or the active snapshot may be an active state to which the application state was undoed or redoed.
|
||||
size_t active_snapshot_time() const;
|
||||
const Snapshot& active_snapshot() const { return this->snapshot(this->active_snapshot_time()); }
|
||||
// Temporary snapshot is active if the topmost snapshot is active and it has not been captured yet.
|
||||
// In that case the Undo action will capture the last snapshot.
|
||||
bool temp_snapshot_active() const;
|
||||
|
||||
// Resets the "dirty project" status.
|
||||
void mark_current_as_saved();
|
||||
// Is the project modified with regard to the last "saved" state marked with mark_current_as_saved()?
|
||||
bool project_modified() const;
|
||||
// BBS: backup and restore
|
||||
bool has_real_change_from(size_t time) const;
|
||||
|
||||
// After load_snapshot() / undo() / redo() the selection is deserialized into a list of ObjectIDs, which needs to be converted
|
||||
// into the list of GLVolume pointers once the 3D scene is updated.
|
||||
const Selection& selection_deserialized() const;
|
||||
|
||||
private:
|
||||
friend class StackImpl;
|
||||
std::unique_ptr<StackImpl> pimpl;
|
||||
};
|
||||
|
||||
}; // namespace UndoRedo
|
||||
}; // namespace Slic3r
|
||||
|
||||
#endif /* slic3r_Utils_UndoRedo_hpp_ */
|
132
src/slic3r/Utils/bambu_networking.hpp
Normal file
132
src/slic3r/Utils/bambu_networking.hpp
Normal file
|
@ -0,0 +1,132 @@
|
|||
#ifndef __BAMBU_NETWORKING_HPP__
|
||||
#define __BAMBU_NETWORKING_HPP__
|
||||
|
||||
#include <string>
|
||||
#include <functional>
|
||||
|
||||
namespace BBL {
|
||||
|
||||
#define BAMBU_NETWORK_SUCCESS 0
|
||||
#define BAMBU_NETWORK_ERR_INVALID_HANDLE -1
|
||||
#define BAMBU_NETWORK_ERR_CONNECT_FAILED -2
|
||||
#define BAMBU_NETWORK_ERR_DISCONNECT_FAILED -3
|
||||
#define BAMBU_NETWORK_ERR_SEND_MSG_FAILED -4
|
||||
#define BAMBU_NETWORK_ERR_BIND_FAILED -5
|
||||
#define BAMBU_NETWORK_ERR_UNBIND_FAILED -6
|
||||
#define BAMBU_NETWORK_ERR_PRINT_FAILED -7
|
||||
#define BAMBU_NETWORK_ERR_LOCAL_PRINT_FAILED -8
|
||||
#define BAMBU_NETWORK_ERR_REQUEST_SETTING_FAILED -9
|
||||
#define BAMBU_NETWORK_ERR_PUT_SETTING_FAILED -10
|
||||
#define BAMBU_NETWORK_ERR_GET_SETTING_LIST_FAILED -11
|
||||
#define BAMBU_NETWORK_ERR_DEL_SETTING_FAILED -12
|
||||
#define BAMBU_NETWORK_ERR_GET_USER_PRINTINFO_FAILED -13
|
||||
#define BAMBU_NETWORK_ERR_GET_PRINTER_FIRMWARE_FAILED -14
|
||||
#define BAMBU_NETWORK_ERR_QUERY_BIND_INFO_FAILED -15
|
||||
#define BAMBU_NETWORK_ERR_MODIFY_PRINTER_NAME_FAILED -16
|
||||
#define BAMBU_NETWORK_ERR_FILE_NOT_EXIST -17
|
||||
#define BAMBU_NETWORK_ERR_FILE_OVER_SIZE -18
|
||||
#define BAMBU_NETWORK_ERR_CHECK_MD5_FAILED -19
|
||||
#define BAMBU_NETWORK_ERR_TIMEOUT -20
|
||||
#define BAMBU_NETWORK_ERR_CANCELED -21
|
||||
#define BAMBU_NETWORK_ERR_INVALID_PARAMS -22
|
||||
#define BAMBU_NETWORK_ERR_INVALID_RESULT -23
|
||||
#define BAMBU_NETWORK_ERR_FTP_UPLOAD_FAILED -24
|
||||
#define BAMBU_NETWORK_ERR_FTP_LOGIN_DENIED -25
|
||||
|
||||
|
||||
#define BAMBU_NETWORK_LIBRARY "bambu_networking"
|
||||
#define BAMBU_NETWORK_AGENT_NAME "bambu_network_agent"
|
||||
#define BAMBU_NETWORK_AGENT_VERSION "1.0.0.2"
|
||||
|
||||
|
||||
//iot preset type strings
|
||||
#define IOT_PRINTER_TYPE_STRING "printer"
|
||||
#define IOT_FILAMENT_STRING "filament"
|
||||
#define IOT_PRINT_TYPE_STRING "print"
|
||||
|
||||
#define IOT_JSON_KEY_VERSION "version"
|
||||
#define IOT_JSON_KEY_NAME "name"
|
||||
#define IOT_JSON_KEY_TYPE "type"
|
||||
#define IOT_JSON_KEY_UPDATE_TIME "updated_time"
|
||||
#define IOT_JSON_KEY_BASE_ID "base_id"
|
||||
#define IOT_JSON_KEY_SETTING_ID "setting_id"
|
||||
#define IOT_JSON_KEY_FILAMENT_ID "filament_id"
|
||||
#define IOT_JSON_KEY_USER_ID "user_id"
|
||||
|
||||
|
||||
// user callbacks
|
||||
typedef std::function<void(int online_login, bool login)> OnUserLoginFn;
|
||||
// printer callbacks
|
||||
typedef std::function<void(std::string topic_str)> OnPrinterConnectedFn;
|
||||
typedef std::function<void(int status, std::string dev_id, std::string msg)> OnLocalConnectedFn;
|
||||
typedef std::function<void()> OnServerConnectedFn;
|
||||
typedef std::function<void(std::string dev_id, std::string msg)> OnMessageFn;
|
||||
// http callbacks
|
||||
typedef std::function<void(unsigned http_code, std::string http_body)> OnHttpErrorFn;
|
||||
typedef std::function<std::string()> GetCountryCodeFn;
|
||||
// print callbacks
|
||||
typedef std::function<void(int status, int code, std::string msg)> OnUpdateStatusFn;
|
||||
typedef std::function<bool()> WasCancelledFn;
|
||||
// local callbacks
|
||||
typedef std::function<void(std::string dev_info_json_str)> OnMsgArrivedFn;
|
||||
|
||||
typedef std::function<void(int progress)> ProgressFn;
|
||||
typedef std::function<void(int retcode, std::string info)> LoginFn;
|
||||
typedef std::function<void(int result, std::string info)> ResultFn;
|
||||
typedef std::function<bool()> CancelFn;
|
||||
|
||||
enum SendingPrintJobStage {
|
||||
PrintingStageCreate = 0,
|
||||
PrintingStageUpload = 1,
|
||||
PrintingStageWaiting = 2,
|
||||
PrintingStageSending = 3,
|
||||
PrintingStageRecord = 4,
|
||||
PrintingStageFinished = 5,
|
||||
};
|
||||
|
||||
enum BindJobStage {
|
||||
LoginStageConnect = 0,
|
||||
LoginStageLogin = 1,
|
||||
LoginStageWaitForLogin = 2,
|
||||
LoginStageGetIdentify = 3,
|
||||
LoginStageWaitAuth = 4,
|
||||
LoginStageFinished = 5,
|
||||
};
|
||||
|
||||
enum ConnectStatus {
|
||||
ConnectStatusOk = 0,
|
||||
ConnectStatusFailed = 1,
|
||||
ConnectStatusLost = 2,
|
||||
};
|
||||
|
||||
/* print job*/
|
||||
struct PrintParams {
|
||||
/* basic info */
|
||||
std::string dev_id;
|
||||
std::string task_name;
|
||||
std::string project_name;
|
||||
std::string preset_name;
|
||||
std::string filename;
|
||||
std::string config_filename;
|
||||
int plate_index;
|
||||
std::string ftp_file;
|
||||
std::string ftp_file_md5;
|
||||
std::string ams_mapping;
|
||||
std::string connection_type;
|
||||
|
||||
/* access options */
|
||||
std::string dev_ip;
|
||||
std::string username;
|
||||
std::string password;
|
||||
|
||||
/*user options */
|
||||
bool task_bed_leveling; /* bed leveling of task */
|
||||
bool task_flow_cali; /* flow calibration of task */
|
||||
bool task_vibration_cali; /* vibration calibration of task */
|
||||
bool task_layer_inspect; /* first layer inspection of task */
|
||||
bool task_record_timelapse; /* record timelapse of task */
|
||||
};
|
||||
|
||||
}
|
||||
|
||||
#endif
|
225
src/slic3r/Utils/json_diff.cpp
Normal file
225
src/slic3r/Utils/json_diff.cpp
Normal file
|
@ -0,0 +1,225 @@
|
|||
#include "json_diff.hpp"
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <thread>
|
||||
#include <functional>
|
||||
|
||||
#include <stdio.h>
|
||||
#include "nlohmann/json.hpp"
|
||||
using namespace std;
|
||||
using json = nlohmann::json;
|
||||
|
||||
int json_diff::diff_objects(json in, json &out, json &base)
|
||||
{
|
||||
for (auto& el: in.items()) {
|
||||
if (el.value().empty()) {
|
||||
//BBL_LOG_INFO("json_c diff empty key: " << el.key());
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!base.contains(el.key()) ) {
|
||||
out[el.key()] = el.value();
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c diff new key: " << el.key()
|
||||
<< " type: " << el.value().type_name()
|
||||
<< " value: " << el.value();
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (el.value().type() != base[el.key()].type()) {
|
||||
out[el.key()] = el.value();
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c diff type changed"
|
||||
<< " key: " << el.key() << " value: " << el.value().dump()
|
||||
<< " last value: " << base[el.key()].dump();
|
||||
continue;
|
||||
}
|
||||
|
||||
|
||||
if (el.value().is_object()) {
|
||||
json recur_out;
|
||||
int recur_ret = diff_objects(
|
||||
el.value(), recur_out, base[el.key()]);
|
||||
if (recur_ret == 0) {
|
||||
out[el.key()] = recur_out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
if (el.value() != base[el.key()]) {
|
||||
out[el.key()] = el.value();
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c diff value changed"
|
||||
<< " key: " << el.key() << " value: " << el.value().dump()
|
||||
<< " last value: " << base[el.key()].dump();
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if (out.empty())
|
||||
return 1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_diff::all2diff_base_reset(json &base)
|
||||
{
|
||||
BOOST_LOG_TRIVIAL(trace) << "all2diff_base_reset";
|
||||
all2diff_base = base;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_diff::all2diff(json& in, json& out)
|
||||
{
|
||||
int ret = 0;
|
||||
if (all2diff_base.empty()) {
|
||||
all2diff_base = in;
|
||||
out = in;
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c diff base reinit";
|
||||
return 0;
|
||||
}
|
||||
|
||||
ret = diff_objects(in, out, all2diff_base);
|
||||
if (ret != 0) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c diff no new info";
|
||||
}
|
||||
all2diff_base = in;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_diff::restore_objects(json in, json &out, json &base)
|
||||
{
|
||||
json jout;
|
||||
|
||||
for (auto& el: base.items()) {
|
||||
/*element not in input json,
|
||||
use base element to restore*/
|
||||
if (!in.contains(el.key()) ) {
|
||||
out[el.key()] = el.value();
|
||||
/*
|
||||
BBL_LOG_INFO("json_c restore compressed key " << el.key()
|
||||
<< " type: " << el.value().type_name()
|
||||
<< " value: " << el.value());
|
||||
*/
|
||||
continue;
|
||||
}
|
||||
|
||||
/*element in both base and input, but json type changed
|
||||
use input to restore*/
|
||||
if (el.value().type() != in[el.key()].type() ){
|
||||
out[el.key()] = in[el.key()];
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c restore type changed"
|
||||
<< " key: " << el.key() << " value: "
|
||||
<< in[el.key()].dump()
|
||||
<< " last value: " << el.value().dump();
|
||||
continue;
|
||||
}
|
||||
|
||||
/*element in both base and input, it is a object
|
||||
recursive until basic type*/
|
||||
if (el.value().is_object()) {
|
||||
json recur_out;
|
||||
int recur_ret = restore_objects(
|
||||
in[el.key()], recur_out, el.value());
|
||||
if (recur_ret == 0) {
|
||||
out[el.key()] = recur_out;
|
||||
}
|
||||
continue;
|
||||
}
|
||||
|
||||
/*element in both base and input, but value changed
|
||||
use input to restore*/
|
||||
if (el.value() != in[el.key()]) {
|
||||
out[el.key()] = in[el.key()];
|
||||
continue;
|
||||
}
|
||||
/*element in both base and input,value is same
|
||||
use base to restore*/
|
||||
out[el.key()] = el.value();
|
||||
}
|
||||
|
||||
if (out.empty())
|
||||
return -1;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_diff::restore_append_objects(json in, json &out)
|
||||
{
|
||||
/*a new element comming, but be recoreded in base
|
||||
need be added to output*/
|
||||
for (auto& el: in.items()) {
|
||||
|
||||
if (!out.contains(el.key()) ) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c append new " << el.key()
|
||||
<< " type: " << el.value().type_name()
|
||||
<< " value: " << el.value();
|
||||
out[el.key()] = el.value();
|
||||
continue;
|
||||
}
|
||||
|
||||
if (el.value().is_object()) {
|
||||
int recur_ret =
|
||||
restore_append_objects(el.value(), out[el.key()]);
|
||||
if (recur_ret != 0) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c append obj failed"
|
||||
<< " key: " << el.key()
|
||||
<< " value: " << el.value();
|
||||
return recur_ret;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
int json_diff::diff2all(json &in, json &out)
|
||||
{
|
||||
if (!diff2all_base.empty()) {
|
||||
int ret = restore_objects(in, out, diff2all_base);
|
||||
if (ret < 0) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c restore failed";
|
||||
decode_error_count++;
|
||||
return ret;
|
||||
}
|
||||
} else {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c restore base empty";
|
||||
decode_error_count++;
|
||||
return -1;
|
||||
}
|
||||
restore_append_objects(in, out);
|
||||
diff2all_base = out;
|
||||
decode_error_count = 0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
void json_diff::compare_print(json &a, json &b)
|
||||
{
|
||||
for (auto& e: a.items()) {
|
||||
if (!b.contains(e.key()) ) { BOOST_LOG_TRIVIAL(trace) << "json_c compare loss " << e.key()
|
||||
<< " type: " << e.value().type_name();
|
||||
}
|
||||
if (e.value() != b[e.key()]) {
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c compare not equal: key: " << e.key()
|
||||
<< " value: " << e.value();
|
||||
BOOST_LOG_TRIVIAL(trace) << "json_c compare vs value "
|
||||
<< " vs value: " << b[e.key()];
|
||||
|
||||
}
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
bool json_diff::is_need_request()
|
||||
{
|
||||
if (decode_error_count > 5) {
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
int json_diff::diff2all_base_reset(json &base){
|
||||
BOOST_LOG_TRIVIAL(trace) << "diff2all_base_reset";
|
||||
diff2all_base = base;
|
||||
return 0;
|
||||
}
|
34
src/slic3r/Utils/json_diff.hpp
Normal file
34
src/slic3r/Utils/json_diff.hpp
Normal file
|
@ -0,0 +1,34 @@
|
|||
#ifndef __JSON_DIFF_HPP
|
||||
#define __JSON_DIFF_HPP
|
||||
|
||||
#include <string>
|
||||
#include <atomic>
|
||||
#include <vector>
|
||||
|
||||
#include "nlohmann/json.hpp"
|
||||
|
||||
|
||||
using json = nlohmann::json;
|
||||
using namespace std;
|
||||
|
||||
class json_diff
|
||||
{
|
||||
private:
|
||||
json diff2all_base;
|
||||
json all2diff_base;
|
||||
int decode_error_count = 0;
|
||||
|
||||
int diff_objects(json in, json &out, json &base);
|
||||
int restore_objects(json in, json &out, json &base);
|
||||
int restore_append_objects(json in, json &out);
|
||||
|
||||
public:
|
||||
int all2diff(json &in, json &out);
|
||||
int diff2all(json &in, json &out);
|
||||
int all2diff_base_reset(json &base);
|
||||
int diff2all_base_reset(json &base);
|
||||
void compare_print(json &a, json &b);
|
||||
|
||||
bool is_need_request();
|
||||
};
|
||||
#endif // __JSON_DIFF_HPP
|
54
src/slic3r/Utils/minilzo_extension.cpp
Normal file
54
src/slic3r/Utils/minilzo_extension.cpp
Normal file
|
@ -0,0 +1,54 @@
|
|||
#include <exception>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include "minilzo_extension.hpp"
|
||||
#include "minilzo/minilzo.h"
|
||||
|
||||
static unsigned char wrkmem[LZO1X_1_MEM_COMPRESS];
|
||||
|
||||
static bool initialized = false;
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
int lzo_compress(unsigned char *in, uint64_t in_len, unsigned char* out, uint64_t* out_len)
|
||||
{
|
||||
int result = 0;
|
||||
if (!initialized) {
|
||||
if (lzo_init() != LZO_E_OK)
|
||||
return LZO_E_ERROR;
|
||||
else
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
lzo_uint lzo_out_len = *out_len;
|
||||
result = lzo1x_1_compress(in, in_len, out, &lzo_out_len, wrkmem);
|
||||
if (result == LZO_E_OK) {
|
||||
*out_len = lzo_out_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
int lzo_decompress(unsigned char *in, uint64_t in_len, unsigned char* out, uint64_t* out_len)
|
||||
{
|
||||
int result = 0;
|
||||
if (!initialized) {
|
||||
if (lzo_init() != LZO_E_OK)
|
||||
return LZO_E_ERROR;
|
||||
else
|
||||
initialized = true;
|
||||
}
|
||||
|
||||
lzo_uint lzo_out_len = *out_len;
|
||||
result = lzo1x_decompress(in, in_len, out, &lzo_out_len, NULL);
|
||||
if (result == LZO_E_OK) {
|
||||
*out_len = lzo_out_len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
} // namespace Slic3r
|
16
src/slic3r/Utils/minilzo_extension.hpp
Normal file
16
src/slic3r/Utils/minilzo_extension.hpp
Normal file
|
@ -0,0 +1,16 @@
|
|||
#ifndef MINILZO_EXTENSION_HPP
|
||||
#define MINILZO_EXTENSION_HPP
|
||||
|
||||
#include <string>
|
||||
#include <stdint.h>
|
||||
#include "minilzo/minilzo.h"
|
||||
|
||||
namespace Slic3r {
|
||||
|
||||
int lzo_compress(unsigned char* in, uint64_t in_len, unsigned char* out, uint64_t* out_len);
|
||||
int lzo_decompress(unsigned char* in, uint64_t in_len, unsigned char* out, uint64_t* out_len);
|
||||
|
||||
|
||||
} // namespace Slic3r
|
||||
|
||||
#endif // MINIZ_EXTENSION_HPP
|
Loading…
Add table
Add a link
Reference in a new issue