69 std::unique_ptr<KICAD_API_SERVER> server = std::make_unique<KICAD_API_SERVER>(
false );
74 if( !socketPath.IsEmpty() )
75 server->SetSocketPath( socketPath );
77 types::DocumentType openDocumentType = types::DOCTYPE_UNKNOWN;
79 wxFileName openProjectPath;
81 auto faceForDocument = []( types::DocumentType aType ) ->
KIWAY::FACE_T
91 auto docFileExtension = []( types::DocumentType aType ) -> std::string
101 auto closeCurrentDocument = [&]()
103 if( openDocumentType != types::DOCTYPE_UNKNOWN )
105 wxString docFileName;
107 if( openDocumentType == types::DOCTYPE_PCB || openDocumentType == types::DOCTYPE_SCHEMATIC )
109 wxFileName docPath( openProjectPath );
110 docPath.SetExt( docFileExtension( openDocumentType ) );
111 docFileName = docPath.GetFullName();
118 openProjectPath.Clear();
119 openDocumentType = types::DOCTYPE_UNKNOWN;
122 auto openDocument = [&](
const commands::OpenDocument& aRequest )
125 types::DocumentType requestType = aRequest.type();
127 if( requestType != types::DOCTYPE_PCB
128 && requestType != types::DOCTYPE_SCHEMATIC
129 && requestType != types::DOCTYPE_PROJECT )
132 e.set_status( ApiStatusCode::AS_UNIMPLEMENTED );
133 e.set_error_message(
"Only PCB, schematic, and project document types are supported" );
134 return tl::unexpected( e );
137 wxString inputPath = wxString::FromUTF8( aRequest.path() );
139 if( inputPath.IsEmpty() )
142 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
143 e.set_error_message(
"OpenDocument requires a non-empty path" );
144 return tl::unexpected( e );
147 wxFileName projectPath( inputPath );
154 projectPath.MakeAbsolute();
156 closeCurrentDocument();
164 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
165 e.set_error_message(
"unsupported document type" );
166 return tl::unexpected( e );
172 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
173 e.set_error_message( error.ToStdString() );
174 return tl::unexpected( e );
177 openProjectPath = projectPath;
178 openDocumentType = requestType;
181 commands::OpenDocumentResponse response;
182 types::DocumentSpecifier* doc = response.mutable_document();
185 doc->set_type( openDocumentType );
187 if( openDocumentType == types::DOCTYPE_PCB )
189 wxFileName boardPath( openProjectPath );
191 doc->set_board_filename( boardPath.GetFullName().ToStdString() );
193 else if( openDocumentType == types::DOCTYPE_SCHEMATIC )
195 wxFileName schPath( openProjectPath );
197 doc->set_schematic_filename( schPath.GetFullName().ToStdString() );
200 doc->mutable_project()->set_name(
project.GetProjectName().ToStdString() );
201 doc->mutable_project()->set_path(
project.GetProjectDirectory().ToStdString() );
209 if( openDocumentType == types::DOCTYPE_UNKNOWN )
212 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
213 e.set_error_message(
"No document is currently open" );
214 return tl::unexpected( e );
217 if( aRequest.has_document() )
219 if( aRequest.document().type() != openDocumentType )
222 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
223 e.set_error_message(
"Requested document type does not match the open document" );
224 return tl::unexpected( e );
227 wxFileName expectedPath( openProjectPath );
228 expectedPath.SetExt( docFileExtension( openDocumentType ) );
230 wxString requestedName;
232 if( openDocumentType == types::DOCTYPE_PCB
233 && !aRequest.document().board_filename().empty() )
235 requestedName = wxString::FromUTF8( aRequest.document().board_filename() );
237 else if( openDocumentType == types::DOCTYPE_SCHEMATIC
238 && !aRequest.document().schematic_filename().empty() )
240 requestedName = wxString::FromUTF8( aRequest.document().schematic_filename() );
243 if( !requestedName.IsEmpty() && expectedPath.GetFullName() != requestedName )
246 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
247 e.set_error_message(
"Requested document does not match the open document" );
248 return tl::unexpected( e );
252 wxString docFileName;
254 if( openDocumentType == types::DOCTYPE_PCB || openDocumentType == types::DOCTYPE_SCHEMATIC )
256 wxFileName expectedPath( openProjectPath );
257 expectedPath.SetExt( docFileExtension( openDocumentType ) );
258 docFileName = expectedPath.GetFullName();
266 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
267 e.set_error_message( error.ToStdString() );
268 return tl::unexpected( e );
271 openProjectPath.Clear();
272 openDocumentType = types::DOCTYPE_UNKNOWN;
274 return google::protobuf::Empty();
280 server->RegisterHandler( &commonHandler );
283 if( !server->Running() )
285 wxFprintf( stderr,
_(
"Failed to start API server\n" ) );
291 if( !preloadPath.IsEmpty() )
295 wxFileName preloadFile( preloadPath );
296 types::DocumentType preloadType = types::DOCTYPE_PROJECT;
299 preloadType = types::DOCTYPE_SCHEMATIC;
301 preloadType = types::DOCTYPE_PCB;
303 commands::OpenDocument request;
304 request.set_type( preloadType );
305 request.set_path( preloadPath.ToStdString() );
307 auto preloadResult = openDocument( request );
311 wxFprintf( stderr,
"%s\n", preloadResult.error().error_message() );
312 server->DeregisterHandler( &commonHandler );
317 server->SetReadyToReply(
true );
319 wxString listenPath = wxString::FromUTF8( server->SocketPath() );
320 wxFprintf( stdout,
"KiCad API server listening at %s\n", listenPath );
331 wxTheApp->ProcessPendingEvents();
335 std::signal( SIGINT, oldSigInt );
337 std::signal( SIGTERM, oldSigTerm );
340 wxFprintf( stdout,
"Shutting down\n" );
342 closeCurrentDocument();
343 server->DeregisterHandler( &commonHandler );