Browse Source
ADDED: A new IPC API based on protobuf and nng
ADDED: A new IPC API based on protobuf and nng
Details, documentation, and language bindings are works in progress and will be evolving over the course of KiCad 9 development.newinvert
75 changed files with 6286 additions and 41 deletions
-
34CMakeLists.txt
-
118api/CMakeLists.txt
-
43api/enums/CMakeLists.txt
-
91api/enums/enum_exporter.cpp
-
110api/proto/board/board_types.proto
-
33api/proto/common/commands/base_commands.proto
-
251api/proto/common/commands/editor_commands.proto
-
90api/proto/common/envelope.proto
-
217api/proto/common/types/base_types.proto
-
26cmake/Findnng.cmake
-
27common/CMakeLists.txt
-
5common/advanced_config.cpp
-
74common/api/api_handler.cpp
-
52common/api/api_handler_common.cpp
-
193common/api/api_server.cpp
-
109common/dialogs/panel_python_settings.cpp
-
70common/dialogs/panel_python_settings_base.cpp
-
371common/dialogs/panel_python_settings_base.fbp
-
56common/dialogs/panel_python_settings_base.h
-
5common/eda_base_frame.cpp
-
6common/kiid.cpp
-
11common/paths.cpp
-
4common/pgm_base.cpp
-
6common/settings/common_settings.cpp
-
17common/single_top.cpp
-
2common/tool/tool_manager.cpp
-
4eeschema/sch_marker.cpp
-
4eeschema/sch_marker.h
-
10eeschema/schematic.cpp
-
7include/advanced_config.h
-
137include/api/api_handler.h
-
42include/api/api_handler_common.h
-
97include/api/api_server.h
-
49include/dialogs/panel_python_settings.h
-
6include/eda_item.h
-
1include/kiid.h
-
5include/layer_ids.h
-
5include/paths.h
-
11include/pgm_base.h
-
4include/properties/property.h
-
7include/settings/common_settings.h
-
5kicad/CMakeLists.txt
-
16kicad/kicad.cpp
-
4libs/CMakeLists.txt
-
38libs/kinng/CMakeLists.txt
-
64libs/kinng/include/kinng.h
-
129libs/kinng/src/kinng.cpp
-
10pcbnew/CMakeLists.txt
-
493pcbnew/api/api_handler_pcb.cpp
-
86pcbnew/api/api_handler_pcb.h
-
6pcbnew/board.cpp
-
12pcbnew/dialogs/dialog_drc.cpp
-
20pcbnew/pcb_edit_frame.cpp
-
9pcbnew/pcb_edit_frame.h
-
6pcbnew/pcb_marker.cpp
-
4pcbnew/pcb_marker.h
-
194pcbnew/pcb_track.cpp
-
9pcbnew/pcb_track.h
-
4qa/tests/libs/CMakeLists.txt
-
41qa/tests/libs/kinng/CMakeLists.txt
-
22qa/tests/libs/kinng/kinng_test_module.cpp
-
34qa/tests/libs/kinng/test_kinng.cpp
-
2qa/tests/pcbnew/drc/test_custom_rule_severities.cpp
-
2qa/tests/pcbnew/drc/test_drc_copper_graphics.cpp
-
2qa/tests/pcbnew/drc/test_drc_regressions.cpp
-
2qa/tests/pcbnew/drc/test_solder_mask_bridging.cpp
-
1scripting/CMakeLists.txt
-
73scripting/python_manager.cpp
-
48scripting/python_manager.h
-
1thirdparty/CMakeLists.txt
-
7thirdparty/expected/CMakeLists.txt
-
121thirdparty/expected/COPYING
-
4thirdparty/expected/README.txt
-
2444thirdparty/expected/include/tl/expected.hpp
-
4vcpkg.json
@ -0,0 +1,118 @@ |
|||||
|
# This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
# |
||||
|
# Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors. |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify it |
||||
|
# under the terms of the GNU General Public License as published by the |
||||
|
# Free Software Foundation, either version 3 of the License, or (at your |
||||
|
# option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, but |
||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
# General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
|
||||
|
# Search paths for protoc when generating code |
||||
|
set( Protobuf_IMPORT_DIRS ${Protobuf_INCLUDE_DIR} ${CMAKE_CURRENT_SOURCE_DIR}/proto ) |
||||
|
|
||||
|
set( KIAPI_PROTO_SRCS |
||||
|
common/envelope.proto |
||||
|
|
||||
|
common/types/base_types.proto |
||||
|
|
||||
|
common/commands/base_commands.proto |
||||
|
common/commands/editor_commands.proto |
||||
|
|
||||
|
board/board_types.proto |
||||
|
) |
||||
|
|
||||
|
# Generated C++ code must be in the build dir; it is dependent on the version of protoc installed |
||||
|
set( KIAPI_CPP_BASEPATH ${CMAKE_CURRENT_BINARY_DIR}/cpp/api ) |
||||
|
|
||||
|
foreach( PROTO_SRC ${KIAPI_PROTO_SRCS} ) |
||||
|
string( REGEX REPLACE "\.proto$" ".pb.cc" CPP_SRC ${PROTO_SRC} ) |
||||
|
string( REGEX REPLACE "\.proto$" ".pb.h" CPP_HEADER ${PROTO_SRC} ) |
||||
|
set( KIAPI_CPP_SRCS ${KIAPI_CPP_SRCS} ${KIAPI_CPP_BASEPATH}/${CPP_SRC} ) |
||||
|
set( KIAPI_CPP_HEADERS ${KIAPI_CPP_HEADERS} ${KIAPI_CPP_BASEPATH}/${CPP_HEADER} ) |
||||
|
set( KIAPI_PROTO_SRC_FULLPATHS ${KIAPI_PROTO_SRC_FULLPATHS} ${CMAKE_CURRENT_SOURCE_DIR}/proto/${PROTO_SRC} ) |
||||
|
endforeach () |
||||
|
|
||||
|
add_custom_command( COMMAND ${CMAKE_COMMAND} -E make_directory ${KIAPI_CPP_BASEPATH} |
||||
|
COMMAND ${Protobuf_PROTOC_EXECUTABLE} |
||||
|
--cpp_out=dllexport_decl=KIAPI_IMPORTEXPORT:${KIAPI_CPP_BASEPATH} |
||||
|
--proto_path=${CMAKE_CURRENT_SOURCE_DIR}/proto |
||||
|
${KIAPI_PROTO_SRCS} |
||||
|
COMMENT "Generating API protobuf source files from proto definitions..." |
||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |
||||
|
DEPENDS ${KIAPI_PROTO_SRC_FULLPATHS} |
||||
|
OUTPUT ${KIAPI_CPP_SRCS} ${KIAPI_CPP_HEADERS} |
||||
|
) |
||||
|
|
||||
|
# kiapi must be a shared DLL because the protobuf messages can only be initialized once |
||||
|
add_library( kiapi SHARED |
||||
|
${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h |
||||
|
${KIAPI_CPP_SRCS} |
||||
|
${KIAPI_CPP_HEADERS} |
||||
|
) |
||||
|
|
||||
|
target_compile_definitions( kiapi PRIVATE KIAPI_IMPORTEXPORT=APIEXPORT ) |
||||
|
target_compile_definitions( kiapi INTERFACE KIAPI_IMPORTEXPORT=APIIMPORT ) |
||||
|
|
||||
|
# https://groups.google.com/g/protobuf/c/PDR1bqRazts |
||||
|
if(MSVC) |
||||
|
target_compile_options( kiapi PRIVATE /FI${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h ) |
||||
|
else() |
||||
|
add_definitions( -include ${CMAKE_CURRENT_SOURCE_DIR}/../include/import_export.h ) |
||||
|
endif() |
||||
|
|
||||
|
if( APPLE ) |
||||
|
# puts library into the main kicad.app bundle in build tree |
||||
|
set_target_properties( kiapi PROPERTIES |
||||
|
LIBRARY_OUTPUT_DIRECTORY "${OSX_BUNDLE_BUILD_LIB_DIR}" |
||||
|
INSTALL_NAME_DIR "${OSX_BUNDLE_BUILD_LIB_DIR}" |
||||
|
) |
||||
|
endif() |
||||
|
|
||||
|
install( TARGETS |
||||
|
kiapi |
||||
|
RUNTIME DESTINATION ${KICAD_LIB} |
||||
|
LIBRARY DESTINATION ${KICAD_LIB} |
||||
|
COMPONENT binary |
||||
|
) |
||||
|
|
||||
|
if( KICAD_WIN32_INSTALL_PDBS ) |
||||
|
# Get the PDBs to copy over for MSVC |
||||
|
install(FILES $<TARGET_PDB_FILE:kiapi> DESTINATION ${KICAD_BIN}) |
||||
|
endif() |
||||
|
|
||||
|
# Because CMake doesn't guess this from the .cc extension generated by protoc |
||||
|
set_target_properties( kiapi PROPERTIES LINKER_LANGUAGE CXX ) |
||||
|
|
||||
|
target_include_directories( kiapi SYSTEM PUBLIC ${Protobuf_INCLUDE_DIRS} ) |
||||
|
|
||||
|
target_link_libraries( kiapi protobuf::libprotobuf ) |
||||
|
|
||||
|
target_include_directories( kiapi INTERFACE |
||||
|
${CMAKE_CURRENT_BINARY_DIR}/cpp # Leaving off the /api/ to make #include statments less ambiguous |
||||
|
) |
||||
|
|
||||
|
# Because when building internally, the generated files do not include the "api" base path |
||||
|
target_include_directories( kiapi PUBLIC ${KIAPI_CPP_BASEPATH} ) |
||||
|
|
||||
|
option( KICAD_BUILD_ENUM_EXPORTER |
||||
|
"Build the enum exporter used as part of generating the IPC APIs" |
||||
|
OFF ) |
||||
|
|
||||
|
if( KICAD_BUILD_ENUM_EXPORTER ) |
||||
|
add_subdirectory( enums ) |
||||
|
|
||||
|
add_custom_target( enum_definitions |
||||
|
COMMAND $<TARGET_FILE:enum_exporter> ${CMAKE_CURRENT_BINARY_DIR}/enums.json |
||||
|
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR} |
||||
|
COMMENT "Generating API definitions from KiCad enums..." |
||||
|
DEPENDS enum_exporter |
||||
|
) |
||||
|
endif() |
||||
@ -0,0 +1,43 @@ |
|||||
|
# This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
# |
||||
|
# Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors. |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify it |
||||
|
# under the terms of the GNU General Public License as published by the |
||||
|
# Free Software Foundation, either version 3 of the License, or (at your |
||||
|
# option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, but |
||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
# General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
|
||||
|
include_directories( BEFORE ${INC_BEFORE} ) |
||||
|
include_directories( |
||||
|
${INC_AFTER} |
||||
|
) |
||||
|
|
||||
|
add_executable( enum_exporter WIN32 |
||||
|
enum_exporter.cpp |
||||
|
) |
||||
|
|
||||
|
target_link_libraries( enum_exporter |
||||
|
common |
||||
|
) |
||||
|
|
||||
|
target_include_directories( enum_exporter PRIVATE |
||||
|
$<TARGET_PROPERTY:magic_enum,INTERFACE_INCLUDE_DIRECTORIES> |
||||
|
) |
||||
|
|
||||
|
if( MSVC ) |
||||
|
# The cli needs subsystem:console or else we can't link wmain/main |
||||
|
set_target_properties(enum_exporter PROPERTIES COMPILE_DEFINITIONS_DEBUG "_CONSOLE") |
||||
|
set_target_properties(enum_exporter PROPERTIES COMPILE_DEFINITIONS_RELWITHDEBINFO "_CONSOLE") |
||||
|
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_DEBUG "/SUBSYSTEM:CONSOLE") |
||||
|
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_RELWITHDEBINFO "/SUBSYSTEM:CONSOLE") |
||||
|
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_RELEASE "/SUBSYSTEM:CONSOLE") |
||||
|
set_target_properties(enum_exporter PROPERTIES LINK_FLAGS_MINSIZEREL "/SUBSYSTEM:CONSOLE") |
||||
|
endif() |
||||
@ -0,0 +1,91 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <filesystem>
|
||||
|
#include <iostream>
|
||||
|
#include <string>
|
||||
|
|
||||
|
#include <argparse/argparse.hpp>
|
||||
|
#include <fmt.h>
|
||||
|
#include <nlohmann/json.hpp>
|
||||
|
|
||||
|
#define MAGIC_ENUM_RANGE_MAX 1024
|
||||
|
#include <magic_enum.hpp>
|
||||
|
|
||||
|
#include <layer_ids.h>
|
||||
|
#include <eda_shape.h>
|
||||
|
#include <core/typeinfo.h>
|
||||
|
|
||||
|
|
||||
|
template<typename T> |
||||
|
nlohmann::json FormatEnum() |
||||
|
{ |
||||
|
nlohmann::json js; |
||||
|
|
||||
|
js["type"] = magic_enum::enum_type_name<T>(); |
||||
|
js["values"] = nlohmann::json::array(); |
||||
|
|
||||
|
for( const std::pair<T, std::string_view>& entry : magic_enum::enum_entries<T>() ) |
||||
|
{ |
||||
|
js["values"].emplace_back( nlohmann::json( { |
||||
|
{ "key", entry.second }, |
||||
|
{ "value", static_cast<int>( entry.first ) } |
||||
|
} ) ); |
||||
|
} |
||||
|
|
||||
|
return js; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
int main( int argc, char* argv[] ) |
||||
|
{ |
||||
|
argparse::ArgumentParser args( "enum_exporter" ); |
||||
|
|
||||
|
args.add_argument( "output_dir" ).default_value( std::string() ); |
||||
|
|
||||
|
try |
||||
|
{ |
||||
|
args.parse_args( argc, argv ); |
||||
|
} |
||||
|
catch( const std::runtime_error& err ) |
||||
|
{ |
||||
|
std::cerr << err.what() << std::endl; |
||||
|
std::cerr << args; |
||||
|
std::exit( 1 ); |
||||
|
} |
||||
|
|
||||
|
std::filesystem::path path( args.get<std::string>( "output_dir" ) ); |
||||
|
std::ofstream outfile; |
||||
|
|
||||
|
if( !path.empty() ) |
||||
|
{ |
||||
|
path = std::filesystem::absolute( path ); |
||||
|
outfile.open( path ); |
||||
|
} |
||||
|
|
||||
|
std::ostream& out = outfile.is_open() ? outfile : std::cout; |
||||
|
|
||||
|
nlohmann::json js = nlohmann::json::array(); |
||||
|
|
||||
|
js += FormatEnum<PCB_LAYER_ID>(); |
||||
|
js += FormatEnum<SHAPE_T>(); |
||||
|
js += FormatEnum<KICAD_T>(); |
||||
|
|
||||
|
out << js.dump( 4 ) << std::endl; |
||||
|
} |
||||
@ -0,0 +1,110 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
syntax = "proto3"; |
||||
|
|
||||
|
package kiapi.board.types; |
||||
|
|
||||
|
import "common/types/base_types.proto"; |
||||
|
|
||||
|
/// Represents a track segment on a board |
||||
|
message Track |
||||
|
{ |
||||
|
kiapi.common.types.KIID id = 1; |
||||
|
kiapi.common.types.Point2D start = 2; |
||||
|
kiapi.common.types.Point2D end = 3; |
||||
|
kiapi.common.types.Distance width = 4; |
||||
|
kiapi.common.types.LockedState locked = 5; |
||||
|
kiapi.common.types.BoardLayer layer = 6; |
||||
|
kiapi.common.types.Net net = 7; |
||||
|
} |
||||
|
|
||||
|
/// Represents an arc track (not a PCB_SHAPE in arc shape) |
||||
|
/// Arc tracks in KiCad store start, midpoint, and end. |
||||
|
/// All other values (center point, angles, etc) are inferred. |
||||
|
message Arc |
||||
|
{ |
||||
|
kiapi.common.types.KIID id = 1; |
||||
|
kiapi.common.types.Point2D start = 2; |
||||
|
kiapi.common.types.Point2D mid = 3; /// Arc midpoint |
||||
|
kiapi.common.types.Point2D end = 4; |
||||
|
kiapi.common.types.Distance width = 5; |
||||
|
kiapi.common.types.LockedState locked = 6; |
||||
|
kiapi.common.types.BoardLayer layer = 7; |
||||
|
kiapi.common.types.Net net = 8; |
||||
|
} |
||||
|
|
||||
|
enum PadStackType |
||||
|
{ |
||||
|
PST_UNKNOWN = 0; |
||||
|
PST_THROUGH = 1; /// Through all layers; same shape on all layers |
||||
|
PST_BLIND_BURIED = 2; /// From a start layer to end layer (inclusive); same shape on all included layers |
||||
|
} |
||||
|
|
||||
|
enum UnconnectedLayerRemoval |
||||
|
{ |
||||
|
ULR_UNKNOWN = 0; |
||||
|
|
||||
|
/// Keep annular rings on all layers |
||||
|
ULR_KEEP = 1; |
||||
|
|
||||
|
/// Remove annular rings on unconnected layers, including start and end layers. |
||||
|
ULR_REMOVE = 2; |
||||
|
|
||||
|
/// Remove annular rings on unconnected layers, but preserve start and end layers even if unconnected. |
||||
|
ULR_REMOVE_EXCEPT_START_AND_END = 3; |
||||
|
} |
||||
|
|
||||
|
/// A pad stack definition for a multilayer pad or via. |
||||
|
message PadStack |
||||
|
{ |
||||
|
/// What type of pad stack this represents. |
||||
|
PadStackType type = 1; |
||||
|
|
||||
|
/// Lowest (closest to F_Cu) layer this stack exists on. Ignored if type == PST_THROUGH. |
||||
|
kiapi.common.types.BoardLayer start_layer = 2; |
||||
|
|
||||
|
/// Highest (closest to B_Cu) layer this stack exists on. Ignored if type == PST_THROUGH. |
||||
|
kiapi.common.types.BoardLayer end_layer = 3; |
||||
|
|
||||
|
/// How to treat annular rings on unconnected layers. |
||||
|
UnconnectedLayerRemoval unconnected_layer_removal = 4; |
||||
|
} |
||||
|
|
||||
|
/// Represents a via |
||||
|
message Via |
||||
|
{ |
||||
|
/// The unique identifier of the via |
||||
|
kiapi.common.types.KIID id = 1; |
||||
|
|
||||
|
/// The location of the via's center point |
||||
|
kiapi.common.types.Point2D position = 2; |
||||
|
|
||||
|
/// The diameter of the via's circular copper pad |
||||
|
kiapi.common.types.Distance pad_diameter = 4; |
||||
|
|
||||
|
/// The diameter of the via's drilled hole |
||||
|
kiapi.common.types.Distance drill_diameter = 5; |
||||
|
|
||||
|
/// The pad stack definition for this via. The via's VIATYPE (blind/buried/normal) is inferred from this. |
||||
|
PadStack pad_stack = 6; |
||||
|
|
||||
|
kiapi.common.types.LockedState locked = 7; |
||||
|
kiapi.common.types.Net net = 8; |
||||
|
} |
||||
@ -0,0 +1,33 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
syntax = "proto3"; |
||||
|
|
||||
|
package kiapi.common.commands; |
||||
|
|
||||
|
import "common/types/base_types.proto"; |
||||
|
|
||||
|
message GetVersion |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
message GetVersionResponse |
||||
|
{ |
||||
|
kiapi.common.types.KiCadVersion version = 1; |
||||
|
} |
||||
@ -0,0 +1,251 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* Commands and responses related to manipulating editor windows |
||||
|
*/ |
||||
|
|
||||
|
syntax = "proto3"; |
||||
|
|
||||
|
package kiapi.common.commands; |
||||
|
|
||||
|
import "google/protobuf/any.proto"; |
||||
|
import "common/types/base_types.proto"; |
||||
|
|
||||
|
/// Refreshes the given frame, if that frame is open |
||||
|
message RefreshEditor |
||||
|
{ |
||||
|
kiapi.common.types.FrameType frame = 1; |
||||
|
} |
||||
|
|
||||
|
/// Retrieves a list of open documents of the given type |
||||
|
message GetOpenDocuments |
||||
|
{ |
||||
|
/// Which type of documents to query |
||||
|
kiapi.common.types.DocumentType type = 1; |
||||
|
} |
||||
|
|
||||
|
message GetOpenDocumentsResponse |
||||
|
{ |
||||
|
repeated kiapi.common.types.DocumentSpecifier documents = 1; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* Runs a TOOL_ACTION using the TOOL_MANAGER of a given frame. |
||||
|
* WARNING: The TOOL_ACTIONs are specifically *not* an API. |
||||
|
* Command names may change as code is refactored, and commands may disappear. |
||||
|
* This API method is provided for low-level prototyping purposes only. |
||||
|
*/ |
||||
|
message RunAction |
||||
|
{ |
||||
|
string action = 1; // Action name, like "eeschema.InteractiveSelection.ClearSelection" |
||||
|
} |
||||
|
|
||||
|
enum RunActionStatus |
||||
|
{ |
||||
|
RAS_UNKNOWN = 0; |
||||
|
RAS_OK = 1; // The action was submitted successfully. |
||||
|
RAS_INVALID = 2; // The action was unknown for the targeted frame. |
||||
|
RAS_FRAME_NOT_OPEN = 3; // The targeted frame was not open when the call was submitted. |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* NOTE: At the moment, RAS_FRAME_NOT_OPEN won't be returned as the handler is inside the frame. |
||||
|
*/ |
||||
|
message RunActionResponse |
||||
|
{ |
||||
|
RunActionStatus status = 1; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
/* |
||||
|
* Begins a staged set of changes. Any modifications made to a document through the API after this |
||||
|
* call will be saved to a pending commit, and will not appear in KiCad until a matching call to |
||||
|
* END_COMMIT. |
||||
|
*/ |
||||
|
message BeginCommit |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
message BeginCommitResponse |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
enum CommitResult |
||||
|
{ |
||||
|
CR_UNKNOWN = 0; |
||||
|
CR_OK = 1; // Commit was pushed successfully |
||||
|
CR_NO_COMMIT = 2; // There was no commit started |
||||
|
} |
||||
|
|
||||
|
|
||||
|
message EndCommit |
||||
|
{ |
||||
|
// Optional message describing this changeset |
||||
|
string message = 1; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
message EndCommitResponse |
||||
|
{ |
||||
|
CommitResult result = 1; |
||||
|
} |
||||
|
|
||||
|
/// Creates new items on a given document |
||||
|
message CreateItems |
||||
|
{ |
||||
|
/// Specifies which document to create on, which fields are included, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// List of items to create |
||||
|
repeated google.protobuf.Any items = 2; |
||||
|
|
||||
|
/// Items may be created on a top-level document (sheet, board, etc) or inside a container |
||||
|
/// (symbol, footprint). If this field is not empty, it holds the ID of a symbol or footprint |
||||
|
/// that the items should be added to. This ID must be an existing symbol (for schematic |
||||
|
/// documents) or footprint (for board documents). If the given container does not exist or is |
||||
|
/// not the correct item type, the CreateItems call will fail. |
||||
|
kiapi.common.types.KIID container = 3; |
||||
|
} |
||||
|
|
||||
|
enum ItemCreationStatus |
||||
|
{ |
||||
|
ICS_UNKNOWN = 0; |
||||
|
ICS_OK = 1; /// The item was created |
||||
|
ICS_INVALID_TYPE = 2; /// The item's type is not valid for the given document |
||||
|
ICS_EXISTING = 3; /// The item had a specified KIID and that KIID was already in use |
||||
|
} |
||||
|
|
||||
|
message ItemCreationResult |
||||
|
{ |
||||
|
ItemCreationStatus status = 1; |
||||
|
|
||||
|
/// The created version of the item, including an updated KIID as applicable |
||||
|
google.protobuf.Any item = 2; |
||||
|
} |
||||
|
|
||||
|
message CreateItemsResponse |
||||
|
{ |
||||
|
/// Specifies which document was modified, which fields are included in created_items, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// Status of the overall request; may return IRS_OK even if no items were created |
||||
|
kiapi.common.types.ItemRequestStatus status = 2; |
||||
|
|
||||
|
/// Status of each item to be created |
||||
|
repeated ItemCreationResult created_items = 3; |
||||
|
} |
||||
|
|
||||
|
message GetItems |
||||
|
{ |
||||
|
/// Specifies which document to query, which fields to return, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// List of one or more types of items to retreive |
||||
|
repeated kiapi.common.types.ItemType types = 2; |
||||
|
} |
||||
|
|
||||
|
message GetItemsResponse |
||||
|
{ |
||||
|
/// Specifies which document was modified, which fields are included in items, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// Status of the overall request; may return IRS_OK even if no items were retrieved |
||||
|
kiapi.common.types.ItemRequestStatus status = 2; |
||||
|
|
||||
|
repeated google.protobuf.Any items = 3; |
||||
|
} |
||||
|
|
||||
|
/// Updates items in a given document |
||||
|
message UpdateItems |
||||
|
{ |
||||
|
/// Specifies which document to modify, which fields are included, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// List of items to modify |
||||
|
repeated google.protobuf.Any items = 2; |
||||
|
} |
||||
|
|
||||
|
enum ItemUpdateStatus |
||||
|
{ |
||||
|
IUS_UNKNOWN = 0; |
||||
|
IUS_OK = 1; /// The item was updated |
||||
|
IUS_INVALID_TYPE = 2; /// The item's type is not valid for the given document |
||||
|
IUS_NONEXISTENT = 3; /// The item did not exist in the given document |
||||
|
IUS_IMMUTABLE = 4; /// The item is not allowed to be modified by the API |
||||
|
} |
||||
|
|
||||
|
message ItemUpdateResult |
||||
|
{ |
||||
|
ItemUpdateStatus status = 1; |
||||
|
|
||||
|
/// The update version of the item |
||||
|
google.protobuf.Any item = 2; |
||||
|
} |
||||
|
|
||||
|
message UpdateItemsResponse |
||||
|
{ |
||||
|
/// Specifies which document was modified, which fields are included in updated_items, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// Status of the overall request; may return IRS_OK even if no items were modified |
||||
|
kiapi.common.types.ItemRequestStatus status = 2; |
||||
|
|
||||
|
/// Status of each item to be created |
||||
|
repeated ItemUpdateResult updated_items = 3; |
||||
|
} |
||||
|
|
||||
|
/// Deletes items in a given document |
||||
|
message DeleteItems |
||||
|
{ |
||||
|
/// Specifies which document to modify |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// List of item KIIDs to delete |
||||
|
repeated kiapi.common.types.KIID item_ids = 2; |
||||
|
} |
||||
|
|
||||
|
enum ItemDeletionStatus |
||||
|
{ |
||||
|
IDS_UNKNOWN = 0; |
||||
|
IDS_OK = 1; |
||||
|
IDS_NONEXISTENT = 2; /// The item did not exist in the given document |
||||
|
IDS_IMMUTABLE = 3; /// The item is not allowed to be modified by the API |
||||
|
} |
||||
|
|
||||
|
message ItemDeletionResult |
||||
|
{ |
||||
|
kiapi.common.types.KIID id = 1; |
||||
|
|
||||
|
ItemDeletionStatus status = 2; |
||||
|
} |
||||
|
|
||||
|
message DeleteItemsResponse |
||||
|
{ |
||||
|
/// Specifies which document was modified, etc. |
||||
|
kiapi.common.types.ItemHeader header = 1; |
||||
|
|
||||
|
/// Status of the overall request; may return IRS_OK even if no items were deleted |
||||
|
kiapi.common.types.ItemRequestStatus status = 2; |
||||
|
|
||||
|
/// Status of each item requested to be deleted |
||||
|
repeated ItemDeletionResult deleted_items = 3; |
||||
|
} |
||||
@ -0,0 +1,90 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
syntax = "proto3"; |
||||
|
|
||||
|
package kiapi.common; |
||||
|
|
||||
|
import "google/protobuf/any.proto"; |
||||
|
|
||||
|
enum ApiStatusCode |
||||
|
{ |
||||
|
AS_UNKNOWN = 0; |
||||
|
AS_OK = 1; // Request succeeded |
||||
|
AS_TIMEOUT = 2; // Request timed out |
||||
|
AS_BAD_REQUEST = 3; // The request had invalid parameters or otherwise was illegal |
||||
|
AS_NOT_READY = 4; // KiCad was not (yet) in a state where it could handle API requests |
||||
|
AS_UNHANDLED = 5; // The request was not handled by KiCad |
||||
|
AS_TOKEN_MISMATCH = 6; // The kicad_token in the request didn't match this KiCad's token |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* For future expansion: any header fields that should be sent with a request |
||||
|
*/ |
||||
|
message ApiRequestHeader |
||||
|
{ |
||||
|
// An opaque string identifying a running instance of KiCad. If this is set to a non-empty |
||||
|
// string in an API request, KiCad will reject the request if the value doesn't match its own |
||||
|
// token. This can be used to let API clients make sure they are still talking to the same |
||||
|
// instance of KiCad if they are long-running. |
||||
|
string kicad_token = 1; |
||||
|
|
||||
|
// A string identifying an API client. Should be set by the client to a value that is unique |
||||
|
// to a specific instance of a client, for example the package name of the client plus its |
||||
|
// process ID or a random string, e.g. "com.github.me.my_awesome_plugin-73951". The main purpose |
||||
|
// of this name is to identify the client in debug logs. |
||||
|
string client_name = 2; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* The top-level envelope container for an API request (message from a client to the KiCad API server) |
||||
|
*/ |
||||
|
message ApiRequest |
||||
|
{ |
||||
|
ApiRequestHeader header = 1; |
||||
|
|
||||
|
google.protobuf.Any message = 2; |
||||
|
} |
||||
|
|
||||
|
/* |
||||
|
* For future expansion: any header fields that should be sent with a response |
||||
|
*/ |
||||
|
message ApiResponseHeader |
||||
|
{ |
||||
|
/// An opaque string identifying a running instance of KiCad. |
||||
|
string kicad_token = 1; |
||||
|
} |
||||
|
|
||||
|
message ApiResponse |
||||
|
{ |
||||
|
ApiResponseHeader header = 1; |
||||
|
|
||||
|
ApiResponseStatus status = 2; |
||||
|
|
||||
|
google.protobuf.Any message = 3; |
||||
|
} |
||||
|
|
||||
|
message ApiResponseStatus |
||||
|
{ |
||||
|
/// A code describing the category of error (or AS_OK if no error) |
||||
|
ApiStatusCode status = 1; |
||||
|
|
||||
|
/// A human-readable description of the error, if any |
||||
|
string error_message = 2; |
||||
|
} |
||||
@ -0,0 +1,217 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2024 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
/* |
||||
|
* base_types.proto |
||||
|
* Includes types used in many parts of the API |
||||
|
*/ |
||||
|
|
||||
|
syntax = "proto3"; |
||||
|
|
||||
|
package kiapi.common.types; |
||||
|
|
||||
|
import "google/protobuf/field_mask.proto"; |
||||
|
|
||||
|
enum CommandStatus |
||||
|
{ |
||||
|
CS_UNKNOWN = 0; |
||||
|
CS_OK = 1; // Command succeeded |
||||
|
CS_FAILED = 2; // Command failed |
||||
|
} |
||||
|
|
||||
|
message CommandStatusResponse |
||||
|
{ |
||||
|
CommandStatus status = 1; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes a particular version of KiCad |
||||
|
*/ |
||||
|
message KiCadVersion |
||||
|
{ |
||||
|
uint32 major = 1; |
||||
|
uint32 minor = 2; |
||||
|
uint32 patch = 3; |
||||
|
|
||||
|
// Full identifier string, potentially containing git hashes, packager-added info, etc. |
||||
|
string full_version = 4; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Some commands are specific to a KiCad window (frame). This list contains all addressable frames. |
||||
|
*/ |
||||
|
enum FrameType |
||||
|
{ |
||||
|
FT_UNKNOWN = 0; |
||||
|
FT_PROJECT_MANAGER = 1; |
||||
|
FT_SCHEMATIC_EDITOR = 2; |
||||
|
FT_PCB_EDITOR = 3; |
||||
|
FT_SPICE_SIMULATOR = 4; |
||||
|
FT_SYMBOL_EDITOR = 5; |
||||
|
FT_FOOTPRINT_EDITOR = 6; |
||||
|
FT_DRAWING_SHEET_EDITOR = 7; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes a KIID, or UUID of an object in a KiCad editor model. |
||||
|
*/ |
||||
|
message KIID |
||||
|
{ |
||||
|
// The KIID's value in standard UUID format, stored as a string for easy portability |
||||
|
string value = 1; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Identifier for the type of document being targeted by a request |
||||
|
*/ |
||||
|
enum DocumentType |
||||
|
{ |
||||
|
DOCTYPE_UNKNOWN = 0; |
||||
|
DOCTYPE_SCHEMATIC = 1; |
||||
|
DOCTYPE_SYMBOL = 2; |
||||
|
DOCTYPE_PCB = 3; |
||||
|
DOCTYPE_FOOTPRINT = 4; |
||||
|
DOCTYPE_DRAWING_SHEET = 5; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes a KiCad LIB_ID; a unique identifier for a loaded symbol or footprint |
||||
|
*/ |
||||
|
message LibraryIdentifier |
||||
|
{ |
||||
|
/// The library portion of the LIB_ID |
||||
|
string library_nickname = 1; |
||||
|
|
||||
|
/// The symbol or footprint name |
||||
|
string entry_name = 2; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes a unique sheet in a schematic |
||||
|
*/ |
||||
|
message SheetPath |
||||
|
{ |
||||
|
/// The canonical path to the sheet. The first KIID will be the root sheet, etc. |
||||
|
repeated KIID path = 1; |
||||
|
|
||||
|
/// The path converted to a human readable form such as "/", "/child", or "/child/grandchild" |
||||
|
string path_human_readable = 2; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes a document that will be the target of a request |
||||
|
*/ |
||||
|
message DocumentSpecifier |
||||
|
{ |
||||
|
DocumentType type = 1; |
||||
|
|
||||
|
oneof identifier |
||||
|
{ |
||||
|
/// If type == DT_SYMBOL or DT_FOOTPRINT, identifies a certain library entry |
||||
|
LibraryIdentifier lib_id = 2; |
||||
|
|
||||
|
/// If type == DT_SCHEMATIC, identifies a sheet with a given path |
||||
|
SheetPath sheet_path = 3; |
||||
|
|
||||
|
/// If type == DT_PCB, identifies a PCB with a given filename, e.g. "board.kicad_pcb" |
||||
|
string board_filename = 4; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Describes the type of a KiCad item (wrapper for KICAD_T) |
||||
|
*/ |
||||
|
message ItemType |
||||
|
{ |
||||
|
/// Must be a valid value in the KICAD_T C++ enum (see typeinfo.h) |
||||
|
int32 type = 1; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* This header is included in requests and responses about item(s) in a document |
||||
|
*/ |
||||
|
message ItemHeader |
||||
|
{ |
||||
|
/// Which document is this request targeting? |
||||
|
DocumentSpecifier document = 1; |
||||
|
|
||||
|
/// Which fields on the item(s) are included with this request or response |
||||
|
google.protobuf.FieldMask field_mask = 2; |
||||
|
} |
||||
|
|
||||
|
/** |
||||
|
* Status of a request that included an ItemHeader |
||||
|
*/ |
||||
|
enum ItemRequestStatus |
||||
|
{ |
||||
|
IRS_UNKNOWN = 0; |
||||
|
IRS_OK = 1; |
||||
|
IRS_DOCUMENT_NOT_FOUND = 2; /// The given document is not open in KiCad |
||||
|
IRS_FIELD_MASK_INVALID = 3; /// The given field_mask contains invalid specifiers |
||||
|
} |
||||
|
|
||||
|
/// Describes a point in 2D space. All coordinates are in nanometers. |
||||
|
message Point2D |
||||
|
{ |
||||
|
int64 x_nm = 1; |
||||
|
int64 y_nm = 2; |
||||
|
} |
||||
|
|
||||
|
/// Describes a point in 3D space. All coordinates are in nanometers. |
||||
|
message Point3D |
||||
|
{ |
||||
|
int64 x_nm = 1; |
||||
|
int64 y_nm = 2; |
||||
|
int64 z_nm = 3; |
||||
|
} |
||||
|
|
||||
|
/// Describes a quantity of distance (size, length, etc). All coordinates are in nanometers. |
||||
|
message Distance |
||||
|
{ |
||||
|
int64 value_nm = 1; |
||||
|
} |
||||
|
|
||||
|
/// Describes whether or not an item is locked for editing or movement |
||||
|
enum LockedState |
||||
|
{ |
||||
|
LS_UNKNOWN = 0; |
||||
|
LS_UNLOCKED = 1; |
||||
|
LS_LOCKED = 2; |
||||
|
} |
||||
|
|
||||
|
message BoardLayer |
||||
|
{ |
||||
|
int32 layer_id = 1; /// From PCB_LAYER_T |
||||
|
} |
||||
|
|
||||
|
/// Describes a copper item's net |
||||
|
message Net |
||||
|
{ |
||||
|
/// A unique code representing this net |
||||
|
int32 code = 1; |
||||
|
|
||||
|
/// Human-readable net name |
||||
|
string name = 2; |
||||
|
} |
||||
|
|
||||
|
/// Describes a net class (a grouping of nets) |
||||
|
message NetClass |
||||
|
{ |
||||
|
string name = 1; |
||||
|
} |
||||
@ -0,0 +1,26 @@ |
|||||
|
find_package(PkgConfig) |
||||
|
|
||||
|
if(PKG_CONFIG_FOUND) |
||||
|
pkg_check_modules(_NNG nng) |
||||
|
endif (PKG_CONFIG_FOUND) |
||||
|
|
||||
|
FIND_PATH(NNG_INCLUDE_DIR |
||||
|
NAMES |
||||
|
nng/nng.h |
||||
|
PATH_SUFFIXES |
||||
|
include |
||||
|
) |
||||
|
|
||||
|
FIND_LIBRARY(NNG_LIBRARY |
||||
|
NAMES |
||||
|
nng |
||||
|
PATH_SUFFIXES |
||||
|
"lib" |
||||
|
"local/lib" |
||||
|
) |
||||
|
|
||||
|
include(FindPackageHandleStandardArgs) |
||||
|
find_package_handle_standard_args(nng |
||||
|
REQUIRED_VARS NNG_INCLUDE_DIR NNG_LIBRARY) |
||||
|
|
||||
|
MARK_AS_ADVANCED(NNG_INCLUDE_DIR NNG_LIBRARY) |
||||
@ -0,0 +1,74 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <api/api_handler.h>
|
||||
|
|
||||
|
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiResponseStatus; |
||||
|
|
||||
|
|
||||
|
API_RESULT API_HANDLER::Handle( ApiRequest& aMsg ) |
||||
|
{ |
||||
|
ApiResponseStatus status; |
||||
|
|
||||
|
if( !aMsg.has_message() ) |
||||
|
{ |
||||
|
status.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
status.set_error_message( "request has no inner message" ); |
||||
|
return tl::unexpected( status ); |
||||
|
} |
||||
|
|
||||
|
std::string typeName; |
||||
|
|
||||
|
if( !google::protobuf::Any::ParseAnyTypeUrl( aMsg.message().type_url(), &typeName ) ) |
||||
|
{ |
||||
|
status.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
status.set_error_message( "could not parse inner message type" ); |
||||
|
return tl::unexpected( status ); |
||||
|
} |
||||
|
|
||||
|
auto it = m_handlers.find( typeName ); |
||||
|
|
||||
|
if( it != m_handlers.end() ) |
||||
|
{ |
||||
|
REQUEST_HANDLER& handler = it->second; |
||||
|
return handler( aMsg ); |
||||
|
} |
||||
|
|
||||
|
status.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
// This response is used internally; no need for an error message
|
||||
|
return tl::unexpected( status ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::optional<KICAD_T> API_HANDLER::TypeNameFromAny( const google::protobuf::Any& aMessage ) |
||||
|
{ |
||||
|
static const std::map<std::string, KICAD_T> s_types = { |
||||
|
{ "type.googleapis.com/kiapi.board.types.Track", PCB_TRACE_T }, |
||||
|
{ "type.googleapis.com/kiapi.board.types.Arc", PCB_ARC_T }, |
||||
|
{ "type.googleapis.com/kiapi.board.types.Via", PCB_VIA_T }, |
||||
|
}; |
||||
|
|
||||
|
auto it = s_types.find( aMessage.type_url() ); |
||||
|
|
||||
|
if( it != s_types.end() ) |
||||
|
return it->second; |
||||
|
|
||||
|
return std::nullopt; |
||||
|
} |
||||
@ -0,0 +1,52 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <tuple>
|
||||
|
|
||||
|
#include <api/api_handler_common.h>
|
||||
|
#include <build_version.h>
|
||||
|
#include <pgm_base.h>
|
||||
|
#include <wx/string.h>
|
||||
|
|
||||
|
using namespace kiapi::common::commands; |
||||
|
using namespace kiapi::common::types; |
||||
|
using google::protobuf::Empty; |
||||
|
|
||||
|
|
||||
|
API_HANDLER_COMMON::API_HANDLER_COMMON() : |
||||
|
API_HANDLER() |
||||
|
{ |
||||
|
registerHandler<GetVersion, GetVersionResponse>( &API_HANDLER_COMMON::handleGetVersion ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<GetVersionResponse> API_HANDLER_COMMON::handleGetVersion( GetVersion& aMsg ) |
||||
|
{ |
||||
|
GetVersionResponse reply; |
||||
|
|
||||
|
reply.mutable_version()->set_full_version( GetBuildVersion().ToStdString() ); |
||||
|
|
||||
|
std::tuple<int, int, int> version = GetMajorMinorPatchTuple(); |
||||
|
reply.mutable_version()->set_major( std::get<0>( version ) ); |
||||
|
reply.mutable_version()->set_minor( std::get<1>( version ) ); |
||||
|
reply.mutable_version()->set_patch( std::get<2>( version ) ); |
||||
|
|
||||
|
return reply; |
||||
|
} |
||||
@ -0,0 +1,193 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <wx/app.h>
|
||||
|
#include <wx/datetime.h>
|
||||
|
#include <wx/event.h>
|
||||
|
|
||||
|
#include <advanced_config.h>
|
||||
|
#include <api/api_server.h>
|
||||
|
#include <api/api_handler_common.h>
|
||||
|
#include <kiid.h>
|
||||
|
#include <kinng.h>
|
||||
|
#include <paths.h>
|
||||
|
#include <pgm_base.h>
|
||||
|
#include <string_utils.h>
|
||||
|
|
||||
|
#include <api/common/envelope.pb.h>
|
||||
|
|
||||
|
using kiapi::common::ApiRequest, kiapi::common::ApiResponse, kiapi::common::ApiStatusCode; |
||||
|
|
||||
|
|
||||
|
wxString KICAD_API_SERVER::s_logFileName = "api.log"; |
||||
|
|
||||
|
|
||||
|
wxDEFINE_EVENT( API_REQUEST_EVENT, wxCommandEvent ); |
||||
|
|
||||
|
|
||||
|
KICAD_API_SERVER::KICAD_API_SERVER() : |
||||
|
wxEvtHandler(), |
||||
|
m_token( KIID().AsStdString() ), |
||||
|
m_readyToReply( false ) |
||||
|
{ |
||||
|
m_server = std::make_unique<KINNG_REQUEST_SERVER>(); |
||||
|
m_server->SetCallback( [&]( std::string* aRequest ) { onApiRequest( aRequest ); } ); |
||||
|
|
||||
|
m_commonHandler = std::make_unique<API_HANDLER_COMMON>(); |
||||
|
RegisterHandler( m_commonHandler.get() ); |
||||
|
|
||||
|
m_logFilePath.AssignDir( PATHS::GetLogsPath() ); |
||||
|
m_logFilePath.SetName( s_logFileName ); |
||||
|
|
||||
|
if( ADVANCED_CFG::GetCfg().m_EnableAPILogging ) |
||||
|
PATHS::EnsurePathExists( PATHS::GetLogsPath() ); |
||||
|
|
||||
|
log( "--- KiCad API server started ---\n" ); |
||||
|
|
||||
|
Bind( API_REQUEST_EVENT, &KICAD_API_SERVER::handleApiEvent, this ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
KICAD_API_SERVER::~KICAD_API_SERVER() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KICAD_API_SERVER::RegisterHandler( API_HANDLER* aHandler ) |
||||
|
{ |
||||
|
wxCHECK( aHandler, /* void */ ); |
||||
|
m_handlers.insert( aHandler ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KICAD_API_SERVER::DeregisterHandler( API_HANDLER* aHandler ) |
||||
|
{ |
||||
|
m_handlers.erase( aHandler ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KICAD_API_SERVER::onApiRequest( std::string* aRequest ) |
||||
|
{ |
||||
|
if( !m_readyToReply ) |
||||
|
{ |
||||
|
ApiResponse notHandled; |
||||
|
notHandled.mutable_status()->set_status( ApiStatusCode::AS_NOT_READY ); |
||||
|
notHandled.mutable_status()->set_error_message( "KiCad is not ready to reply" ); |
||||
|
m_server->Reply( notHandled.SerializeAsString() ); |
||||
|
log( "Got incoming request but was not yet ready to reply." ); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
wxCommandEvent* evt = new wxCommandEvent( API_REQUEST_EVENT ); |
||||
|
|
||||
|
// We don't actually need write access to this string, but client data is non-const
|
||||
|
evt->SetClientData( static_cast<void*>( aRequest ) ); |
||||
|
|
||||
|
// Takes ownership and frees the wxCommandEvent
|
||||
|
QueueEvent( evt ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KICAD_API_SERVER::handleApiEvent( wxCommandEvent& aEvent ) |
||||
|
{ |
||||
|
std::string& requestString = *static_cast<std::string*>( aEvent.GetClientData() ); |
||||
|
ApiRequest request; |
||||
|
|
||||
|
if( !request.ParseFromString( requestString ) ) |
||||
|
{ |
||||
|
ApiResponse error; |
||||
|
error.mutable_header()->set_kicad_token( m_token ); |
||||
|
error.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
error.mutable_status()->set_error_message( "request could not be parsed" ); |
||||
|
m_server->Reply( error.SerializeAsString() ); |
||||
|
log( "Response (ERROR): " + error.Utf8DebugString() ); |
||||
|
} |
||||
|
|
||||
|
log( "Request: " + request.Utf8DebugString() ); |
||||
|
|
||||
|
if( !request.header().kicad_token().empty() && |
||||
|
request.header().kicad_token().compare( m_token ) != 0 ) |
||||
|
{ |
||||
|
ApiResponse error; |
||||
|
error.mutable_header()->set_kicad_token( m_token ); |
||||
|
error.mutable_status()->set_status( ApiStatusCode::AS_TOKEN_MISMATCH ); |
||||
|
error.mutable_status()->set_error_message( |
||||
|
"the provided kicad_token did not match this KiCad instance's token" ); |
||||
|
m_server->Reply( error.SerializeAsString() ); |
||||
|
log( "Response (ERROR): " + error.Utf8DebugString() ); |
||||
|
} |
||||
|
|
||||
|
API_RESULT result; |
||||
|
|
||||
|
for( API_HANDLER* handler : m_handlers ) |
||||
|
{ |
||||
|
result = handler->Handle( request ); |
||||
|
|
||||
|
if( result.has_value() ) |
||||
|
break; |
||||
|
else if( result.error().status() != ApiStatusCode::AS_UNHANDLED ) |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
// Note: at the point we call Reply(), we no longer own requestString.
|
||||
|
|
||||
|
if( result.has_value() ) |
||||
|
{ |
||||
|
result->mutable_header()->set_kicad_token( m_token ); |
||||
|
m_server->Reply( result->SerializeAsString() ); |
||||
|
log( "Response: " + result->Utf8DebugString() ); |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
ApiResponse error; |
||||
|
error.mutable_status()->CopyFrom( result.error() ); |
||||
|
error.mutable_header()->set_kicad_token( m_token ); |
||||
|
|
||||
|
if( result.error().status() == ApiStatusCode::AS_UNHANDLED ) |
||||
|
{ |
||||
|
std::string type = "<unparseable Any>"; |
||||
|
google::protobuf::Any::ParseAnyTypeUrl( request.message().type_url(), &type ); |
||||
|
std::string msg = fmt::format( "no handler available for request of type {}", type ); |
||||
|
error.mutable_status()->set_error_message( msg ); |
||||
|
} |
||||
|
|
||||
|
m_server->Reply( error.SerializeAsString() ); |
||||
|
log( "Response (ERROR): " + error.Utf8DebugString() ); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KICAD_API_SERVER::log( const std::string& aOutput ) |
||||
|
{ |
||||
|
if( !ADVANCED_CFG::GetCfg().m_EnableAPILogging ) |
||||
|
return; |
||||
|
|
||||
|
FILE* fp = wxFopen( m_logFilePath.GetFullPath(), wxT( "a" ) ); |
||||
|
|
||||
|
if( !fp ) |
||||
|
return; |
||||
|
|
||||
|
wxString out; |
||||
|
wxDateTime now = wxDateTime::Now(); |
||||
|
|
||||
|
fprintf( fp, "%s", TO_UTF8( out.Format( wxS( "%s: %s" ), |
||||
|
now.FormatISOCombined(), aOutput ) ) ); |
||||
|
fclose( fp ); |
||||
|
} |
||||
@ -0,0 +1,109 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <dialogs/panel_python_settings.h>
|
||||
|
#include <widgets/ui_common.h>
|
||||
|
#include <pgm_base.h>
|
||||
|
#include <python_manager.h>
|
||||
|
#include <settings/common_settings.h>
|
||||
|
#include <settings/settings_manager.h>
|
||||
|
|
||||
|
|
||||
|
PANEL_PYTHON_SETTINGS::PANEL_PYTHON_SETTINGS( wxWindow* aParent ) : |
||||
|
PANEL_PYTHON_SETTINGS_BASE( aParent ) |
||||
|
{ |
||||
|
wxFont helpFont = KIUI::GetInfoFont( this ).Italic(); |
||||
|
m_stPythonStatus->SetFont( helpFont ); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void PANEL_PYTHON_SETTINGS::ResetPanel() |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool PANEL_PYTHON_SETTINGS::TransferDataToWindow() |
||||
|
{ |
||||
|
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); |
||||
|
COMMON_SETTINGS* settings = mgr.GetCommonSettings(); |
||||
|
|
||||
|
m_pickerPythonInterpreter->SetFileName( settings->m_Python.interpreter_path ); |
||||
|
validateInterpreter(); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool PANEL_PYTHON_SETTINGS::TransferDataFromWindow() |
||||
|
{ |
||||
|
SETTINGS_MANAGER& mgr = Pgm().GetSettingsManager(); |
||||
|
COMMON_SETTINGS* settings = mgr.GetCommonSettings(); |
||||
|
|
||||
|
if( m_interpreterValid ) |
||||
|
settings->m_Python.interpreter_path = m_pickerPythonInterpreter->GetTextCtrlValue(); |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void PANEL_PYTHON_SETTINGS::OnPythonInterpreterChanged( wxFileDirPickerEvent& event ) |
||||
|
{ |
||||
|
validateInterpreter(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void PANEL_PYTHON_SETTINGS::OnBtnDetectAutomaticallyClicked( wxCommandEvent& aEvent ) |
||||
|
{ |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void PANEL_PYTHON_SETTINGS::validateInterpreter() |
||||
|
{ |
||||
|
m_interpreterValid = false; |
||||
|
|
||||
|
wxFileName pythonExe( m_pickerPythonInterpreter->GetTextCtrlValue() ); |
||||
|
|
||||
|
if( !pythonExe.FileExists() ) |
||||
|
{ |
||||
|
m_stPythonStatus->SetLabel( _( "No valid Python interpreter chosen; external Python " |
||||
|
"plugins will not be available" ) ); |
||||
|
return; |
||||
|
} |
||||
|
|
||||
|
PYTHON_MANAGER manager( pythonExe.GetFullPath() ); |
||||
|
|
||||
|
manager.Execute( wxS( "--version" ), |
||||
|
[&]( int aRetCode, const wxString& aStdOut ) |
||||
|
{ |
||||
|
wxString msg; |
||||
|
|
||||
|
if( aRetCode == 0 && aStdOut.Contains( wxS( "Python 3" ) ) ) |
||||
|
{ |
||||
|
msg = wxString::Format( _( "Found %s" ), aStdOut ); |
||||
|
m_interpreterValid = true; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
msg = _( "Not a valid Python 3 interpreter" ); |
||||
|
} |
||||
|
|
||||
|
m_stPythonStatus->SetLabel( msg ); |
||||
|
} ); |
||||
|
} |
||||
@ -0,0 +1,70 @@ |
|||||
|
///////////////////////////////////////////////////////////////////////////
|
||||
|
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3)
|
||||
|
// http://www.wxformbuilder.org/
|
||||
|
//
|
||||
|
// PLEASE DO *NOT* EDIT THIS FILE!
|
||||
|
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
||||
|
#include "panel_python_settings_base.h"
|
||||
|
|
||||
|
///////////////////////////////////////////////////////////////////////////
|
||||
|
|
||||
|
PANEL_PYTHON_SETTINGS_BASE::PANEL_PYTHON_SETTINGS_BASE( wxWindow* parent, wxWindowID id, const wxPoint& pos, const wxSize& size, long style, const wxString& name ) : RESETTABLE_PANEL( parent, id, pos, size, style, name ) |
||||
|
{ |
||||
|
wxBoxSizer* bPanelSizer; |
||||
|
bPanelSizer = new wxBoxSizer( wxHORIZONTAL ); |
||||
|
|
||||
|
wxBoxSizer* bSizer8; |
||||
|
bSizer8 = new wxBoxSizer( wxVERTICAL ); |
||||
|
|
||||
|
wxStaticBoxSizer* sbSizer1; |
||||
|
sbSizer1 = new wxStaticBoxSizer( new wxStaticBox( this, wxID_ANY, _("Python Interpreter") ), wxVERTICAL ); |
||||
|
|
||||
|
wxBoxSizer* bSizer4; |
||||
|
bSizer4 = new wxBoxSizer( wxHORIZONTAL ); |
||||
|
|
||||
|
m_staticText2 = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("Path to Python interpreter:"), wxDefaultPosition, wxDefaultSize, 0 ); |
||||
|
m_staticText2->Wrap( -1 ); |
||||
|
bSizer4->Add( m_staticText2, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); |
||||
|
|
||||
|
m_pickerPythonInterpreter = new wxFilePickerCtrl( sbSizer1->GetStaticBox(), wxID_ANY, wxEmptyString, _("Select the path to a Python interpreter"), _("*.*"), wxDefaultPosition, wxDefaultSize, wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL ); |
||||
|
bSizer4->Add( m_pickerPythonInterpreter, 1, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); |
||||
|
|
||||
|
m_btnDetectAutomatically = new wxButton( sbSizer1->GetStaticBox(), wxID_ANY, _("Detect Automatically"), wxDefaultPosition, wxDefaultSize, 0 ); |
||||
|
bSizer4->Add( m_btnDetectAutomatically, 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 ); |
||||
|
|
||||
|
|
||||
|
sbSizer1->Add( bSizer4, 0, wxEXPAND, 5 ); |
||||
|
|
||||
|
m_stPythonStatus = new wxStaticText( sbSizer1->GetStaticBox(), wxID_ANY, _("No Python interpreter chosen; external Python plugins will not be available"), wxDefaultPosition, wxDefaultSize, 0 ); |
||||
|
m_stPythonStatus->Wrap( -1 ); |
||||
|
m_stPythonStatus->SetToolTip( _("Python interpreter status") ); |
||||
|
|
||||
|
sbSizer1->Add( m_stPythonStatus, 0, wxALL, 5 ); |
||||
|
|
||||
|
|
||||
|
bSizer8->Add( sbSizer1, 0, wxALL|wxEXPAND, 5 ); |
||||
|
|
||||
|
|
||||
|
bSizer8->Add( 0, 0, 1, wxEXPAND, 5 ); |
||||
|
|
||||
|
|
||||
|
bPanelSizer->Add( bSizer8, 1, wxEXPAND, 5 ); |
||||
|
|
||||
|
|
||||
|
this->SetSizer( bPanelSizer ); |
||||
|
this->Layout(); |
||||
|
bPanelSizer->Fit( this ); |
||||
|
|
||||
|
// Connect Events
|
||||
|
m_pickerPythonInterpreter->Connect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnPythonInterpreterChanged ), NULL, this ); |
||||
|
m_btnDetectAutomatically->Connect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnBtnDetectAutomaticallyClicked ), NULL, this ); |
||||
|
} |
||||
|
|
||||
|
PANEL_PYTHON_SETTINGS_BASE::~PANEL_PYTHON_SETTINGS_BASE() |
||||
|
{ |
||||
|
// Disconnect Events
|
||||
|
m_pickerPythonInterpreter->Disconnect( wxEVT_COMMAND_FILEPICKER_CHANGED, wxFileDirPickerEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnPythonInterpreterChanged ), NULL, this ); |
||||
|
m_btnDetectAutomatically->Disconnect( wxEVT_COMMAND_BUTTON_CLICKED, wxCommandEventHandler( PANEL_PYTHON_SETTINGS_BASE::OnBtnDetectAutomaticallyClicked ), NULL, this ); |
||||
|
|
||||
|
} |
||||
@ -0,0 +1,371 @@ |
|||||
|
<?xml version="1.0" encoding="UTF-8" standalone="yes" ?> |
||||
|
<wxFormBuilder_Project> |
||||
|
<FileVersion major="1" minor="16" /> |
||||
|
<object class="Project" expanded="1"> |
||||
|
<property name="class_decoration"></property> |
||||
|
<property name="code_generation">C++</property> |
||||
|
<property name="disconnect_events">1</property> |
||||
|
<property name="disconnect_mode">source_name</property> |
||||
|
<property name="disconnect_php_events">0</property> |
||||
|
<property name="disconnect_python_events">0</property> |
||||
|
<property name="embedded_files_path">res</property> |
||||
|
<property name="encoding">UTF-8</property> |
||||
|
<property name="event_generation">connect</property> |
||||
|
<property name="file">panel_python_settings_base</property> |
||||
|
<property name="first_id">1000</property> |
||||
|
<property name="help_provider">none</property> |
||||
|
<property name="image_path_wrapper_function_name"></property> |
||||
|
<property name="indent_with_spaces"></property> |
||||
|
<property name="internationalize">1</property> |
||||
|
<property name="name">PanelPythonSettings</property> |
||||
|
<property name="namespace"></property> |
||||
|
<property name="path">.</property> |
||||
|
<property name="precompiled_header"></property> |
||||
|
<property name="relative_path">1</property> |
||||
|
<property name="skip_lua_events">1</property> |
||||
|
<property name="skip_php_events">1</property> |
||||
|
<property name="skip_python_events">1</property> |
||||
|
<property name="ui_table">UI</property> |
||||
|
<property name="use_array_enum">0</property> |
||||
|
<property name="use_enum">1</property> |
||||
|
<property name="use_microsoft_bom">0</property> |
||||
|
<object class="Panel" expanded="1"> |
||||
|
<property name="aui_managed">0</property> |
||||
|
<property name="aui_manager_style">wxAUI_MGR_DEFAULT</property> |
||||
|
<property name="bg"></property> |
||||
|
<property name="context_help"></property> |
||||
|
<property name="context_menu">1</property> |
||||
|
<property name="enabled">1</property> |
||||
|
<property name="event_handler">impl_virtual</property> |
||||
|
<property name="fg"></property> |
||||
|
<property name="font"></property> |
||||
|
<property name="hidden">0</property> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="maximum_size"></property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="name">PANEL_PYTHON_SETTINGS_BASE</property> |
||||
|
<property name="pos"></property> |
||||
|
<property name="size">-1,-1</property> |
||||
|
<property name="subclass">RESETTABLE_PANEL; widgets/resettable_panel.h; Not forward_declare</property> |
||||
|
<property name="tooltip"></property> |
||||
|
<property name="two_step_creation">0</property> |
||||
|
<property name="window_extra_style"></property> |
||||
|
<property name="window_name"></property> |
||||
|
<property name="window_style">wxTAB_TRAVERSAL</property> |
||||
|
<object class="wxBoxSizer" expanded="1"> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="name">bPanelSizer</property> |
||||
|
<property name="orient">wxHORIZONTAL</property> |
||||
|
<property name="permission">none</property> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxEXPAND</property> |
||||
|
<property name="proportion">1</property> |
||||
|
<object class="wxBoxSizer" expanded="1"> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="name">bSizer8</property> |
||||
|
<property name="orient">wxVERTICAL</property> |
||||
|
<property name="permission">none</property> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxALL|wxEXPAND</property> |
||||
|
<property name="proportion">0</property> |
||||
|
<object class="wxStaticBoxSizer" expanded="1"> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="label">Python Interpreter</property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="name">sbSizer1</property> |
||||
|
<property name="orient">wxVERTICAL</property> |
||||
|
<property name="parent">1</property> |
||||
|
<property name="permission">none</property> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxEXPAND</property> |
||||
|
<property name="proportion">0</property> |
||||
|
<object class="wxBoxSizer" expanded="1"> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="name">bSizer4</property> |
||||
|
<property name="orient">wxHORIZONTAL</property> |
||||
|
<property name="permission">none</property> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> |
||||
|
<property name="proportion">0</property> |
||||
|
<object class="wxStaticText" expanded="1"> |
||||
|
<property name="BottomDockable">1</property> |
||||
|
<property name="LeftDockable">1</property> |
||||
|
<property name="RightDockable">1</property> |
||||
|
<property name="TopDockable">1</property> |
||||
|
<property name="aui_layer"></property> |
||||
|
<property name="aui_name"></property> |
||||
|
<property name="aui_position"></property> |
||||
|
<property name="aui_row"></property> |
||||
|
<property name="best_size"></property> |
||||
|
<property name="bg"></property> |
||||
|
<property name="caption"></property> |
||||
|
<property name="caption_visible">1</property> |
||||
|
<property name="center_pane">0</property> |
||||
|
<property name="close_button">1</property> |
||||
|
<property name="context_help"></property> |
||||
|
<property name="context_menu">1</property> |
||||
|
<property name="default_pane">0</property> |
||||
|
<property name="dock">Dock</property> |
||||
|
<property name="dock_fixed">0</property> |
||||
|
<property name="docking">Left</property> |
||||
|
<property name="enabled">1</property> |
||||
|
<property name="fg"></property> |
||||
|
<property name="floatable">1</property> |
||||
|
<property name="font"></property> |
||||
|
<property name="gripper">0</property> |
||||
|
<property name="hidden">0</property> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="label">Path to Python interpreter:</property> |
||||
|
<property name="markup">0</property> |
||||
|
<property name="max_size"></property> |
||||
|
<property name="maximize_button">0</property> |
||||
|
<property name="maximum_size"></property> |
||||
|
<property name="min_size"></property> |
||||
|
<property name="minimize_button">0</property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="moveable">1</property> |
||||
|
<property name="name">m_staticText2</property> |
||||
|
<property name="pane_border">1</property> |
||||
|
<property name="pane_position"></property> |
||||
|
<property name="pane_size"></property> |
||||
|
<property name="permission">protected</property> |
||||
|
<property name="pin_button">1</property> |
||||
|
<property name="pos"></property> |
||||
|
<property name="resize">Resizable</property> |
||||
|
<property name="show">1</property> |
||||
|
<property name="size"></property> |
||||
|
<property name="style"></property> |
||||
|
<property name="subclass">; ; forward_declare</property> |
||||
|
<property name="toolbar_pane">0</property> |
||||
|
<property name="tooltip"></property> |
||||
|
<property name="window_extra_style"></property> |
||||
|
<property name="window_name"></property> |
||||
|
<property name="window_style"></property> |
||||
|
<property name="wrap">-1</property> |
||||
|
</object> |
||||
|
</object> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> |
||||
|
<property name="proportion">1</property> |
||||
|
<object class="wxFilePickerCtrl" expanded="1"> |
||||
|
<property name="BottomDockable">1</property> |
||||
|
<property name="LeftDockable">1</property> |
||||
|
<property name="RightDockable">1</property> |
||||
|
<property name="TopDockable">1</property> |
||||
|
<property name="aui_layer"></property> |
||||
|
<property name="aui_name"></property> |
||||
|
<property name="aui_position"></property> |
||||
|
<property name="aui_row"></property> |
||||
|
<property name="best_size"></property> |
||||
|
<property name="bg"></property> |
||||
|
<property name="caption"></property> |
||||
|
<property name="caption_visible">1</property> |
||||
|
<property name="center_pane">0</property> |
||||
|
<property name="close_button">1</property> |
||||
|
<property name="context_help"></property> |
||||
|
<property name="context_menu">1</property> |
||||
|
<property name="default_pane">0</property> |
||||
|
<property name="dock">Dock</property> |
||||
|
<property name="dock_fixed">0</property> |
||||
|
<property name="docking">Left</property> |
||||
|
<property name="enabled">1</property> |
||||
|
<property name="fg"></property> |
||||
|
<property name="floatable">1</property> |
||||
|
<property name="font"></property> |
||||
|
<property name="gripper">0</property> |
||||
|
<property name="hidden">0</property> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="max_size"></property> |
||||
|
<property name="maximize_button">0</property> |
||||
|
<property name="maximum_size"></property> |
||||
|
<property name="message">Select the path to a Python interpreter</property> |
||||
|
<property name="min_size"></property> |
||||
|
<property name="minimize_button">0</property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="moveable">1</property> |
||||
|
<property name="name">m_pickerPythonInterpreter</property> |
||||
|
<property name="pane_border">1</property> |
||||
|
<property name="pane_position"></property> |
||||
|
<property name="pane_size"></property> |
||||
|
<property name="permission">protected</property> |
||||
|
<property name="pin_button">1</property> |
||||
|
<property name="pos"></property> |
||||
|
<property name="resize">Resizable</property> |
||||
|
<property name="show">1</property> |
||||
|
<property name="size"></property> |
||||
|
<property name="style">wxFLP_DEFAULT_STYLE|wxFLP_USE_TEXTCTRL</property> |
||||
|
<property name="subclass">; ; forward_declare</property> |
||||
|
<property name="toolbar_pane">0</property> |
||||
|
<property name="tooltip"></property> |
||||
|
<property name="validator_data_type"></property> |
||||
|
<property name="validator_style">wxFILTER_NONE</property> |
||||
|
<property name="validator_type">wxDefaultValidator</property> |
||||
|
<property name="validator_variable"></property> |
||||
|
<property name="value"></property> |
||||
|
<property name="wildcard">*.*</property> |
||||
|
<property name="window_extra_style"></property> |
||||
|
<property name="window_name"></property> |
||||
|
<property name="window_style"></property> |
||||
|
<event name="OnFileChanged">OnPythonInterpreterChanged</event> |
||||
|
</object> |
||||
|
</object> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxALIGN_CENTER_VERTICAL|wxALL</property> |
||||
|
<property name="proportion">0</property> |
||||
|
<object class="wxButton" expanded="1"> |
||||
|
<property name="BottomDockable">1</property> |
||||
|
<property name="LeftDockable">1</property> |
||||
|
<property name="RightDockable">1</property> |
||||
|
<property name="TopDockable">1</property> |
||||
|
<property name="aui_layer"></property> |
||||
|
<property name="aui_name"></property> |
||||
|
<property name="aui_position"></property> |
||||
|
<property name="aui_row"></property> |
||||
|
<property name="auth_needed">0</property> |
||||
|
<property name="best_size"></property> |
||||
|
<property name="bg"></property> |
||||
|
<property name="bitmap"></property> |
||||
|
<property name="caption"></property> |
||||
|
<property name="caption_visible">1</property> |
||||
|
<property name="center_pane">0</property> |
||||
|
<property name="close_button">1</property> |
||||
|
<property name="context_help"></property> |
||||
|
<property name="context_menu">1</property> |
||||
|
<property name="current"></property> |
||||
|
<property name="default">0</property> |
||||
|
<property name="default_pane">0</property> |
||||
|
<property name="disabled"></property> |
||||
|
<property name="dock">Dock</property> |
||||
|
<property name="dock_fixed">0</property> |
||||
|
<property name="docking">Left</property> |
||||
|
<property name="enabled">1</property> |
||||
|
<property name="fg"></property> |
||||
|
<property name="floatable">1</property> |
||||
|
<property name="focus"></property> |
||||
|
<property name="font"></property> |
||||
|
<property name="gripper">0</property> |
||||
|
<property name="hidden">0</property> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="label">Detect Automatically</property> |
||||
|
<property name="margins"></property> |
||||
|
<property name="markup">0</property> |
||||
|
<property name="max_size"></property> |
||||
|
<property name="maximize_button">0</property> |
||||
|
<property name="maximum_size"></property> |
||||
|
<property name="min_size"></property> |
||||
|
<property name="minimize_button">0</property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="moveable">1</property> |
||||
|
<property name="name">m_btnDetectAutomatically</property> |
||||
|
<property name="pane_border">1</property> |
||||
|
<property name="pane_position"></property> |
||||
|
<property name="pane_size"></property> |
||||
|
<property name="permission">protected</property> |
||||
|
<property name="pin_button">1</property> |
||||
|
<property name="pos"></property> |
||||
|
<property name="position"></property> |
||||
|
<property name="pressed"></property> |
||||
|
<property name="resize">Resizable</property> |
||||
|
<property name="show">1</property> |
||||
|
<property name="size"></property> |
||||
|
<property name="style"></property> |
||||
|
<property name="subclass">; ; forward_declare</property> |
||||
|
<property name="toolbar_pane">0</property> |
||||
|
<property name="tooltip"></property> |
||||
|
<property name="validator_data_type"></property> |
||||
|
<property name="validator_style">wxFILTER_NONE</property> |
||||
|
<property name="validator_type">wxDefaultValidator</property> |
||||
|
<property name="validator_variable"></property> |
||||
|
<property name="window_extra_style"></property> |
||||
|
<property name="window_name"></property> |
||||
|
<property name="window_style"></property> |
||||
|
<event name="OnButtonClick">OnBtnDetectAutomaticallyClicked</event> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxALL</property> |
||||
|
<property name="proportion">0</property> |
||||
|
<object class="wxStaticText" expanded="1"> |
||||
|
<property name="BottomDockable">1</property> |
||||
|
<property name="LeftDockable">1</property> |
||||
|
<property name="RightDockable">1</property> |
||||
|
<property name="TopDockable">1</property> |
||||
|
<property name="aui_layer"></property> |
||||
|
<property name="aui_name"></property> |
||||
|
<property name="aui_position"></property> |
||||
|
<property name="aui_row"></property> |
||||
|
<property name="best_size"></property> |
||||
|
<property name="bg"></property> |
||||
|
<property name="caption"></property> |
||||
|
<property name="caption_visible">1</property> |
||||
|
<property name="center_pane">0</property> |
||||
|
<property name="close_button">1</property> |
||||
|
<property name="context_help"></property> |
||||
|
<property name="context_menu">1</property> |
||||
|
<property name="default_pane">0</property> |
||||
|
<property name="dock">Dock</property> |
||||
|
<property name="dock_fixed">0</property> |
||||
|
<property name="docking">Left</property> |
||||
|
<property name="enabled">1</property> |
||||
|
<property name="fg"></property> |
||||
|
<property name="floatable">1</property> |
||||
|
<property name="font"></property> |
||||
|
<property name="gripper">0</property> |
||||
|
<property name="hidden">0</property> |
||||
|
<property name="id">wxID_ANY</property> |
||||
|
<property name="label">No Python interpreter chosen; external Python plugins will not be available</property> |
||||
|
<property name="markup">0</property> |
||||
|
<property name="max_size"></property> |
||||
|
<property name="maximize_button">0</property> |
||||
|
<property name="maximum_size"></property> |
||||
|
<property name="min_size"></property> |
||||
|
<property name="minimize_button">0</property> |
||||
|
<property name="minimum_size"></property> |
||||
|
<property name="moveable">1</property> |
||||
|
<property name="name">m_stPythonStatus</property> |
||||
|
<property name="pane_border">1</property> |
||||
|
<property name="pane_position"></property> |
||||
|
<property name="pane_size"></property> |
||||
|
<property name="permission">public</property> |
||||
|
<property name="pin_button">1</property> |
||||
|
<property name="pos"></property> |
||||
|
<property name="resize">Resizable</property> |
||||
|
<property name="show">1</property> |
||||
|
<property name="size"></property> |
||||
|
<property name="style"></property> |
||||
|
<property name="subclass">; ; forward_declare</property> |
||||
|
<property name="toolbar_pane">0</property> |
||||
|
<property name="tooltip">Python interpreter status</property> |
||||
|
<property name="window_extra_style"></property> |
||||
|
<property name="window_name"></property> |
||||
|
<property name="window_style"></property> |
||||
|
<property name="wrap">-1</property> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
<object class="sizeritem" expanded="1"> |
||||
|
<property name="border">5</property> |
||||
|
<property name="flag">wxEXPAND</property> |
||||
|
<property name="proportion">1</property> |
||||
|
<object class="spacer" expanded="1"> |
||||
|
<property name="height">0</property> |
||||
|
<property name="permission">protected</property> |
||||
|
<property name="width">0</property> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</object> |
||||
|
</wxFormBuilder_Project> |
||||
@ -0,0 +1,56 @@ |
|||||
|
/////////////////////////////////////////////////////////////////////////// |
||||
|
// C++ code generated with wxFormBuilder (version 3.10.1-0-g8feb16b3) |
||||
|
// http://www.wxformbuilder.org/ |
||||
|
// |
||||
|
// PLEASE DO *NOT* EDIT THIS FILE! |
||||
|
/////////////////////////////////////////////////////////////////////////// |
||||
|
|
||||
|
#pragma once |
||||
|
|
||||
|
#include <wx/artprov.h> |
||||
|
#include <wx/xrc/xmlres.h> |
||||
|
#include <wx/intl.h> |
||||
|
#include "widgets/resettable_panel.h" |
||||
|
#include <wx/string.h> |
||||
|
#include <wx/stattext.h> |
||||
|
#include <wx/gdicmn.h> |
||||
|
#include <wx/font.h> |
||||
|
#include <wx/colour.h> |
||||
|
#include <wx/settings.h> |
||||
|
#include <wx/filepicker.h> |
||||
|
#include <wx/button.h> |
||||
|
#include <wx/bitmap.h> |
||||
|
#include <wx/image.h> |
||||
|
#include <wx/icon.h> |
||||
|
#include <wx/sizer.h> |
||||
|
#include <wx/statbox.h> |
||||
|
#include <wx/panel.h> |
||||
|
|
||||
|
/////////////////////////////////////////////////////////////////////////// |
||||
|
|
||||
|
/////////////////////////////////////////////////////////////////////////////// |
||||
|
/// Class PANEL_PYTHON_SETTINGS_BASE |
||||
|
/////////////////////////////////////////////////////////////////////////////// |
||||
|
class PANEL_PYTHON_SETTINGS_BASE : public RESETTABLE_PANEL |
||||
|
{ |
||||
|
private: |
||||
|
|
||||
|
protected: |
||||
|
wxStaticText* m_staticText2; |
||||
|
wxFilePickerCtrl* m_pickerPythonInterpreter; |
||||
|
wxButton* m_btnDetectAutomatically; |
||||
|
|
||||
|
// Virtual event handlers, override them in your derived class |
||||
|
virtual void OnPythonInterpreterChanged( wxFileDirPickerEvent& event ) { event.Skip(); } |
||||
|
virtual void OnBtnDetectAutomaticallyClicked( wxCommandEvent& event ) { event.Skip(); } |
||||
|
|
||||
|
|
||||
|
public: |
||||
|
wxStaticText* m_stPythonStatus; |
||||
|
|
||||
|
PANEL_PYTHON_SETTINGS_BASE( wxWindow* parent, wxWindowID id = wxID_ANY, const wxPoint& pos = wxDefaultPosition, const wxSize& size = wxSize( -1,-1 ), long style = wxTAB_TRAVERSAL, const wxString& name = wxEmptyString ); |
||||
|
|
||||
|
~PANEL_PYTHON_SETTINGS_BASE(); |
||||
|
|
||||
|
}; |
||||
|
|
||||
@ -0,0 +1,137 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_API_HANDLER_H |
||||
|
#define KICAD_API_HANDLER_H |
||||
|
|
||||
|
#include <functional> |
||||
|
#include <optional> |
||||
|
|
||||
|
#include <fmt/format.h> |
||||
|
#include <tl/expected.hpp> |
||||
|
|
||||
|
#include <wx/debug.h> |
||||
|
#include <wx/string.h> |
||||
|
|
||||
|
#include <google/protobuf/message.h> |
||||
|
|
||||
|
#include <import_export.h> |
||||
|
#include <api/common/envelope.pb.h> |
||||
|
#include <core/typeinfo.h> |
||||
|
|
||||
|
using kiapi::common::ApiRequest, kiapi::common::ApiResponse; |
||||
|
using kiapi::common::ApiResponseStatus, kiapi::common::ApiStatusCode; |
||||
|
|
||||
|
typedef tl::expected<ApiResponse, ApiResponseStatus> API_RESULT; |
||||
|
|
||||
|
template <typename T> |
||||
|
using HANDLER_RESULT = tl::expected<T, ApiResponseStatus>; |
||||
|
|
||||
|
class API_HANDLER |
||||
|
{ |
||||
|
public: |
||||
|
API_HANDLER() {} |
||||
|
|
||||
|
/** |
||||
|
* Attempt to handle the given API request, if a handler exists in this class for the message. |
||||
|
* @param aMsg is a request to attempt to handle |
||||
|
* @return a response to send to the client, or an appropriate error |
||||
|
*/ |
||||
|
API_RESULT Handle( ApiRequest& aMsg ); |
||||
|
|
||||
|
static std::optional<KICAD_T> TypeNameFromAny( const google::protobuf::Any& aMessage ); |
||||
|
|
||||
|
protected: |
||||
|
|
||||
|
/** |
||||
|
* A handler for outer messages (envelopes) that will unpack to inner messages and call a |
||||
|
* specific handler function. @see registerHandler. |
||||
|
*/ |
||||
|
typedef std::function<HANDLER_RESULT<ApiResponse>( ApiRequest& )> REQUEST_HANDLER; |
||||
|
|
||||
|
/** |
||||
|
* Registers an API command handler for the given message types. |
||||
|
* |
||||
|
* When an API request matching the given type comes in, the handler will be called and its |
||||
|
* response will be packed into an envelope for sending back to the API client. |
||||
|
* |
||||
|
* If the given message does not unpack into the request type, an envelope is returned with |
||||
|
* status AS_BAD_REQUEST, which probably indicates corruption in the message. |
||||
|
* |
||||
|
* @tparam RequestType is a protobuf message type containing a command |
||||
|
* @tparam ResponseType is a protobuf message type containing a command response |
||||
|
* @tparam HandlerType is the implied type of the API_HANDLER subclass |
||||
|
* @param aHandler is the handler function for the given request and response types |
||||
|
*/ |
||||
|
template <class RequestType, class ResponseType, class HandlerType> |
||||
|
void registerHandler( HANDLER_RESULT<ResponseType>( HandlerType::* aHandler )( RequestType& ) ) |
||||
|
{ |
||||
|
std::string typeName = RequestType().GetTypeName(); |
||||
|
|
||||
|
wxASSERT_MSG( !m_handlers.count( typeName ), |
||||
|
wxString::Format( "Duplicate API handler for type %s", typeName ) ); |
||||
|
|
||||
|
m_handlers[typeName] = |
||||
|
[=]( ApiRequest& aRequest ) -> API_RESULT |
||||
|
{ |
||||
|
RequestType command; |
||||
|
ApiResponse envelope; |
||||
|
|
||||
|
if( !tryUnpack( aRequest, envelope, command ) ) |
||||
|
return envelope; |
||||
|
|
||||
|
HANDLER_RESULT<ResponseType> response = |
||||
|
std::invoke( aHandler, static_cast<HandlerType*>( this ), command ); |
||||
|
|
||||
|
if( response.has_value() ) |
||||
|
{ |
||||
|
envelope.mutable_status()->set_status( ApiStatusCode::AS_OK ); |
||||
|
envelope.mutable_message()->PackFrom( *response ); |
||||
|
return envelope; |
||||
|
} |
||||
|
else |
||||
|
{ |
||||
|
return tl::unexpected( response.error() ); |
||||
|
} |
||||
|
}; |
||||
|
} |
||||
|
|
||||
|
/// Maps type name (without the URL prefix) to a handler method |
||||
|
std::map<std::string, REQUEST_HANDLER> m_handlers; |
||||
|
|
||||
|
private: |
||||
|
|
||||
|
template<typename MessageType> |
||||
|
bool tryUnpack( ApiRequest& aRequest, ApiResponse& aReply, MessageType& aDest ) |
||||
|
{ |
||||
|
if( !aRequest.message().UnpackTo( &aDest ) ) |
||||
|
{ |
||||
|
std::string msg = fmt::format( "could not unpack message of type {} from request", |
||||
|
aDest.GetTypeName() ); |
||||
|
aReply.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
aReply.mutable_status()->set_error_message( msg ); |
||||
|
return false; |
||||
|
} |
||||
|
|
||||
|
return true; |
||||
|
} |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_API_HANDLER_H |
||||
@ -0,0 +1,42 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_API_HANDLER_COMMON_H |
||||
|
#define KICAD_API_HANDLER_COMMON_H |
||||
|
|
||||
|
#include <api/api_handler.h> |
||||
|
#include <api/common/commands/base_commands.pb.h> |
||||
|
#include <api/common/commands/editor_commands.pb.h> |
||||
|
|
||||
|
#include <google/protobuf/empty.pb.h> |
||||
|
|
||||
|
using namespace kiapi; |
||||
|
using namespace kiapi::common; |
||||
|
|
||||
|
class API_HANDLER_COMMON : public API_HANDLER |
||||
|
{ |
||||
|
public: |
||||
|
API_HANDLER_COMMON(); |
||||
|
|
||||
|
private: |
||||
|
HANDLER_RESULT<commands::GetVersionResponse> handleGetVersion( commands::GetVersion& aMsg ); |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_API_HANDLER_COMMON_H |
||||
@ -0,0 +1,97 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_API_SERVER_H |
||||
|
#define KICAD_API_SERVER_H |
||||
|
|
||||
|
#include <memory> |
||||
|
#include <set> |
||||
|
#include <string> |
||||
|
|
||||
|
#include <wx/event.h> |
||||
|
#include <wx/filename.h> |
||||
|
|
||||
|
class API_HANDLER; |
||||
|
class API_HANDLER_COMMON; |
||||
|
class KINNG_REQUEST_SERVER; |
||||
|
class wxEvtHandler; |
||||
|
|
||||
|
|
||||
|
wxDECLARE_EVENT( API_REQUEST_EVENT, wxCommandEvent ); |
||||
|
|
||||
|
|
||||
|
class KICAD_API_SERVER : public wxEvtHandler |
||||
|
{ |
||||
|
public: |
||||
|
KICAD_API_SERVER(); |
||||
|
|
||||
|
~KICAD_API_SERVER(); |
||||
|
|
||||
|
/** |
||||
|
* Adds a new request handler to the server. Each handler maintains its own list of API |
||||
|
* messages that it knows how to handle, and the server will pass every incoming message to all |
||||
|
* handlers in succession until one of them handles it. |
||||
|
* |
||||
|
* The caller is responsible for the lifetime of the handler and must call DeregisterHandler |
||||
|
* before the pointer is freed. |
||||
|
* |
||||
|
* @param aHandler is a pointer (non-owned) to API_HANDLER |
||||
|
*/ |
||||
|
void RegisterHandler( API_HANDLER* aHandler ); |
||||
|
|
||||
|
void DeregisterHandler( API_HANDLER* aHandler ); |
||||
|
|
||||
|
void SetReadyToReply( bool aReady = true ) { m_readyToReply = aReady; } |
||||
|
|
||||
|
private: |
||||
|
|
||||
|
/** |
||||
|
* Callback that executes on the server thread and generates an event that will be handled by |
||||
|
* the wxWidgets event loop to process an incoming request. Temporarily takes ownership of the |
||||
|
* request pointer so that it can be passed through the event system. |
||||
|
* |
||||
|
* @param aRequest is a pointer to a string containing bytes that came in over the wire |
||||
|
*/ |
||||
|
void onApiRequest( std::string* aRequest ); |
||||
|
|
||||
|
/** |
||||
|
* Event handler that receives the event on the main thread sent by onApiRequest |
||||
|
* @param aEvent will contain a pointer to an incoming API request string in the client data |
||||
|
*/ |
||||
|
void handleApiEvent( wxCommandEvent& aEvent ); |
||||
|
|
||||
|
void log( const std::string& aOutput ); |
||||
|
|
||||
|
std::unique_ptr<KINNG_REQUEST_SERVER> m_server; |
||||
|
|
||||
|
std::set<API_HANDLER*> m_handlers; |
||||
|
|
||||
|
std::string m_token; |
||||
|
|
||||
|
bool m_readyToReply; |
||||
|
|
||||
|
std::unique_ptr<API_HANDLER_COMMON> m_commonHandler; |
||||
|
|
||||
|
static wxString s_logFileName; |
||||
|
|
||||
|
wxFileName m_logFilePath; |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_API_SERVER_H |
||||
@ -0,0 +1,49 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_PANEL_PYTHON_SETTINGS_H |
||||
|
#define KICAD_PANEL_PYTHON_SETTINGS_H |
||||
|
|
||||
|
#include <dialogs/panel_python_settings_base.h> |
||||
|
|
||||
|
class PAGED_DIALOG; |
||||
|
|
||||
|
|
||||
|
class PANEL_PYTHON_SETTINGS : public PANEL_PYTHON_SETTINGS_BASE |
||||
|
{ |
||||
|
public: |
||||
|
PANEL_PYTHON_SETTINGS( wxWindow* aParent ); |
||||
|
|
||||
|
void ResetPanel() override; |
||||
|
|
||||
|
protected: |
||||
|
bool TransferDataFromWindow() override; |
||||
|
bool TransferDataToWindow() override; |
||||
|
|
||||
|
void OnPythonInterpreterChanged( wxFileDirPickerEvent& event ) override; |
||||
|
void OnBtnDetectAutomaticallyClicked( wxCommandEvent& aEvent ) override; |
||||
|
|
||||
|
private: |
||||
|
void validateInterpreter(); |
||||
|
|
||||
|
bool m_interpreterValid; |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_PANEL_PYTHON_SETTINGS_H |
||||
@ -0,0 +1,38 @@ |
|||||
|
# This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
# |
||||
|
# Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors. |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify it |
||||
|
# under the terms of the GNU General Public License as published by the |
||||
|
# Free Software Foundation, either version 3 of the License, or (at your |
||||
|
# option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, but |
||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
# General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
|
||||
|
set( KINNG_SRCS |
||||
|
src/kinng.cpp |
||||
|
) |
||||
|
|
||||
|
add_library( kinng STATIC |
||||
|
${KINNG_SRCS} |
||||
|
) |
||||
|
|
||||
|
target_link_libraries( kinng |
||||
|
${NNG_LIBRARY} |
||||
|
) |
||||
|
|
||||
|
target_include_directories( kinng PUBLIC |
||||
|
${PROJECT_BINARY_DIR} |
||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include |
||||
|
) |
||||
|
|
||||
|
target_include_directories( kinng PRIVATE |
||||
|
${PROJECT_SOURCE_DIR}/include |
||||
|
${NNG_INCLUDE_DIR} |
||||
|
) |
||||
@ -0,0 +1,64 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_KINNG_H |
||||
|
#define KICAD_KINNG_H |
||||
|
|
||||
|
#include <atomic> |
||||
|
#include <condition_variable> |
||||
|
#include <functional> |
||||
|
#include <mutex> |
||||
|
#include <thread> |
||||
|
|
||||
|
|
||||
|
class KINNG_REQUEST_SERVER |
||||
|
{ |
||||
|
public: |
||||
|
KINNG_REQUEST_SERVER(); |
||||
|
|
||||
|
~KINNG_REQUEST_SERVER(); |
||||
|
|
||||
|
bool Start(); |
||||
|
|
||||
|
void Stop(); |
||||
|
|
||||
|
void SetCallback( std::function<void(std::string*)> aFunc ) { m_callback = aFunc; } |
||||
|
|
||||
|
void Reply( const std::string& aReply ); |
||||
|
|
||||
|
private: |
||||
|
void listenThread(); |
||||
|
|
||||
|
std::thread m_thread; |
||||
|
|
||||
|
std::atomic<bool> m_shutdown; |
||||
|
|
||||
|
std::string m_socketUrl; |
||||
|
|
||||
|
std::function<void(std::string*)> m_callback; |
||||
|
|
||||
|
std::string m_pendingReply; |
||||
|
|
||||
|
std::condition_variable m_replyReady; |
||||
|
|
||||
|
std::mutex m_mutex; |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_KINNG_H |
||||
@ -0,0 +1,129 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <kinng.h>
|
||||
|
#include <nng/nng.h>
|
||||
|
#include <nng/protocol/reqrep0/rep.h>
|
||||
|
#include <nng/protocol/reqrep0/req.h>
|
||||
|
|
||||
|
|
||||
|
KINNG_REQUEST_SERVER::KINNG_REQUEST_SERVER() : |
||||
|
m_callback() |
||||
|
{ |
||||
|
#ifdef WIN32
|
||||
|
m_socketUrl = "ipc://\\.\\pipe\\kicad"; |
||||
|
#else
|
||||
|
m_socketUrl = "ipc:///tmp/kicad.sock"; |
||||
|
#endif
|
||||
|
|
||||
|
Start(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
KINNG_REQUEST_SERVER::~KINNG_REQUEST_SERVER() |
||||
|
{ |
||||
|
Stop(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool KINNG_REQUEST_SERVER::Start() |
||||
|
{ |
||||
|
m_shutdown.store( false ); |
||||
|
m_thread = std::thread( [&]() { listenThread(); } ); |
||||
|
return true; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KINNG_REQUEST_SERVER::Stop() |
||||
|
{ |
||||
|
if( !m_thread.joinable() ) |
||||
|
return; |
||||
|
|
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lock( m_mutex ); |
||||
|
m_replyReady.notify_all(); |
||||
|
} |
||||
|
|
||||
|
m_shutdown.store( true ); |
||||
|
m_thread.join(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KINNG_REQUEST_SERVER::Reply( const std::string& aReply ) |
||||
|
{ |
||||
|
std::lock_guard<std::mutex> lock( m_mutex ); |
||||
|
m_pendingReply = aReply; |
||||
|
m_replyReady.notify_all(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void KINNG_REQUEST_SERVER::listenThread() |
||||
|
{ |
||||
|
nng_socket socket; |
||||
|
nng_listener listener; |
||||
|
int retCode = 0; |
||||
|
|
||||
|
retCode = nng_rep0_open( &socket ); |
||||
|
|
||||
|
if( retCode != 0 ) |
||||
|
return; |
||||
|
|
||||
|
retCode = nng_listener_create( &listener, socket, m_socketUrl.c_str() ); |
||||
|
|
||||
|
if( retCode != 0 ) |
||||
|
return; |
||||
|
|
||||
|
nng_socket_set_ms( socket, NNG_OPT_RECVTIMEO, 500 ); |
||||
|
|
||||
|
nng_listener_start( listener, 0 ); |
||||
|
|
||||
|
while( !m_shutdown.load() ) |
||||
|
{ |
||||
|
char* buf = nullptr; |
||||
|
size_t sz; |
||||
|
uint64_t val; |
||||
|
|
||||
|
retCode = nng_recv( socket, &buf, &sz, NNG_FLAG_ALLOC ); |
||||
|
|
||||
|
if( retCode == NNG_ETIMEDOUT ) |
||||
|
continue; |
||||
|
|
||||
|
if( retCode != 0 ) |
||||
|
{ |
||||
|
nng_free( buf, sz ); |
||||
|
break; |
||||
|
} |
||||
|
|
||||
|
std::string message( buf, sz ); |
||||
|
|
||||
|
if( m_callback ) |
||||
|
m_callback( &message ); |
||||
|
|
||||
|
std::unique_lock<std::mutex> lock( m_mutex ); |
||||
|
m_replyReady.wait( lock, [&]() { return !m_pendingReply.empty(); } ); |
||||
|
|
||||
|
retCode = nng_send( socket, const_cast<std::string::value_type*>( m_pendingReply.c_str() ), |
||||
|
m_pendingReply.length(), 0 ); |
||||
|
|
||||
|
m_pendingReply.clear(); |
||||
|
} |
||||
|
|
||||
|
nng_close( socket ); |
||||
|
} |
||||
@ -0,0 +1,493 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <magic_enum.hpp>
|
||||
|
|
||||
|
#include <api/api_handler_pcb.h>
|
||||
|
#include <board_commit.h>
|
||||
|
#include <pcb_edit_frame.h>
|
||||
|
#include <pcb_track.h>
|
||||
|
#include <tool/tool_manager.h>
|
||||
|
|
||||
|
#include <api/common/types/base_types.pb.h>
|
||||
|
|
||||
|
using namespace kiapi::common::commands; |
||||
|
using kiapi::common::types::CommandStatus; |
||||
|
using kiapi::common::types::DocumentType; |
||||
|
using kiapi::common::types::ItemRequestStatus; |
||||
|
|
||||
|
static const wxString s_defaultCommitMessage = wxS( "Modification from API" ); |
||||
|
|
||||
|
|
||||
|
API_HANDLER_PCB::API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ) : |
||||
|
API_HANDLER(), |
||||
|
m_frame( aFrame ) |
||||
|
{ |
||||
|
registerHandler<RunAction, RunActionResponse>( &API_HANDLER_PCB::handleRunAction ); |
||||
|
registerHandler<GetOpenDocuments, GetOpenDocumentsResponse>( |
||||
|
&API_HANDLER_PCB::handleGetOpenDocuments ); |
||||
|
|
||||
|
registerHandler<BeginCommit, BeginCommitResponse>( &API_HANDLER_PCB::handleBeginCommit ); |
||||
|
registerHandler<EndCommit, EndCommitResponse>( &API_HANDLER_PCB::handleEndCommit ); |
||||
|
|
||||
|
registerHandler<CreateItems, CreateItemsResponse>( &API_HANDLER_PCB::handleCreateItems ); |
||||
|
registerHandler<GetItems, GetItemsResponse>( &API_HANDLER_PCB::handleGetItems ); |
||||
|
registerHandler<UpdateItems, UpdateItemsResponse>( &API_HANDLER_PCB::handleUpdateItems ); |
||||
|
registerHandler<DeleteItems, DeleteItemsResponse>( &API_HANDLER_PCB::handleDeleteItems ); |
||||
|
|
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<RunActionResponse> API_HANDLER_PCB::handleRunAction( RunAction& aRequest ) |
||||
|
{ |
||||
|
RunActionResponse response; |
||||
|
|
||||
|
if( m_frame->GetToolManager()->RunAction( aRequest.action(), true ) ) |
||||
|
response.set_status( RunActionStatus::RAS_OK ); |
||||
|
else |
||||
|
response.set_status( RunActionStatus::RAS_INVALID ); |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<GetOpenDocumentsResponse> API_HANDLER_PCB::handleGetOpenDocuments( |
||||
|
GetOpenDocuments& aMsg ) |
||||
|
{ |
||||
|
if( aMsg.type() != DocumentType::DOCTYPE_PCB ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
|
e.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
GetOpenDocumentsResponse response; |
||||
|
common::types::DocumentSpecifier doc; |
||||
|
|
||||
|
wxFileName fn( m_frame->GetCurrentFileName() ); |
||||
|
|
||||
|
doc.set_type( DocumentType::DOCTYPE_PCB ); |
||||
|
doc.set_board_filename( fn.GetFullName() ); |
||||
|
|
||||
|
response.mutable_documents()->Add( std::move( doc ) ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<BeginCommitResponse> API_HANDLER_PCB::handleBeginCommit( BeginCommit& aMsg ) |
||||
|
{ |
||||
|
BeginCommitResponse response; |
||||
|
|
||||
|
if( m_commit ) |
||||
|
{ |
||||
|
// TODO: right now there is no way for m_transactionInProgress to be true here, but
|
||||
|
// we should still check it as a safety measure and return a specific error
|
||||
|
//if( !m_transactionInProgress )
|
||||
|
|
||||
|
m_commit->Revert(); |
||||
|
} |
||||
|
|
||||
|
m_commit.reset( new BOARD_COMMIT( m_frame ) ); |
||||
|
|
||||
|
// TODO: return an opaque ID for this new commit to make this more robust
|
||||
|
m_transactionInProgress = true; |
||||
|
|
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<EndCommitResponse> API_HANDLER_PCB::handleEndCommit( EndCommit& aMsg ) |
||||
|
{ |
||||
|
EndCommitResponse response; |
||||
|
|
||||
|
// TODO: return more specific error if m_transactionInProgress is false
|
||||
|
if( !m_transactionInProgress ) |
||||
|
{ |
||||
|
// Make sure we don't get stuck with a commit we can never push
|
||||
|
m_commit.reset(); |
||||
|
response.set_result( CommitResult::CR_NO_COMMIT ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
if( !m_commit ) |
||||
|
{ |
||||
|
response.set_result( CommitResult::CR_NO_COMMIT ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
pushCurrentCommit( aMsg.message() ); |
||||
|
m_transactionInProgress = false; |
||||
|
|
||||
|
response.set_result( CommitResult::CR_OK ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
BOARD_COMMIT* API_HANDLER_PCB::getCurrentCommit() |
||||
|
{ |
||||
|
if( !m_commit ) |
||||
|
m_commit.reset( new BOARD_COMMIT( m_frame ) ); |
||||
|
|
||||
|
return m_commit.get(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
void API_HANDLER_PCB::pushCurrentCommit( const std::string& aMessage ) |
||||
|
{ |
||||
|
wxCHECK( m_commit, /* void */ ); |
||||
|
|
||||
|
wxString msg( aMessage.c_str(), wxConvUTF8 ); |
||||
|
|
||||
|
if( msg.IsEmpty() ) |
||||
|
msg = s_defaultCommitMessage; |
||||
|
|
||||
|
m_commit->Push( msg ); |
||||
|
m_commit.reset(); |
||||
|
|
||||
|
m_frame->Refresh(); |
||||
|
} |
||||
|
|
||||
|
|
||||
|
bool API_HANDLER_PCB::validateItemHeaderDocument( const common::types::ItemHeader& aHeader ) |
||||
|
{ |
||||
|
// TODO: this should return a more complex error type.
|
||||
|
// We should provide detailed feedback when a header fails validation, and distinguish between
|
||||
|
// "skip this handler" and "this is the right handler, but the request is invalid"
|
||||
|
if( !aHeader.has_document() || aHeader.document().type() != DocumentType::DOCTYPE_PCB ) |
||||
|
return false; |
||||
|
|
||||
|
wxFileName fn( m_frame->GetCurrentFileName() ); |
||||
|
|
||||
|
return aHeader.document().board_filename().compare( fn.GetFullName() ) == 0; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
std::unique_ptr<BOARD_ITEM> API_HANDLER_PCB::createItemForType( KICAD_T aType, |
||||
|
BOARD_ITEM_CONTAINER* aContainer ) |
||||
|
{ |
||||
|
switch( aType ) |
||||
|
{ |
||||
|
case PCB_TRACE_T: return std::make_unique<PCB_TRACK>( aContainer ); |
||||
|
case PCB_ARC_T: return std::make_unique<PCB_ARC>( aContainer ); |
||||
|
case PCB_VIA_T: return std::make_unique<PCB_VIA>( aContainer ); |
||||
|
default: return nullptr; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<CreateItemsResponse> API_HANDLER_PCB::handleCreateItems( CreateItems& aMsg ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
|
||||
|
if( !validateItemHeaderDocument( aMsg.header() ) ) |
||||
|
{ |
||||
|
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
|
e.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
BOARD* board = m_frame->GetBoard(); |
||||
|
BOARD_ITEM_SET boardItems = board->GetItemSet(); |
||||
|
|
||||
|
std::map<KIID, BOARD_ITEM*> itemUuidMap; |
||||
|
|
||||
|
std::for_each( boardItems.begin(), boardItems.end(), |
||||
|
[&]( BOARD_ITEM* aItem ) |
||||
|
{ |
||||
|
itemUuidMap[aItem->m_Uuid] = aItem; |
||||
|
} ); |
||||
|
|
||||
|
BOARD_COMMIT* commit = getCurrentCommit(); |
||||
|
|
||||
|
CreateItemsResponse response; |
||||
|
|
||||
|
for( const google::protobuf::Any& anyItem : aMsg.items() ) |
||||
|
{ |
||||
|
ItemCreationResult itemResult; |
||||
|
std::optional<KICAD_T> type = TypeNameFromAny( anyItem ); |
||||
|
|
||||
|
if( !type ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemCreationStatus::ICS_INVALID_TYPE ); |
||||
|
response.mutable_created_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<BOARD_ITEM> item = createItemForType( *type, board ); |
||||
|
|
||||
|
if( !item ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemCreationStatus::ICS_INVALID_TYPE ); |
||||
|
e.set_error_message( fmt::format( "item type {} not supported for board", |
||||
|
magic_enum::enum_name( *type ) ) ); |
||||
|
response.mutable_created_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if( !item->Deserialize( anyItem ) ) |
||||
|
{ |
||||
|
e.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
e.set_error_message( fmt::format( "could not unpack {} from request", |
||||
|
item->GetClass().ToStdString() ) ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
if( itemUuidMap.count( item->m_Uuid ) ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemCreationStatus::ICS_EXISTING ); |
||||
|
response.mutable_created_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
itemResult.set_status( ItemCreationStatus::ICS_OK ); |
||||
|
item->Serialize( *itemResult.mutable_item() ); |
||||
|
commit->Add( item.release() ); |
||||
|
|
||||
|
response.mutable_created_items()->Add( std::move( itemResult ) ); |
||||
|
} |
||||
|
|
||||
|
pushCurrentCommit( "Added items via API" ); |
||||
|
response.set_status( ItemRequestStatus::IRS_OK ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<GetItemsResponse> API_HANDLER_PCB::handleGetItems( GetItems& aMsg ) |
||||
|
{ |
||||
|
if( !validateItemHeaderDocument( aMsg.header() ) ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
|
e.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
GetItemsResponse response; |
||||
|
|
||||
|
BOARD* board = m_frame->GetBoard(); |
||||
|
std::vector<BOARD_ITEM*> items; |
||||
|
std::set<KICAD_T> typesRequested, typesInserted; |
||||
|
bool handledAnything = false; |
||||
|
|
||||
|
for( const common::types::ItemType& typeMessage : aMsg.types() ) |
||||
|
{ |
||||
|
KICAD_T type; |
||||
|
|
||||
|
if( std::optional<KICAD_T> opt_type = magic_enum::enum_cast<KICAD_T>( typeMessage.type() ) ) |
||||
|
type = *opt_type; |
||||
|
else |
||||
|
continue; |
||||
|
|
||||
|
typesRequested.emplace( type ); |
||||
|
|
||||
|
if( typesInserted.count( type ) ) |
||||
|
continue; |
||||
|
|
||||
|
switch( type ) |
||||
|
{ |
||||
|
case PCB_TRACE_T: |
||||
|
case PCB_ARC_T: |
||||
|
case PCB_VIA_T: |
||||
|
handledAnything = true; |
||||
|
std::copy( board->Tracks().begin(), board->Tracks().end(), |
||||
|
std::back_inserter( items ) ); |
||||
|
typesInserted.insert( { PCB_TRACE_T, PCB_ARC_T, PCB_VIA_T } ); |
||||
|
break; |
||||
|
|
||||
|
default: |
||||
|
break; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if( !handledAnything ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
e.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
e.set_error_message( "none of the requested types are valid for a Board object" ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
for( const BOARD_ITEM* item : items ) |
||||
|
{ |
||||
|
if( !typesRequested.count( item->Type() ) ) |
||||
|
continue; |
||||
|
|
||||
|
google::protobuf::Any itemBuf; |
||||
|
item->Serialize( itemBuf ); |
||||
|
response.mutable_items()->Add( std::move( itemBuf ) ); |
||||
|
} |
||||
|
|
||||
|
response.set_status( ItemRequestStatus::IRS_OK ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<UpdateItemsResponse> API_HANDLER_PCB::handleUpdateItems( UpdateItems& aMsg ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
|
||||
|
if( !validateItemHeaderDocument( aMsg.header() ) ) |
||||
|
{ |
||||
|
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
|
e.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
BOARD* board = m_frame->GetBoard(); |
||||
|
BOARD_ITEM_SET boardItems = board->GetItemSet(); |
||||
|
|
||||
|
std::map<KIID, BOARD_ITEM*> itemUuidMap; |
||||
|
|
||||
|
std::for_each( boardItems.begin(), boardItems.end(), |
||||
|
[&]( BOARD_ITEM* aItem ) |
||||
|
{ |
||||
|
itemUuidMap[aItem->m_Uuid] = aItem; |
||||
|
} ); |
||||
|
|
||||
|
BOARD_COMMIT* commit = getCurrentCommit(); |
||||
|
|
||||
|
UpdateItemsResponse response; |
||||
|
|
||||
|
for( const google::protobuf::Any& anyItem : aMsg.items() ) |
||||
|
{ |
||||
|
ItemUpdateResult itemResult; |
||||
|
std::optional<KICAD_T> type = TypeNameFromAny( anyItem ); |
||||
|
|
||||
|
if( !type ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemUpdateStatus::IUS_INVALID_TYPE ); |
||||
|
response.mutable_updated_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
std::unique_ptr<BOARD_ITEM> temporaryItem = createItemForType( *type, board ); |
||||
|
|
||||
|
if( !temporaryItem ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemUpdateStatus::IUS_INVALID_TYPE ); |
||||
|
response.mutable_updated_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
if( !temporaryItem->Deserialize( anyItem ) ) |
||||
|
{ |
||||
|
e.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
e.set_error_message( fmt::format( "could not unpack {} from request", |
||||
|
magic_enum::enum_name( *type ) ) ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
if( !itemUuidMap.count( temporaryItem->m_Uuid ) ) |
||||
|
{ |
||||
|
itemResult.set_status( ItemUpdateStatus::IUS_NONEXISTENT ); |
||||
|
response.mutable_updated_items()->Add( std::move( itemResult ) ); |
||||
|
continue; |
||||
|
} |
||||
|
|
||||
|
BOARD_ITEM* boardItem = itemUuidMap[temporaryItem->m_Uuid]; |
||||
|
|
||||
|
boardItem->SwapItemData( temporaryItem.get() ); |
||||
|
|
||||
|
itemResult.set_status( ItemUpdateStatus::IUS_OK ); |
||||
|
boardItem->Serialize( *itemResult.mutable_item() ); |
||||
|
commit->Modify( boardItem ); |
||||
|
|
||||
|
itemResult.set_status( ItemUpdateStatus::IUS_OK ); |
||||
|
response.mutable_updated_items()->Add( std::move( itemResult ) ); |
||||
|
} |
||||
|
|
||||
|
response.set_status( ItemRequestStatus::IRS_OK ); |
||||
|
pushCurrentCommit( "Updated items via API" ); |
||||
|
return response; |
||||
|
} |
||||
|
|
||||
|
|
||||
|
HANDLER_RESULT<DeleteItemsResponse> API_HANDLER_PCB::handleDeleteItems( DeleteItems& aMsg ) |
||||
|
{ |
||||
|
if( !validateItemHeaderDocument( aMsg.header() ) ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
// No message needed for AS_UNHANDLED; this is an internal flag for the API server
|
||||
|
e.set_status( ApiStatusCode::AS_UNHANDLED ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
std::map<KIID, ItemDeletionStatus> itemsToDelete; |
||||
|
|
||||
|
for( const common::types::KIID& kiidBuf : aMsg.item_ids() ) |
||||
|
{ |
||||
|
if( !kiidBuf.value().empty() ) |
||||
|
{ |
||||
|
KIID kiid( kiidBuf.value() ); |
||||
|
itemsToDelete[kiid] = ItemDeletionStatus::IDS_NONEXISTENT; |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
if( itemsToDelete.empty() ) |
||||
|
{ |
||||
|
ApiResponseStatus e; |
||||
|
e.set_status( ApiStatusCode::AS_BAD_REQUEST ); |
||||
|
e.set_error_message( "no valid items to delete were given" ); |
||||
|
return tl::unexpected( e ); |
||||
|
} |
||||
|
|
||||
|
BOARD* board = m_frame->GetBoard(); |
||||
|
|
||||
|
// This is somewhat inefficient on paper, but the total number of items on a board is
|
||||
|
// not computationally-speaking very high even on what we'd consider a large design.
|
||||
|
// If this ends up not being the case, we should consider doing something like refactoring
|
||||
|
// BOARD to contain all items in a contiguous memory arena and constructing views over it
|
||||
|
// when we want to filter to just tracks, etc.
|
||||
|
BOARD_ITEM_SET items = board->GetItemSet(); |
||||
|
std::vector<BOARD_ITEM*> validatedItems; |
||||
|
|
||||
|
for( BOARD_ITEM* item : items ) |
||||
|
{ |
||||
|
if( itemsToDelete.count( item->m_Uuid ) ) |
||||
|
{ |
||||
|
validatedItems.push_back( item ); |
||||
|
itemsToDelete[item->m_Uuid] = ItemDeletionStatus::IDS_OK; |
||||
|
} |
||||
|
|
||||
|
// Note: we don't currently support locking items from API modification, but here is where
|
||||
|
// to add it in the future (and return IDS_IMMUTABLE)
|
||||
|
} |
||||
|
|
||||
|
BOARD_COMMIT* commit = getCurrentCommit(); |
||||
|
|
||||
|
for( BOARD_ITEM* item : validatedItems ) |
||||
|
commit->Remove( item ); |
||||
|
|
||||
|
if( !m_transactionInProgress ) |
||||
|
pushCurrentCommit( "Deleted items via API" ); |
||||
|
|
||||
|
DeleteItemsResponse response; |
||||
|
|
||||
|
for( const auto& [id, status] : itemsToDelete ) |
||||
|
{ |
||||
|
ItemDeletionResult result; |
||||
|
result.mutable_id()->set_value( id.AsStdString() ); |
||||
|
result.set_status( status ); |
||||
|
} |
||||
|
|
||||
|
response.set_status( ItemRequestStatus::IRS_OK ); |
||||
|
return response; |
||||
|
} |
||||
@ -0,0 +1,86 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_API_HANDLER_PCB_H |
||||
|
#define KICAD_API_HANDLER_PCB_H |
||||
|
|
||||
|
#include <google/protobuf/empty.pb.h> |
||||
|
|
||||
|
#include <api/api_handler.h> |
||||
|
|
||||
|
#include <api/common/commands/editor_commands.pb.h> |
||||
|
|
||||
|
#include <properties/property_mgr.h> |
||||
|
|
||||
|
using namespace kiapi; |
||||
|
using namespace kiapi::common; |
||||
|
|
||||
|
using google::protobuf::Empty; |
||||
|
|
||||
|
|
||||
|
class BOARD_COMMIT; |
||||
|
class BOARD_ITEM; |
||||
|
class BOARD_ITEM_CONTAINER; |
||||
|
class EDA_ITEM; |
||||
|
class PCB_EDIT_FRAME; |
||||
|
class PCB_TRACK; |
||||
|
class PROPERTY_BASE; |
||||
|
|
||||
|
|
||||
|
class API_HANDLER_PCB : public API_HANDLER |
||||
|
{ |
||||
|
public: |
||||
|
API_HANDLER_PCB( PCB_EDIT_FRAME* aFrame ); |
||||
|
|
||||
|
private: |
||||
|
typedef std::map<std::string, PROPERTY_BASE*> PROTO_PROPERTY_MAP; |
||||
|
|
||||
|
static std::unique_ptr<BOARD_ITEM> createItemForType( KICAD_T aType, |
||||
|
BOARD_ITEM_CONTAINER* aContainer ); |
||||
|
|
||||
|
HANDLER_RESULT<commands::RunActionResponse> handleRunAction( commands::RunAction& aMsg ); |
||||
|
|
||||
|
HANDLER_RESULT<commands::GetOpenDocumentsResponse> handleGetOpenDocuments( |
||||
|
commands::GetOpenDocuments& aMsg ); |
||||
|
|
||||
|
HANDLER_RESULT<commands::BeginCommitResponse> handleBeginCommit( commands::BeginCommit& aMsg ); |
||||
|
HANDLER_RESULT<commands::EndCommitResponse> handleEndCommit( commands::EndCommit& aMsg ); |
||||
|
|
||||
|
HANDLER_RESULT<commands::CreateItemsResponse> handleCreateItems( commands::CreateItems& aMsg ); |
||||
|
HANDLER_RESULT<commands::GetItemsResponse> handleGetItems( commands::GetItems& aMsg ); |
||||
|
HANDLER_RESULT<commands::UpdateItemsResponse> handleUpdateItems( commands::UpdateItems& aMsg ); |
||||
|
HANDLER_RESULT<commands::DeleteItemsResponse> handleDeleteItems( commands::DeleteItems& aMsg ); |
||||
|
|
||||
|
private: |
||||
|
|
||||
|
bool validateItemHeaderDocument( const common::types::ItemHeader& aHeader ); |
||||
|
|
||||
|
BOARD_COMMIT* getCurrentCommit(); |
||||
|
|
||||
|
void pushCurrentCommit( const std::string& aMessage ); |
||||
|
|
||||
|
PCB_EDIT_FRAME* m_frame; |
||||
|
|
||||
|
std::unique_ptr<BOARD_COMMIT> m_commit; |
||||
|
|
||||
|
bool m_transactionInProgress; |
||||
|
}; |
||||
|
|
||||
|
#endif //KICAD_API_HANDLER_PCB_H |
||||
@ -0,0 +1,41 @@ |
|||||
|
# This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
# |
||||
|
# Copyright (C) 2023 KiCad Developers, see AUTHORS.TXT for contributors. |
||||
|
# |
||||
|
# This program is free software: you can redistribute it and/or modify it |
||||
|
# under the terms of the GNU General Public License as published by the |
||||
|
# Free Software Foundation, either version 3 of the License, or (at your |
||||
|
# option) any later version. |
||||
|
# |
||||
|
# This program is distributed in the hope that it will be useful, but |
||||
|
# WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
# General Public License for more details. |
||||
|
# |
||||
|
# You should have received a copy of the GNU General Public License along |
||||
|
# with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
|
||||
|
set( QA_KINNG_SRCS |
||||
|
kinng_test_module.cpp |
||||
|
test_kinng.cpp |
||||
|
) |
||||
|
|
||||
|
add_executable( qa_kinng |
||||
|
${QA_KINNG_SRCS} |
||||
|
) |
||||
|
|
||||
|
target_link_libraries( qa_kinng |
||||
|
qa_utils |
||||
|
kinng |
||||
|
kiapi |
||||
|
${NNG_LIBRARY} |
||||
|
${wxWidgets_LIBRARIES} |
||||
|
) |
||||
|
|
||||
|
target_include_directories( qa_kinng PRIVATE |
||||
|
${CMAKE_SOURCE_DIR}/include |
||||
|
${CMAKE_SOURCE_DIR}/qa/mocks/include |
||||
|
${CMAKE_CURRENT_SOURCE_DIR} |
||||
|
) |
||||
|
|
||||
|
kicad_add_boost_test( qa_kinng qa_kinng ) |
||||
@ -0,0 +1,22 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#define BOOST_TEST_MODULE KiNNG
|
||||
|
#include <boost/test/unit_test.hpp>
|
||||
@ -0,0 +1,34 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <qa_utils/wx_utils/unit_test_utils.h>
|
||||
|
#include <kinng.h>
|
||||
|
|
||||
|
#include <import_export.h>
|
||||
|
#include <api/common/envelope.pb.h>
|
||||
|
|
||||
|
BOOST_AUTO_TEST_SUITE( KiNNG ) |
||||
|
|
||||
|
BOOST_AUTO_TEST_CASE( CreateIPCResponder ) |
||||
|
{ |
||||
|
KINNG_REQUEST_SERVER server; |
||||
|
} |
||||
|
|
||||
|
BOOST_AUTO_TEST_SUITE_END() |
||||
@ -0,0 +1,73 @@ |
|||||
|
/*
|
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
*/ |
||||
|
|
||||
|
#include <wx/process.h>
|
||||
|
|
||||
|
#include <utility>
|
||||
|
|
||||
|
#include "python_manager.h"
|
||||
|
|
||||
|
class PYTHON_PROCESS : public wxProcess |
||||
|
{ |
||||
|
public: |
||||
|
PYTHON_PROCESS( std::function<void(int, const wxString&)> aCallback ) : |
||||
|
wxProcess(), |
||||
|
m_callback( std::move( aCallback ) ) |
||||
|
{} |
||||
|
|
||||
|
void OnTerminate( int aPid, int aStatus ) override |
||||
|
{ |
||||
|
if( m_callback ) |
||||
|
{ |
||||
|
wxString output; |
||||
|
wxInputStream* processOut = GetInputStream(); |
||||
|
size_t bytesRead = 0; |
||||
|
|
||||
|
while( processOut->CanRead() && bytesRead < MAX_OUTPUT_LEN ) |
||||
|
{ |
||||
|
char buffer[4096]; |
||||
|
buffer[ processOut->Read( buffer, sizeof( buffer ) - 1 ).LastRead() ] = '\0'; |
||||
|
output.append( buffer, sizeof( buffer ) ); |
||||
|
bytesRead += processOut->LastRead(); |
||||
|
} |
||||
|
|
||||
|
m_callback( aStatus, output ); |
||||
|
} |
||||
|
} |
||||
|
|
||||
|
static constexpr size_t MAX_OUTPUT_LEN = 1024L * 1024L; |
||||
|
|
||||
|
private: |
||||
|
std::function<void(int, const wxString&)> m_callback; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
void PYTHON_MANAGER::Execute( const wxString& aArgs, |
||||
|
const std::function<void( int, const wxString& )>& aCallback ) |
||||
|
{ |
||||
|
PYTHON_PROCESS* process = new PYTHON_PROCESS( aCallback ); |
||||
|
process->Redirect(); |
||||
|
|
||||
|
wxString cmd = wxString::Format( wxS( "%s %s" ), m_interpreterPath, aArgs ); |
||||
|
long pid = wxExecute( cmd, wxEXEC_ASYNC, process ); |
||||
|
|
||||
|
if( pid == 0 ) |
||||
|
aCallback( -1, wxEmptyString ); |
||||
|
} |
||||
@ -0,0 +1,48 @@ |
|||||
|
/* |
||||
|
* This program source code file is part of KiCad, a free EDA CAD application. |
||||
|
* |
||||
|
* Copyright (C) 2023 Jon Evans <jon@craftyjon.com> |
||||
|
* Copyright (C) 2023 KiCad Developers, see AUTHORS.txt for contributors. |
||||
|
* |
||||
|
* This program is free software: you can redistribute it and/or modify it |
||||
|
* under the terms of the GNU General Public License as published by the |
||||
|
* Free Software Foundation, either version 3 of the License, or (at your |
||||
|
* option) any later version. |
||||
|
* |
||||
|
* This program is distributed in the hope that it will be useful, but |
||||
|
* WITHOUT ANY WARRANTY; without even the implied warranty of |
||||
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU |
||||
|
* General Public License for more details. |
||||
|
* |
||||
|
* You should have received a copy of the GNU General Public License along |
||||
|
* with this program. If not, see <http://www.gnu.org/licenses/>. |
||||
|
*/ |
||||
|
|
||||
|
#ifndef KICAD_PYTHON_MANAGER_H |
||||
|
#define KICAD_PYTHON_MANAGER_H |
||||
|
|
||||
|
#include <functional> |
||||
|
#include <optional> |
||||
|
|
||||
|
#include <wx/wx.h> |
||||
|
|
||||
|
|
||||
|
class PYTHON_MANAGER |
||||
|
{ |
||||
|
public: |
||||
|
PYTHON_MANAGER( const wxString& aInterpreterPath ) : |
||||
|
m_interpreterPath( aInterpreterPath ) |
||||
|
{} |
||||
|
|
||||
|
void Execute( const wxString& aArgs, |
||||
|
const std::function<void(int, const wxString&)>& aCallback ); |
||||
|
|
||||
|
wxString GetInterpreterPath() const { return m_interpreterPath; } |
||||
|
void SetInterpreterPath( const wxString& aPath ) { m_interpreterPath = aPath; } |
||||
|
|
||||
|
private: |
||||
|
wxString m_interpreterPath; |
||||
|
}; |
||||
|
|
||||
|
|
||||
|
#endif //KICAD_PYTHON_MANAGER_H |
||||
@ -0,0 +1,7 @@ |
|||||
|
add_library( expected INTERFACE ) |
||||
|
|
||||
|
target_include_directories( expected INTERFACE ${CMAKE_CURRENT_SOURCE_DIR}/include ) |
||||
|
|
||||
|
target_sources( expected INTERFACE |
||||
|
${CMAKE_CURRENT_SOURCE_DIR}/include/tl/expected.hpp |
||||
|
) |
||||
@ -0,0 +1,121 @@ |
|||||
|
Creative Commons Legal Code |
||||
|
|
||||
|
CC0 1.0 Universal |
||||
|
|
||||
|
CREATIVE COMMONS CORPORATION IS NOT A LAW FIRM AND DOES NOT PROVIDE |
||||
|
LEGAL SERVICES. DISTRIBUTION OF THIS DOCUMENT DOES NOT CREATE AN |
||||
|
ATTORNEY-CLIENT RELATIONSHIP. CREATIVE COMMONS PROVIDES THIS |
||||
|
INFORMATION ON AN "AS-IS" BASIS. CREATIVE COMMONS MAKES NO WARRANTIES |
||||
|
REGARDING THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS |
||||
|
PROVIDED HEREUNDER, AND DISCLAIMS LIABILITY FOR DAMAGES RESULTING FROM |
||||
|
THE USE OF THIS DOCUMENT OR THE INFORMATION OR WORKS PROVIDED |
||||
|
HEREUNDER. |
||||
|
|
||||
|
Statement of Purpose |
||||
|
|
||||
|
The laws of most jurisdictions throughout the world automatically confer |
||||
|
exclusive Copyright and Related Rights (defined below) upon the creator |
||||
|
and subsequent owner(s) (each and all, an "owner") of an original work of |
||||
|
authorship and/or a database (each, a "Work"). |
||||
|
|
||||
|
Certain owners wish to permanently relinquish those rights to a Work for |
||||
|
the purpose of contributing to a commons of creative, cultural and |
||||
|
scientific works ("Commons") that the public can reliably and without fear |
||||
|
of later claims of infringement build upon, modify, incorporate in other |
||||
|
works, reuse and redistribute as freely as possible in any form whatsoever |
||||
|
and for any purposes, including without limitation commercial purposes. |
||||
|
These owners may contribute to the Commons to promote the ideal of a free |
||||
|
culture and the further production of creative, cultural and scientific |
||||
|
works, or to gain reputation or greater distribution for their Work in |
||||
|
part through the use and efforts of others. |
||||
|
|
||||
|
For these and/or other purposes and motivations, and without any |
||||
|
expectation of additional consideration or compensation, the person |
||||
|
associating CC0 with a Work (the "Affirmer"), to the extent that he or she |
||||
|
is an owner of Copyright and Related Rights in the Work, voluntarily |
||||
|
elects to apply CC0 to the Work and publicly distribute the Work under its |
||||
|
terms, with knowledge of his or her Copyright and Related Rights in the |
||||
|
Work and the meaning and intended legal effect of CC0 on those rights. |
||||
|
|
||||
|
1. Copyright and Related Rights. A Work made available under CC0 may be |
||||
|
protected by copyright and related or neighboring rights ("Copyright and |
||||
|
Related Rights"). Copyright and Related Rights include, but are not |
||||
|
limited to, the following: |
||||
|
|
||||
|
i. the right to reproduce, adapt, distribute, perform, display, |
||||
|
communicate, and translate a Work; |
||||
|
ii. moral rights retained by the original author(s) and/or performer(s); |
||||
|
iii. publicity and privacy rights pertaining to a person's image or |
||||
|
likeness depicted in a Work; |
||||
|
iv. rights protecting against unfair competition in regards to a Work, |
||||
|
subject to the limitations in paragraph 4(a), below; |
||||
|
v. rights protecting the extraction, dissemination, use and reuse of data |
||||
|
in a Work; |
||||
|
vi. database rights (such as those arising under Directive 96/9/EC of the |
||||
|
European Parliament and of the Council of 11 March 1996 on the legal |
||||
|
protection of databases, and under any national implementation |
||||
|
thereof, including any amended or successor version of such |
||||
|
directive); and |
||||
|
vii. other similar, equivalent or corresponding rights throughout the |
||||
|
world based on applicable law or treaty, and any national |
||||
|
implementations thereof. |
||||
|
|
||||
|
2. Waiver. To the greatest extent permitted by, but not in contravention |
||||
|
of, applicable law, Affirmer hereby overtly, fully, permanently, |
||||
|
irrevocably and unconditionally waives, abandons, and surrenders all of |
||||
|
Affirmer's Copyright and Related Rights and associated claims and causes |
||||
|
of action, whether now known or unknown (including existing as well as |
||||
|
future claims and causes of action), in the Work (i) in all territories |
||||
|
worldwide, (ii) for the maximum duration provided by applicable law or |
||||
|
treaty (including future time extensions), (iii) in any current or future |
||||
|
medium and for any number of copies, and (iv) for any purpose whatsoever, |
||||
|
including without limitation commercial, advertising or promotional |
||||
|
purposes (the "Waiver"). Affirmer makes the Waiver for the benefit of each |
||||
|
member of the public at large and to the detriment of Affirmer's heirs and |
||||
|
successors, fully intending that such Waiver shall not be subject to |
||||
|
revocation, rescission, cancellation, termination, or any other legal or |
||||
|
equitable action to disrupt the quiet enjoyment of the Work by the public |
||||
|
as contemplated by Affirmer's express Statement of Purpose. |
||||
|
|
||||
|
3. Public License Fallback. Should any part of the Waiver for any reason |
||||
|
be judged legally invalid or ineffective under applicable law, then the |
||||
|
Waiver shall be preserved to the maximum extent permitted taking into |
||||
|
account Affirmer's express Statement of Purpose. In addition, to the |
||||
|
extent the Waiver is so judged Affirmer hereby grants to each affected |
||||
|
person a royalty-free, non transferable, non sublicensable, non exclusive, |
||||
|
irrevocable and unconditional license to exercise Affirmer's Copyright and |
||||
|
Related Rights in the Work (i) in all territories worldwide, (ii) for the |
||||
|
maximum duration provided by applicable law or treaty (including future |
||||
|
time extensions), (iii) in any current or future medium and for any number |
||||
|
of copies, and (iv) for any purpose whatsoever, including without |
||||
|
limitation commercial, advertising or promotional purposes (the |
||||
|
"License"). The License shall be deemed effective as of the date CC0 was |
||||
|
applied by Affirmer to the Work. Should any part of the License for any |
||||
|
reason be judged legally invalid or ineffective under applicable law, such |
||||
|
partial invalidity or ineffectiveness shall not invalidate the remainder |
||||
|
of the License, and in such case Affirmer hereby affirms that he or she |
||||
|
will not (i) exercise any of his or her remaining Copyright and Related |
||||
|
Rights in the Work or (ii) assert any associated claims and causes of |
||||
|
action with respect to the Work, in either case contrary to Affirmer's |
||||
|
express Statement of Purpose. |
||||
|
|
||||
|
4. Limitations and Disclaimers. |
||||
|
|
||||
|
a. No trademark or patent rights held by Affirmer are waived, abandoned, |
||||
|
surrendered, licensed or otherwise affected by this document. |
||||
|
b. Affirmer offers the Work as-is and makes no representations or |
||||
|
warranties of any kind concerning the Work, express, implied, |
||||
|
statutory or otherwise, including without limitation warranties of |
||||
|
title, merchantability, fitness for a particular purpose, non |
||||
|
infringement, or the absence of latent or other defects, accuracy, or |
||||
|
the present or absence of errors, whether or not discoverable, all to |
||||
|
the greatest extent permissible under applicable law. |
||||
|
c. Affirmer disclaims responsibility for clearing rights of other persons |
||||
|
that may apply to the Work or any use thereof, including without |
||||
|
limitation any person's Copyright and Related Rights in the Work. |
||||
|
Further, Affirmer disclaims responsibility for obtaining any necessary |
||||
|
consents, permissions or other rights required for any use of the |
||||
|
Work. |
||||
|
d. Affirmer understands and acknowledges that Creative Commons is not a |
||||
|
party to this document and has no duty or obligation with respect to |
||||
|
this CC0 or use of the Work. |
||||
@ -0,0 +1,4 @@ |
|||||
|
This directory contains the expected library from https://github.com/TartanLlama/expected |
||||
|
|
||||
|
It is licensed under CC0-1.0, with the license text in the COPYING file in this directory. |
||||
|
|
||||
2444
thirdparty/expected/include/tl/expected.hpp
File diff suppressed because it is too large
View File
File diff suppressed because it is too large
View File
Write
Preview
Loading…
Cancel
Save
Reference in new issue