26#include <bs_thread_pool.hpp>
28#include <wx/tokenzr.h>
41 std::vector<HTTP_LIB_PART>& aParts )
43 if( !aConn.
SelectAll( aCategory, aParts ) )
48 if( part.detailsLoaded )
54 if( fullPart.desc.empty() )
55 fullPart.desc = part.desc;
57 if( fullPart.keywords.empty() )
58 fullPart.keywords = part.keywords;
60 fullPart.id = part.id;
61 fullPart.name = part.name;
62 part = std::move( fullPart );
71 SCH_IO( wxS(
"HTTP library" ) ),
92 wxLogTrace(
traceHTTPLib, wxT(
"Starting background refresh thread" ) );
99 BS::this_thread::set_os_thread_name(
"httplib bg" );
103 long long maxAge = 0;
109 maxAge = std::max(
m_settings->m_Source.timeout_categories,
m_settings->m_Source.timeout_parts );
121 wxLogTrace(
traceHTTPLib, wxT(
"Initiating background refresh" ) );
125 std::map<std::string, HTTP_LIB_CATEGORY> categoryData;
126 bool fetchSuccess =
true;
130 std::vector<HTTP_LIB_PART> foundParts;
134 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: fetch failed for category %s" ),
136 fetchSuccess =
false;
142 categoryData[category.id] = std::move( cached );
148 bool dataChanged =
false;
160 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: new data" ) );
171 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: no new data" ) );
177 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh failed: %s" ), e.
What() );
179 catch(
const std::exception& e )
181 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh failed: %s" ), e.
what() );
188 m_refreshCV.wait_for( lock, std::chrono::seconds( maxAge ),
200 size_t signature = 0;
202 for(
const auto& [catId, category] : aCategoryData )
205 hash_combine( signature, std::string_view( category.name ) );
218 for(
const auto& [fieldName, fieldProps] : part.
fields )
220 hash_combine( signature, std::string_view( fieldName ) );
221 hash_combine( signature, std::string_view( std::get<0>( fieldProps ) ) );
238 if( std::optional<int> libHash =
m_adapter->GetLibraryModifyHash( nickname ) )
250 const std::map<std::string, HTTP_LIB_CATEGORY>& aCategoryData )
252 std::map<wxString, std::unique_ptr<LIB_SYMBOL>> newSymbolCache;
253 std::map<wxString, std::pair<std::string, std::string>> newPartIdMap;
254 std::set<wxString> newCustomFields;
260 wxString symbolName( part.
name );
261 newPartIdMap[symbolName] = { part.
id, category.id };
266 newSymbolCache[symbolName] = std::unique_ptr<LIB_SYMBOL>( symbol );
298 struct CACHE_LIB_GUARD
301 ~CACHE_LIB_GUARD() { *
flag =
false; }
306 std::map<std::string, HTTP_LIB_CATEGORY> categoryData;
310 std::vector<HTTP_LIB_PART> foundParts;
314 if( !
m_conn->GetLastError().empty() )
316 THROW_IO_ERROR( wxString::Format(
_(
"Error retrieving data from HTTP library %s: %s" ), category.name,
317 m_conn->GetLastError() ) );
325 categoryData[category.id] = std::move( cached );
350 const std::map<std::string, UTF8>* aProperties )
352 wxCHECK_RET(
m_adapter,
"HTTP plugin missing library manager adapter handle!" );
367 if( !powerSymbolsOnly || symbol->IsPower() )
368 aSymbolNameList.Add(
name );
374 const std::map<std::string, UTF8>* aProperties )
376 wxCHECK_RET(
m_adapter,
"HTTP plugin missing library manager adapter handle!" );
389 for(
const std::unique_ptr<LIB_SYMBOL>& symbol :
m_symbolCache | std::views::values )
391 if( !powerSymbolsOnly || symbol->IsPower() )
392 aSymbolList.emplace_back( symbol->Duplicate() );
398 const std::map<std::string, UTF8>* aProperties )
406 const std::map<std::string, UTF8>* aProperties )
408 wxCHECK_MSG(
m_adapter,
nullptr,
"HTTP plugin missing library manager adapter handle!" );
421 return it->second->Duplicate();
427 std::string categoryId;
434 partId = it->second.first;
435 categoryId = it->second.second;
441 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: no cached part found for %s" ), aAliasName );
449 if( category.id == categoryId )
451 foundCategory = &category;
458 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: no category found for %s" ), aAliasName );
466 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: SelectOne (%s) failed for category %s" ),
467 partId, foundCategory->
name );
468 THROW_IO_ERROR( wxString::Format(
_(
"Error retrieving part %s from HTTP library: %s" ),
469 partId,
m_conn->GetLastError() ) );
472 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: SelectOne (%s) found in %s" ),
473 partId, foundCategory->
name );
477 std::set<wxString> transientFields;
495 std::set<wxString> categoryNames;
499 if( categoryNames.count( categoryIter.name ) )
502 aNames.emplace_back( categoryIter.name );
503 categoryNames.insert( categoryIter.name );
514 return wxEmptyString;
516 return m_conn->getCategoryDescription( std::string( aName.mb_str() ) );
540 THROW_IO_ERRORF(
_(
"HTTP library settings file %s missing or invalid." ), aSettingsPath );
542 if(
m_settings->m_Source.api_version.empty() )
544 THROW_IO_ERRORF(
_(
"HTTP library settings file %s is missing the API version number." ),
550 THROW_IO_ERRORF(
_(
"HTTP library settings file %s uses API version %s, but KiCad requires "
558 THROW_IO_ERRORF(
_(
"HTTP library settings file %s is missing the root URL." ), aSettingsPath );
564 THROW_IO_ERRORF(
_(
"HTTP library settings file %s has invalid library type." ), aSettingsPath );
579 std::string
path( aSettingsPath.ToUTF8() );
593 wxLogTrace(
traceHTTPLib, wxT(
"ensureSettings: no settings available!" ) );
600 wxCHECK_RET(
m_settings,
"Call ensureSettings before ensureConnection!" );
611 wxCHECK_RET(
m_settings,
"Call ensureSettings before connect()!" );
621 m_conn = std::make_unique<HTTP_LIB_CONNECTION>(
m_settings->m_Source,
true );
623 if( !
m_conn->IsValidEndpoint() )
636 const wxString& aSymbolName,
639 std::set<wxString>& aCustomFields )
648 wxFileName libFileName( aLibraryPath );
649 wxString libNickname = libFileName.GetName();
652 if( !symbolIdStr.empty() )
654 symbolId.
Parse( symbolIdStr );
662 std::unordered_set<wxString>* set;
684 wxT(
"loadSymbolFromPart: cycle detected resolving '%s' "
685 "(part '%s'); skipping recursive load" ),
686 symbolIdStr, aSymbolName );
690 originalSymbol =
m_adapter->LoadSymbol( symbolId );
696 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: found original symbol '%s'" ),
701 symbol->
SetName( aSymbolName );
710 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol '%s' is a "
711 "self-reference, will create empty symbol" ),
716 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol id '%s' is invalid, "
717 "will create empty symbol" ), symbolIdStr );
721 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol '%s' not found, "
722 "will create empty symbol" ), symbolIdStr );
744 wxArrayString fp_filters;
746 for(
auto& [fieldName, fieldProperties] : aPart.
fields )
748 wxString lowerFieldName = wxString( fieldName ).Lower();
753 wxStringTokenizer tokenizer( std::get<0>( fieldProperties ),
";\t\r\n", wxTOKEN_STRTOK );
755 while( tokenizer.HasMoreTokens() )
756 fp_filters.Add( tokenizer.GetNextToken() );
758 if( fp_filters.size() > 0 )
759 field->
SetText( fp_filters[0] );
761 field->
SetVisible( std::get<1>( fieldProperties ) );
766 field->
SetText( std::get<0>( fieldProperties ) );
767 field->
SetVisible( std::get<1>( fieldProperties ) );
772 field->
SetText( std::get<0>( fieldProperties ) );
773 field->
SetVisible( std::get<1>( fieldProperties ) );
778 field->
SetText( std::get<0>( fieldProperties ) );
779 field->
SetVisible( std::get<1>( fieldProperties ) );
784 field->
SetText( std::get<0>( fieldProperties ) );
785 field->
SetVisible( std::get<1>( fieldProperties ) );
789 symbol->
SetKeyWords( std::get<0>( fieldProperties ) );
800 if( field !=
nullptr )
803 field->
SetText( std::get<0>( fieldProperties ) );
804 field->
SetVisible( std::get<1>( fieldProperties ) );
812 field->
SetText( std::get<0>( fieldProperties ) );
813 field->
SetVisible( std::get<1>( fieldProperties ) );
816 aCustomFields.insert( fieldName );
822 if( !aPart.
desc.empty() )
829 fp_filters.push_back(
filter );
845 if( !aPart.
pin_map.empty() && !assignedFootprint.IsEmpty() )
847 const wxString mapName = wxS(
"HTTP Library" );
852 fpId.
Parse( assignedFootprint );
861 const std::map<std::string, UTF8>* aProperties )
virtual void SetVisible(bool aVisible)
bool SelectAll(const HTTP_LIB_CATEGORY &aCategory, std::vector< HTTP_LIB_PART > &aParts)
Retrieve all parts from a specific category from the HTTP library.
bool SelectOne(const std::string &aPartID, HTTP_LIB_PART &aFetchedPart)
Retrieve a single part with full details from the HTTP library.
Hold an error message and may be used when throwing exceptions containing meaningful error messages.
virtual const wxString What() const
A composite of Problem() and Where()
virtual const char * what() const override
std::exception interface, returned as UTF-8
A logical library item identifier and consists of various portions much like a URI.
int Parse(const UTF8 &aId, bool aFix=false)
Parse LIB_ID with the information from aId.
bool IsValid() const
Check if this LID_ID is valid.
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
void SetSubLibraryName(const UTF8 &aName)
const UTF8 & GetLibNickname() const
Return the logical library name portion of a LIB_ID.
Define a library symbol object.
SCH_FIELD & GetDescriptionField()
Return reference to the description field.
const LIB_ID & GetLibId() const override
void SetSourceLibId(const LIB_ID &aLibId)
SCH_FIELD & GetDatasheetField()
Return reference to the datasheet field.
virtual LIB_SYMBOL * Duplicate() const
Create a copy of a LIB_SYMBOL and assigns unique KIIDs to the copy and its children.
SCH_FIELD * GetField(const wxString &aFieldName)
Find a field within this symbol matching aFieldName; return nullptr if not found.
SCH_FIELD & GetFootprintField()
Return reference to the footprint field.
void SetAssociatedFootprints(std::vector< ASSOCIATED_FOOTPRINT > aList)
void SetDescription(const wxString &aDescription)
Gets the Description field text value */.
void SetKeyWords(const wxString &aKeyWords)
SCH_FIELD & GetValueField()
Return reference to the value field.
void SetPinMaps(const PIN_MAP_SET &aPinMaps)
void SetFPFilters(const wxArrayString &aFilters)
void SetLibId(const LIB_ID &aLibId)
void AddField(SCH_FIELD *aField)
Add a field.
virtual void SetName(const wxString &aName)
SCH_FIELD & GetReferenceField()
Return reference to the reference designator field.
void AddOrReplace(PIN_MAP aMap)
Insert aMap, replacing any existing entry with the same name.
virtual const wxString & GetText() const override
Return the string associated with the text object.
void SetName(const wxString &aName)
void SetText(const wxString &aText) override
std::thread m_refreshThread
LIB_SYMBOL * loadSymbolFromPart(const wxString &aLibraryPath, const wxString &aSymbolName, const HTTP_LIB_CATEGORY &aCategory, const HTTP_LIB_PART &aPart, std::set< wxString > &aCustomFields)
std::unique_ptr< HTTP_LIB_CONNECTION > m_conn
Generally will be null if no valid connection is established.
LIB_SYMBOL * LoadSymbol(const wxString &aLibraryPath, const wxString &aAliasName, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Load a LIB_SYMBOL object having aPartName from the aLibraryPath containing a library format that this...
std::map< wxString, std::unique_ptr< LIB_SYMBOL > > m_symbolCache
std::unique_ptr< HTTP_LIB_SETTINGS > m_settings
wxString GetSubLibraryDescription(const wxString &aName) override
Gets a description of a sublibrary.
SYMBOL_LIBRARY_ADAPTER * m_adapter
void startBackgroundRefresh()
void ensureSettings(const wxString &aSettingsPath)
std::set< wxString > m_customFields
void GetDefaultSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that should be shown by default for this library in the symb...
void GetAvailableSymbolFields(std::vector< wxString > &aNames) override
Retrieves a list of (custom) field names that are present on symbols in this library.
std::map< wxString, std::pair< std::string, std::string > > m_partIdMap
Symbol name -> (part id, category id); used for the SelectOne fallback in LoadSymbol.
std::set< wxString > m_defaultShownFields
void SaveSymbol(const wxString &aLibraryPath, std::unique_ptr< LIB_SYMBOL > aSymbol, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Write aSymbol to an existing library located at aLibraryPath.
SOURCE_PATCHER m_sourcePatcher
std::unordered_set< wxString > m_inProgressLoads
void backgroundRefreshWorker()
std::mutex m_refreshMutex
std::mutex m_symbolLoadMutex
Serializes loadSymbolFromPart calls.
CONNECTION_BUILDER m_connectionFactory
Allows replacing actual HTTP connection for QA tests.
wxString description_field
std::atomic< bool > m_refreshRunning
void materializeCache(const wxString &aLibraryPath, const std::map< std::string, HTTP_LIB_CATEGORY > &aCategoryData)
size_t computeSignature(const std::map< std::string, HTTP_LIB_CATEGORY > &aCategoryData) const
void stopBackgroundRefresh()
std::atomic< bool > m_cachePopulated
void CheckLibrary(const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Validate that the library at aLibraryPath is reachable and well-formed, without necessarily loading s...
std::condition_variable m_refreshCV
void cacheLib(const wxString &aLibraryPath)
void EnumerateSymbolLib(wxArrayString &aSymbolNameList, const wxString &aLibraryPath, const std::map< std::string, UTF8 > *aProperties=nullptr) override
Populate a list of LIB_SYMBOL alias names contained within the library aLibraryPath.
std::shared_mutex m_cacheMutex
Protects m_symbolCache, m_partIdMap, and m_customFields.
void GetSubLibraryNames(std::vector< wxString > &aNames) override
Retrieves a list of sub-libraries in this library.
SCH_IO(const wxString &aName)
static const char * PropPowerSymsOnly
void SetExcludedFromBoard(bool aExclude, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear exclude from board netlist flag.
virtual void SetExcludedFromSim(bool aExcludeFromSim, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from simulation flag.
virtual void SetExcludedFromBOM(bool aExcludeFromBOM, const SCH_SHEET_PATH *aInstance=nullptr, const wxString &aVariantName=wxEmptyString) override
Set or clear the exclude from schematic bill of materials flag.
An 8 bit string that is assuredly encoded in UTF8, and supplies special conversion support to and fro...
const char * c_str() const
static constexpr void hash_combine(std::size_t &seed)
This is a dummy function to take the final case of hash_combine below.
const char *const traceHTTPLib
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
PIN_MAP MakeLegacyPinMap(const wxString &aName, const std::unordered_map< wxString, std::vector< wxString > > &aAssignments)
Build a single named PIN_MAP from a legacy symbol-pin to footprint-pad(s) assignment table (the flat ...
static bool fetchCategoryParts(HTTP_LIB_CONNECTION &aConn, const HTTP_LIB_CATEGORY &aCategory, std::vector< HTTP_LIB_PART > &aParts)
std::vector< HTTP_LIB_PART > cachedParts
std::string name
name of category
std::vector< ASSOCIATED_FOOTPRINT > associated_footprints
std::unordered_map< wxString, std::vector< wxString > > pin_map
Legacy flat MR !2540 pin assignment table (read for one release; issue #2282).
std::vector< std::string > fp_filters
std::vector< std::pair< std::string, field_type > > fields
PIN_MAP_SET named_pin_maps
Spec-form named pin maps and their footprint associations (issue #2282).
@ USER
The field ID hasn't been set yet; field is invalid.
wxString result
Test unit parsing edge cases and error handling.