diff --git a/.github/workflows/build-and-test.yml b/.github/workflows/build-and-test.yml index 0ab2ddcff..3ad5dc4ec 100644 --- a/.github/workflows/build-and-test.yml +++ b/.github/workflows/build-and-test.yml @@ -20,7 +20,7 @@ jobs: - name: Install dependencies run: | sudo apt-get update - sudo apt-get install -y gcc g++ cmake golang uuid-dev + sudo apt-get install -y gcc g++ cmake golang uuid-dev libssl-dev - name: Run pre-build script run: | diff --git a/ACT/LibMC.xml b/ACT/LibMC.xml index 4096d0a73..60794069a 100644 --- a/ACT/LibMC.xml +++ b/ACT/LibMC.xml @@ -705,6 +705,12 @@ + + + + + + @@ -838,6 +844,11 @@ + + + + + diff --git a/ACT/LibMCEnv.xml b/ACT/LibMCEnv.xml index 143e3f965..7489871d4 100644 --- a/ACT/LibMCEnv.xml +++ b/ACT/LibMCEnv.xml @@ -290,11 +290,10 @@ + + - - - @@ -793,9 +792,25 @@ + + + + + + + + + + + + + + + + @@ -4819,10 +4834,6 @@ - - @@ -4831,22 +4842,14 @@ - - + + + + @@ -4858,7 +4861,6 @@ - @@ -4866,7 +4868,6 @@ - @@ -4913,13 +4914,21 @@ - + - + + + + + + + + + @@ -4962,6 +4971,14 @@ + + + + + + + + diff --git a/Artifacts/clientdist/_githash_client.txt b/Artifacts/clientdist/_githash_client.txt index 4b36a2a9b..12d5bafd0 100644 --- a/Artifacts/clientdist/_githash_client.txt +++ b/Artifacts/clientdist/_githash_client.txt @@ -1 +1 @@ -864af701b933b1d4bae3e21bac376e640f076aa3 +0e824076e1184dd9a9734cf70b23c0f84ec54fd9 diff --git a/Artifacts/clientdist/clientpackage.zip b/Artifacts/clientdist/clientpackage.zip index 287203dd4..2e97cc943 100644 Binary files a/Artifacts/clientdist/clientpackage.zip and b/Artifacts/clientdist/clientpackage.zip differ diff --git a/Artifacts/clientdist/clientsourcepackage.zip b/Artifacts/clientdist/clientsourcepackage.zip index c400fcebe..ccd8afd62 100644 Binary files a/Artifacts/clientdist/clientsourcepackage.zip and b/Artifacts/clientdist/clientsourcepackage.zip differ diff --git a/Artifacts/lib3mf/_githash_linux64_lib3mf.txt b/Artifacts/lib3mf/_githash_linux64_lib3mf.txt new file mode 100644 index 000000000..c8ca305ab --- /dev/null +++ b/Artifacts/lib3mf/_githash_linux64_lib3mf.txt @@ -0,0 +1 @@ +5c58ceb256c9951fdaa029426fe777e1890293bc diff --git a/Artifacts/lib3mf/_githash_rpi_lib3mf.txt b/Artifacts/lib3mf/_githash_rpi_lib3mf.txt index 075b29bcf..c8ca305ab 100644 --- a/Artifacts/lib3mf/_githash_rpi_lib3mf.txt +++ b/Artifacts/lib3mf/_githash_rpi_lib3mf.txt @@ -1 +1 @@ -c852ea7065689634e0b23eb3aec11668c9203892 +5c58ceb256c9951fdaa029426fe777e1890293bc diff --git a/Artifacts/lib3mf/lib3mf_linux64.so b/Artifacts/lib3mf/lib3mf_linux64.so index e60760a7a..a324e6ccf 100755 Binary files a/Artifacts/lib3mf/lib3mf_linux64.so and b/Artifacts/lib3mf/lib3mf_linux64.so differ diff --git a/Artifacts/lib3mf/lib3mf_rpi.so b/Artifacts/lib3mf/lib3mf_rpi.so old mode 100644 new mode 100755 index c437941fb..5d9d95246 Binary files a/Artifacts/lib3mf/lib3mf_rpi.so and b/Artifacts/lib3mf/lib3mf_rpi.so differ diff --git a/BuildScripts/CrossCompile_Win32FromDebian.txt b/BuildScripts/CrossCompile_Win32FromDebian.txt deleted file mode 100644 index 0fb65e4b0..000000000 --- a/BuildScripts/CrossCompile_Win32FromDebian.txt +++ /dev/null @@ -1,23 +0,0 @@ -# Toolchain file for building for Windows from an Ubuntu Linux system. -# -# Typical usage: -# *) install cross compiler: `sudo apt-get install mingw-w64` -# *) cd build -# *) cmake -DCMAKE_TOOLCHAIN_FILE=~/mingw-w64-x86_64.cmake .. - -set(CMAKE_SYSTEM_NAME Windows) -set(TOOLCHAIN_PREFIX x86_64-w64-mingw32) - -# cross compilers to use for C, C++ and Fortran -set(CMAKE_C_COMPILER ${TOOLCHAIN_PREFIX}-gcc) -set(CMAKE_CXX_COMPILER ${TOOLCHAIN_PREFIX}-g++) -set(CMAKE_Fortran_COMPILER ${TOOLCHAIN_PREFIX}-gfortran) -set(CMAKE_RC_COMPILER ${TOOLCHAIN_PREFIX}-windres) - -# target environment on the build host system -set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX}) - -# modify default behavior of FIND_XXX() commands -set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) -set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) -set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) diff --git a/BuildScripts/build_packageManager.bat b/BuildScripts/build_packageManager.bat deleted file mode 100644 index a8374cae1..000000000 --- a/BuildScripts/build_packageManager.bat +++ /dev/null @@ -1,21 +0,0 @@ -@echo off - -set GO111MODULE=off - -echo "Building DownloadPackage..." -set GOARCH=amd64 -set GOOS=windows -go build -o ../build_win64/DevPackage/packageManager.exe -ldflags="-s -w" ../BuildScripts/packageManager.go - -set GOARCH=arm -set GOOS=linux -set GOARM=5 -go build -o ../build_win64/DevPackage/packageManager.arm -ldflags="-s -w" ../BuildScripts/packageManager.go - -set GOARCH=amd64 -set GOOS=linux -go build -o ../build_win64/DevPackage/packageManager.linux64 -ldflags="-s -w" ../BuildScripts/packageManager.go - -echo "done." - -pause \ No newline at end of file diff --git a/BuildScripts/packageManager.cpp b/BuildScripts/packageManager.cpp new file mode 100644 index 000000000..5d22f92bd --- /dev/null +++ b/BuildScripts/packageManager.cpp @@ -0,0 +1,245 @@ +// packageManager.cpp +// C++17 translation using cpp-httplib + PicoSHA2 (header-only) for SHA-256. +// Also includes rapidjson and pugixml headers to respect the "only dependencies" constraint. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define CPPHTTPLIB_OPENSSL_SUPPORT + +#include "common_utils.hpp" +#include "common_exportstream_native.hpp" +#include "common_importstream_native.hpp" + +#include "Libraries/cpp-httplib/httplib.h" +#include "Libraries/PugiXML/pugixml.hpp" +#include "Libraries/RapidJSON/document.h" +#include "Libraries/PicoSHA2/picosha2.h" // SHA-256 (header-only) + + +struct ParsedURL { + std::string scheme; // "http" or "https" + std::string host; + int port = -1; + std::string path; // starts with '/' +}; + +// Very small URL parser for forms like: http(s)://host[:port][/path...] +static bool parse_url(const std::string& url, ParsedURL& out) { + auto pos_scheme = url.find("://"); + if (pos_scheme == std::string::npos) return false; + out.scheme = url.substr(0, pos_scheme); + auto rest = url.substr(pos_scheme + 3); + + auto pos_slash = rest.find('/'); + std::string hostport = (pos_slash == std::string::npos) ? rest : rest.substr(0, pos_slash); + out.path = (pos_slash == std::string::npos) ? "/" : rest.substr(pos_slash); + + auto pos_colon = hostport.find(':'); + if (pos_colon == std::string::npos) { + out.host = hostport; + out.port = -1; + } else { + out.host = hostport.substr(0, pos_colon); + out.port = std::stoi(hostport.substr(pos_colon + 1)); + } + + if (out.scheme != "http" && out.scheme != "https") + return false; + if (out.path.empty()) out.path = "/"; + return !out.host.empty(); +} + +static std::string join_url_path(const std::string& base_path, const std::string& segment) { + if (base_path.empty() || base_path.back() != '/') { + if (!segment.empty() && segment.front() == '/') return base_path + segment; + return base_path + "/" + segment; + } else { + if (!segment.empty() && segment.front() == '/') return base_path + segment.substr(1); + return base_path + segment; + } +} + +template void download_with_client(ClientT& client, const std::string& path, const std::string& out_path) { + + client.set_follow_location (true); + + AMCCommon::CExportStream_Native ofs_stream (out_path); + + size_t nReceivedSize = 0; + + auto res = client.Get(path.c_str(), [&ofs_stream, &nReceivedSize](const char* data, size_t len) { + + size_t nOldReceivedMB = nReceivedSize / (1024 * 1024); + + ofs_stream.writeBuffer(data, len); + + nReceivedSize += len; + + size_t nNewReceivedMB = nReceivedSize / (1024 * 1024); + + if (nNewReceivedMB != nOldReceivedMB) { + std::cout << "Received " << nNewReceivedMB << " MB...\n"; + } + + + return true; + }); + + if (!res) { + throw std::runtime_error ("HTTP request failed (network/connection error)."); + } + + if (res->status != 200) { + throw std::runtime_error("HTTP error status: " + std::to_string(res->status)); + } + +} + + +// Download to file using cpp-httplib. +void download_to_file(const std::string& full_url, const std::string& out_path) +{ + ParsedURL u; + if (!parse_url(full_url, u)) + { + throw std::runtime_error("Invalid URL: " + full_url); + } + + std::vector receivedBuffer; + + if (u.scheme == "http") { + httplib::Client client(u.host.c_str(), (u.port > 0 ? u.port : 80)); + + download_with_client(client, u.path, out_path); + + } else { + + httplib::SSLClient sslclient(u.host.c_str(), (u.port > 0 ? u.port : 443)); + + sslclient.enable_server_certificate_verification(true); + download_with_client(sslclient, u.path, out_path); + + } + + +} + + +// ---------------------- Main ---------------------- +int main(int argc, char* argv[]) { + + try { + + if (argc < 2) { + std::cerr << "Please start with: packageManager ....\n"; + std::cerr << "for example: packageManager download \n"; + return 1; + } + + std::string command = argv[1]; + + if (command == "download") { + if (argc < 6) { + std::cerr << "Please start with: packageManager download \n"; + return 1; + } + + const std::string localFileName = argv[2]; + const std::string downloadURLBase = argv[3]; + const std::string gitHash = argv[4]; + const std::string shaCheckSum = argv[5]; + + std::cout << "---------------------------------------------------------------------------------\n"; + std::cout << "-- AMCF Package Manager --\n"; + std::cout << "---------------------------------------------------------------------------------\n"; + std::cout << "Repository URL: " << downloadURLBase << "\n"; + std::cout << "Local Filename: " << localFileName << "\n"; + std::cout << "GIT Hash: " << gitHash << "\n"; + std::cout << "SHA 256 Checksum: " << shaCheckSum << "\n"; + std::cout << "---------------------------------------------------------------------------------\n"; + + std::cout << "Verifying " << localFileName << "...\n"; + + std::string calculatedChecksum; + + if (!AMCCommon::CUtils::fileOrPathExistsOnDisk (localFileName)) { + std::cout << "Local package does not exist...\n"; + } + else { + try { + std::vector fileBytes; + AMCCommon::CImportStream_Native ifs_stream(localFileName); + ifs_stream.readIntoMemory(fileBytes); + + calculatedChecksum = picosha2::hash256_hex_string(fileBytes); + std::cout << "Calculated Checksum: " << calculatedChecksum << "\n"; + if (calculatedChecksum != shaCheckSum) { + std::cout << "Checksum mismatch!\n"; + } + } + catch (const std::exception& ex) { + std::cerr << "Error reading file: " << ex.what() << "\n"; + return 1; + } + } + + if (calculatedChecksum != shaCheckSum) { + std::cout << "Creating " << localFileName << "...\n"; + + const std::string fileSegment = "amcf_" + gitHash + ".zip"; + + ParsedURL baseParsed; + if (!parse_url(downloadURLBase, baseParsed)) { + std::cerr << "Invalid repository URL: " << downloadURLBase << "\n"; + return 1; + } + std::string finalPath = join_url_path(baseParsed.path, fileSegment); + std::string finalURL = baseParsed.scheme + "://" + baseParsed.host; + if (baseParsed.port > 0) finalURL += ":" + std::to_string(baseParsed.port); + finalURL += finalPath; + + std::cout << "Downloading package from " << finalURL << "\n"; + std::string err; + download_to_file(finalURL, localFileName); + + try { + std::vector fileBytes; + AMCCommon::CImportStream_Native ifs_stream(localFileName); + ifs_stream.readIntoMemory(fileBytes); + + auto finalChecksum = picosha2::hash256_hex_string(fileBytes); + std::cout << "Final Checksum: " << finalChecksum << "\n"; + if (finalChecksum != shaCheckSum) { + std::cerr << "Checksum mismatch!\n"; + return 1; + } + } + catch (const std::exception& ex) { + std::cerr << "Error reading downloaded file: " << ex.what() << "\n"; + return 1; + } + } + + std::cout << "done..\n"; + return 0; + + } + else { + std::cerr << "Unknown command. Valid commands are download.\n"; + return 1; + } + } + catch (const std::exception& ex) { + std::cerr << "Fatal error: " << ex.what() << "\n"; + return 1; + } + +} diff --git a/BuildScripts/packageManager.go b/BuildScripts/packageManager.go deleted file mode 100644 index e45c43841..000000000 --- a/BuildScripts/packageManager.go +++ /dev/null @@ -1,123 +0,0 @@ -package main - -import ( - "log" - "net/http" - "io/ioutil" - "encoding/hex" - "io" - "crypto/sha256" - "os" -) - - -func main() { - - argsWithProg := os.Args; - - - if (len (argsWithProg) < 2) { - log.Fatal ("Please start with packageManager ...."); - } - - commandToUse := argsWithProg[1]; - - if (commandToUse == "download") { - - - if (len (argsWithProg) < 6) { - log.Fatal ("Please start with packageManager download "); - } - - downloadURLBase := argsWithProg[3]; - localFileName := argsWithProg[2]; - gitHash := argsWithProg[4]; - shaCheckSum := argsWithProg[5]; - - log.Println ("---------------------------------------------------------------------------------"); - log.Println ("-- AMCF Package Manager --"); - log.Println ("---------------------------------------------------------------------------------"); - log.Println ("Repository URL:" + downloadURLBase); - log.Println ("Local Filename:" + localFileName); - log.Println ("GIT Hash:" + gitHash); - log.Println ("SHA 256 Checksum:" + shaCheckSum); - log.Println ("---------------------------------------------------------------------------------"); - - log.Println ("Verifying " + localFileName + "..."); - - calculatedCheckSum := ""; - _, err := os.Stat(localFileName); - if err != nil { - if !os.IsNotExist(err) { - log.Fatal(err); - } - - log.Println ("Local package does not exist..."); - - } else { - - hasher := sha256.New() - fileContent, err := ioutil.ReadFile(localFileName) - hasher.Write(fileContent) - - if err != nil { - log.Fatal(err) - } - calculatedCheckSum = hex.EncodeToString(hasher.Sum(nil)); - log.Println ("Calculated Checksum: " + calculatedCheckSum); - - if (calculatedCheckSum != shaCheckSum) { - log.Println ("Checksum mismatch!"); - } - - } - - - if (calculatedCheckSum != shaCheckSum) { - - log.Println ("Creating " + localFileName + "..."); - targetFile, err := os.Create(localFileName) - if err != nil { - log.Fatal(err) - } - defer targetFile.Close() - - downloadURL := downloadURLBase + "/amcf_" + gitHash + ".zip"; - log.Println ("Downloading package from " + downloadURL); - - response, err := http.Get(downloadURL); - defer response.Body.Close() - - _, err = io.Copy(targetFile, response.Body) - if err != nil { - log.Fatal(err) - } - - hasher := sha256.New() - fileContent, err := ioutil.ReadFile(localFileName) - hasher.Write(fileContent) - - if err != nil { - log.Fatal(err) - } - finalCheckSum := hex.EncodeToString(hasher.Sum(nil)); - log.Println ("Final Checksum: " + finalCheckSum); - - - if (finalCheckSum != shaCheckSum) { - log.Fatal ("Checksum mismatch!"); - } - - } - - - log.Println ("done.."); - - - } else { - - log.Fatal ("Unknown command. Valid commands are download and extract."); - } - - -} \ No newline at end of file diff --git a/CMakeLists.txt b/CMakeLists.txt index 6780bc676..06fdfd12a 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -901,3 +901,78 @@ if(UNIX) endif() + + +#[[++ + +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ +++ packageManager Target +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ + +]] + + +if(UNIX AND NOT APPLE) + # If you ever want to force static later, set this to TRUE before find_package. + # set(OPENSSL_USE_STATIC_LIBS TRUE) + find_package(OpenSSL REQUIRED) # provides OpenSSL::SSL and OpenSSL::Crypto +endif() + +file(GLOB PACKAGE_MANAGER_SRC + ${CMAKE_CURRENT_SOURCE_DIR}/BuildScripts/packageManager.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Implementation/Common/common_utils.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Implementation/Common/common_importstream_native.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Implementation/Common/common_exportstream_native.cpp + ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/crossguid/guid.cpp +) + +add_executable(package_manager ${PACKAGE_MANAGER_SRC} ${LIBMC_SRC_DEP_PUGIXML}) + +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Implementation/Common) +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/PugiXML) +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries) +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/PicoSHA2) +if(MSVC) +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libressl) +endif() +target_include_directories(package_manager PRIVATE ${CMAKE_CURRENT_SOURCE_DIR}/) + +set_target_properties(package_manager + PROPERTIES + RUNTIME_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/DevPackage/Framework" + RUNTIME_OUTPUT_DIRECTORY_DEBUG "${PROJECT_BINARY_DIR}/DevPackage/Framework" + RUNTIME_OUTPUT_DIRECTORY_RELEASE "${PROJECT_BINARY_DIR}/DevPackage/Framework" + LIBRARY_OUTPUT_DIRECTORY "${PROJECT_BINARY_DIR}/DevPackage/Framework" + + OUTPUT_NAME "package_manager" + + VS_DEBUGGER_WORKING_DIRECTORY "${PROJECT_BINARY_DIR}/Output" +) + + +target_compile_options(package_manager PRIVATE "-D__GITHASH=${GLOBALGITHASH}") +target_compile_options(package_manager PRIVATE "-DUNICODE") +target_compile_options(package_manager PRIVATE "-D_UNICODE") + + +if(MSVC) + target_link_libraries(package_manager shlwapi.lib) + target_link_libraries(package_manager ws2_32.lib) + target_link_libraries(package_manager bcrypt.lib) + + target_link_libraries(package_manager ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libressl/win64/tls-24.lib) + target_link_libraries(package_manager ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libressl/win64/crypto-49.lib) + target_link_libraries(package_manager ${CMAKE_CURRENT_SOURCE_DIR}/Libraries/libressl/win64/ssl-52.lib) +endif() + +if(UNIX AND NOT APPLE) + + find_package(Threads REQUIRED) + + if(NOT LIBUUID_PATH) + message(FATAL_ERROR "libuuid not found") + endif() + target_link_libraries(package_manager ${LIBUUID_PATH} OpenSSL::SSL OpenSSL::Crypto Threads::Threads) +endif() + + diff --git a/Client/src/common/AMCImplementation_LayerView.js b/Client/src/common/AMCImplementation_LayerView.js index 8653ef5e7..b0a392bfb 100644 --- a/Client/src/common/AMCImplementation_LayerView.js +++ b/Client/src/common/AMCImplementation_LayerView.js @@ -326,6 +326,28 @@ class LayerViewImpl { } + computeChannelColumnRange (pointsChannelName, pointsColumnName) + { + if (this[pointsChannelName] && this[pointsChannelName][pointsColumnName]) { + let dataArray = this[pointsChannelName][pointsColumnName]; + + let maxValue = Number.NEGATIVE_INFINITY; + let minValue = Number.POSITIVE_INFINITY; + + for (let i = 0; i < dataArray.length; i++) { + let value = dataArray[i]; + if (value > maxValue) { + maxValue = value; + } + if (value < minValue) { + minValue = value; + } + } + this[pointsChannelName][pointsColumnName].max = maxValue; + this[pointsChannelName][pointsColumnName].min = minValue; + } + } + makeLaserOnColors () { this.laserOnPointsColorArray = null; @@ -351,6 +373,37 @@ class LayerViewImpl { } + makeLaserPowerColors () + { + this.layerPointsColorArray = null; + + if (this.laser && this.laser.power && this.layerPointsArray) { + const powerRange = (this.laser.power.max - this.laser.power.min); + if (powerRange > 0) { + + let pointCount = this.laser.power.length; + let colors = []; + + for (let pointIndex = 0; pointIndex < pointCount; pointIndex++) { + let power = this.laser.power[pointIndex]; + let fraction = (power - this.laser.power.min) / powerRange; + if (fraction >= 0.0) { + if (fraction > 1.0) + fraction = 1.0; + } else { + fraction = 0.0; + } + + const hue = (fraction) * 240 / 360; + colors.push (this.hslToRgb (hue, 1.0, 0.5)); + } + + this.layerPointsColorArray = colors; + } + } + } + + hslToRgb(h, s, l) { // Ensure h, s, l are in the range [0, 1] h = h % 1; // Wrap around if h is greater than 1 @@ -429,6 +482,8 @@ class LayerViewImpl { // Assign the data array to the corresponding column this[pointsChannelName][pointsColumnName] = pointsChannelDataArray; + + this.computeChannelColumnRange (pointsChannelName, pointsColumnName); } clearPoints () @@ -469,6 +524,10 @@ class LayerViewImpl { if (this.layerPointsMode == "laseron") { this.makeLaserOnColors (); } + + if (this.layerPointsMode == "powerramp") { + this.makeLaserPowerColors (); + } } setColorMode (newColorMode) { @@ -587,6 +646,16 @@ class LayerViewImpl { } + getPointPower (pointIndex) + { + if (this.laser && this.laser.power) { + if (pointIndex >= 0 && pointIndex < this.laser.power.length) { + return this.laser.power[pointIndex]; + } + } + return null; + } + updateLoadedLayer () { if (!this.glInstance) return; diff --git a/Client/src/modules/AMCModule_ContentItem_Form.vue b/Client/src/modules/AMCModule_ContentItem_Form.vue index e45b81185..f41a2d4fc 100644 --- a/Client/src/modules/AMCModule_ContentItem_Form.vue +++ b/Client/src/modules/AMCModule_ContentItem_Form.vue @@ -35,7 +35,7 @@ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.