23#include <wx/translation.h>
26#include <boost/algorithm/string.hpp>
43 if( aTestConnectionNow )
60 res = curl->GetBuffer();
65 if(
res.length() == 0 )
67 m_lastError += wxString::Format(
_(
"KiCad received an empty response!" ) +
"\n" );
71 nlohmann::json response = nlohmann::json::parse(
res );
74 if( !response.at(
"categories" ).empty() && !response.at(
"parts" ).empty() )
78 catch(
const std::exception& e )
80 m_lastError += wxString::Format(
_(
"Error: %s" ) +
"\n" +
_(
"API Response: %s" ) +
"\n",
83 wxLogTrace(
traceHTTPLib, wxT(
"validateHttpLibraryEndpoints: Exception while testing API connection: %s" ),
100 wxLogTrace(
traceHTTPLib, wxT(
"syncCategories: without valid connection!" ) );
104 std::string
res =
"";
107 curl->SetURL(
m_source.root_url +
"categories.json" );
113 res = curl->GetBuffer();
118 nlohmann::json response = nlohmann::json::parse(
res );
121 for(
const auto& item : response.items() )
125 auto& value = item.value();
126 category.
id = value[
"id"].get<std::string>();
127 category.
name = value[
"name"].get<std::string>();
129 if( value.contains(
"description" ) )
131 category.
description = value[
"description"].get<std::string>();
138 catch(
const std::exception& e )
140 m_lastError += wxString::Format(
_(
"Error: %s" ) +
"\n" +
_(
"API Response: %s" ) +
"\n",
158 wxLogTrace(
traceHTTPLib, wxT(
"SelectOne: without valid connection!" ) );
166 if( std::difftime( std::time(
nullptr ),
m_cachedParts[aPartID].lastCached ) <
m_source.timeout_parts )
173 std::string
res =
"";
176 std::string url =
m_source.root_url + fmt::format(
"parts/{}.json", aPartID );
183 res = curl->GetBuffer();
188 nlohmann::ordered_json response = nlohmann::ordered_json::parse(
res );
189 std::string key =
"";
190 std::string value =
"";
194 aFetchedPart.
id = response.at(
"id" );
197 aFetchedPart.
lastCached = std::time(
nullptr );
200 if( response.contains(
"name" ) )
201 aFetchedPart.
name = response.at(
"name" );
203 aFetchedPart.
name = aFetchedPart.
id;
206 aFetchedPart.
name = sanitizedFetchedName.
c_str();
208 aFetchedPart.
symbolIdStr = response.at(
"symbolIdStr" );
213 if( response.contains(
"exclude_from_bom" ) )
216 exclude = response.at(
"exclude_from_bom" );
221 if( response.contains(
"exclude_from_board" ) )
224 exclude = response.at(
"exclude_from_board" );
229 if( response.contains(
"exclude_from_sim" ) )
232 exclude = response.at(
"exclude_from_sim" );
237 aFetchedPart.
fields.clear();
240 for(
const auto& field : response.at(
"fields" ).items() )
248 auto& properties = field.value();
250 value = properties.at(
"value" );
253 if( properties.contains(
"visible" ) )
255 std::string vis = properties.at(
"visible" );
260 aFetchedPart.
fields.push_back( std::make_pair( key, std::make_tuple( value, visible ) ) );
263 if( response.contains(
"description" ) )
264 aFetchedPart.
desc = response.at(
"description" );
266 if( response.contains(
"keywords" ) )
267 aFetchedPart.
keywords = response.at(
"keywords" );
269 if( response.contains(
"footprint_filters" ) )
271 nlohmann::json filters_json = response.at(
"footprint_filters" );
273 if( filters_json.is_array() )
275 for(
const auto& val : filters_json )
280 aFetchedPart.
fp_filters.push_back( filters_json );
284 catch(
const std::exception& e )
286 m_lastError += wxString::Format(
_(
"Error: %s" ) +
"\n" +
_(
"API Response: %s" ) +
"\n",
304 wxLogTrace(
traceHTTPLib, wxT(
"SelectAll: without valid connection!" ) );
308 std::string
res =
"";
312 curl->SetURL(
m_source.root_url + fmt::format(
"parts/category/{}.json", aCategory.
id ) );
318 res = curl->GetBuffer();
320 nlohmann::json response = nlohmann::json::parse(
res );
322 for( nlohmann::json& item : response )
327 part.
id = item.at(
"id" );
329 if( item.contains(
"description" ) )
332 part.
fields.push_back( std::make_pair(
"description",
333 std::make_tuple( item.at(
"description" ),
false ) ) );
337 if( item.contains(
"name" ) )
338 part.
name = item.at(
"name" );
342 std::string originalName = part.
name;
346 if( part.
name != originalName )
352 aParts.emplace_back( std::move( part ) );
355 catch(
const std::exception& e )
357 m_lastError += wxString::Format(
_(
"Error: %s" ) +
"\n" +
_(
"API Response: %s" ) +
"\n",
371 int statusCode = aCurl->GetResponseStatusCode();
373 if( statusCode != 200 )
375 m_lastError += wxString::Format(
_(
"API responded with error code: %s" ) +
"\n",
388 wxString strval( std::any_cast<std::string>( aVal ).c_str(), wxConvUTF8 );
390 if( strval.IsEmpty() )
391 return aDefaultValue;
395 for(
const auto& trueVal : { wxS(
"true" ), wxS(
"yes" ), wxS(
"y" ), wxS(
"1" ) } )
397 if( strval.Matches( trueVal ) )
401 for(
const auto& falseVal : { wxS(
"false" ), wxS(
"no" ), wxS(
"n" ), wxS(
"0" ) } )
403 if( strval.Matches( falseVal ) )
407 catch(
const std::bad_any_cast& )
411 return aDefaultValue;
417 auto codeDescription =
418 []( uint16_t aCode ) -> wxString
422 case 100:
return wxS(
"Continue" );
423 case 101:
return wxS(
"Switching Protocols" );
424 case 102:
return wxS(
"Processing" );
425 case 103:
return wxS(
"Early Hints" );
427 case 200:
return wxS(
"OK" );
428 case 201:
return wxS(
"Created" );
429 case 203:
return wxS(
"Non-Authoritative Information" );
430 case 204:
return wxS(
"No Content" );
431 case 205:
return wxS(
"Reset Content" );
432 case 206:
return wxS(
"Partial Content" );
433 case 207:
return wxS(
"Multi-Status" );
434 case 208:
return wxS(
"Already Reported" );
435 case 226:
return wxS(
"IM Used" );
437 case 300:
return wxS(
"Multiple Choices" );
438 case 301:
return wxS(
"Moved Permanently" );
439 case 302:
return wxS(
"Found" );
440 case 303:
return wxS(
"See Other" );
441 case 304:
return wxS(
"Not Modified" );
442 case 305:
return wxS(
"Use Proxy (Deprecated)" );
443 case 306:
return wxS(
"Unused" );
444 case 307:
return wxS(
"Temporary Redirect" );
445 case 308:
return wxS(
"Permanent Redirect" );
447 case 400:
return wxS(
"Bad Request" );
448 case 401:
return wxS(
"Unauthorized" );
449 case 402:
return wxS(
"Payment Required (Experimental)" );
450 case 403:
return wxS(
"Forbidden" );
451 case 404:
return wxS(
"Not Found" );
452 case 405:
return wxS(
"Method Not Allowed" );
453 case 406:
return wxS(
"Not Acceptable" );
454 case 407:
return wxS(
"Proxy Authentication Required" );
455 case 408:
return wxS(
"Request Timeout" );
456 case 409:
return wxS(
"Conflict" );
457 case 410:
return wxS(
"Gone" );
458 case 411:
return wxS(
"Length Required" );
459 case 412:
return wxS(
"Payload Too Large" );
460 case 414:
return wxS(
"URI Too Long" );
461 case 415:
return wxS(
"Unsupported Media Type" );
462 case 416:
return wxS(
"Range Not Satisfiable" );
463 case 417:
return wxS(
"Expectation Failed" );
464 case 418:
return wxS(
"I'm a teapot" );
465 case 421:
return wxS(
"Misdirected Request" );
466 case 422:
return wxS(
"Unprocessable Content" );
467 case 423:
return wxS(
"Locked" );
468 case 424:
return wxS(
"Failed Dependency" );
469 case 425:
return wxS(
"Too Early (Experimental)" );
470 case 426:
return wxS(
"Upgrade Required" );
471 case 428:
return wxS(
"Precondition Required" );
472 case 429:
return wxS(
"Too Many Requests" );
473 case 431:
return wxS(
"Request Header Fields Too Large" );
474 case 451:
return wxS(
"Unavailable For Legal Reasons" );
476 case 500:
return wxS(
"Internal Server Error" );
477 case 501:
return wxS(
"Not Implemented" );
478 case 502:
return wxS(
"Bad Gateway" );
479 case 503:
return wxS(
"Service Unavailable" );
480 case 504:
return wxS(
"Gateway Timeout" );
481 case 505:
return wxS(
"HTTP Version Not Supported" );
482 case 506:
return wxS(
"Variant Also Negotiates" );
483 case 507:
return wxS(
"Insufficient Storage" );
484 case 508:
return wxS(
"Loop Detected" );
485 case 510:
return wxS(
"Not Extended" );
486 case 511:
return wxS(
"Network Authentication Required" );
487 default:
return wxS(
"Unknown" );
491 return wxString::Format( wxS(
"%d: %s" ), aHttpCode, codeDescription( aHttpCode ) );
bool checkServerResponse(std::unique_ptr< KICAD_CURL_EASY > &aCurl)
bool validateHttpLibraryEndpoints()
std::map< std::string, HTTP_LIB_PART > m_cachedParts
std::unique_ptr< KICAD_CURL_EASY > createCurlEasyObject()
std::map< std::string, std::string > m_categoryDescriptions
bool boolFromString(const std::any &aVal, bool aDefaultValue=false)
bool SelectAll(const HTTP_LIB_CATEGORY &aCategory, std::vector< HTTP_LIB_PART > &aParts)
Retrieve all parts from a specific category from the HTTP library.
HTTP_LIB_CONNECTION(const HTTP_LIB_SOURCE &aSource, bool aTestConnectionNow)
std::map< std::string, std::tuple< std::string, std::string > > m_cache
std::vector< HTTP_LIB_CATEGORY > m_categories
bool IsValidEndpoint() const
bool SelectOne(const std::string &aPartID, HTTP_LIB_PART &aFetchedPart)
Retrieve a single part with full details from the HTTP library.
wxString httpErrorCodeDescription(uint16_t aHttpCode)
HTTP response status codes indicate whether a specific HTTP request has been successfully completed.
static UTF8 FixIllegalChars(const UTF8 &aLibItemName, bool aLib)
Replace illegal LIB_ID item name characters with underscores '_'.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
const char * c_str() const
const char *const traceHTTPLib
const char *const traceHTTPLib
std::string id
id of category
std::string name
name of category
std::string description
description of category
std::vector< std::string > fp_filters
std::vector< std::pair< std::string, std::tuple< std::string, bool > > > fields