51#include <wx/datetime.h>
57#include <wx/mstream.h>
58#include <wx/settings.h>
60#include <wx/stdpaths.h>
61#include <wx/webview.h>
65#include <nlohmann/json.hpp>
70 std::vector<uint8_t>& aOutput,
71 wxString& aError )
const
73 if( aEncoded.empty() )
75 aError =
_(
"Missing payload data." );
79 wxMemoryBuffer buffer = wxBase64Decode( wxString::FromUTF8( aEncoded.c_str() ) );
81 if( buffer.IsEmpty() )
83 aError =
_(
"Failed to decode base64 payload." );
87 aOutput.resize( buffer.GetDataLen() );
88 memcpy( aOutput.data(), buffer.GetData(), buffer.GetDataLen() );
94 const std::vector<uint8_t>& aInput,
95 std::vector<uint8_t>& aOutput,
96 wxString& aError )
const
98 if( aCompression.empty() || aCompression ==
"NONE" )
104 if( aCompression !=
"ZSTD" )
106 aError = wxString::Format(
_(
"Unsupported compression '%s'." ),
107 wxString::FromUTF8( aCompression ) );
113 aError =
_(
"Compressed payload was empty." );
117 unsigned long long expectedSize = ZSTD_getFrameContentSize( aInput.data(), aInput.size() );
119 if( expectedSize == ZSTD_CONTENTSIZE_ERROR || expectedSize == ZSTD_CONTENTSIZE_UNKNOWN )
120 expectedSize =
static_cast<unsigned long long>( aInput.size() ) * 4;
122 static constexpr unsigned long long FALLBACK_MAX = 64ULL * 1024 * 1024;
126 ?
static_cast<unsigned long long>(
130 if( expectedSize > maxBytes )
132 aError = wxString::Format(
_(
"Decompressed size %llu exceeds limit %llu." ),
133 expectedSize, maxBytes );
137 aOutput.resize( expectedSize );
139 size_t decompressed = ZSTD_decompress( aOutput.data(), expectedSize, aInput.data(), aInput.size() );
141 if( ZSTD_isError( decompressed ) )
143 aError = wxString::Format(
_(
"ZSTD decompression failed: %s" ),
144 wxString::FromUTF8( ZSTD_getErrorName( decompressed ) ) );
148 aOutput.resize( decompressed );
155 wxString script = wxString::FromUTF8( aJson.c_str() );
156 script.Replace(
"\\",
"\\\\" );
157 script.Replace(
"'",
"\\'" );
174 wxBoxSizer* topSizer =
new wxBoxSizer( wxVERTICAL );
175 wxBoxSizer* controlsSizer =
new wxBoxSizer( wxHORIZONTAL );
191 topSizer->Add( controlsSizer, 0, wxEXPAND | wxALL, FromDIP( 4 ) );
192 SetSizer( topSizer );
224 m_webView->AddMessageHandler( wxS(
"kicad" ),
225 [
this](
const wxString& aPayload )
229 m_webView->SetHandleExternalLinks(
true );
232 if( wxWebView* browser =
m_webView->GetWebView() )
235 GetSizer()->Add(
m_webView, 1, wxEXPAND | wxLEFT | wxRIGHT | wxBOTTOM, FromDIP( 2 ) );
249 wxFileName cookieFile( wxStandardPaths::Get().GetUserDataDir(), wxEmptyString );
250 cookieFile.AppendDir( wxS(
"remote-provider-cookies" ) );
251 cookieFile.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
262 if( wxWebView* browser =
m_webView->GetWebView() )
275 if( wxWebView* browser =
m_webView->GetWebView() )
279 if( cookieFile.FileExists() )
295 if( cookieFile.FileExists() )
296 wxRemoveFile( cookieFile.GetFullPath() );
317 wxString label = entry.display_name_override.IsEmpty() ? entry.metadata_url : entry.display_name_override;
341 selected =
static_cast<int>( ii );
362 wxUnusedVar( aEvent );
372 wxUnusedVar( aEvent );
411 settings->m_RemoteSymbol.last_used_provider_id =
m_providerEntries[aIndex].provider_id;
420 const wxString& aAccessToken )
438 const wxString& aAccessToken )
443 if( !
m_providerClient.ExchangeBootstrapNonce( aMetadata, aAccessToken, nonceUrl, error ) )
445 wxLogWarning(
"Session bootstrap nonce exchange failed: %s", error.
message );
459 wxColour bgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOW );
460 wxColour fgColour = wxSystemSettings::GetColour( wxSYS_COLOUR_WINDOWTEXT );
463 html << wxS(
"<html><head><style>" )
464 << wxString::Format( wxS(
"body { background-color: #%02x%02x%02x; color: #%02x%02x%02x; "
465 "font-family: system-ui, sans-serif; padding: 10px; }" ),
466 bgColour.Red(), bgColour.Green(), bgColour.Blue(),
467 fgColour.Red(), fgColour.Green(), fgColour.Blue() )
468 << wxS(
"</style></head><body><p>" ) <<
EscapeHTML( aMessage )
469 << wxS(
"</p></body></html>" );
479 const wxString url = aEvent.GetURL();
481 if( !url.StartsWith( wxS(
"file://" ) ) )
503 nlohmann::json params = nlohmann::json::object();
504 params[
"client_name"] =
"KiCad";
516 const wxString script = wxString::Format( wxS(
"window.kiclient.postMessage('%s');" ),
523 nlohmann::json aParameters )
525 nlohmann::json envelope = nlohmann::json::object();
527 envelope[
"session_id"] =
m_sessionId.AsStdString();
529 envelope[
"command"] = aCommand.ToStdString();
530 envelope[
"status"] =
"OK";
531 envelope[
"response_to"] = aResponseTo;
533 if( !aParameters.is_null() && !aParameters.empty() )
534 envelope[
"parameters"] = std::move( aParameters );
541 const wxString& aErrorCode,
const wxString& aErrorMessage )
543 nlohmann::json envelope = nlohmann::json::object();
545 envelope[
"session_id"] =
m_sessionId.AsStdString();
547 envelope[
"command"] = aCommand.ToStdString();
548 envelope[
"status"] =
"ERROR";
549 envelope[
"response_to"] = aResponseTo;
550 envelope[
"error_code"] = aErrorCode.ToStdString();
551 envelope[
"error_message"] = aErrorMessage.ToStdString();
558 nlohmann::json envelope = nlohmann::json::object();
560 envelope[
"session_id"] =
m_sessionId.AsStdString();
562 envelope[
"command"] = aCommand.ToStdString();
563 envelope[
"status"] =
"OK";
565 if( !aParameters.is_null() && !aParameters.empty() )
566 envelope[
"parameters"] = std::move( aParameters );
574 wxScopedCharBuffer utf8 = aMessage.ToUTF8();
576 if( !utf8 || utf8.length() == 0 )
583 catch(
const std::exception& e )
585 wxLogWarning(
"Remote symbol RPC parse error: %s", e.what() );
598 std::optional<OAUTH_TOKEN_SET> tokens =
loadTokens( aProvider );
603 const long long now =
static_cast<long long>( wxDateTime::Now().GetTicks() );
605 if( tokens->expires_at == 0 || tokens->expires_at > now + 60 )
606 return tokens->access_token;
620 tokens->refresh_token, refreshed, error ) )
646 aError =
_(
"A remote provider sign-in flow is already in progress." );
662 wxArrayString scopes;
664 for(
const wxString& scope : aMetadata.
auth.
scopes )
678 aError =
_(
"Unable to start the local OAuth callback listener." );
688 aError =
_(
"Unable to open the system browser for sign-in." );
700 if( std::optional<OAUTH_TOKEN_SET> tokens =
loadTokens( aProvider ); tokens )
708 const wxString tokenToRevoke = !tokens->refresh_token.IsEmpty() ? tokens->refresh_token
709 : tokens->access_token;
712 tokenToRevoke, revokeError );
718 aError =
_(
"Failed to delete stored remote provider tokens." );
728 provider->last_account_label.clear();
729 provider->last_auth_status = wxS(
"signed_out" );
739 if( !aMessage.is_object() )
744 if( command.IsEmpty() )
747 auto messageIdIt = aMessage.find(
"message_id" );
749 if( messageIdIt == aMessage.end() || !messageIdIt->is_number_integer() )
752 const int messageId = messageIdIt->get<
int>();
753 const int version = aMessage.value(
"version", 0 );
757 sendRpcError( command, messageId, wxS(
"UNSUPPORTED_VERSION" ),
758 wxString::Format(
_(
"Unsupported RPC version %d." ), version ) );
764 if( sessionId.IsEmpty() )
766 sendRpcError( command, messageId, wxS(
"INVALID_PARAMETERS" ),
767 _(
"Missing session identifier." ) );
771 if( !sessionId.IsSameAs(
m_sessionId.AsString() ) )
773 sendRpcError( command, messageId, wxS(
"SESSION_MISMATCH" ),
774 _(
"Session identifier did not match the active provider session." ) );
778 nlohmann::json params = nlohmann::json::object();
779 auto paramsIt = aMessage.find(
"parameters" );
781 if( paramsIt != aMessage.end() && paramsIt->is_object() )
784 const std::string data = aMessage.value(
"data", std::string() );
786 if( command == wxS(
"NEW_SESSION" ) )
788 nlohmann::json reply = nlohmann::json::object();
789 reply[
"client_name"] =
"KiCad";
796 if( command == wxS(
"GET_KICAD_VERSION" ) )
798 nlohmann::json reply = nlohmann::json::object();
804 if( command == wxS(
"LIST_SUPPORTED_VERSIONS" ) )
806 nlohmann::json reply = nlohmann::json::object();
812 if( command == wxS(
"CAPABILITIES" ) )
814 nlohmann::json reply = nlohmann::json::object();
815 reply[
"commands"] = {
"NEW_SESSION",
"GET_KICAD_VERSION",
"LIST_SUPPORTED_VERSIONS",
816 "CAPABILITIES",
"GET_SOURCE_INFO",
"REMOTE_LOGIN",
"DL_SYMBOL",
817 "DL_COMPONENT",
"DL_FOOTPRINT",
"DL_SPICE",
"DL_3DMODEL",
819 reply[
"compression"] = {
"NONE",
"ZSTD" };
820 reply[
"max_message_size"] = 0;
825 if( command == wxS(
"GET_SOURCE_INFO" ) )
827 nlohmann::json reply = nlohmann::json::object();
838 bool authenticated =
false;
843 reply[
"authenticated"] = authenticated;
849 reply[
"supports_direct_downloads"] =
851 reply[
"supports_inline_payloads"] =
857 if( command == wxS(
"REMOTE_LOGIN" ) )
862 _(
"No remote provider is currently selected." ) );
867 const bool signOut = params.value(
"sign_out",
false );
868 const bool interactive = params.value(
"interactive",
true );
876 sendRpcError( command, messageId, wxS(
"SIGN_OUT_FAILED" ), error );
882 nlohmann::json reply = nlohmann::json::object();
883 reply[
"authenticated"] =
false;
884 reply[
"signed_out"] =
true;
891 if( !accessToken.IsEmpty() )
893 nlohmann::json reply = nlohmann::json::object();
894 reply[
"authenticated"] =
true;
895 reply[
"provider_id"] = provider.
provider_id.ToStdString();
902 nlohmann::json reply = nlohmann::json::object();
903 reply[
"authenticated"] =
false;
904 reply[
"auth_type"] =
"none";
911 nlohmann::json reply = nlohmann::json::object();
912 reply[
"authenticated"] =
false;
913 reply[
"started"] =
false;
922 sendRpcError( command, messageId, wxS(
"LOGIN_FAILED" ), error );
926 nlohmann::json reply = nlohmann::json::object();
927 reply[
"authenticated"] =
false;
928 reply[
"started"] =
true;
933 if( command == wxS(
"PLACE_COMPONENT" ) || command == wxS(
"DL_COMPONENT" ) || command == wxS(
"DL_SYMBOL" )
934 || command == wxS(
"DL_FOOTPRINT" ) || command == wxS(
"DL_3DMODEL" ) || command == wxS(
"DL_SPICE" ) )
936 const bool placeSymbol = command == wxS(
"PLACE_COMPONENT" )
938 const bool isComponent = command == wxS(
"DL_COMPONENT" ) || command == wxS(
"PLACE_COMPONENT" );
942 if( isComponent && params.contains(
"assets" ) && params[
"assets"].is_array() )
949 std::vector<uint8_t> decoded;
953 sendRpcError( command, messageId, wxS(
"INVALID_PAYLOAD" ), error );
957 std::vector<uint8_t> payload;
958 const std::string compressionStr =
959 compression.IsEmpty() ? std::string() : std::string( compression.ToUTF8().data() );
963 sendRpcError( command, messageId, wxS(
"INVALID_PAYLOAD" ), error );
969 else if( command == wxS(
"DL_SYMBOL" ) )
971 else if( command == wxS(
"DL_FOOTPRINT" ) )
973 else if( command == wxS(
"DL_3DMODEL" ) )
975 else if( command == wxS(
"DL_SPICE" ) )
982 sendRpcError( command, messageId, wxS(
"IMPORT_FAILED" ),
983 error.IsEmpty() ?
_(
"Unable to process provider payload." ) : error );
988 sendRpcError( command, messageId, wxS(
"UNKNOWN_COMMAND" ),
989 wxString::Format(
_(
"Command '%s' is not supported." ), command ) );
994 const std::vector<uint8_t>& aPayload,
996 const std::vector<LIB_ID>& aFootprintLinks )
999 const bool placeAfterDownload = mode.IsSameAs( wxS(
"PLACE" ),
false );
1001 if( !mode.IsEmpty() && !mode.IsSameAs( wxS(
"SAVE" ),
false ) && !placeAfterDownload )
1003 aError = wxString::Format(
_(
"Unsupported transfer mode '%s'." ), mode );
1009 aError =
_(
"Unsupported symbol payload type." );
1015 aError =
_(
"No schematic editor is available to store symbols." );
1023 aError =
_(
"Unable to load schematic settings." );
1032 wxFileName symDir = baseDir;
1033 symDir.AppendDir( wxS(
"symbols" ) );
1034 symDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1038 if( libItemName.IsEmpty() )
1039 libItemName = wxS(
"symbol" );
1043 if( libraryName.IsEmpty() )
1044 libraryName = wxS(
"symbols" );
1049 wxFileName outFile( symDir );
1050 outFile.SetFullName( nickname + wxS(
".kicad_sym" ) );
1060 aError =
_(
"Unable to access the symbol library manager." );
1064 std::unique_ptr<LIB_SYMBOL> downloadedSymbol =
1067 if( !downloadedSymbol )
1070 downloadedSymbol->SetName( libItemName );
1074 downloadedSymbol->SetLibId( savedId );
1080 aError =
_(
"Unable to save the downloaded symbol." );
1085 (void) downloadedSymbol.release();
1097 if( placeAfterDownload )
1105 const std::vector<uint8_t>& aPayload,
1106 bool aPlaceSymbol, wxString& aError )
1108 nlohmann::json components;
1112 components = nlohmann::json::parse( aPayload.begin(), aPayload.end() );
1114 catch(
const std::exception& e )
1116 aError = wxString::Format(
_(
"Failed to parse component list: %s" ), e.what() );
1120 if( !components.is_array() || components.empty() )
1122 aError =
_(
"Component list must be a non-empty array." );
1128 struct PreparedEntry
1131 nlohmann::json params;
1132 std::vector<uint8_t> content;
1135 std::vector<PreparedEntry> footprints;
1136 std::vector<PreparedEntry> others;
1137 std::vector<PreparedEntry> symbols;
1139 for(
const nlohmann::json& entry : components )
1141 if( !entry.is_object() )
1143 aError =
_(
"Component entries must be objects." );
1147 std::string entryType = entry.value(
"type",
"" );
1149 if( entryType.empty() )
1151 aError =
_(
"Component entry was missing a type." );
1155 std::transform( entryType.begin(), entryType.end(), entryType.begin(),
1156 [](
unsigned char c ) { return static_cast<char>( std::tolower( c ) ); } );
1158 std::vector<uint8_t> content;
1163 const std::string compression = entry.value(
"compression", std::string() );
1165 if( !compression.empty() && compression !=
"NONE" )
1167 std::vector<uint8_t> decoded = content;
1173 wxString entryName = wxString::FromUTF8( entry.value(
"name",
"" ) );
1174 nlohmann::json entryParams = nlohmann::json::object();
1176 if( !libraryName.IsEmpty() )
1177 entryParams[
"library"] = libraryName.ToStdString();
1179 if( !entryName.IsEmpty() )
1180 entryParams[
"name"] = entryName.ToStdString();
1182 if( entryType ==
"symbol" )
1184 entryParams[
"content_type"] =
"KICAD_SYMBOL_V1";
1185 entryParams[
"mode"] = aPlaceSymbol ?
"PLACE" :
"SAVE";
1186 symbols.push_back( { std::move( entryType ), std::move( entryParams ),
1187 std::move( content ) } );
1189 else if( entryType ==
"footprint" )
1191 entryParams[
"content_type"] =
"KICAD_FOOTPRINT_V1";
1192 entryParams[
"mode"] =
"SAVE";
1193 footprints.push_back( { std::move( entryType ), std::move( entryParams ),
1194 std::move( content ) } );
1196 else if( entryType ==
"3dmodel" )
1198 entryParams[
"content_type"] =
"KICAD_3D_MODEL_STEP";
1199 entryParams[
"mode"] =
"SAVE";
1200 others.push_back( { std::move( entryType ), std::move( entryParams ),
1201 std::move( content ) } );
1203 else if( entryType ==
"spice" )
1205 entryParams[
"content_type"] =
"KICAD_SPICE_MODEL_V1";
1206 entryParams[
"mode"] =
"SAVE";
1207 others.push_back( { std::move( entryType ), std::move( entryParams ),
1208 std::move( content ) } );
1212 aError = wxString::Format(
_(
"Unsupported component type '%s'." ),
1213 wxString::FromUTF8( entryType.c_str() ) );
1220 std::vector<LIB_ID> footprintLinks;
1222 for(
const PreparedEntry& entry : footprints )
1226 if( !
receiveFootprint( entry.params, entry.content, aError, &resolvedId ) )
1229 footprintLinks.push_back( resolvedId );
1232 for(
const PreparedEntry& entry : others )
1236 if( entry.type ==
"3dmodel" )
1245 for(
const PreparedEntry& entry : symbols )
1247 if( !
receiveSymbol( entry.params, entry.content, aError, footprintLinks ) )
1256 const std::vector<uint8_t>& aPayload,
1257 wxString& aError,
LIB_ID* aOutLibId )
1261 aError =
_(
"Unsupported footprint payload type." );
1270 wxFileName fpRoot = baseDir;
1271 fpRoot.AppendDir( wxS(
"footprints" ) );
1272 fpRoot.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1277 if( libraryName.IsEmpty() )
1278 libraryName = wxS(
"footprints" );
1287 wxFileName libDir = fpRoot;
1288 libDir.AppendDir( libNickname + wxS(
".pretty" ) );
1289 libDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1291 wxString fileName = fpItemName;
1293 if( !fileName.Lower().EndsWith( wxS(
".kicad_mod" ) ) )
1294 fileName += wxS(
".kicad_mod" );
1296 wxFileName outFile( libDir );
1297 outFile.SetFullName( fileName );
1306 aError =
_(
"Unable to load schematic settings." );
1323 *aOutLibId = resolvedId;
1330 const std::vector<uint8_t>& aPayload,
1338 wxFileName modelDir = baseDir;
1340 modelDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1344 if( fileName.IsEmpty() )
1349 wxFileName outFile( modelDir );
1350 outFile.SetFullName( fileName );
1356 const std::vector<uint8_t>& aPayload,
1364 wxFileName spiceDir = baseDir;
1366 spiceDir.Mkdir( wxS_DIR_DEFAULT, wxPATH_MKDIR_FULL );
1370 if( fileName.IsEmpty() )
1375 if( !fileName.Lower().EndsWith( wxS(
".cir" ) ) )
1376 fileName += wxS(
".cir" );
1378 wxFileName outFile( spiceDir );
1379 outFile.SetFullName( fileName );
1385 bool aPlaceSymbol, wxString& aError )
1389 aError =
_(
"Remote provider metadata is not loaded." );
1399 for(
const nlohmann::json& assetJson : aParams.at(
"assets" ) )
1409 asset.
required = assetJson.value(
"required",
false );
1411 auto sizeIt = assetJson.find(
"size_bytes" );
1413 if( sizeIt != assetJson.end() && sizeIt->is_number_integer() )
1419 aError =
_(
"Manifest assets require asset_type, content_type, size_bytes, and download_url." );
1423 manifest.
assets.push_back( asset );
1455 showMessage(
_(
"Remote provider sign-in was cancelled or failed." ) );
1463 aEvent.GetString(), tokens, error ) )
1482 showMessage(
_(
"Failed to store remote provider tokens securely." ) );
1490 provider->last_account_label = wxS(
"default" );
1491 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
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.
const wxString GetUniStringLibItemName() const
Get strings for display messages in dialogs.
const wxString GetUniStringLibNickname() const
static wxString GenerateCodeVerifier()
static wxString GenerateState()
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)
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)
bool receiveFootprint(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError, LIB_ID *aOutLibId=nullptr)
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
bool receiveSymbol(const nlohmann::json &aParams, const std::vector< uint8_t > &aPayload, wxString &aError, const std::vector< LIB_ID > &aFootprintLinks={})
void beginSessionHandshake()
void onOAuthLoopback(wxCommandEvent &aEvent)
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.
#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...
void ApplyFootprintLinks(LIB_SYMBOL &aSymbol, const std::vector< LIB_ID > &aLinks)
Apply a list of footprint LIB_IDs to a symbol about to be saved.
std::unique_ptr< LIB_SYMBOL > LoadRemoteSymbolFromPayload(const std::vector< uint8_t > &aPayload, const wxString &aLibItemName, wxString &aError)
Deserialize a remote-downloaded symbol payload into a LIB_SYMBOL.
LIB_ID BuildRemoteLibId(const wxString &aResolvedLibrary, const wxString &aResolvedItemName)
Build the local LIB_ID for a remote-downloaded library item.
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