Files
Eric F d398a6ced2 Add extracted tools: CitrineOS, OpenOCPP, ShapeShifter
- CitrineOS core extracted (CSMS OCPP 2.0.1)
- OpenOCPP extracted (firmware OCPP 1.6J/2.0.1)
- ShapeShifter library installed (pip install -e)
- ShapeShifter specification extracted
- EVerest extracted

TODO updated with progress
2026-06-08 00:38:27 -04:00

236 lines
11 KiB
C++

// SPDX-License-Identifier: Apache-2.0
// Copyright Pionix GmbH and Contributors to EVerest
#include <everest/helpers/helpers.hpp>
#include <utility>
#include "Auth.hpp"
#include <everest/logging.hpp>
namespace module {
void Auth::init() {
invoke_init(*p_main);
invoke_init(*p_reservation);
this->auth_handler = std::make_unique<AuthHandler>(
string_to_selection_algorithm(this->config.selection_algorithm), this->config.connection_timeout,
this->config.plug_in_timeout_enabled, this->config.prioritize_authorization_over_stopping_transaction,
this->config.ignore_connector_faults, this->info.id,
(!this->r_kvs.empty() ? this->r_kvs.at(0).get() : nullptr));
for (const auto& token_provider : this->r_token_provider) {
token_provider->subscribe_provided_token([this](ProvidedIdToken provided_token) {
{
auto state = this->event_state.handle();
if (!state->started) {
EVLOG_warning << "Auth not fully initialized. Discarding provided token";
return;
}
}
std::thread t([this, provided_token]() { this->auth_handler->on_token(provided_token); });
t.detach();
});
}
for (const auto& token_validator : this->r_token_validator) {
token_validator->subscribe_validate_result_update([this](ValidationResultUpdate validation_result_update) {
{
auto state = this->event_state.handle();
if (!state->started) {
EVLOG_warning << "Auth not fully initialized. Discarding validation result update";
return;
}
}
this->auth_handler->handle_token_validation_result_update(validation_result_update);
});
}
// Subscribe to session events and errors in init() so we don't miss any events
// Events received before ready() are queued.
int32_t evse_index = 0;
for (const auto& evse_manager : this->r_evse_manager) {
const int32_t evse_idx = evse_index;
evse_manager->subscribe_session_event([this, evse_idx](SessionEvent session_event) {
{
auto state = this->event_state.handle();
if (!state->started) {
EVLOG_debug << "Auth not fully initialized, but received a session event on evse_index: "
<< evse_idx << " that will be queued up: " << session_event.event;
state->event_queue.emplace(evse_idx, session_event);
return;
}
}
this->auth_handler->handle_session_event(this->auth_handler->get_evse_id_by_index(evse_idx), session_event);
});
evse_manager->subscribe_error(
"evse_manager/Inoperative",
[this, evse_idx](const Everest::error::Error& error) {
{
auto state = this->event_state.handle();
if (!state->started) {
EVLOG_debug << "Auth not fully initialized, queuing permanent fault raised for evse_index: "
<< evse_idx;
state->event_queue.emplace(evse_idx, PermanentFaultRaised{1});
return;
}
}
this->auth_handler->handle_permanent_fault_raised(this->auth_handler->get_evse_id_by_index(evse_idx),
1);
},
[this, evse_idx](const Everest::error::Error& error) {
{
auto state = this->event_state.handle();
if (!state->started) {
EVLOG_debug << "Auth not fully initialized, queuing permanent fault cleared for evse_index: "
<< evse_idx;
state->event_queue.emplace(evse_idx, PermanentFaultCleared{1});
return;
}
}
this->auth_handler->handle_permanent_fault_cleared(this->auth_handler->get_evse_id_by_index(evse_idx),
1);
});
evse_index++;
}
}
void Auth::ready() {
invoke_ready(*p_main);
invoke_ready(*p_reservation);
int32_t evse_index = 0;
for (const auto& evse_manager : this->r_evse_manager) {
const int32_t evse_id = evse_manager->call_get_evse().id;
std::vector<Connector> connectors;
for (const auto& connector : evse_manager->call_get_evse().connectors) {
connectors.push_back(
Connector(connector.id, connector.type.value_or(types::evse_manager::ConnectorTypeEnum::Unknown)));
}
this->auth_handler->init_evse(evse_id, evse_index, connectors);
evse_index++;
}
this->auth_handler->register_publish_token_validation_status_callback(
[this](const ProvidedIdToken& token, TokenValidationStatus status,
const std::vector<MessageContent>& tariff_messages) {
this->p_main->publish_token_validation_status({token, status, tariff_messages});
});
this->auth_handler->register_notify_evse_callback(
[this](const int evse_index, const ProvidedIdToken& provided_token, const ValidationResult& validation_result) {
this->r_evse_manager.at(evse_index)->call_authorize_response(provided_token, validation_result);
});
this->auth_handler->register_withdraw_authorization_callback(
[this](const int32_t evse_index) { this->r_evse_manager.at(evse_index)->call_withdraw_authorization(); });
this->auth_handler->register_validate_token_callback([this](const ProvidedIdToken& provided_token) {
std::vector<ValidationResult> validation_results;
for (const auto& token_validator : this->r_token_validator) {
try {
const auto result = token_validator->call_validate_token(provided_token);
validation_results.push_back(result);
// TODO: This is very broad catch, make it more narrow when the everest-framework error handling will be
// established
} catch (const std::exception& e) {
EVLOG_warning << "Exception during validating token: " << e.what();
ValidationResult validation_result;
validation_result.authorization_status = AuthorizationStatus::Unknown;
validation_results.push_back(validation_result);
}
}
return validation_results;
});
this->auth_handler->register_stop_transaction_callback(
[this](const int32_t evse_index, const StopTransactionRequest& request) {
this->r_evse_manager.at(evse_index)->call_stop_transaction(request);
});
this->auth_handler->register_reserved_callback(
[this](const std::optional<int32_t> evse_id, const int32_t& reservation_id) {
// Only call the evse manager to store the reservation if it is done for a specific evse.
if (evse_id.has_value()) {
EVLOG_info << "Call reserved callback for evse id " << evse_id.value();
if (!this->r_evse_manager.at(evse_id.value() - 1)->call_reserve(reservation_id)) {
EVLOG_warning << "EVSE manager does not allow placing a reservation for evse id " << evse_id.value()
<< ": cancelling reservation.";
this->auth_handler->handle_cancel_reservation(reservation_id);
return false;
}
}
ReservationUpdateStatus status;
status.reservation_id = reservation_id;
status.reservation_status = Reservation_status::Placed;
this->p_reservation->publish_reservation_update(status);
return true;
});
this->auth_handler->register_reservation_cancelled_callback(
[this](const std::optional<int32_t> evse_id, const int32_t reservation_id, const ReservationEndReason reason,
const bool send_reservation_update) {
// Only call the evse manager to cancel the reservation if it was for a specific evse
if (evse_id.has_value() && evse_id.value() > 0) {
EVLOG_debug << "Call evse manager to cancel the reservation with evse id " << evse_id.value();
this->r_evse_manager.at(evse_id.value() - 1)->call_cancel_reservation();
}
if (send_reservation_update) {
ReservationUpdateStatus status;
status.reservation_id = reservation_id;
if (reason == ReservationEndReason::Expired) {
status.reservation_status = Reservation_status::Expired;
} else if (reason == ReservationEndReason::Cancelled) {
status.reservation_status = Reservation_status::Removed;
} else {
// On reservation used: do not publish a reservation update!!
return;
}
this->p_reservation->publish_reservation_update(status);
}
});
// Process any events that were queued during init before we were ready
{
auto state = this->event_state.handle();
while (!state->event_queue.empty()) {
auto queued_event = state->event_queue.front();
state->event_queue.pop();
const int32_t evse_id = this->auth_handler->get_evse_id_by_index(queued_event.evse_index);
if (std::holds_alternative<SessionEvent>(queued_event.data)) {
const auto& session_event = std::get<SessionEvent>(queued_event.data);
EVLOG_debug << "Processing queued session event for evse_id: " << evse_id
<< ", event: " << session_event.event;
this->auth_handler->handle_session_event(evse_id, session_event);
} else if (std::holds_alternative<PermanentFaultRaised>(queued_event.data)) {
const auto& fault = std::get<PermanentFaultRaised>(queued_event.data);
EVLOG_debug << "Processing queued permanent fault raised for evse_id: " << evse_id;
this->auth_handler->handle_permanent_fault_raised(evse_id, fault.connector_id);
} else if (std::holds_alternative<PermanentFaultCleared>(queued_event.data)) {
const auto& fault = std::get<PermanentFaultCleared>(queued_event.data);
EVLOG_debug << "Processing queued permanent fault cleared for evse_id: " << evse_id;
this->auth_handler->handle_permanent_fault_cleared(evse_id, fault.connector_id);
}
}
state->started = true;
}
this->auth_handler->initialize();
}
void Auth::set_connection_timeout(int& connection_timeout) {
this->auth_handler->set_connection_timeout(connection_timeout);
}
void Auth::set_master_pass_group_id(const std::string& master_pass_group_id) {
this->auth_handler->set_master_pass_group_id(master_pass_group_id);
}
WithdrawAuthorizationResult Auth::handle_withdraw_authorization(const WithdrawAuthorizationRequest& request) {
return this->auth_handler->handle_withdraw_authorization(request);
}
} // namespace module