Stp2Glb/src/config_utils.cpp
sladro 096812b7d2 feat: add HTTP/HTTPS URL input support for STP files
Add capability to download STP files directly from HTTP/HTTPS URLs in both CLI and HTTP server modes.

Changes:
- Add http_downloader module for downloading files from URLs
- Extend GlobalConfig to track downloaded files
- Update CLI parameter processing to detect and handle URLs
- Enhance HTTP server to accept URL parameter alongside file upload
- Implement automatic cleanup of downloaded temporary files
- Add comprehensive usage documentation (USAGE.md)

Usage examples:
  CLI: STP2GLB.exe --stp https://example.com/model.stp --glb output.glb
  API: curl -X POST http://localhost:8080/convert -F "url=https://example.com/model.stp"

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-11 17:19:35 +08:00

156 lines
5.5 KiB
C++

//
// Created by ofskrand on 13.01.2025.
//
#include "config_utils.h"
#include <fstream>
#include <iostream>
#include <stdexcept>
#include <string>
#include <vector>
#include "config_structs.h"
#include "cadit/occt/helpers.h"
#include "CLI/App.hpp"
#include "http_downloader.h"
// Helper function to process filter names from input or file
std::vector<std::string> process_filter_names(const std::string& input, const std::string& file_name)
{
std::vector<std::string> filter_names;
// Process input string
if (!input.empty())
{
std::string stripped_input = strip_quotes(input);
auto names = split(stripped_input, ',');
filter_names.insert(filter_names.end(), names.begin(), names.end());
}
// Process file
if (!file_name.empty())
{
if (std::ifstream file(file_name); file.is_open())
{
std::string line;
while (std::getline(file, line))
{
if (!line.empty())
{
filter_names.push_back(line);
}
}
file.close();
}
else
{
throw std::runtime_error("Error: Could not open file: " + file_name);
}
}
return filter_names;
}
// Helper function to check if a string ends with a specific suffix (case insensitive)
bool endsWithCaseInsensitive(const std::string& str, const std::string& suffix) {
if (str.size() < suffix.size()) {
return false;
}
auto strIt = str.end() - suffix.size();
auto suffixIt = suffix.begin();
while (suffixIt != suffix.end()) {
if (tolower(*strIt++) != tolower(*suffixIt++)) {
return false;
}
}
return true;
}
// Main processing function
GlobalConfig process_parameters(CLI::App& app)
{
const auto filter_names_include_input = app.get_option("--filter-names-include")->as<std::string>();
const auto filter_names_file_include = app.get_option("--filter-names-file-include")->as<std::string>();
const auto filter_names_exclude_input = app.get_option("--filter-names-exclude")->as<std::string>();
const auto filter_names_file_exclude = app.get_option("--filter-names-file-exclude")->as<std::string>();
// Process include and exclude filter names
const auto filter_names_include = process_filter_names(filter_names_include_input, filter_names_file_include);
const auto filter_names_exclude = process_filter_names(filter_names_exclude_input, filter_names_file_exclude);
std::string stpFilename = app.get_option("--stp")->results()[0];
std::string glbFilename = app.get_option("--glb")->results()[0];
bool isDownloadedFromUrl = false;
std::string originalUrl;
std::filesystem::path stpFilePath;
std::filesystem::path glbFilePath;
// Check if input is HTTP URL
if (is_http_url(stpFilename)) {
std::cout << "Detected HTTP URL, downloading..." << std::endl;
try {
std::string downloaded_path = download_file_from_url(stpFilename, "./temp");
stpFilePath = std::filesystem::path(downloaded_path);
isDownloadedFromUrl = true;
originalUrl = stpFilename;
std::cout << "URL download completed: " << downloaded_path << std::endl;
} catch (const std::exception& ex) {
throw std::runtime_error("Failed to download from URL: " + std::string(ex.what()));
}
} else {
stpFilePath = std::filesystem::path(stpFilename);
// Check if local file exists
if (!exists(stpFilePath)) {
throw std::invalid_argument("Invalid --stp filename \"" + stpFilename + "\". File does not exist.");
}
}
glbFilePath = std::filesystem::path(glbFilename);
// Validate extensions
bool isStpValid = endsWithCaseInsensitive(stpFilePath.string(), ".stp") || endsWithCaseInsensitive(stpFilePath.string(), ".step");
bool isGlbValid = endsWithCaseInsensitive(glbFilename, ".glb");
if (exists(glbFilePath)) {
std::cout << "Warning: --glb filename \"" << glbFilename << "\" already exists and will be overwritten.\n";
}
if (!isStpValid) {
throw std::invalid_argument("Invalid --stp filename. It must end with .stp or .step.");
}
if (!isGlbValid) {
throw std::invalid_argument("Invalid --glb filename. It must end with .glb.");
}
// Create configuration
return {
.stpFile = stpFilePath,
.glbFile = glbFilename,
.debug_mode = app.get_option("--debug")->as<bool>(),
.linearDeflection = app.get_option("--lin-defl")->as<double>(),
.angularDeflection = app.get_option("--ang-defl")->as<double>(),
.relativeDeflection = app.get_option("--rel-defl")->as<bool>(),
.solidOnly = app.get_option("--solid-only")->as<bool>(),
.max_geometry_num = app.get_option("--max-geometry-num")->as<int>(),
.tessellation_timout = app.get_option("--tessellation-timeout")->as<int>(),
.filter_names_include = filter_names_include,
.filter_names_exclude = filter_names_exclude,
.buildConfig = {
.build_bspline_surf = false
},
.serverConfig = {
.enable_server = app.get_option("--server")->as<bool>(),
.port = app.get_option("--port")->as<int>(),
.host = app.get_option("--host")->as<std::string>(),
.max_file_size_mb = app.get_option("--max-file-size")->as<size_t>(),
.temp_dir = "./temp"
},
.is_downloaded_from_url = isDownloadedFromUrl,
.original_url = originalUrl
};
}