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 )
198 doc->mutable_project()->set_name(
project.GetProjectName().ToUTF8() );
199 doc->mutable_project()->set_path(
project.GetProjectPath().ToUTF8() );
207 if( openDocumentType == types::DOCTYPE_UNKNOWN )
210 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
211 e.set_error_message(
"No document is currently open" );
212 return tl::unexpected( e );
215 if( aRequest.has_document() )
217 if( aRequest.document().type() != openDocumentType )
220 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
221 e.set_error_message(
"Requested document type does not match the open document" );
222 return tl::unexpected( e );
225 wxFileName expectedPath( openProjectPath );
226 expectedPath.SetExt( docFileExtension( openDocumentType ) );
228 wxString requestedName;
230 if( openDocumentType == types::DOCTYPE_PCB
231 && !aRequest.document().board_filename().empty() )
233 requestedName = wxString::FromUTF8( aRequest.document().board_filename() );
235 else if( openDocumentType == types::DOCTYPE_SCHEMATIC
236 && !aRequest.document().project().path().empty() )
238 requestedName = wxString::FromUTF8( aRequest.document().project().name() )
242 if( !requestedName.IsEmpty() && expectedPath.GetFullName() != requestedName )
245 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
246 e.set_error_message(
"Requested document does not match the open document" );
247 return tl::unexpected( e );
251 wxString docFileName;
253 if( openDocumentType == types::DOCTYPE_PCB || openDocumentType == types::DOCTYPE_SCHEMATIC )
255 wxFileName expectedPath( openProjectPath );
256 expectedPath.SetExt( docFileExtension( openDocumentType ) );
257 docFileName = expectedPath.GetFullName();
265 e.set_status( ApiStatusCode::AS_BAD_REQUEST );
266 e.set_error_message( error.ToStdString() );
267 return tl::unexpected( e );
270 openProjectPath.Clear();
271 openDocumentType = types::DOCTYPE_UNKNOWN;
273 return google::protobuf::Empty();
279 server->RegisterHandler( &commonHandler );
282 if( !server->Running() )
284 wxFprintf( stderr,
_(
"Failed to start API server\n" ) );
290 if( !preloadPath.IsEmpty() )
294 wxFileName preloadFile( preloadPath );
295 types::DocumentType preloadType = types::DOCTYPE_PROJECT;
298 preloadType = types::DOCTYPE_SCHEMATIC;
300 preloadType = types::DOCTYPE_PCB;
302 commands::OpenDocument request;
303 request.set_type( preloadType );
304 request.set_path( preloadPath.ToStdString() );
306 auto preloadResult = openDocument( request );
310 wxFprintf( stderr,
"%s\n", preloadResult.error().error_message() );
311 server->DeregisterHandler( &commonHandler );
316 server->SetReadyToReply(
true );
318 wxString listenPath = wxString::FromUTF8( server->SocketPath() );
319 wxFprintf( stdout,
"KiCad API server listening at %s\n", listenPath );
330 wxTheApp->ProcessPendingEvents();
334 std::signal( SIGINT, oldSigInt );
336 std::signal( SIGTERM, oldSigTerm );
339 wxFprintf( stdout,
"Shutting down\n" );
341 closeCurrentDocument();
342 server->DeregisterHandler( &commonHandler );