52#include <wx/datetime.h>
58#include <wx/mstream.h>
59#include <wx/settings.h>
61#include <wx/stdpaths.h>
62#include <wx/webview.h>
66#include <nlohmann/json.hpp>
71 std::vector<uint8_t>& aOutput,
72 wxString& aError )
const
74 if( aEncoded.empty() )
76 aError =
_(
"Missing payload data." );
80 wxMemoryBuffer buffer = wxBase64Decode( wxString::FromUTF8( aEncoded.c_str() ) );
82 if( buffer.IsEmpty() )
84 aError =
_(
"Failed to decode base64 payload." );
88 aOutput.resize( buffer.GetDataLen() );
89 memcpy( aOutput.data(), buffer.GetData(), buffer.GetDataLen() );
95 const std::vector<uint8_t>& aInput,
96 std::vector<uint8_t>& aOutput,
97 wxString& aError )
const
99 if( aCompression.empty() || aCompression ==
"NONE" )
105 if( aCompression !=
"ZSTD" )
107 aError = wxString::Format(
_(
"Unsupported compression '%s'." ),
108 wxString::FromUTF8( aCompression ) );
114 aError =
_(
"Compressed payload was empty." );
118 unsigned long long expectedSize = ZSTD_getFrameContentSize( aInput.data(), aInput.size() );
120 if( expectedSize == ZSTD_CONTENTSIZE_ERROR || expectedSize == ZSTD_CONTENTSIZE_UNKNOWN )
121 expectedSize =
static_cast<unsigned long long>( aInput.size() ) * 4;
123 static constexpr unsigned long long FALLBACK_MAX = 64ULL * 1024 * 1024;
127 ?
static_cast<unsigned long long>(
131 if( expectedSize > maxBytes )
133 aError = wxString::Format(
_(
"Decompressed size %llu exceeds limit %llu." ),
134 expectedSize, maxBytes );
138 aOutput.resize( expectedSize );
140 size_t decompressed = ZSTD_decompress( aOutput.data(), expectedSize, aInput.data(), aInput.size() );
142 if( ZSTD_isError( decompressed ) )
144 aError = wxString::Format(
_(
"ZSTD decompression failed: %s" ),
145 wxString::FromUTF8( ZSTD_getErrorName( decompressed ) ) );
149 aOutput.resize( decompressed );
156 wxString script = wxString::FromUTF8( aJson.c_str() );
157 script.Replace(
"\\",
"\\\\" );
158 script.Replace(
"'",
"\\'" );
164 const wxString& aLibItemName,
165 wxString& aError )
const
167 if( aPayload.empty() )
169 aError =
_(
"Symbol payload was empty." );
173 wxString tempPath = wxFileName::CreateTempFileName( wxS(
"remote_symbol" ) );
175 if( tempPath.IsEmpty() )
177 aError =
_(
"Unable to create a temporary file for the symbol payload." );
181 wxFileName tempFile( tempPath );
182 wxFFile file( tempFile.GetFullPath(), wxS(
"wb" ) );
184 if( !file.IsOpened() )
186 aError =
_(
"Unable to create a temporary file for the symbol payload." );
187 wxRemoveFile( tempFile.GetFullPath() );
191 if( file.Write( aPayload.data(), aPayload.size() ) != aPayload.size() )
193 aError =
_(
"Failed to write the temporary symbol payload." );
195 wxRemoveFile( tempFile.GetFullPath() );
205 aError =
_(
"Unable to access the KiCad symbol plugin." );
206 wxRemoveFile( tempFile.GetFullPath() );
210 std::unique_ptr<LIB_SYMBOL> symbol;
214 LIB_SYMBOL* loaded = plugin->LoadSymbol( tempFile.GetFullPath(), aLibItemName );
217 symbol = std::make_unique<LIB_SYMBOL>( *loaded );
219 aError =
_(
"Symbol payload did not include the expected symbol." );
223 aError = wxString::Format(
_(
"Unable to decode the symbol payload: %s" ), e.
What() );
226 wxRemoveFile( tempFile.GetFullPath() );
243 wxBoxSizer* topSizer =
new wxBoxSizer( wxVERTICAL );
244 wxBoxSizer* controlsSizer =
new wxBoxSizer( wxHORIZONTAL );
260 topSizer->Add( controlsSizer, 0, wxEXPAND | wxALL, FromDIP( 4 ) );
261 SetSizer( topSizer );
293 m_webView->AddMessageHandler( wxS(
"kicad" ),
294 [
this](
const wxString& aPayload )
298 m_webView->SetHandleExternalLinks(
true );
301 if( wxWebView* browser =
m_webView->GetWebView() )
304 GetSizer()->Add(
m_webView, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP( 2 ) );
318 wxFileName cookieFile( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
319 cookieFile.AppendDir( wxS(
"remote-provider-cookies" ) );
320 cookieFile.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
331 if( wxWebView* browser =
m_webView->GetWebView() )
344 if( wxWebView* browser =
m_webView->GetWebView() )
348 if( cookieFile.FileExists() )
364 if( cookieFile.FileExists() )
365 wxRemoveFile( cookieFile.GetFullPath() );
386 wxString label = entry.display_name_override.IsEmpty() ? entry.metadata_url : entry.display_name_override;
410 selected =
static_cast<int>( ii );
431 wxUnusedVar( aEvent );
441 wxUnusedVar( aEvent );
480 settings->m_RemoteSymbol.last_used_provider_id =
m_providerEntries[aIndex].provider_id;
489 const wxString& aAccessToken )
507 const wxString& aAccessToken )
512 if( !
m_providerClient.ExchangeBootstrapNonce( aMetadata, aAccessToken, nonceUrl, error ) )
514 wxLogWarning(
"Session bootstrap nonce exchange failed: %s", error.
message );
528 wxColour bgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
529 wxColour fgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
532 html << wxS(
"<html><head><style>" )
533 << wxString::Format( wxS(
"body { background-color: #%02x%02x%02x; color: #%02x%02x%02x; "
534 "font-family: system-ui, sans-serif; padding: 10px; }" ),
535 bgColour.Red(), bgColour.Green(), bgColour.Blue(),
536 fgColour.Red(), fgColour.Green(), fgColour.Blue() )
537 << wxS(
"</style></head><body><p>" ) <<
EscapeHTML( aMessage )
538 << wxS(
"</p></body></html>" );
548 const wxString url = aEvent.GetURL();
550 if( !url.StartsWith( wxS(
"file://" ) ) )
572 nlohmann::json params = nlohmann::json::object();
573 params[
"client_name"] =
"KiCad";
585 const wxString script = wxString::Format( wxS(
"window.kiclient.postMessage('%s');" ),
592 nlohmann::json aParameters )
594 nlohmann::json envelope = nlohmann::json::object();
596 envelope[
"session_id"] =
m_sessionId.AsStdString();
598 envelope[
"command"] = aCommand.ToStdString();
599 envelope[
"status"] =
"OK";
600 envelope[
"response_to"] = aResponseTo;
602 if( !aParameters.is_null() && !aParameters.empty() )
603 envelope[
"parameters"] = std::move( aParameters );
610 const wxString& aErrorCode,
const wxString& aErrorMessage )
612 nlohmann::json envelope = nlohmann::json::object();
614 envelope[
"session_id"] =
m_sessionId.AsStdString();
616 envelope[
"command"] = aCommand.ToStdString();
617 envelope[
"status"] =
"ERROR";
618 envelope[
"response_to"] = aResponseTo;
619 envelope[
"error_code"] = aErrorCode.ToStdString();
620 envelope[
"error_message"] = aErrorMessage.ToStdString();
627 nlohmann::json envelope = nlohmann::json::object();
629 envelope[
"session_id"] =
m_sessionId.AsStdString();
631 envelope[
"command"] = aCommand.ToStdString();
632 envelope[
"status"] =
"OK";
634 if( !aParameters.is_null() && !aParameters.empty() )
635 envelope[
"parameters"] = std::move( aParameters );
643 wxScopedCharBuffer utf8 = aMessage.ToUTF8();
645 if( !utf8 || utf8.length() == 0 )
652 catch(
const std::exception& e )
654 wxLogWarning(
"Remote symbol RPC parse error: %s", e.what() );
667 std::optional<OAUTH_TOKEN_SET> tokens =
loadTokens( aProvider );
672 const long long now =
static_cast<long long>( wxDateTime::Now().GetTicks() );
674 if( tokens->expires_at == 0 || tokens->expires_at > now + 60 )
675 return tokens->access_token;
689 tokens->refresh_token, refreshed, error ) )
715 aError =
_(
"A remote provider sign-in flow is already in progress." );
731 wxArrayString scopes;
733 for(
const wxString& scope : aMetadata.
auth.
scopes )
747 aError =
_(
"Unable to start the local OAuth callback listener." );
757 aError =
_(
"Unable to open the system browser for sign-in." );
769 if( std::optional<OAUTH_TOKEN_SET> tokens =
loadTokens( aProvider ); tokens )
777 const wxString tokenToRevoke = !tokens->refresh_token.IsEmpty() ? tokens->refresh_token
778 : tokens->access_token;
781 tokenToRevoke, revokeError );
787 aError =
_(
"Failed to delete stored remote provider tokens." );
797 provider->last_account_label.clear();
798 provider->last_auth_status = wxS(
"signed_out" );
808 if( !aMessage.is_object() )
813 if( command.IsEmpty() )
816 auto messageIdIt = aMessage.find(
"message_id" );
818 if( messageIdIt == aMessage.end() || !messageIdIt->is_number_integer() )
821 const int messageId = messageIdIt->get<
int>();
822 const int version = aMessage.value(
"version", 0 );
826 sendRpcError( command, messageId, wxS(
"UNSUPPORTED_VERSION" ),
827 wxString::Format(
_(
"Unsupported RPC version %d." ), version ) );
833 if( sessionId.IsEmpty() )
835 sendRpcError( command, messageId, wxS(
"INVALID_PARAMETERS" ),
836 _(
"Missing session identifier." ) );
840 if( !sessionId.IsSameAs(
m_sessionId.AsString() ) )
842 sendRpcError( command, messageId, wxS(
"SESSION_MISMATCH" ),
843 _(
"Session identifier did not match the active provider session." ) );
847 nlohmann::json params = nlohmann::json::object();
848 auto paramsIt = aMessage.find(
"parameters" );
850 if( paramsIt != aMessage.end() && paramsIt->is_object() )
853 const std::string data = aMessage.value(
"data", std::string() );
855 if( command == wxS(
"NEW_SESSION" ) )
857 nlohmann::json reply = nlohmann::json::object();
858 reply[
"client_name"] =
"KiCad";
865 if( command == wxS(
"GET_KICAD_VERSION" ) )
867 nlohmann::json reply = nlohmann::json::object();
873 if( command == wxS(
"LIST_SUPPORTED_VERSIONS" ) )
875 nlohmann::json reply = nlohmann::json::object();
881 if( command == wxS(
"CAPABILITIES" ) )
883 nlohmann::json reply = nlohmann::json::object();
884 reply[
"commands"] = {
"NEW_SESSION",
"GET_KICAD_VERSION",
"LIST_SUPPORTED_VERSIONS",
885 "CAPABILITIES",
"GET_SOURCE_INFO",
"REMOTE_LOGIN",
"DL_SYMBOL",
886 "DL_COMPONENT",
"DL_FOOTPRINT",
"DL_SPICE",
"DL_3DMODEL",
888 reply[
"compression"] = {
"NONE",
"ZSTD" };
889 reply[
"max_message_size"] = 0;
894 if( command == wxS(
"GET_SOURCE_INFO" ) )
896 nlohmann::json reply = nlohmann::json::object();
907 bool authenticated =
false;
912 reply[
"authenticated"] = authenticated;
918 reply[
"supports_direct_downloads"] =
920 reply[
"supports_inline_payloads"] =
926 if( command == wxS(
"REMOTE_LOGIN" ) )
931 _(
"No remote provider is currently selected." ) );
936 const bool signOut = params.value(
"sign_out",
false );
937 const bool interactive = params.value(
"interactive",
true );
945 sendRpcError( command, messageId, wxS(
"SIGN_OUT_FAILED" ), error );
951 nlohmann::json reply = nlohmann::json::object();
952 reply[
"authenticated"] =
false;
953 reply[
"signed_out"] =
true;
960 if( !accessToken.IsEmpty() )
962 nlohmann::json reply = nlohmann::json::object();
963 reply[
"authenticated"] =
true;
964 reply[
"provider_id"] = provider.
provider_id.ToStdString();
971 nlohmann::json reply = nlohmann::json::object();
972 reply[
"authenticated"] =
false;
973 reply[
"auth_type"] =
"none";
980 nlohmann::json reply = nlohmann::json::object();
981 reply[
"authenticated"] =
false;
982 reply[
"started"] =
false;
991 sendRpcError( command, messageId, wxS(
"LOGIN_FAILED" ), error );
995 nlohmann::json reply = nlohmann::json::object();
996 reply[
"authenticated"] =
false;
997 reply[
"started"] =
true;
1002 if( command == wxS(
"PLACE_COMPONENT" ) || command == wxS(
"DL_COMPONENT" ) || command == wxS(
"DL_SYMBOL" )
1003 || command == wxS(
"DL_FOOTPRINT" ) || command == wxS(
"DL_3DMODEL" ) || command == wxS(
"DL_SPICE" ) )
1005 const bool placeSymbol = command == wxS(
"PLACE_COMPONENT" )
1007 const bool isComponent = command == wxS(
"DL_COMPONENT" ) || command == wxS(
"PLACE_COMPONENT" );
1011 if( isComponent && params.contains(
"assets" ) && params[
"assets"].is_array() )
1018 std::vector<uint8_t> decoded;
1022 sendRpcError( command, messageId, wxS(
"INVALID_PAYLOAD" ), error );
1026 std::vector<uint8_t> payload;
1027 const std::string compressionStr =
1028 compression.IsEmpty() ? std::string() : std::string( compression.ToUTF8().data() );
1032 sendRpcError( command, messageId, wxS(
"INVALID_PAYLOAD" ), error );
1038 else if( command == wxS(
"DL_SYMBOL" ) )
1040 else if( command == wxS(
"DL_FOOTPRINT" ) )
1042 else if( command == wxS(
"DL_3DMODEL" ) )
1044 else if( command == wxS(
"DL_SPICE" ) )
1051 sendRpcError( command, messageId, wxS(
"IMPORT_FAILED" ),
1052 error.IsEmpty() ?
_(
"Unable to process provider payload." ) : error );
1057 sendRpcError( command, messageId, wxS(
"UNKNOWN_COMMAND" ),
1058 wxString::Format(
_(
"Command '%s' is not supported." ), command ) );
1063 const std::vector<uint8_t>& aPayload,
1067 const bool placeAfterDownload = mode.IsSameAs( wxS(
"PLACE" ),
false );
1069 if( !mode.IsEmpty() && !mode.IsSameAs( wxS(
"SAVE" ),
false ) && !placeAfterDownload )
1071 aError = wxString::Format(
_(
"Unsupported transfer mode '%s'." ), mode );
1077 aError =
_(
"Unsupported symbol payload type." );
1083 aError =
_(
"No schematic editor is available to store symbols." );
1091 aError =
_(
"Unable to load schematic settings." );
1100 wxFileName symDir = baseDir;
1101 symDir.AppendDir( wxS(
"symbols" ) );
1102 symDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1106 if( libItemName.IsEmpty() )
1107 libItemName = wxS(
"symbol" );
1111 if( libraryName.IsEmpty() )
1112 libraryName = wxS(
"symbols" );
1117 wxFileName outFile( symDir );
1118 outFile.SetFullName( nickname + wxS(
".kicad_sym" ) );
1128 aError =
_(
"Unable to access the symbol library manager." );
1132 std::unique_ptr<LIB_SYMBOL> downloadedSymbol =
loadSymbolFromPayload( aPayload, libItemName, aError );
1134 if( !downloadedSymbol )
1137 downloadedSymbol->SetName( libItemName );
1141 downloadedSymbol->SetLibId( savedId );
1145 aError =
_(
"Unable to save the downloaded symbol." );
1159 if( placeAfterDownload )
1167 const std::vector<uint8_t>& aPayload,
1168 bool aPlaceSymbol, wxString& aError )
1170 nlohmann::json components;
1174 components = nlohmann::json::parse( aPayload.begin(), aPayload.end() );
1176 catch(
const std::exception& e )
1178 aError = wxString::Format(
_(
"Failed to parse component list: %s" ), e.what() );
1182 if( !components.is_array() || components.empty() )
1184 aError =
_(
"Component list must be a non-empty array." );
1190 for(
const nlohmann::json& entry : components )
1192 if( !entry.is_object() )
1194 aError =
_(
"Component entries must be objects." );
1198 std::string entryType = entry.value(
"type",
"" );
1200 if( entryType.empty() )
1202 aError =
_(
"Component entry was missing a type." );
1206 std::transform( entryType.begin(), entryType.end(), entryType.begin(),
1207 [](
unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
1209 std::vector<uint8_t> content;
1214 const std::string compression = entry.value(
"compression", std::string() );
1216 if( !compression.empty() && compression !=
"NONE" )
1218 std::vector<uint8_t> decoded = content;
1224 wxString entryName = wxString::FromUTF8( entry.value(
"name",
"" ) );
1225 nlohmann::json entryParams = nlohmann::json::object();
1227 if( !libraryName.IsEmpty() )
1228 entryParams[
"library"] = libraryName.ToStdString();
1230 if( !entryName.IsEmpty() )
1231 entryParams[
"name"] = entryName.ToStdString();
1235 if( entryType ==
"symbol" )
1237 entryParams[
"content_type"] =
"KICAD_SYMBOL_V1";
1238 entryParams[
"mode"] = aPlaceSymbol ?
"PLACE" :
"SAVE";
1241 else if( entryType ==
"footprint" )
1243 entryParams[
"content_type"] =
"KICAD_FOOTPRINT_V1";
1244 entryParams[
"mode"] =
"SAVE";
1247 else if( entryType ==
"3dmodel" )
1249 entryParams[
"content_type"] =
"KICAD_3D_MODEL_STEP";
1250 entryParams[
"mode"] =
"SAVE";
1253 else if( entryType ==
"spice" )
1255 entryParams[
"content_type"] =
"KICAD_SPICE_MODEL_V1";
1256 entryParams[
"mode"] =
"SAVE";
1261 aError = wxString::Format(
_(
"Unsupported component type '%s'." ),
1262 wxString::FromUTF8( entryType.c_str() ) );
1275 const std::vector<uint8_t>& aPayload,
1280 aError =
_(
"Unsupported footprint payload type." );
1289 wxFileName fpRoot = baseDir;
1290 fpRoot.AppendDir( wxS(
"footprints" ) );
1291 fpRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1296 if( libraryName.IsEmpty() )
1297 libraryName = wxS(
"footprints" );
1302 wxFileName libDir = fpRoot;
1303 libDir.AppendDir( libNickname + wxS(
".pretty" ) );
1304 libDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1306 if( !footprintName.Lower().EndsWith( wxS(
".kicad_mod" ) ) )
1307 footprintName += wxS(
".kicad_mod" );
1309 wxFileName outFile( libDir );
1310 outFile.SetFullName( footprintName );
1319 aError =
_(
"Unable to load schematic settings." );
1339 const std::vector<uint8_t>& aPayload,
1347 wxFileName modelDir = baseDir;
1349 modelDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1353 if( fileName.IsEmpty() )
1358 wxFileName outFile( modelDir );
1359 outFile.SetFullName( fileName );
1365 const std::vector<uint8_t>& aPayload,
1373 wxFileName spiceDir = baseDir;
1375 spiceDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1379 if( fileName.IsEmpty() )
1384 if( !fileName.Lower().EndsWith( wxS(
".cir" ) ) )
1385 fileName += wxS(
".cir" );
1387 wxFileName outFile( spiceDir );
1388 outFile.SetFullName( fileName );
1394 bool aPlaceSymbol, wxString& aError )
1398 aError =
_(
"Remote provider metadata is not loaded." );
1408 for(
const nlohmann::json& assetJson : aParams.at(
"assets" ) )
1418 asset.
required = assetJson.value(
"required",
false );
1420 auto sizeIt = assetJson.find(
"size_bytes" );
1422 if( sizeIt != assetJson.end() && sizeIt->is_number_integer() )
1428 aError =
_(
"Manifest assets require asset_type, content_type, size_bytes, and download_url." );
1432 manifest.
assets.push_back( asset );
1464 showMessage(
_(
"Remote provider sign-in was cancelled or failed." ) );
1472 aEvent.GetString(), tokens, error ) )
1491 showMessage(
_(
"Failed to store remote provider tokens securely." ) );
1499 provider->last_account_label = wxS(
"default" );
1500 provider->last_auth_status = wxS(
"signed_in" );
wxBitmapBundle KiBitmapBundle(BITMAPS aBitmap, int aMinHeight)
wxString GetSemanticVersion()
Get the semantic version string for KiCad defined inside the KiCadVersion.cmake file in the variable ...
REMOTE_PROVIDER_SETTINGS m_RemoteSymbol
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()
void ReloadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname, LIBRARY_TABLE_SCOPE aScope=LIBRARY_TABLE_SCOPE::BOTH)
std::optional< LIB_STATUS > LoadLibraryEntry(LIBRARY_TABLE_TYPE aType, const wxString &aNickname)
Synchronously loads the named library to LOADED state for the given type.
A logical library item identifier and consists of various portions much like a URI.
int SetLibItemName(const UTF8 &aLibItemName)
Override the library item name portion of the LIB_ID to aLibItemName.
int SetLibNickname(const UTF8 &aLibNickname)
Override the logical library name portion of the LIB_ID to aLibNickname.
Define a library symbol object.
static wxString GenerateCodeVerifier()
static wxString GenerateState()
bool receiveSymbol(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError)
void onWebViewLoaded(wxWebViewEvent &aEvent)
void onKicadMessage(const wxString &aMessage)
void showMessage(const wxString &aMessage)
wxString m_pendingProviderId
void handleRpcMessage(const nlohmann::json &aMessage)
wxFileName cookieFilePath(const wxString &aProviderId) const
void loadProviderPage(const REMOTE_PROVIDER_METADATA &aMetadata, const wxString &aAccessToken)
bool receiveFootprint(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError)
void sendRpcError(const wxString &aCommand, int aResponseTo, const wxString &aErrorCode, const wxString &aErrorMessage)
int m_selectedProviderIndex
bool loadProvider(int aIndex)
bool signOutProvider(const REMOTE_PROVIDER_ENTRY &aProvider, wxString &aError)
OAUTH_SESSION m_pendingOAuthSession
bool receiveComponentManifest(const nlohmann::json &aParams, bool aPlaceSymbol, wxString &aError)
void sendRpcEnvelope(nlohmann::json aEnvelope)
bool m_hasSelectedProviderMetadata
PANEL_REMOTE_SYMBOL(SCH_EDIT_FRAME *aParent)
wxChoice * m_dataSourceChoice
bool decompressIfNeeded(const std::string &aCompression, const std::vector< uint8_t > &aInput, std::vector< uint8_t > &aOutput, wxString &aError) const
REMOTE_PROVIDER_METADATA m_selectedProviderMetadata
bool decodeBase64Payload(const std::string &aMessage, std::vector< uint8_t > &aOutPayload, wxString &aError) const
void RefreshDataSources()
void clearCookies(bool aDeleteSavedCookieFile=true)
wxString sanitizeForScript(const std::string &aJson) const
void beginSessionHandshake()
void onOAuthLoopback(wxCommandEvent &aEvent)
std::unique_ptr< LIB_SYMBOL > loadSymbolFromPayload(const std::vector< uint8_t > &aPayload, const wxString &aLibItemName, wxString &aError) const
void onConfigure(wxCommandEvent &aEvent)
bool receiveComponent(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, bool aPlaceSymbol, wxString &aError)
void sendRpcReply(const wxString &aCommand, int aResponseTo, nlohmann::json aParameters=nlohmann::json::object())
bool startInteractiveLogin(const REMOTE_PROVIDER_ENTRY &aProvider, const REMOTE_PROVIDER_METADATA &aMetadata, wxString &aError)
std::vector< REMOTE_PROVIDER_ENTRY > m_providerEntries
wxString loadAccessToken(const REMOTE_PROVIDER_ENTRY &aProvider)
void sendRpcNotification(const wxString &aCommand, nlohmann::json aParameters=nlohmann::json::object())
bool receiveSPICEModel(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError)
BITMAP_BUTTON * m_configButton
void onDarkModeToggle(wxSysColourChangedEvent &aEvent)
REMOTE_PROVIDER_CLIENT m_providerClient
SECURE_TOKEN_STORE m_tokenStore
WEBVIEW_PANEL * m_webView
bool receive3DModel(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError)
BITMAP_BUTTON * m_refreshButton
~PANEL_REMOTE_SYMBOL() override
void onRefresh(wxCommandEvent &aEvent)
void bootstrapAuthenticatedSession(const REMOTE_PROVIDER_METADATA &aMetadata, const wxString &aAccessToken)
REMOTE_PROVIDER_OAUTH_SERVER_METADATA m_pendingOAuthMetadata
std::unique_ptr< OAUTH_LOOPBACK_SERVER > m_oauthLoopbackServer
std::optional< OAUTH_TOKEN_SET > loadTokens(const REMOTE_PROVIDER_ENTRY &aProvider) const
void onDataSourceChanged(wxCommandEvent &aEvent)
virtual LIBRARY_MANAGER & GetLibraryManager() const
static SYMBOL_LIBRARY_ADAPTER * SymbolLibAdapter(PROJECT *aProject)
Accessor for project symbol library manager adapter.
bool Import(const REMOTE_PROVIDER_METADATA &aProvider, const REMOTE_SYMBOL_IMPORT_CONTEXT &aContext, const REMOTE_PROVIDER_PART_MANIFEST &aManifest, bool aPlaceSymbol, wxString &aError)
Schematic editor (Eeschema) main window.
An interface to the global shared library manager that is schematic-specific and linked to one projec...
std::optional< LIB_STATUS > LoadOne(LIB_DATA *aLib) override
Loads or reloads the given library, if it exists.
SAVE_T SaveSymbol(const wxString &aNickname, const LIB_SYMBOL *aSymbol, bool aOverwrite=true)
Write aSymbol to an existing library given by aNickname.
std::unique_ptr< T > IO_RELEASER
Helper to hold and release an IO_BASE object when exceptions are thrown.
#define REMOTE_SYMBOL_SESSION_VERSION
PGM_BASE & Pgm()
The global program "get" accessor.
wxString RemoteProviderJsonString(const nlohmann::json &aObject, const char *aKey)
Extract an optional string value from a JSON object, returning an empty wxString when the key is abse...
bool PlaceRemoteDownloadedSymbol(SCH_EDIT_FRAME *aFrame, const wxString &aNickname, const wxString &aLibItemName, wxString &aError)
Place a symbol from a remote download into the schematic editor.
bool EnsureRemoteLibraryEntry(LIBRARY_TABLE_TYPE aTableType, const wxFileName &aLibraryPath, const wxString &aNickname, bool aGlobalTable, bool aStrict, wxString &aError)
Add or update a library table entry for a remote download library.
bool WriteRemoteBinaryFile(const wxFileName &aOutput, const std::vector< uint8_t > &aPayload, wxString &aError)
Write binary data to a file, creating parent directories as needed.
bool EnsureRemoteDestinationRoot(wxFileName &aOutDir, wxString &aError)
Resolve and create the configured destination root directory for remote symbol downloads.
wxString RemoteLibraryPrefix()
Return the configured (or default) library prefix for remote downloads, sanitized for use as a filena...
wxString SanitizeRemoteFileComponent(const wxString &aValue, const wxString &aDefault, bool aLower)
Replace non-alphanumeric characters (other than _ - .) with underscores.
T * GetAppSettings(const char *aFilename)
wxString EscapeHTML(const wxString &aString)
Return a new wxString escaped for embedding in HTML.
std::vector< REMOTE_PROVIDER_PART_ASSET > assets
std::vector< REMOTE_PROVIDER_ENTRY > providers
wxString last_used_provider_id