81    socket.AssignDir( wxS( 
"/tmp" ) );
 
   83    socket.AssignDir( wxStandardPaths::Get().GetTempDir() );
 
   85    socket.AppendDir( wxS( 
"kicad" ) );
 
   86    socket.SetFullName( wxS( 
"api.sock" ) );
 
   90        wxLogTrace( 
traceApi, wxString::Format( 
"Server: socket path %s could not be created",
 
  100    wxFileName lockFilePath( socket.GetPath(), wxS( 
"api.lock" ) );
 
  102    int lockFile = open( lockFilePath.GetFullPath().c_str(), O_RDONLY | O_CREAT, 0600 );
 
  104    if( lockFile >= 0 && flock( lockFile, LOCK_EX | LOCK_NB ) == 0 )
 
  106        if( socket.Exists() )
 
  108            wxLogTrace( 
traceApi, wxString::Format( 
"Server: cleaning up stale socket path %s",
 
  109                                                    socket.GetFullPath() ) );
 
  110            wxRemoveFile( socket.GetFullPath() );
 
  115    if( socket.Exists() )
 
  117        socket.SetFullName( wxString::Format( wxS( 
"api-%lu.sock" ), ::wxGetProcessId() ) );
 
  119        if( socket.Exists() )
 
  121            wxLogTrace( 
traceApi, wxString::Format( 
"Server: PID socket path %s already exists!",
 
  122                                                    socket.GetFullPath() ) );
 
  127    m_server = std::make_unique<KINNG_REQUEST_SERVER>(
 
  128            fmt::format( 
"ipc://{}", socket.GetFullPath().ToStdString() ) );
 
  137        log( fmt::format( 
"--- KiCad API server started at {} ---\n", 
SocketPath() ) );
 
 
  188        ApiResponse notHandled;
 
  189        notHandled.mutable_status()->set_status( ApiStatusCode::AS_NOT_READY );
 
  190        notHandled.mutable_status()->set_error_message( 
"KiCad is not ready to reply" );
 
  191        m_server->Reply( notHandled.SerializeAsString() );
 
  192        log( 
"Got incoming request but was not yet ready to reply." );
 
  196    wxCommandEvent* evt = 
new wxCommandEvent( API_REQUEST_EVENT );
 
  199    evt->SetClientData( 
static_cast<void*
>( aRequest ) );
 
 
  208    std::string& requestString = *
static_cast<std::string*
>( aEvent.GetClientData() );
 
  211    if( !request.ParseFromString( requestString ) )
 
  214        error.mutable_header()->set_kicad_token( 
m_token );
 
  215        error.mutable_status()->set_status( ApiStatusCode::AS_BAD_REQUEST );
 
  216        error.mutable_status()->set_error_message( 
"request could not be parsed" );
 
  217        m_server->Reply( error.SerializeAsString() );
 
  220            log( 
"Response (ERROR): " + error.Utf8DebugString() );
 
  224        log( 
"Request: " + request.Utf8DebugString() );
 
  226    if( !request.header().kicad_token().empty() &&
 
  227        request.header().kicad_token().compare( 
m_token ) != 0 )
 
  230        error.mutable_header()->set_kicad_token( 
m_token );
 
  231        error.mutable_status()->set_status( ApiStatusCode::AS_TOKEN_MISMATCH );
 
  232        error.mutable_status()->set_error_message(
 
  233                "the provided kicad_token did not match this KiCad instance's token" );
 
  234        m_server->Reply( error.SerializeAsString() );
 
  237            log( 
"Response (ERROR): " + error.Utf8DebugString() );
 
  246        result = handler->Handle( request );
 
  250        else if( 
result.error().status() != ApiStatusCode::AS_UNHANDLED )
 
  262            log( 
"Response: " + 
result->Utf8DebugString() );
 
  267        error.mutable_status()->CopyFrom( 
result.error() );
 
  268        error.mutable_header()->set_kicad_token( 
m_token );
 
  270        if( 
result.error().status() == ApiStatusCode::AS_UNHANDLED )
 
  272            std::string type = 
"<unparseable Any>";
 
  273            google::protobuf::Any::ParseAnyTypeUrl( request.message().type_url(), &type );
 
  274            std::string msg = fmt::format( 
"no handler available for request of type {}", type );
 
  275            error.mutable_status()->set_error_message( msg );
 
  278        m_server->Reply( error.SerializeAsString() );
 
  281            log( 
"Response (ERROR): " + error.Utf8DebugString() );
 
 
wxString result
Test unit parsing edge cases and error handling.