70 std::unique_ptr<KICAD_API_SERVER> server = std::make_unique<KICAD_API_SERVER>(
false );
75 if( !socketPath.IsEmpty() )
76 server->SetSocketPath( socketPath );
78 types::DocumentType openDocumentType = types::DOCTYPE_UNKNOWN;
80 wxFileName openProjectPath;
82 auto faceForDocument = []( types::DocumentType aType ) ->
KIWAY::FACE_T
93 auto docFileExtension = []( types::DocumentType aType ) -> std::string
103 auto closeCurrentDocument = [&]()
105 if( openDocumentType != types::DOCTYPE_UNKNOWN )
107 wxString docFileName;
109 if( openDocumentType == types::DOCTYPE_PCB || openDocumentType == types::DOCTYPE_SCHEMATIC )
111 wxFileName docPath( openProjectPath );
112 docPath.SetExt( docFileExtension( openDocumentType ) );
113 docFileName = docPath.GetFullName();
120 openProjectPath.Clear();
121 openDocumentType = types::DOCTYPE_UNKNOWN;
124 auto openDocument = [&](
const commands::OpenDocument& aRequest )
127 types::DocumentType requestType = aRequest.type();
129 if( requestType != types::DOCTYPE_PCB && requestType != types::DOCTYPE_SCHEMATIC
130 && requestType != types::DOCTYPE_PROJECT && requestType != types::DOCTYPE_FOOTPRINT )
133 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
134 e.set_error_message(
"Only PCB, schematic, footprint, and project document types are supported" );
135 return tl::unexpected( e );
138 wxString inputPath = wxString::FromUTF8( aRequest.path() );
140 if( inputPath.IsEmpty() )
143 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
144 e.set_error_message(
"OpenDocument requires a non-empty path" );
145 return tl::unexpected( e );
148 closeCurrentDocument();
156 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
157 e.set_error_message(
"unsupported document type" );
158 return tl::unexpected( e );
161 wxFileName projectPath;
164 projectPath = wxFileName( inputPath );
171 projectPath.MakeAbsolute();
172 openPath = projectPath.GetFullPath();
177 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
178 e.set_error_message( error.ToStdString() );
179 return tl::unexpected( e );
182 openProjectPath = projectPath;
183 openDocumentType = requestType;
186 commands::OpenDocumentResponse response;
187 types::DocumentSpecifier* doc = response.mutable_document();
190 doc->set_type( openDocumentType );
192 if( openDocumentType == types::DOCTYPE_PCB )
194 wxFileName boardPath( openProjectPath );
196 doc->set_board_filename( boardPath.GetFullName().ToStdString() );
198 else if( openDocumentType == types::DOCTYPE_SCHEMATIC )
203 doc->mutable_project()->set_name(
project.GetProjectName().ToUTF8() );
204 doc->mutable_project()->set_path(
project.GetProjectPath().ToUTF8() );
212 if( openDocumentType == types::DOCTYPE_UNKNOWN )
215 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
216 e.set_error_message(
"No document is currently open" );
217 return tl::unexpected( e );
220 if( aRequest.has_document() )
222 if( aRequest.document().type() != openDocumentType )
225 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
226 e.set_error_message(
"Requested document type does not match the open document" );
227 return tl::unexpected( e );
230 wxFileName expectedPath( openProjectPath );
231 expectedPath.SetExt( docFileExtension( openDocumentType ) );
233 wxString requestedName;
235 if( openDocumentType == types::DOCTYPE_PCB
236 && !aRequest.document().board_filename().empty() )
238 requestedName = wxString::FromUTF8( aRequest.document().board_filename() );
240 else if( openDocumentType == types::DOCTYPE_SCHEMATIC
241 && !aRequest.document().project().path().empty() )
243 requestedName = wxString::FromUTF8( aRequest.document().project().name() )
247 if( !requestedName.IsEmpty() && expectedPath.GetFullName() != requestedName )
250 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
251 e.set_error_message(
"Requested document does not match the open document" );
252 return tl::unexpected( e );
256 wxString docFileName;
258 if( openDocumentType == types::DOCTYPE_PCB || openDocumentType == types::DOCTYPE_SCHEMATIC )
260 wxFileName expectedPath( openProjectPath );
261 expectedPath.SetExt( docFileExtension( openDocumentType ) );
262 docFileName = expectedPath.GetFullName();
270 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
271 e.set_error_message( error.ToStdString() );
272 return tl::unexpected( e );
275 openProjectPath.Clear();
276 openDocumentType = types::DOCTYPE_UNKNOWN;
278 return google::protobuf::Empty();
284 server->RegisterHandler( &commonHandler );
287 if( !server->Running() )
289 wxFprintf( stderr,
_(
"Failed to start API server\n" ) );
295 if( !preloadPath.IsEmpty() )
299 wxFileName preloadFile( preloadPath );
300 types::DocumentType preloadType = types::DOCTYPE_PROJECT;
303 preloadType = types::DOCTYPE_SCHEMATIC;
305 preloadType = types::DOCTYPE_PCB;
307 commands::OpenDocument request;
308 request.set_type( preloadType );
309 request.set_path( preloadPath.ToStdString() );
311 auto preloadResult = openDocument( request );
315 wxFprintf( stderr,
"%s\n", preloadResult.error().error_message() );
316 server->DeregisterHandler( &commonHandler );
321 server->SetReadyToReply(
true );
323 wxString listenPath = wxString::FromUTF8( server->SocketPath() );
324 wxFprintf( stdout,
"KiCad API server listening at %s\n", listenPath );
335 wxTheApp->ProcessPendingEvents();
339 std::signal( SIGINT, oldSigInt );
341 std::signal( SIGTERM, oldSigTerm );
344 wxFprintf( stdout,
"Shutting down\n" );
346 closeCurrentDocument();
347 server->DeregisterHandler( &commonHandler );