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" ) ),
97 wxLogTrace(
traceHTTPLib, wxT(
"Starting background refresh thread" ) );
104 BS::this_thread::set_os_thread_name(
"httplib bg" );
108 long long maxAge = 0;
114 maxAge = std::max(
m_settings->m_Source.timeout_categories,
m_settings->m_Source.timeout_parts );
126 wxLogTrace(
traceHTTPLib, wxT(
"Initiating background refresh" ) );
130 std::map<std::string, HTTP_LIB_CATEGORY> categoryData;
131 bool fetchSuccess =
true;
135 std::vector<HTTP_LIB_PART> foundParts;
139 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: fetch failed for category %s" ),
141 fetchSuccess =
false;
147 categoryData[category.id] = std::move( cached );
153 bool dataChanged =
false;
165 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: new data" ) );
176 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh: no new data" ) );
182 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh failed: %s" ), e.
What() );
184 catch(
const std::exception& e )
186 wxLogTrace(
traceHTTPLib, wxT(
"Background refresh failed: %s" ), e.
what() );
193 m_refreshCV.wait_for( lock, std::chrono::seconds( maxAge ),
205 size_t signature = 0;
207 for(
const auto& [catId, category] : aCategoryData )
210 hash_combine( signature, std::string_view( category.name ) );
223 for(
const auto& [fieldName, fieldProps] : part.
fields )
225 hash_combine( signature, std::string_view( fieldName ) );
226 hash_combine( signature, std::string_view( std::get<0>( fieldProps ) ) );
243 if( std::optional<int> libHash =
m_adapter->GetLibraryModifyHash( nickname ) )
255 const std::map<std::string, HTTP_LIB_CATEGORY>& aCategoryData )
257 std::map<wxString, std::unique_ptr<LIB_SYMBOL>> newSymbolCache;
258 std::map<wxString, std::pair<std::string, std::string>> newPartIdMap;
259 std::set<wxString> newCustomFields;
265 wxString symbolName( part.
name );
266 newPartIdMap[symbolName] = { part.
id, category.id };
271 newSymbolCache[symbolName] = std::unique_ptr<LIB_SYMBOL>( symbol );
303 struct CACHE_LIB_GUARD
306 ~CACHE_LIB_GUARD() { *
flag =
false; }
311 std::map<std::string, HTTP_LIB_CATEGORY> categoryData;
315 std::vector<HTTP_LIB_PART> foundParts;
319 if( !
m_conn->GetLastError().empty() )
321 THROW_IO_ERROR( wxString::Format(
_(
"Error retrieving data from HTTP library %s: %s" ), category.name,
322 m_conn->GetLastError() ) );
330 categoryData[category.id] = std::move( cached );
355 const std::map<std::string, UTF8>* aProperties )
357 wxCHECK_RET(
m_adapter,
"HTTP plugin missing library manager adapter handle!" );
372 if( !powerSymbolsOnly || symbol->IsPower() )
373 aSymbolNameList.Add(
name );
379 const std::map<std::string, UTF8>* aProperties )
381 wxCHECK_RET(
m_adapter,
"HTTP plugin missing library manager adapter handle!" );
394 for(
const std::unique_ptr<LIB_SYMBOL>& symbol :
m_symbolCache | std::views::values )
396 if( !powerSymbolsOnly || symbol->IsPower() )
397 aSymbolList.emplace_back( symbol->Duplicate() );
403 const std::map<std::string, UTF8>* aProperties )
411 const std::map<std::string, UTF8>* aProperties )
413 wxCHECK_MSG(
m_adapter,
nullptr,
"HTTP plugin missing library manager adapter handle!" );
426 return it->second->Duplicate();
432 std::string categoryId;
439 partId = it->second.first;
440 categoryId = it->second.second;
446 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: no cached part found for %s" ), aAliasName );
454 if( category.id == categoryId )
456 foundCategory = &category;
463 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: no category found for %s" ), aAliasName );
471 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: SelectOne (%s) failed for category %s" ),
472 partId, foundCategory->
name );
473 THROW_IO_ERROR( wxString::Format(
_(
"Error retrieving part %s from HTTP library: %s" ),
474 partId,
m_conn->GetLastError() ) );
477 wxLogTrace(
traceHTTPLib, wxT(
"LoadSymbol: SelectOne (%s) found in %s" ),
478 partId, foundCategory->
name );
482 std::set<wxString> transientFields;
500 std::set<wxString> categoryNames;
504 if( categoryNames.count( categoryIter.name ) )
507 aNames.emplace_back( categoryIter.name );
508 categoryNames.insert( categoryIter.name );
519 return wxEmptyString;
521 return m_conn->getCategoryDescription( std::string( aName.mb_str() ) );
545 THROW_IO_ERRORF(
_(
"HTTP library settings file %s missing or invalid." ), aSettingsPath );
547 if(
m_settings->m_Source.api_version.empty() )
549 THROW_IO_ERRORF(
_(
"HTTP library settings file %s is missing the API version number." ),
555 THROW_IO_ERRORF(
_(
"HTTP library settings file %s uses API version %s, but KiCad requires "
563 THROW_IO_ERRORF(
_(
"HTTP library settings file %s is missing the root URL." ), aSettingsPath );
569 THROW_IO_ERRORF(
_(
"HTTP library settings file %s has invalid library type." ), aSettingsPath );
584 std::string
path( aSettingsPath.ToUTF8() );
598 wxLogTrace(
traceHTTPLib, wxT(
"ensureSettings: no settings available!" ) );
605 wxCHECK_RET(
m_settings,
"Call ensureSettings before ensureConnection!" );
616 wxCHECK_RET(
m_settings,
"Call ensureSettings before connect()!" );
626 m_conn = std::make_unique<HTTP_LIB_CONNECTION>(
m_settings->m_Source,
true );
628 if( !
m_conn->IsValidEndpoint() )
641 const wxString& aSymbolName,
644 std::set<wxString>& aCustomFields )
653 wxFileName libFileName( aLibraryPath );
654 wxString libNickname = libFileName.GetName();
657 if( !symbolIdStr.empty() )
659 symbolId.
Parse( symbolIdStr );
667 std::unordered_set<wxString>* set;
689 wxT(
"loadSymbolFromPart: cycle detected resolving '%s' "
690 "(part '%s'); skipping recursive load" ),
691 symbolIdStr, aSymbolName );
695 originalSymbol =
m_adapter->LoadSymbol( symbolId );
701 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: found original symbol '%s'" ),
706 symbol->
SetName( aSymbolName );
715 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol '%s' is a "
716 "self-reference, will create empty symbol" ),
721 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol id '%s' is invalid, "
722 "will create empty symbol" ), symbolIdStr );
726 wxLogTrace(
traceHTTPLib, wxT(
"loadSymbolFromPart: source symbol '%s' not found, "
727 "will create empty symbol" ), symbolIdStr );
749 wxArrayString fp_filters;
751 for(
auto& [fieldName, fieldProperties] : aPart.
fields )
753 wxString lowerFieldName = wxString( fieldName ).Lower();
758 wxStringTokenizer tokenizer( std::get<0>( fieldProperties ),
";\t\r\n", wxTOKEN_STRTOK );
760 while( tokenizer.HasMoreTokens() )
761 fp_filters.Add( tokenizer.GetNextToken() );
763 if( fp_filters.size() > 0 )
764 field->
SetText( fp_filters[0] );
766 field->
SetVisible( std::get<1>( fieldProperties ) );
771 field->
SetText( std::get<0>( fieldProperties ) );
772 field->
SetVisible( std::get<1>( fieldProperties ) );
777 field->
SetText( std::get<0>( fieldProperties ) );
778 field->
SetVisible( std::get<1>( fieldProperties ) );
783 field->
SetText( std::get<0>( fieldProperties ) );
784 field->
SetVisible( std::get<1>( fieldProperties ) );
789 field->
SetText( std::get<0>( fieldProperties ) );
790 field->
SetVisible( std::get<1>( fieldProperties ) );
794 symbol->
SetKeyWords( std::get<0>( fieldProperties ) );
805 if( field !=
nullptr )
808 field->
SetText( std::get<0>( fieldProperties ) );
809 field->
SetVisible( std::get<1>( fieldProperties ) );
817 field->
SetText( std::get<0>( fieldProperties ) );
818 field->
SetVisible( std::get<1>( fieldProperties ) );
821 aCustomFields.insert( fieldName );
827 if( !aPart.
desc.empty() )
834 fp_filters.push_back(
filter );
850 if( !aPart.
pin_map.empty() && !assignedFootprint.IsEmpty() )
852 const wxString mapName = wxS(
"HTTP Library" );
857 fpId.
Parse( assignedFootprint );
866 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()
const LIB_ID & GetLibId() const override
void SetSourceLibId(const LIB_ID &aLibId)
SCH_FIELD & GetDatasheetField()
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()
void SetAssociatedFootprints(std::vector< ASSOCIATED_FOOTPRINT > aList)
void SetDescription(const wxString &aDescription)
Set the Description field text value.
void SetKeyWords(const wxString &aKeyWords)
SCH_FIELD & GetValueField()
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()
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
#define THROW_IO_ERROR(msg)
macro which captures the "call site" values of FILE_, __FUNCTION & LINE
#define THROW_IO_ERRORF(msg,...)
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
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.