mirror of
https://github.com/eclipse-openvehicle-api/openvehicle-api.git
synced 2026-08-30 04:15:10 +00:00
connection between 2 systems and bug fixes (#14)
This commit is contained in:
@@ -103,12 +103,6 @@ module sdv
|
||||
* @return The instance ID.
|
||||
*/
|
||||
uint32 GetInstanceID() const;
|
||||
|
||||
/**
|
||||
* @brief Return the number of retries to establish a connection.
|
||||
* @return Number of retries.
|
||||
*/
|
||||
uint32 GetRetries() const;
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -181,5 +175,96 @@ module sdv
|
||||
void RequestShutdown() raises(XAccessDenied, XInvalidState);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Load and save the application settings.
|
||||
* @remarks The interface is only available in maintenance mode.
|
||||
*/
|
||||
interface IAppSettingsPersist
|
||||
{
|
||||
/**
|
||||
* @brief Load the application settings.
|
||||
* @remarks When there is no settings file, this is not an error. Default settings will be assumed.
|
||||
* @return Returns whether the loading was successful.
|
||||
*/
|
||||
boolean LoadSettings();
|
||||
|
||||
/**
|
||||
* @brief Save the application settings file (or create when not existing yet).
|
||||
* @return Returns whether the saving was successful.
|
||||
*/
|
||||
boolean SaveSettings();
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Application connections
|
||||
* @remarks The interface is only available in maintenance mode.
|
||||
*/
|
||||
interface IAppConnections
|
||||
{
|
||||
/**
|
||||
* @brief Get a sequence with listener names.
|
||||
* @return Sequence with listener name strings.
|
||||
*/
|
||||
sequence<u8string> GetListeners() const;
|
||||
|
||||
/**
|
||||
* @brief Get the listener configuration.
|
||||
* @param[in] ssName Name of the listener.
|
||||
* @return String containing the listener configuration.
|
||||
*/
|
||||
u8string GetListenerConfig(in u8string ssName) const;
|
||||
|
||||
/**
|
||||
* @brief Add or update a listener configuration.
|
||||
* @param[in] ssName Name of the listener configuration.
|
||||
* @param[in] ssConfig The configuration string for the listener.
|
||||
* @return Returns whether the listener could be added.
|
||||
*/
|
||||
boolean AddListenerConfig(in u8string ssName, in u8string ssConfig);
|
||||
|
||||
/**
|
||||
* @brief Remove a listener configuration with the provided name.
|
||||
* @param[in] ssName Name of the listener configuration.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
boolean RemoveListenerConfig(in u8string ssName);
|
||||
|
||||
/**
|
||||
* @brief Get a sequence with connection names.
|
||||
* @return Sequence with name strings.
|
||||
*/
|
||||
sequence<u8string> GetConnections() const;
|
||||
|
||||
/**
|
||||
* @brief Get the connection configuration.
|
||||
* @param[in] ssName Name of the connection.
|
||||
* @return String containing the connection configuration.
|
||||
*/
|
||||
u8string GetConnectionConfig(in u8string ssName) const;
|
||||
|
||||
/**
|
||||
* @brief Add or update a connection configuration.
|
||||
* @param[in] ssName Name of the connection configuration.
|
||||
* @param[in] ssConfig The configuration string for the connection.
|
||||
* @param[in] ssInsertBefore Reference to the string to connection to insert the the new connection before, or empty
|
||||
* when the the new connection should be placed at the end.
|
||||
* @return Returns whether the connection could be added (fails when the connection already exists).
|
||||
*/
|
||||
boolean AddConnectionConfig(in u8string ssName, in u8string ssConfig, in u8string ssInsertBefore);
|
||||
|
||||
/**
|
||||
* @brief Remove a connection configuration with the provided name.
|
||||
* @param[in] ssName Name of the connection configuration.
|
||||
* @return Returns whether the removal was successful.
|
||||
*/
|
||||
boolean RemoveConnectionConfig(in u8string ssName);
|
||||
|
||||
/**
|
||||
* @brief Return the number of retries to establish a connection.
|
||||
* @return Number of retries.
|
||||
*/
|
||||
uint32 GetConnectRetries() const;
|
||||
};
|
||||
|
||||
}; // module app
|
||||
}; // module sdv
|
||||
|
||||
@@ -53,31 +53,56 @@ module sdv
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Connect to a remote system. Provided by the ConnectClient utility.
|
||||
* @brief Connect to a remote system. Provided by the Connection service.
|
||||
* @details This interface is exposed by the connection client service. The configuration is provided during instantiation
|
||||
* of the object and is of the form:
|
||||
* @code
|
||||
* # Provider to use for the connection
|
||||
* [Provider]
|
||||
* Name = ""
|
||||
*
|
||||
* # Additional channel information for the client
|
||||
* [IpcChannel]
|
||||
* xyz = ""
|
||||
* @endcode
|
||||
*
|
||||
* For example for shared memory:
|
||||
* @code
|
||||
* [Provider]
|
||||
* Name = "DefaultSharedMemory"
|
||||
* [IpcChannel]
|
||||
* Name = "LISTENER_1234"
|
||||
* @endcode
|
||||
*/
|
||||
interface IClientConnect
|
||||
{
|
||||
/**
|
||||
* @brief Connect to a remote system using the connection string to contact the system.
|
||||
* @remarks After a successful connection, the ConnectClient utility is not needed any more.
|
||||
* @param[in] ssConnectString Optional connection string to use for connection. If not provided, the connection will
|
||||
* automatically get the connection ID from the app-control service (default). The connection string for a local
|
||||
* connection can be of the form:
|
||||
* @code
|
||||
* [Client]
|
||||
* Type = "local"
|
||||
* Instance = 1234 # Optional: only use when connecting to a system with a different instance ID.
|
||||
* @endcode
|
||||
* And the following can be used for a remote connection:
|
||||
* @code
|
||||
* [Client]
|
||||
* Type = "remote"
|
||||
* Interface = "127.0.0.1"
|
||||
* Port = 2000
|
||||
* @endcode
|
||||
* @return Returns an interface to the repository of the remote system or a NULL pointer if not found.
|
||||
* @brief Connect to a remote system.
|
||||
* @return Returns whether connect was successful.
|
||||
*/
|
||||
IInterfaceAccess Connect(in u8string ssConnectString) raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
|
||||
boolean Connect() raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
|
||||
|
||||
/**
|
||||
* @brief Disconnect from a connected system.
|
||||
* @return Returns whether disconnect was successful.
|
||||
*/
|
||||
boolean Disconnect() raises(XAccessDenied, XNotFound, XInvalidState, XTimeout);
|
||||
|
||||
/**
|
||||
* @brief State of the current connection.
|
||||
* @return Returns whether an active connection exists.
|
||||
*/
|
||||
boolean IsConnected() const;
|
||||
|
||||
/**
|
||||
* @brief Get the remote repository that is available after connection.
|
||||
* @remarks For main, isolated and external applications, the remote repository will be automatically linked to the
|
||||
* local repository. Hence a requests for the repository is not needed. For all other applications, access must be
|
||||
* explicitly acquired through this interface.
|
||||
* @return Interface to the remote repository if a successful connection is established. The interface is valid until
|
||||
* disconnect is called or the client connection service is terminated.
|
||||
*/
|
||||
IInterfaceAccess GetRemoteRepository();
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -389,6 +389,17 @@ module sdv
|
||||
u8string ssInstallName; ///< Name of the installation.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The package exceeds the maximum size.
|
||||
*/
|
||||
exception XPackageSizeExceeded : XSysExcept
|
||||
{
|
||||
/** Description */
|
||||
const char _description[] = "Maximum package size exceeded.";
|
||||
|
||||
u8string ssFileName; ///< Name of the file which causes the exception.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The installation doesn't contain a module.
|
||||
*/
|
||||
|
||||
@@ -57,11 +57,28 @@ module sdv
|
||||
template <typename TInterface>
|
||||
TInterface* GetInterface()
|
||||
{
|
||||
return GetInterface(sdv::GetInterfaceId<TInterface>()).template get<TInterface>();
|
||||
try
|
||||
{
|
||||
return GetInterface(sdv::GetInterfaceId<TInterface>()).template get<TInterface>();
|
||||
} catch (const XSysExcept&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
#verbatim_end
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Core features.
|
||||
*/
|
||||
module core
|
||||
{
|
||||
/**
|
||||
* @brief Object ID.
|
||||
*/
|
||||
typedef uint64 TObjectID;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Object type enumeration.
|
||||
*/
|
||||
@@ -163,13 +180,24 @@ module sdv
|
||||
|
||||
/**
|
||||
* @brief Component operation mode.
|
||||
*/
|
||||
*/
|
||||
enum EOperationMode : uint32
|
||||
{
|
||||
configuring = 20, ///< The component should switch to configuration mode.
|
||||
running = 30, ///< The component should switch to running mode.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Object information supplied to the object initialization function.
|
||||
*/
|
||||
struct SObjectInfo
|
||||
{
|
||||
core::TObjectID tObjectID; ///< Object ID (local for the running process)
|
||||
SClassInfo sClassInfo; ///< Object class information
|
||||
u8string ssName; ///< Object name
|
||||
u8string ssConfig; ///< Object configuration TOML
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Optional interface allowing for additional control of more complex SDVObjects.
|
||||
* To be implemented if the object in question calls other SDVobjects via running threads or callbacks,
|
||||
@@ -179,9 +207,9 @@ module sdv
|
||||
{
|
||||
/**
|
||||
* @brief Initialize the object.
|
||||
* @param[in] ssObjectConfig Optional configuration string.
|
||||
* @param[in] sObjectInfo The registration information of this object.
|
||||
*/
|
||||
void Initialize(in u8string ssObjectConfig);
|
||||
void Initialize(in SObjectInfo sObjectInfo);
|
||||
|
||||
/**
|
||||
* @brief Get the current state of the object.
|
||||
@@ -247,50 +275,6 @@ module sdv
|
||||
*/
|
||||
uint32 GetCount() const;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Attribute flags.
|
||||
*/
|
||||
enum EAttributeFlags : uint32
|
||||
{
|
||||
read_only = 0x100, ///< When set, the attribute is readonly.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Attribute interface
|
||||
*/
|
||||
interface IAttributes
|
||||
{
|
||||
/**
|
||||
* @brief Get a sequence with the available attribute names.
|
||||
* @return The sequence of attribute names.
|
||||
*/
|
||||
sequence<u8string> GetNames() const;
|
||||
|
||||
/**
|
||||
* @brief Get the attribute value.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
|
||||
*/
|
||||
any Get(in u8string ssAttribute) const;
|
||||
|
||||
/**
|
||||
* @brief Set the attribute value.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @param[in] anyAttribute Attribute value to set.
|
||||
* @return Returns 'true' when setting the attribute was successful or 'false' when the attribute was not found or the
|
||||
* attribute is read-only or another error occurred.
|
||||
*/
|
||||
boolean Set(in u8string ssAttribute, in any anyAttribute);
|
||||
|
||||
/**
|
||||
* @brief Get the attribute flags belonging to a certain attribute.
|
||||
* @param[in] ssAttribute Name of the attribute.
|
||||
* @return Returns the attribute flags (zero or more EAttributeFlags flags) or 0 when the attribute could not be found.
|
||||
*/
|
||||
uint32 GetFlags(in u8string ssAttribute) const;
|
||||
};
|
||||
|
||||
}; // module sdv
|
||||
|
||||
#verbatim_begin
|
||||
|
||||
@@ -13,6 +13,7 @@
|
||||
|
||||
#include "core.idl"
|
||||
#include "process.idl"
|
||||
#include "permission.idl"
|
||||
|
||||
/**
|
||||
* @brief Software Defined Vehicle framework.
|
||||
@@ -149,6 +150,7 @@ module sdv
|
||||
TMarshallID tProxyID; ///< Proxy id to identify the proxy this packet is sending from or destined to.
|
||||
TMarshallID tStubID; ///< Stub id to identify the stub this packet is destined to or receiving from.
|
||||
uint64 uiCallIndex; ///< Call index to uniquely identify the call.
|
||||
core::TPermissionID tPermissionID; ///< Permission ID used to elevate permission, or 0 for standard permission.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -35,12 +35,15 @@ module sdv
|
||||
///< identification must be similar to the following example:
|
||||
///< @code
|
||||
///< [Provider]
|
||||
///< Name = "DefaultSharedMemoryChannelControl"
|
||||
///< Name = "DefaultSharedMemory"
|
||||
///< @endcode
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Interface for creating an IPC connection, which other participants can connect to via IChannelAccess
|
||||
* @brief Interface for creating an IPC connection, which other participants can connect to via IChannelAccess.
|
||||
* @attention The channel control object should allow the creation of channels with a fixed configuration (e.g. a provided
|
||||
* name or a port), which is necessary for the creation of a listener. It also should allow dynamic channel creation (e.g.
|
||||
* automatic name or port-number) to create additional connections between components.
|
||||
*/
|
||||
interface ICreateEndpoint
|
||||
{
|
||||
|
||||
96
export/interfaces/permission.idl
Normal file
96
export/interfaces/permission.idl
Normal file
@@ -0,0 +1,96 @@
|
||||
/********************************************************************************
|
||||
* Copyright (c) 2025-2026 ZF Friedrichshafen AG
|
||||
*
|
||||
* This program and the accompanying materials are made available under the
|
||||
* terms of the Apache License Version 2.0 which is available at
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* SPDX-License-Identifier: Apache-2.0
|
||||
*
|
||||
* Contributors:
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#include "core.idl"
|
||||
|
||||
/**
|
||||
* @brief Software Defined Vehicle framework.
|
||||
*/
|
||||
module sdv
|
||||
{
|
||||
/**
|
||||
* @brief Core features.
|
||||
*/
|
||||
module core
|
||||
{
|
||||
/// ID corresponding to a thread specific permission request.
|
||||
typedef uint64 TPermissionID;
|
||||
|
||||
/// ID identifying a permission transfer.
|
||||
typedef uint64 TPermissionTransferID;
|
||||
|
||||
/**
|
||||
* @brief Access type restriction. The lower the access, the more restricted.
|
||||
*/
|
||||
enum EAccessPermission : int32
|
||||
{
|
||||
not_set = -1001, ///< Permissions are not set; will be treated as restricted access.
|
||||
restricted_access = -1000, ///< Restricted access (default when no other set).
|
||||
remote_access = -200, ///< Access for remote execution. Access allowed to basic and complex services.
|
||||
local_access = -100, ///< Access for isolated execution. Access allowed to system, basic and complex services.
|
||||
full_access = 0, ///< Full access is allowed to complete system.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Permission control interface. This interface is used for restricting permission on a thread and transferring
|
||||
* permissions from one thread to another.
|
||||
*/
|
||||
interface IPermissionControl
|
||||
{
|
||||
/**
|
||||
* @brief Restrict the access permission for the current thread.
|
||||
* @remarks The access restriction will be assigned to the current thread and combined with previous and future
|
||||
* permissions. The lowest assigned permission will determine the actual access permission for the current thread.
|
||||
* @remarks The access restriction will stay in effect until it is released by the function ReleaseAccessPermission.
|
||||
* @remarks A newly created thread has fully restricted access. This cannot be changed using this function. Use an
|
||||
* access restriction transfer from one thread to this thread to set a higher level of access permission.
|
||||
* @param[in] ePermission The permission to restrict to.
|
||||
* @return The permission ID for this restriction or 0 when the access permission could not be set. Use the
|
||||
* ReleaseAccessPermission to release the restriction again.
|
||||
*/
|
||||
TPermissionID RestrictAccessPermission(in EAccessPermission ePermission);
|
||||
|
||||
/**
|
||||
* @brief Release a previously set access restriction for the current thread.
|
||||
* @param[in] tPermissionID The ID of the access restriction previously set for the current thread.
|
||||
* @return Returns whether the restriction could be released successfully.
|
||||
*/
|
||||
boolean ReleaseAccessPermission(in TPermissionID tPermissionID);
|
||||
|
||||
/**
|
||||
* @brief Prepares a transfer of the access restriction from the current thread.
|
||||
* @return The ID of the transfer object containing the current access permissions or 0 when the transfer preparation
|
||||
* has failed.
|
||||
*/
|
||||
TPermissionTransferID TransferCurrentPermission();
|
||||
|
||||
/**
|
||||
* @brief Set the access permission using a transfer object from one thread to another.
|
||||
* @remarks An new thread has fully restricted access per default. Use this function to set the required access level.
|
||||
* If a thread has already initialized with the proper access level, this function will set identical or lower access
|
||||
* permissions for the current thread.
|
||||
* @param[in] tTransferID The IS of the prepared access permission transfer.
|
||||
* @return The permission ID for this restriction or 0 when the access permission could not be transferred. Use the
|
||||
* ReleaseAccessPermission to release the restriction again.
|
||||
*/
|
||||
TPermissionID SetAccessPermission(in TPermissionTransferID tTransferID);
|
||||
|
||||
/**
|
||||
* @brief Get the access permission level for the current thread. This will be the lowest restriction set for the
|
||||
* current thread.
|
||||
* @return The current access permission level.
|
||||
*/
|
||||
EAccessPermission GetCurrentPermission() const;
|
||||
};
|
||||
}; // module core
|
||||
}; // module sdv
|
||||
@@ -25,11 +25,6 @@ module sdv
|
||||
module core
|
||||
{
|
||||
|
||||
/**
|
||||
* @brief Object ID.
|
||||
*/
|
||||
typedef uint64 TObjectID;
|
||||
|
||||
/**
|
||||
* @brief Interface used to access objects from other modules via the repository service
|
||||
*/
|
||||
@@ -229,6 +224,32 @@ module sdv
|
||||
TObjectID RegisterObject(in IInterfaceAccess pObjectIfc, in u8string ssObjectName);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief The object dependency can be used to state dependencies between two objects. This influence is used during
|
||||
* shutdown to determine the termination order.
|
||||
*/
|
||||
interface IObjectDependency
|
||||
{
|
||||
/**
|
||||
* @brief Add a dependency for an object.
|
||||
* @param ssObjectName Name of the object.
|
||||
* @param ssDependsOnObject Name of the object it depends on.
|
||||
*/
|
||||
void AddObjectDependency(in u8string ssObjectName, in u8string ssDependsOnObject);
|
||||
|
||||
/**
|
||||
* @brief Remove an object dependency.
|
||||
* @param ssObjectName Name of the object.
|
||||
* @param ssDependsOnObject Name of the object it depends on.
|
||||
*/
|
||||
void RemoveObjectDependency(in u8string ssObjectName, in u8string ssDependsOnObject);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Link ID.
|
||||
*/
|
||||
typedef uint64 TLinkID;
|
||||
|
||||
/**
|
||||
* @brief Connect the core repository to the local repository to allow object access by the locally running components.
|
||||
* @remarks This interface is available only for isolated and external applications.
|
||||
@@ -238,13 +259,15 @@ module sdv
|
||||
/**
|
||||
* @brief Register the core repository.
|
||||
* @param[in] pCoreRepository Pointer to the proxy interface of the core repository.
|
||||
* @return Returns a link ID to be used in the Unlink function. Or 0 on failure.
|
||||
*/
|
||||
void LinkCoreRepository(in IInterfaceAccess pCoreRepository);
|
||||
TLinkID LinkCoreRepository(in IInterfaceAccess pCoreRepository);
|
||||
|
||||
/**
|
||||
* @brief Unlink a previously linked core repository.
|
||||
* @param[in] tLinkID Link ID of the repository link to remove.
|
||||
*/
|
||||
void UnlinkCoreRepository();
|
||||
void UnlinkCoreRepository(in TLinkID tLinkID);
|
||||
};
|
||||
|
||||
}; // module core
|
||||
|
||||
@@ -142,10 +142,10 @@ module sdv
|
||||
u8string GetComment(in ECommentType eType);
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically. This will remove the whitespace between the elements within the node. Comments
|
||||
* will not be changed.
|
||||
* @brief Format the node automatically, remove redundant whitespace.
|
||||
* @param[in] bRemoveComments When set, the comments are removed from the node.
|
||||
*/
|
||||
void AutomaticFormat();
|
||||
void AutomaticFormat(in boolean bRemoveComments);
|
||||
|
||||
/**
|
||||
* @brief Is the node inline?
|
||||
@@ -265,10 +265,21 @@ module sdv
|
||||
|
||||
/**
|
||||
* @brief Convert the node to a standard node.
|
||||
* @param[in] bIncludeChildren When set, applicable child nodes are made are converted to standard nodes as well (only
|
||||
* tables and table-arrays can be defined as standard).
|
||||
* @return Returns whether the conversion was successful. Returns 'true' when the node was already defined as standard
|
||||
* node.
|
||||
*/
|
||||
boolean MakeStandard();
|
||||
boolean MakeStandard(in boolean bIncludeChildren);
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Insertion preference for tables and table arrays, being standard or inline.
|
||||
*/
|
||||
enum EInsertPreference
|
||||
{
|
||||
prefer_standard = 0, ///< When the parent node is not inline, the node will be inserted as standard node.
|
||||
prefer_inline = 1, ///< The node will be inserted as inline node.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -278,71 +289,67 @@ module sdv
|
||||
{
|
||||
/**
|
||||
* @brief Insert a value into the collection at the location before the supplied index.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Value nodes cannot be inserted behind external
|
||||
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
|
||||
* is automatically corrected.
|
||||
* @param[in] ssName Name of the node to insert. Will be ignored for an array collection. The name must adhere to the
|
||||
* key names defined by the TOML specification. Defining the key multiple times is not allowed. Quotation of key names
|
||||
* is done automatically; the parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] anyValue The value of the node, being either an integer, floating point number, boolean value or a string.
|
||||
* Conversion is automatically done to int64, double float, bool or u8string.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
IInterfaceAccess InsertValue(in uint32 uiIndex, in u8string ssName, in any anyValue);
|
||||
IInterfaceAccess InsertValue(in u8string ssInsertBefore, in u8string ssName, in any anyValue);
|
||||
|
||||
/**
|
||||
* @brief Insert an array into the collection at the location before the supplied index.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Array nodes cannot be inserted behind external
|
||||
* tables and table arrays. If the index is referencing a position behind an external table or a table array, the index
|
||||
* is automatically corrected.
|
||||
* @param[in] ssName Name of the array node to insert. Will be ignored if the current node is also an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
IInterfaceAccess InsertArray(in uint32 uiIndex, in u8string ssName);
|
||||
|
||||
/**
|
||||
* @brief Insertion preference for tables and table arrays, being standard or inline.
|
||||
*/
|
||||
enum EInsertPreference
|
||||
{
|
||||
prefer_standard = 0, ///< When the parent node is not inline, the node will be inserted as standard node.
|
||||
prefer_inline = 1, ///< The node will be inserted as inline node.
|
||||
};
|
||||
IInterfaceAccess InsertArray(in u8string ssInsertBefore, in u8string ssName);
|
||||
|
||||
/**
|
||||
* @brief Insert a table into the collection at the location before the supplied index.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table nodes cannot be inserted before value nodes
|
||||
* or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssName Name of the table node to insert. Will be ignored if the parent node is an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
|
||||
* case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
IInterfaceAccess InsertTable(in uint32 uiIndex, in u8string ssName, in EInsertPreference ePreference);
|
||||
IInterfaceAccess InsertTable(in u8string ssInsertBefore, in u8string ssName, in EInsertPreference ePreference);
|
||||
|
||||
/**
|
||||
* @brief Insert a table array into the collection at the location before the supplied index.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @param[in] ssName Name of the array node to insert. Will be ignored if the parent node is also an array collection.
|
||||
* The name must adhere to the key names defined by the TOML specification. Defining the key multiple times is not
|
||||
* allowed. Quotation of key names is done automatically; the parser decides itself whether the key is bare-key, a
|
||||
* literal key or a quoted key.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
|
||||
* which case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssName Name of the node to insert. This name can contain parent nodes, which are automatically created if
|
||||
* not existing. With arrays, since the value in TOML doesn't have a name, the name of the value must be an empty
|
||||
* string and any names provided are considered parent nodes. The name must adhere to the key names defined by the TOML
|
||||
* specification. Defining the key multiple times is not allowed. Quotation of key names is done automatically; the
|
||||
* parser decides itself whether the key is bare-key, a literal key or a quoted key.
|
||||
* @param[in] ePreference The preferred form of the node to be inserted.
|
||||
* @return On success the interface to the newly inserted node is returned or NULL otherwise.
|
||||
*/
|
||||
IInterfaceAccess InsertTableArray(in uint32 uiIndex, in u8string ssName, in EInsertPreference ePreference);
|
||||
IInterfaceAccess InsertTableArray(in u8string ssInsertBefore, in u8string ssName, in EInsertPreference ePreference);
|
||||
|
||||
/**
|
||||
* @brief The result of the TOML string to insert.
|
||||
@@ -358,17 +365,15 @@ module sdv
|
||||
* @brief Insert a TOML string as a child of the current collection node. If the collection is a table, the TOML string
|
||||
* should contain values and inline/external/array-table nodes with names. If the collection is an array, the TOML
|
||||
* string should contain and inline table nodes without names.
|
||||
* @attention Even though the TOML might be defining the node(s) in standard form, if the parent node is an inline node,
|
||||
* the node will be inserted as inline node.
|
||||
* @param[in] uiIndex The insertion location to insert the node before. Can be npos or any value larger than the
|
||||
* collection count to insert the node at the end of the collection. Table array nodes cannot be inserted before value
|
||||
* nodes or arrays. If the index is referencing a position before a value node or an array, the index is automatically
|
||||
* corrected.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
|
||||
* might be transferred to inline or they might be inserted at a different location.
|
||||
* @param[in] ssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] ssTOML The TOML string to insert. This string can hold one or more nodes that should be inserted.
|
||||
* @param[in] bRollbackOnFailure If only part of the nodes could be inserted, no node will be inserted.
|
||||
* @return The result of the insertion.
|
||||
*/
|
||||
EInsertResult InsertTOML(in uint32 uiIndex, in u8string ssTOML, in boolean bRollbackOnFailure);
|
||||
EInsertResult InsertTOML(in u8string ssInsertBefore, in u8string ssTOML, in boolean bRollbackOnFailure);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -24,6 +24,9 @@
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(push)
|
||||
#pragma warning(disable : 26495)
|
||||
#else
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wmaybe-uninitialized"
|
||||
#endif
|
||||
|
||||
namespace sdv
|
||||
@@ -1738,6 +1741,8 @@ namespace sdv
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#pragma warning(pop)
|
||||
#else
|
||||
#pragma GCC diagnostic pop
|
||||
#endif
|
||||
|
||||
#endif // !defined SDV_ANY_INL
|
||||
@@ -65,6 +65,7 @@ namespace sdv
|
||||
bool Startup(const std::string& rssConfig)
|
||||
{
|
||||
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
|
||||
|
||||
if (!pAppControl) return false;
|
||||
if (m_eState != EAppOperationState::not_started) return false;
|
||||
try
|
||||
@@ -78,45 +79,6 @@ namespace sdv
|
||||
{
|
||||
m_eContext = pAppContext->GetContextType();
|
||||
m_uiInstanceID = pAppContext->GetInstanceID();
|
||||
m_uiRetries = pAppContext->GetRetries();
|
||||
}
|
||||
|
||||
// Automatically connect to the server
|
||||
if (m_eContext == EAppContext::external)
|
||||
{
|
||||
// Try to connect
|
||||
m_ptrServerRepository = sdv::com::ConnectToLocalServerRepository(m_uiInstanceID, m_uiRetries);
|
||||
if (!m_ptrServerRepository)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Failed to connect to the server repository." << std::endl;
|
||||
Shutdown();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get access to the module control service
|
||||
sdv::core::IObjectAccess* pObjectAccess = m_ptrServerRepository.GetInterface<sdv::core::IObjectAccess>();
|
||||
const sdv::core::IRepositoryControl* pRepoControl = nullptr;
|
||||
if (pObjectAccess)
|
||||
pRepoControl = sdv::TInterfaceAccessPtr(pObjectAccess->GetObject("RepositoryService")).
|
||||
GetInterface<sdv::core::IRepositoryControl>();
|
||||
if (!pRepoControl)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Failed to access the server repository." << std::endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
// Link the local repository to the server repository.
|
||||
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
|
||||
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
|
||||
if (!pLinkCoreRepo)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Cannot link local and server repositories." << std::endl;
|
||||
return false;
|
||||
}
|
||||
pLinkCoreRepo->LinkCoreRepository(m_ptrServerRepository);
|
||||
}
|
||||
|
||||
return bRet;
|
||||
@@ -154,23 +116,6 @@ namespace sdv
|
||||
*/
|
||||
void Shutdown()
|
||||
{
|
||||
// Disconnect local and remote repositories.
|
||||
if (m_ptrServerRepository)
|
||||
{
|
||||
// Link the local repository to the server repository.
|
||||
sdv::core::ILinkCoreRepository* pLinkCoreRepo =
|
||||
sdv::core::GetObject<sdv::core::ILinkCoreRepository>("RepositoryService");
|
||||
if (!pLinkCoreRepo)
|
||||
{
|
||||
if (!ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Cannot unlink local and server repositories." << std::endl;
|
||||
} else
|
||||
pLinkCoreRepo->UnlinkCoreRepository();
|
||||
}
|
||||
|
||||
// Disconnect from the server (if connected at all).
|
||||
m_ptrServerRepository.Clear();
|
||||
|
||||
// Shutdown.
|
||||
IAppControl* pAppControl = core::GetCore() ? core::GetCore<IAppControl>() : nullptr;
|
||||
try
|
||||
@@ -194,28 +139,86 @@ namespace sdv
|
||||
return m_eState == EAppOperationState::running;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the absolute path to the currently run executable
|
||||
* @return Absolute std::filesystem::path to the currently run executable
|
||||
*/
|
||||
static std::filesystem::path GetAppDirectory()
|
||||
{
|
||||
static std::filesystem::path pathExeDir;
|
||||
if (!pathExeDir.empty())
|
||||
return pathExeDir;
|
||||
#ifdef _WIN32
|
||||
// Windows specific
|
||||
std::wstring ssPath(32768, '\0');
|
||||
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
|
||||
#elif defined __linux__
|
||||
// Linux specific
|
||||
std::string ssPath(PATH_MAX + 1, '\0');
|
||||
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
|
||||
if (nCount < 0 || nCount >= PATH_MAX)
|
||||
return pathExeDir; // some error
|
||||
ssPath.at(nCount) = '\0';
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
pathExeDir = std::filesystem::path{ssPath.c_str()}.parent_path() / ""; // To finish the folder path with (back)slash
|
||||
return pathExeDir;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the filename of the currently run executable
|
||||
* @return The filename to the currently run executable
|
||||
*/
|
||||
static std::filesystem::path GetAppFilename()
|
||||
{
|
||||
static std::filesystem::path pathExeFilename;
|
||||
if (!pathExeFilename.empty())
|
||||
return pathExeFilename;
|
||||
#ifdef _WIN32
|
||||
// Windows specific
|
||||
std::wstring ssPath(32768, '\0');
|
||||
GetModuleFileNameW(NULL, ssPath.data(), static_cast<DWORD>(ssPath.size() - 1));
|
||||
#elif defined __linux__
|
||||
// Linux specific
|
||||
std::string ssPath(PATH_MAX + 1, '\0');
|
||||
const ssize_t nCount = readlink("/proc/self/exe", ssPath.data(), PATH_MAX);
|
||||
if (nCount < 0 || nCount >= PATH_MAX)
|
||||
return pathExeFilename; // some error
|
||||
ssPath.at(nCount) = '\0';
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
pathExeFilename = std::filesystem::path{ssPath.c_str()}.filename();
|
||||
return pathExeFilename;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief Get the SDV_FRAMEWORK_RUNTIME environment variable for this application.
|
||||
* @return Path directing to the SDV V-API Framework directory if available or an empty path if not.
|
||||
* @remarks If the environment variable is empty or if the variable contains a relative path, the path will be enhanced
|
||||
* with the application path.
|
||||
* @return Absolute path directing to the SDV Vehicle API Framework directory.
|
||||
*/
|
||||
static std::filesystem::path GetFrameworkRuntimeDirectory()
|
||||
{
|
||||
std::filesystem::path path;
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szFrameworkDir = _wgetenv(L"SDV_FRAMEWORK_RUNTIME");
|
||||
if (!szFrameworkDir) return {};
|
||||
return szFrameworkDir;
|
||||
if (szFrameworkDir) path = szFrameworkDir;
|
||||
#elif defined __unix__
|
||||
const char* szFrameworkDir = getenv("SDV_FRAMEWORK_RUNTIME");
|
||||
if (!szFrameworkDir) return {};
|
||||
return szFrameworkDir;
|
||||
if (szFrameworkDir) path = szFrameworkDir;
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
if (path.empty() || path.is_relative()) path = GetAppDirectory() / path;
|
||||
return path.lexically_normal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set or overwrite the SDV_FRAMEWORK_RUNTIME environment variable for this application.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV V-API Framework directory.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API Framework directory.
|
||||
*/
|
||||
static void SetFrameworkRuntimeDirectory(const std::filesystem::path& rpathDir)
|
||||
{
|
||||
@@ -232,26 +235,30 @@ namespace sdv
|
||||
|
||||
/**
|
||||
* @brief Get the SDV_COMPONENT_INSTALL environment variable for this application.
|
||||
* @return Path directing to the SDV V-API component installation directory if available or an empty path if not.
|
||||
* @remarks If the environment variable is empty, the runtime directory is taken. If the variable contains a relative
|
||||
* path, the path will be enhanced with the application path.
|
||||
* @return Absolute path directing to the SDV Vehicle API component installation directory.
|
||||
*/
|
||||
static std::filesystem::path GetComponentInstallDirectory()
|
||||
{
|
||||
std::filesystem::path path;
|
||||
#ifdef _WIN32
|
||||
const wchar_t* szComponentDir = _wgetenv(L"SDV_COMPONENT_INSTALL");
|
||||
if (!szComponentDir) return {};
|
||||
return szComponentDir;
|
||||
if (szComponentDir) path = szComponentDir;
|
||||
#elif defined __unix__
|
||||
const char* szComponentDir = getenv("SDV_COMPONENT_INSTALL");
|
||||
if (!szComponentDir) return {};
|
||||
return szComponentDir;
|
||||
if (szComponentDir) path = szComponentDir;
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
if (path.empty()) return GetFrameworkRuntimeDirectory();
|
||||
if (path.is_relative()) path = GetAppDirectory() / path;
|
||||
return path.lexically_normal();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set or overwrite the SDV_COMPONENT_INSTALL environment variable for this application.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV V-API component installation directory.
|
||||
* @param[in] rpathDir Reference of the path directing to the SDV Vehicle API component installation directory.
|
||||
*/
|
||||
static void SetComponentInstallDirectory(const std::filesystem::path& rpathDir)
|
||||
{
|
||||
@@ -527,8 +534,7 @@ namespace sdv
|
||||
EAppOperationState m_eState = EAppOperationState::not_started; ///< Application state.
|
||||
EAppContext m_eContext = EAppContext::no_context; ///< Application context.
|
||||
uint32_t m_uiInstanceID = 0u; ///< Core instance.
|
||||
uint32_t m_uiRetries = 0u; ///< Number of retries to establish a connection.
|
||||
sdv::TObjectPtr m_ptrServerRepository; ///< Server repository interface.
|
||||
uint32_t m_uiConnectRetries = 0u; ///< Number of retries to establish a connection.
|
||||
};
|
||||
} // namespace app
|
||||
} // namespace sdv
|
||||
|
||||
@@ -20,6 +20,8 @@
|
||||
#include <vector>
|
||||
#include <string>
|
||||
#include <sstream>
|
||||
#include <atomic>
|
||||
#include <memory>
|
||||
|
||||
#include "../interfaces/core_types.h"
|
||||
#include "../interfaces/core.h"
|
||||
@@ -683,9 +685,9 @@ namespace sdv
|
||||
|
||||
/**
|
||||
* @brief Initialize the object. Overload of IObjectControl::Initialize.
|
||||
* @param[in] ssObjectConfig Optional configuration string.
|
||||
* @param[in] sObjectInfo The registration information of this object.
|
||||
*/
|
||||
virtual void Initialize(/*in*/ const u8string& ssObjectConfig) override
|
||||
virtual void Initialize(/*in*/ const SObjectInfo& sObjectInfo) override
|
||||
{
|
||||
// Not started before or ended completely?
|
||||
if (GetObjectState() != EObjectState::initialization_pending && GetObjectState() != EObjectState::destruction_pending)
|
||||
@@ -700,19 +702,19 @@ namespace sdv
|
||||
// Initialize the parameter map.
|
||||
InitParamMap();
|
||||
|
||||
// Copy the configuration
|
||||
m_ssObjectConfig = ssObjectConfig;
|
||||
// Copy the object information
|
||||
m_sSelf = sObjectInfo;
|
||||
|
||||
// Prepare initialization
|
||||
OnPreInitialize();
|
||||
|
||||
// Parse the object configuration if there is any.
|
||||
if (!ssObjectConfig.empty())
|
||||
if (!m_sSelf.ssConfig.empty())
|
||||
{
|
||||
try
|
||||
{
|
||||
// Parse the config TOML.
|
||||
toml::CTOMLParser parser(ssObjectConfig);
|
||||
toml::CTOMLParser parser(m_sSelf.ssConfig);
|
||||
if (!parser.IsValid())
|
||||
{
|
||||
m_eObjectState = EObjectState::config_error;
|
||||
@@ -781,6 +783,15 @@ namespace sdv
|
||||
return m_eObjectState;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get information about ourself.
|
||||
* @return The object information about ourself.
|
||||
*/
|
||||
const SObjectInfo& Self() const
|
||||
{
|
||||
return m_sSelf;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the component operation mode. Overload of IObjectControl::SetOperationMode.
|
||||
* @param[in] eMode The operation mode, the component should run in.
|
||||
@@ -831,15 +842,11 @@ namespace sdv
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the object configuration for persistence.
|
||||
* @brief Build the object configuration from the parameter map and the stored initial configuration.
|
||||
* @return The object configuration as TOML string.
|
||||
*/
|
||||
virtual u8string GetObjectConfig() const override
|
||||
virtual u8string BuildObjectConfig() const
|
||||
{
|
||||
// During the initialization, return the stored object configuration.
|
||||
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
|
||||
return m_ssObjectConfig;
|
||||
|
||||
// Split path function (splits the group from the parameter names)
|
||||
auto fnSplitPath = [](const u8string& rssPath) -> std::pair<u8string, u8string>
|
||||
{
|
||||
@@ -849,13 +856,10 @@ namespace sdv
|
||||
return std::make_pair(rssPath.substr(0, nPos), rssPath.substr(nPos + 1));
|
||||
};
|
||||
|
||||
// Create a new configuration string from the parameters.
|
||||
auto seqParameters = GetParamPaths();
|
||||
if (seqParameters.empty()) return {};
|
||||
|
||||
// Iterate through the list of parameter names and create the TOML entries for it.
|
||||
auto seqParameters = GetParamPaths();
|
||||
u8string ssGroup;
|
||||
toml::CTOMLParser parser("");
|
||||
toml::CTOMLParser parser(m_sSelf.ssConfig);
|
||||
toml::CNodeCollection table(parser);
|
||||
for (auto ssParamPath : seqParameters)
|
||||
{
|
||||
@@ -863,7 +867,7 @@ namespace sdv
|
||||
auto ptrParam = FindParamObject(ssParamPath);
|
||||
|
||||
// Read only and temporary parameters are not stored
|
||||
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || !ptrParam->Temporary())
|
||||
if ((!ptrParam->Locked() && ptrParam->ReadOnly()) || ptrParam->Temporary())
|
||||
continue;
|
||||
|
||||
// Get the value
|
||||
@@ -877,7 +881,9 @@ namespace sdv
|
||||
// Need to add a group?
|
||||
if (prParam.first != ssGroup)
|
||||
{
|
||||
table = parser.AddTable(prParam.first);
|
||||
table = parser.GetDirect(prParam.first);
|
||||
if (!table)
|
||||
table = parser.AddTable(prParam.first);
|
||||
ssGroup = prParam.first;
|
||||
}
|
||||
|
||||
@@ -888,6 +894,20 @@ namespace sdv
|
||||
return parser.GetTOML();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the object configuration for persistence. Overload of IObjectControl::GetObjectConfig.
|
||||
* @return The object configuration as TOML string.
|
||||
*/
|
||||
virtual u8string GetObjectConfig() const override
|
||||
{
|
||||
// During the initialization, return the stored object configuration.
|
||||
if (m_eObjectState == EObjectState::initializing || m_eObjectState == EObjectState::initialization_pending)
|
||||
return m_sSelf.ssConfig;
|
||||
|
||||
|
||||
return BuildObjectConfig();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Shutdown called before the object is destroyed. Overload of IObjectControl::Shutdown.
|
||||
* @attention Implement calls to other SDV objects here as this is no longer considered safe during the destructor of the
|
||||
@@ -930,7 +950,7 @@ namespace sdv
|
||||
* @post Reset by switching to configuration mode.
|
||||
*/
|
||||
void SetObjectIntoRuntimeErrorState()
|
||||
{
|
||||
{
|
||||
if (m_eObjectState == EObjectState::running)
|
||||
m_eObjectState = EObjectState::runtime_error;
|
||||
}
|
||||
@@ -992,6 +1012,12 @@ namespace sdv
|
||||
*/
|
||||
virtual void OnShutdown() {}
|
||||
|
||||
/**
|
||||
* @brief Last function called before destruction. The object integrity is still in tact. It can be assumed that all
|
||||
* dependencies to the object have been released.
|
||||
*/
|
||||
virtual void OnDestroy() {}
|
||||
|
||||
/**
|
||||
* @brief Interface map
|
||||
*/
|
||||
@@ -1002,7 +1028,8 @@ namespace sdv
|
||||
|
||||
private:
|
||||
std::atomic<EObjectState> m_eObjectState = EObjectState::initialization_pending; ///< Object state
|
||||
std::string m_ssObjectConfig; ///< Copy of the configuration TOML.
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Manage module lifetime.
|
||||
SObjectInfo m_sSelf; ///< Information about ourself.
|
||||
};
|
||||
|
||||
/**
|
||||
@@ -1022,6 +1049,206 @@ namespace sdv
|
||||
END_SDV_INTERFACE_MAP()
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Lifetime control implementation class.
|
||||
*/
|
||||
class CLifetimeControlImpl : public virtual IInterfaceAccess, public IObjectLifetime, protected IObjectDestroy
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Deleted copy constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CLifetimeControlImpl(const CLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CLifetimeControlImpl(CLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~CLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
// Interface map (IObjectDestroy is not exposed)
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(IObjectLifetime)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Deleted copy assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CLifetimeControlImpl& operator=(const CLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CLifetimeControlImpl& operator=(CLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
|
||||
*/
|
||||
virtual void Increment() override
|
||||
{
|
||||
m_uiLifetimeCnt++;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
|
||||
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
|
||||
* @return Returns 'true' if the object was destroyed, false if not.
|
||||
*/
|
||||
virtual bool Decrement() override
|
||||
{
|
||||
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
|
||||
{
|
||||
DestroyObject();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
|
||||
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
|
||||
* @return Returns the current counter value.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override
|
||||
{
|
||||
return m_uiLifetimeCnt;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
|
||||
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
|
||||
*/
|
||||
virtual void DestroyObject() override
|
||||
{
|
||||
delete this;
|
||||
}
|
||||
|
||||
private:
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
|
||||
std::atomic_uint32_t m_uiLifetimeCnt = 1; ///< Lifetime reference counter
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Lifetime control implementation class based on shared pointer.
|
||||
* @tparam TClass The type of class deriving CSharedLifetimeControlImpl class.
|
||||
*/
|
||||
template <class TClass>
|
||||
class CSharedLifetimeControlImpl : public std::enable_shared_from_this<TClass>, public CLifetimeControlImpl
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CSharedLifetimeControlImpl()
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Deleted copy constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CSharedLifetimeControlImpl(const CSharedLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
*/
|
||||
CSharedLifetimeControlImpl(CSharedLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Destructor.
|
||||
*/
|
||||
virtual ~CSharedLifetimeControlImpl()
|
||||
{
|
||||
}
|
||||
|
||||
// Interface map (IObjectDestroy is not exposed)
|
||||
BEGIN_SDV_INTERFACE_MAP()
|
||||
SDV_INTERFACE_ENTRY(IObjectLifetime)
|
||||
END_SDV_INTERFACE_MAP()
|
||||
|
||||
/**
|
||||
* @brief Deleted copy assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CSharedLifetimeControlImpl& operator=(const CSharedLifetimeControlImpl& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Deleted move assignment constructor.
|
||||
* @param[in] rClass Reference to the class to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CSharedLifetimeControlImpl& operator=(CSharedLifetimeControlImpl&& rClass) = delete;
|
||||
|
||||
/**
|
||||
* @brief Increment the lifetime. Needs to be balanced by a call to Decrement. Overload of IObjectLifetime::Increment.
|
||||
*/
|
||||
virtual void Increment() override
|
||||
{
|
||||
if (!m_uiLifetimeCnt++)
|
||||
m_ptrLocking = std::enable_shared_from_this<TClass>::shared_from_this();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Decrement the lifetime. If the lifetime reaches zero, the object will be destroyed (through the exposed
|
||||
* IObjectDestroy interface). Overload of IObjectLifetime::Decrement.
|
||||
* @return Returns 'true' if the object was destroyed, false if not.
|
||||
*/
|
||||
virtual bool Decrement() override
|
||||
{
|
||||
if (m_uiLifetimeCnt && !(--m_uiLifetimeCnt))
|
||||
{
|
||||
DestroyObject();
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current lifetime count. Overload of IObjectLifetime::GetCount.
|
||||
* @remarks The GetCount function returns a momentary value, which can be changed at any moment.
|
||||
* @return Returns the current counter value.
|
||||
*/
|
||||
virtual uint32_t GetCount() const override
|
||||
{
|
||||
return m_uiLifetimeCnt;
|
||||
}
|
||||
|
||||
protected:
|
||||
/**
|
||||
* @brief Destroy the object. Default implementation deletes 'this'. Overload of IObjectDestroy::DestroyObject.
|
||||
* @attention After a call of this function, all exposed interfaces render invalid and should not be used any more.
|
||||
*/
|
||||
virtual void DestroyObject() override
|
||||
{
|
||||
// Reset the locking; this might delete the class if no other references are present.
|
||||
m_ptrLocking.reset();
|
||||
}
|
||||
|
||||
private:
|
||||
std::shared_ptr<TClass> m_ptrLocking; ///< Holder of the instance of the class during lifetime.
|
||||
CLifetimeCookie m_lifetime = CreateLifetimeCookie(); ///< Module lifetime
|
||||
std::atomic_uint32_t m_uiLifetimeCnt = 0; ///< Lifetime reference counter
|
||||
};
|
||||
|
||||
/////////////////////////////////////////
|
||||
// Object control class implementation //
|
||||
/////////////////////////////////////////
|
||||
@@ -1114,6 +1341,7 @@ namespace sdv
|
||||
auto objectPtr = std::move(*iter);
|
||||
m_vecActiveObjects.erase(iter);
|
||||
lockObjects.unlock();
|
||||
objectPtr->OnDestroy();
|
||||
objectPtr = nullptr;
|
||||
if (m_uiActiveObjectCount) --m_uiActiveObjectCount;
|
||||
return;
|
||||
|
||||
@@ -389,7 +389,13 @@ namespace sdv
|
||||
template <typename TIfc>
|
||||
TIfc* GetInterface() const
|
||||
{
|
||||
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
|
||||
try
|
||||
{
|
||||
return m_pInterface ? m_pInterface.load()->GetInterface(GetInterfaceId<TIfc>()).template get<TIfc>() : nullptr;
|
||||
} catch (const XSysExcept&)
|
||||
{
|
||||
return nullptr;
|
||||
}
|
||||
}
|
||||
|
||||
private:
|
||||
|
||||
@@ -18,10 +18,17 @@
|
||||
#include "../interfaces/log.h"
|
||||
#include "../interfaces/repository.h"
|
||||
#include "../interfaces/com.h"
|
||||
#include "../interfaces/app.h"
|
||||
#include "../interfaces/param.h"
|
||||
#include "../interfaces/permission.h"
|
||||
#include "interface_ptr.h"
|
||||
#include <thread>
|
||||
#include <utility>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
#include <utility>
|
||||
|
||||
#include <string>
|
||||
#include <stdexcept>
|
||||
#ifdef __GNUC__
|
||||
// Needed for getpid()
|
||||
#include <unistd.h>
|
||||
@@ -49,9 +56,11 @@ namespace sdv
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetObject(const std::string& rssObjectName)
|
||||
{
|
||||
if (!GetCore()) return nullptr;
|
||||
if (!GetCore())
|
||||
return nullptr;
|
||||
IObjectAccess* pRepository = GetCore<IObjectAccess>();
|
||||
if (!pRepository) return nullptr;
|
||||
if (!pRepository)
|
||||
return nullptr;
|
||||
return pRepository->GetObject(rssObjectName);
|
||||
}
|
||||
|
||||
@@ -63,9 +72,11 @@ namespace sdv
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetObject(TObjectID tObjectID)
|
||||
{
|
||||
if (!GetCore()) return nullptr;
|
||||
if (!GetCore())
|
||||
return nullptr;
|
||||
IObjectAccess* pRepository = GetCore<IObjectAccess>();
|
||||
if (!pRepository) return nullptr;
|
||||
if (!pRepository)
|
||||
return nullptr;
|
||||
return pRepository->GetObjectByID(tObjectID);
|
||||
}
|
||||
#else
|
||||
@@ -113,21 +124,23 @@ namespace sdv
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Log function enables logging for SDV.
|
||||
* @param[in] eSeverity Severity level of the log message which will be logged, e.g. Info, Warning, Error etc.
|
||||
* @param[in] rssSrcFile Name of the file from which the message is logged.
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged.
|
||||
* @param[in] rssMessage Reference to the log message to be logged.
|
||||
*/
|
||||
* @brief Log function enables logging for SDV.
|
||||
* @param[in] eSeverity Severity level of the log message which will be logged, e.g. Info, Warning, Error etc.
|
||||
* @param[in] rssSrcFile Name of the file from which the message is logged.
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged.
|
||||
* @param[in] rssMessage Reference to the log message to be logged.
|
||||
*/
|
||||
inline void Log(ELogSeverity eSeverity, const u8string& rssSrcFile, uint32_t uiSrcLine, const u8string& rssMessage)
|
||||
{
|
||||
ILogger* pLogger = GetCore() ? GetCore<ILogger>() : nullptr;
|
||||
#ifdef _WIN32
|
||||
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
|
||||
if (pLogger)
|
||||
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, _getpid(), "", rssMessage);
|
||||
#elif defined __unix__
|
||||
if (pLogger) pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
|
||||
if (pLogger)
|
||||
pLogger->Log(eSeverity, rssSrcFile, uiSrcLine, getpid(), "", rssMessage);
|
||||
#else
|
||||
#error The OS is currently not supported!
|
||||
#error The OS is currently not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
@@ -137,34 +150,34 @@ namespace sdv
|
||||
*/
|
||||
#define SDV_LOG(severity, ...) sdv::core::internal::CSDVLogImpl(severity, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
/**
|
||||
* @brief Log a trace message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_TRACE(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::trace, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a debug message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a debug message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_DEBUG(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::debug, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log an information message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log an information message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_INFO(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::info, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a warning message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a warning message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_WARNING(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::warning, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log an error message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log an error message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_ERROR(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::error, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
/**
|
||||
* @brief Log a fatal message with line and position.
|
||||
*/
|
||||
/**
|
||||
* @brief Log a fatal message with line and position.
|
||||
*/
|
||||
#define SDV_LOG_FATAL(...) sdv::core::internal::CSDVLogImpl(sdv::core::ELogSeverity::fatal, __FILE__, __LINE__, __VA_ARGS__)
|
||||
|
||||
namespace internal
|
||||
@@ -176,22 +189,22 @@ namespace sdv
|
||||
* @param[in] uiSrcLine Line of the file from which the message is logged. Specified by C++ standard.
|
||||
* @param[in] ...args identifier specified by C++ standard that uses the ellipsis notation in the parameters.
|
||||
*/
|
||||
template <typename ...Args>
|
||||
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&& ...args)
|
||||
template <typename... Args>
|
||||
inline void CSDVLogImpl(ELogSeverity eSeverity, const char* szSrcFile, uint32_t uiSrcLine, Args&&... args)
|
||||
{
|
||||
std::ostringstream stream;
|
||||
(stream << ... << std::forward<Args>(args));
|
||||
|
||||
Log(eSeverity, szSrcFile ? szSrcFile : "", uiSrcLine, stream.str().c_str());
|
||||
}
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Create a utility
|
||||
* @param[in] rssUtilityName Reference to the utility name.
|
||||
* @param[in] rssUtilityConfig Optional reference to the utility configuration.
|
||||
* @return Smart pointer to the utility or NULL when the utility could not be found.
|
||||
*/
|
||||
*/
|
||||
inline TObjectPtr CreateUtility(const std::string& rssUtilityName, const std::string& rssUtilityConfig = std::string())
|
||||
{
|
||||
TInterfaceAccessPtr ptrRepository = GetObject("RepositoryService");
|
||||
@@ -199,8 +212,529 @@ namespace sdv
|
||||
if (!pUtilityCreate) return nullptr;
|
||||
return pUtilityCreate->CreateUtility(rssUtilityName, rssUtilityConfig);
|
||||
}
|
||||
} // namespace core
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object smart pointer.
|
||||
* @param[in] pParameters Pointer to the parameter map interface of an object.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const IParameters* pParameters, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
any_t any = pParameters->GetParam(rssParamName);
|
||||
if (any.empty())
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The parameter could not be found.");
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the parameter interface.
|
||||
* @param[in] rptrObject Reference to object smart pointer to the the parameter of.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const TInterfaceAccessPtr& rptrObject, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
const IParameters* pParameters = rptrObject.GetInterface<IParameters>();
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
return GetParameter(pParameters, rssParamName, bNoExcept);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object with the supplied name.
|
||||
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter or an empty any_t when the object or the parameter could not be found and
|
||||
* bNoExcept was set.
|
||||
*/
|
||||
inline any_t GetParameter(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
|
||||
if (!ptrObject)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
|
||||
}
|
||||
return GetParameter(ptrObject, rssParamName, bNoExcept);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get a parameter from the object with the supplied name. Resolve enums and bitmask objects in the returned
|
||||
* parameter string.
|
||||
* @param[in] rssObjectName Reference to the string containing the name of the object or service.
|
||||
* @param[in] rssParamName Name of the parameter (incl. groups preceding the name and separated with a dot).
|
||||
* @param[in] bNoExcept When set, do not trigger an std::runtime exception when the object or the parameter could not be
|
||||
* found.
|
||||
* @return Returns the value of the parameter as a text string or an empty string when the object or the parameter could
|
||||
* not be found and bNoExcept was set.
|
||||
*/
|
||||
inline std::string GetParameterExpand(const std::string& rssObjectName, const std::string& rssParamName, bool bNoExcept = true)
|
||||
{
|
||||
TInterfaceAccessPtr ptrObject = GetObject(rssObjectName);
|
||||
if (!ptrObject)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("An object with the name '" + rssObjectName + "' could not be found.");
|
||||
}
|
||||
|
||||
const IParameters* pParameters = ptrObject.GetInterface<IParameters>();
|
||||
if (!pParameters)
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The object doesn't expose IParameters interface.");
|
||||
}
|
||||
any_t any = pParameters->GetParam(rssParamName);
|
||||
if (any.empty())
|
||||
{
|
||||
if (bNoExcept) return {};
|
||||
throw std::runtime_error("The parameter could not be found.");
|
||||
}
|
||||
|
||||
SParamInfo sParamInfo = pParameters->GetParamInfo(rssParamName);
|
||||
if (sParamInfo.get_switch() == EParamType::enum_param)
|
||||
{
|
||||
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sEnumInfo.seqLabels)
|
||||
{
|
||||
if (rsLabel.anyValue == any)
|
||||
return rsLabel.ssLabel;
|
||||
}
|
||||
}
|
||||
if (sParamInfo.get_switch() == EParamType::bitmask_param)
|
||||
{
|
||||
uint64_t uiValue = static_cast<uint64_t>(any);
|
||||
std::stringstream sstreamValue;
|
||||
for (const SLabelInfo::SLabel& rsLabel : sParamInfo.uExtInfo.sBitmaskInfo.seqLabels)
|
||||
{
|
||||
uint64_t uiValueLabel = static_cast<uint64_t>(rsLabel.anyValue);
|
||||
if (uiValue & uiValueLabel)
|
||||
{
|
||||
if (sstreamValue.rdbuf()->in_avail()) // Has characters
|
||||
sstreamValue << "|";
|
||||
sstreamValue << rsLabel.ssLabel;
|
||||
uiValue = uiValue & ~uiValueLabel;
|
||||
}
|
||||
}
|
||||
if (uiValue) // Not all bits have labels
|
||||
{
|
||||
if (sstreamValue.rdbuf()->in_avail()) // Has characters
|
||||
sstreamValue << "|";
|
||||
sstreamValue << uiValue;
|
||||
}
|
||||
return sstreamValue.str();
|
||||
}
|
||||
return any;
|
||||
}
|
||||
|
||||
/// Internal namespace
|
||||
namespace internal
|
||||
{
|
||||
/**
|
||||
* @brief Trim whitespace at the begin and end of the text.
|
||||
* @param[in] rssText Reference to the text to trim whitespace for.
|
||||
* @return The trimmed text.
|
||||
*/
|
||||
inline std::string TrimWhitespace(const std::string& rssText)
|
||||
{
|
||||
size_t nFirst = rssText.find_first_not_of(" \t\r\n");
|
||||
if (nFirst == std::string::npos) return "";
|
||||
size_t nLast = rssText.find_last_not_of(" \t\r\n");
|
||||
return rssText.substr(nFirst, (nLast - nFirst + 1));
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Helper function to safely check if a string contains a valid, unescaped $(...) sequence.
|
||||
* @param[in] rssText The text to check.
|
||||
* @return Returns whether the text represents a valid variable.
|
||||
*/
|
||||
inline bool ContainsValidVariable(const std::string& rssText)
|
||||
{
|
||||
size_t nLength = rssText.length();
|
||||
size_t nIndex = 0;
|
||||
|
||||
while (nIndex < nLength)
|
||||
{
|
||||
if (rssText[nIndex] == '\\')
|
||||
{
|
||||
// Skip the escape and the escaped character
|
||||
nIndex += 2;
|
||||
}
|
||||
else if (rssText[nIndex] == '$')
|
||||
{
|
||||
// Check if it forms the start of a token sequence '$( '
|
||||
if (nIndex + 1 < nLength && rssText[nIndex + 1] == '(')
|
||||
{
|
||||
size_t nClose = rssText.find(')', nIndex + 2);
|
||||
if (nClose != std::string::npos)
|
||||
{
|
||||
// Found a valid structural candidate
|
||||
return true;
|
||||
}
|
||||
}
|
||||
nIndex++;
|
||||
}
|
||||
else
|
||||
{
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
/**
|
||||
* @brief Resolves embedded object parameter variables formatted as $(object:param) within a text string.
|
||||
* @param[in] rssText The source text containing potential variables and backslash escapes.
|
||||
* @param[in] bRecursive If true, continues resolving until no more unescaped variables remain.
|
||||
* @param[in] bNoExcept If true, returns an empty string for errors; if false, throws std::runtime_error.
|
||||
* @return The fully resolved text string.
|
||||
*/
|
||||
inline std::string ResolveText(const std::string& rssText, bool bRecursive = true, bool bNoExcept = true)
|
||||
{
|
||||
std::string ssCurrentText = rssText;
|
||||
bool bMayHaveMoreVariables = true;
|
||||
|
||||
while (bMayHaveMoreVariables)
|
||||
{
|
||||
bMayHaveMoreVariables = false;
|
||||
std::string ssResult = "";
|
||||
ssResult.reserve(ssCurrentText.length()); // Pre-allocate memory for performance
|
||||
|
||||
size_t nLength = ssCurrentText.length();
|
||||
size_t nIndex = 0;
|
||||
|
||||
while (nIndex < nLength)
|
||||
{
|
||||
char cCurrent = ssCurrentText[nIndex];
|
||||
|
||||
// Handle backslash escape sequences
|
||||
if (cCurrent == '\\')
|
||||
{
|
||||
// Check if the next character is a '$'
|
||||
if (nIndex + 1 < nLength && ssCurrentText[nIndex + 1] == '$')
|
||||
{
|
||||
ssResult.push_back('$'); // Strip the escape character, keep the literal '$'
|
||||
nIndex += 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
ssResult.push_back('\\'); // Preserve other backslashes for paths
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
// Identify potential variables
|
||||
else if (cCurrent == '$')
|
||||
{
|
||||
// extension 2: Only throw an error or treat as a variable if it is
|
||||
// explicitly part of a dynamic sequence tracking towards a '$(...)' match.
|
||||
if (nIndex + 1 >= nLength || ssCurrentText[nIndex + 1] != '(')
|
||||
{
|
||||
// It is a loose literal '$' (like currency). Keep it and do not throw.
|
||||
ssResult.push_back('$');
|
||||
nIndex++;
|
||||
continue;
|
||||
}
|
||||
|
||||
size_t nVarStart = nIndex + 2; // Position right after "$("
|
||||
size_t nVarEnd = ssCurrentText.find(')', nVarStart);
|
||||
|
||||
// Validate that a matching closing parenthesis exists
|
||||
if (nVarEnd == std::string::npos)
|
||||
{
|
||||
if (!bNoExcept)
|
||||
throw std::runtime_error(
|
||||
"Format error: Missing closing parenthesis ')' for variable starting at index "
|
||||
+ std::to_string(nIndex));
|
||||
return "";
|
||||
}
|
||||
|
||||
// Extract the inner payload block
|
||||
std::string sVariableContent = ssCurrentText.substr(nVarStart, nVarEnd - nVarStart);
|
||||
size_t nColonPos = sVariableContent.find(':');
|
||||
|
||||
// Validate that the delimiter ':' separates object and parameter names
|
||||
if (nColonPos == std::string::npos)
|
||||
{
|
||||
if (!bNoExcept)
|
||||
throw std::runtime_error("Format error: Variable content '" + sVariableContent
|
||||
+ "' lacks an 'object:param' colon separator");
|
||||
return "";
|
||||
}
|
||||
|
||||
// Extract and clean whitespace before/after tokens, preserving inner spaces
|
||||
std::string sObjName = internal::TrimWhitespace(sVariableContent.substr(0, nColonPos));
|
||||
std::string sParamName = internal::TrimWhitespace(sVariableContent.substr(nColonPos + 1));
|
||||
|
||||
// Request the parameter.
|
||||
std::string ssValue = GetParameterExpand(sObjName, sParamName, bNoExcept);
|
||||
|
||||
// Add the parameter to the string
|
||||
ssResult.append(ssValue);
|
||||
|
||||
nIndex = nVarEnd + 1; // Move parsing index past the ')'
|
||||
}
|
||||
else
|
||||
{
|
||||
ssResult.push_back(cCurrent);
|
||||
nIndex++;
|
||||
}
|
||||
}
|
||||
|
||||
ssCurrentText = ssResult;
|
||||
|
||||
// Exit immediately if recursive resolution was disabled
|
||||
if (!bRecursive) break;
|
||||
|
||||
// extension 2: Intelligently analyze if a recursive processing loop is required
|
||||
if (internal::ContainsValidVariable(ssCurrentText))
|
||||
bMayHaveMoreVariables = true;
|
||||
}
|
||||
|
||||
return ssCurrentText;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current access permission.
|
||||
* @return The current access permission.
|
||||
*/
|
||||
inline EAccessPermission GetCurrentAccessPermission()
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl)
|
||||
return EAccessPermission::not_set;
|
||||
return pPermissionControl->GetCurrentPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the current transmission from this thread and prepare a transfer to another thread.
|
||||
* @return Transfer ID identifying the permission of this thread.
|
||||
*/
|
||||
inline TPermissionTransferID TransferCurrentPermission()
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return 0u;
|
||||
return pPermissionControl->TransferCurrentPermission();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Class managing the lifetime of an access permission.
|
||||
*/
|
||||
class CAccessPermission
|
||||
{
|
||||
// Friend functions
|
||||
friend CAccessPermission RestrictAccessPermission(EAccessPermission);
|
||||
friend CAccessPermission SetAccessPermission(TPermissionTransferID);
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
CAccessPermission() = default;
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Constructor
|
||||
* @param[in] tPermissionID The access permission to manage.
|
||||
*/
|
||||
CAccessPermission(TPermissionID tPermissionID) : m_tPermissionID(tPermissionID)
|
||||
{}
|
||||
|
||||
public:
|
||||
/**
|
||||
* @brief Copy constructor is deleted.
|
||||
* @param[in] rPermission Reference to the permission to copy from.
|
||||
*/
|
||||
CAccessPermission(const CAccessPermission& rPermission) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param[in] rPermission Reference to the permission to move from.
|
||||
*/
|
||||
CAccessPermission(CAccessPermission&& rPermission) : m_tPermissionID(rPermission.m_tPermissionID)
|
||||
{
|
||||
rPermission.m_tPermissionID = 0u;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Destructor
|
||||
*/
|
||||
~CAccessPermission()
|
||||
{
|
||||
Release();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Copy assignment operator is deleted.
|
||||
* @param[in] rPermission Reference to the permission to copy from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CAccessPermission& operator=(const CAccessPermission& rPermission) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param[in] rPermission Reference to the permission to move from.
|
||||
* @return Reference to this class.
|
||||
*/
|
||||
CAccessPermission& operator=(CAccessPermission&& rPermission)
|
||||
{
|
||||
m_tPermissionID = rPermission.m_tPermissionID;
|
||||
rPermission.m_tPermissionID = 0u;
|
||||
return *this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Boolean operator.
|
||||
* @return Returns whether a valid permission ID is assigned to this class.
|
||||
*/
|
||||
operator bool() const
|
||||
{
|
||||
return m_tPermissionID ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Does the access permission class contain a valid permission ID.
|
||||
* @return Returns whether a valid permission ID is assigned to this class.
|
||||
*/
|
||||
bool IsValid() const
|
||||
{
|
||||
return m_tPermissionID ? true : false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Release the permission.
|
||||
*/
|
||||
void Release()
|
||||
{
|
||||
if (!m_tPermissionID) return;
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return;
|
||||
pPermissionControl->ReleaseAccessPermission(m_tPermissionID);
|
||||
m_tPermissionID = 0u;
|
||||
}
|
||||
|
||||
private:
|
||||
TPermissionID m_tPermissionID = 0u; ///< Permission ID to be managed by this class.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Restrict the current access permission.
|
||||
* @param[in] ePermission The permission the access should be restricted to.
|
||||
* @return The access permission connected to this restriction. The lifetime of the access permission is managed by the
|
||||
* returned class.
|
||||
*/
|
||||
inline CAccessPermission RestrictAccessPermission(EAccessPermission ePermission)
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return {};
|
||||
return pPermissionControl->RestrictAccessPermission(ePermission);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Set the access permission from a transfer ID that defined the access permission of a different thread.
|
||||
* @param[in] tTransferID The ID of the transferred access permission.
|
||||
* @return The access permission for the current thread. The lifetime of the access permission is managed by the returned
|
||||
* class.
|
||||
*/
|
||||
inline CAccessPermission SetAccessPermission(TPermissionTransferID tTransferID)
|
||||
{
|
||||
IPermissionControl* pPermissionControl = GetCore<IPermissionControl>();
|
||||
if (!pPermissionControl) return {};
|
||||
return pPermissionControl->SetAccessPermission(tTransferID);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Secure thread implementation based on std::thread transferring the permissions from the creation thread to the
|
||||
* execution thread.
|
||||
*/
|
||||
class secure_thread : public std::thread
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor
|
||||
*/
|
||||
secure_thread() = default;
|
||||
|
||||
/**
|
||||
* @brief Copy constructor is deleted.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
*/
|
||||
secure_thread(const secure_thread& rthread) = delete;
|
||||
|
||||
/**
|
||||
* @brief Move constructor.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
*/
|
||||
secure_thread(secure_thread&& rthread) : std::thread(static_cast<std::thread&&>(rthread))
|
||||
{}
|
||||
|
||||
/**
|
||||
* @brief Assignment constructor for thread execution.
|
||||
* @tparam F The function to execute.
|
||||
* @tparam Args The argument types of the function to execute.
|
||||
* @param[in] f Reference to the function.
|
||||
* @param[in] args Reference to zero or more arguments.
|
||||
*/
|
||||
template <class F, class... Args>
|
||||
explicit secure_thread(F&& f, Args&&... args)
|
||||
{
|
||||
static_cast<std::thread&>(*this) = std::thread(
|
||||
[](TPermissionTransferID tTransferID, auto&& function, auto&&... arguments)
|
||||
{
|
||||
CAccessPermission permission = SetAccessPermission(tTransferID);
|
||||
std::invoke(std::forward<decltype(function)>(function), std::forward<decltype(arguments)>(arguments)...);
|
||||
}, TransferCurrentPermission(), std::forward<F>(f), std::forward<Args>(args)...);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Move assignment operator.
|
||||
* @param[in] rthread Reference to the thread object.
|
||||
* @return Reference to this object.
|
||||
*/
|
||||
secure_thread& operator=(secure_thread&& rthread)
|
||||
{
|
||||
static_cast<std::thread&>(*this) = static_cast<std::thread&&>(rthread);
|
||||
return *this;
|
||||
}
|
||||
};
|
||||
} // namespace core
|
||||
}// namespace sdv
|
||||
|
||||
/**
|
||||
* @{
|
||||
* @brief Comparison operators
|
||||
* @param[in] e1 First permission
|
||||
* @param[in] e2 Second permission
|
||||
* @return Result of the comparison
|
||||
*/
|
||||
inline bool operator<(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) < static_cast<int32_t>(e2); }
|
||||
inline bool operator<=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) <= static_cast<int32_t>(e2); }
|
||||
inline bool operator>(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) > static_cast<int32_t>(e2); }
|
||||
inline bool operator>=(sdv::core::EAccessPermission e1, sdv::core::EAccessPermission e2) { return static_cast<int32_t>(e1) >= static_cast<int32_t>(e2); }
|
||||
/**
|
||||
* @}
|
||||
*/
|
||||
|
||||
namespace sdv
|
||||
{
|
||||
namespace app
|
||||
{
|
||||
/**
|
||||
@@ -208,11 +742,11 @@ namespace sdv
|
||||
* @param[in] rssAttribute Name of the attribute.
|
||||
* @return The attribute value or an empty any-value if the attribute wasn't found or didn't have a value.
|
||||
*/
|
||||
inline any_t GetAppAttribute(const std::string& rssAttribute)
|
||||
inline any_t GetAppSettingsAttribute(const std::string& rssAttribute)
|
||||
{
|
||||
const IAttributes* ptrAppAttributes = core::GetObject<IAttributes>("AppControlService");
|
||||
if (!ptrAppAttributes) return {};
|
||||
return ptrAppAttributes->Get(rssAttribute);
|
||||
const IParameters* pParameters = core::GetObject<IParameters>("AppSettingsService");
|
||||
if (!pParameters) return {};
|
||||
return pParameters->GetParam(rssAttribute);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -221,7 +755,7 @@ namespace sdv
|
||||
*/
|
||||
inline bool ConsoleIsSilent()
|
||||
{
|
||||
return GetAppAttribute("console.info_level") == "silent";
|
||||
return GetAppSettingsAttribute("Console.Reporting") == "Silent";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -230,7 +764,7 @@ namespace sdv
|
||||
*/
|
||||
inline bool ConsoleIsVerbose()
|
||||
{
|
||||
return GetAppAttribute("console.info_level") == "verbose";
|
||||
return GetAppSettingsAttribute("Console.Reporting") == "Verbose";
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -239,7 +773,7 @@ namespace sdv
|
||||
*/
|
||||
inline uint32_t GetAppInstanceID()
|
||||
{
|
||||
return GetAppAttribute("app.instance_id");
|
||||
return GetAppSettingsAttribute("Application.Instance");
|
||||
}
|
||||
} // namespace app
|
||||
|
||||
@@ -247,64 +781,81 @@ namespace sdv
|
||||
{
|
||||
/**
|
||||
* @brief Create a repository connection to a local server.
|
||||
* @param[in] uiInstanceID Optionally the instance ID of the target system to connect to or 0 (default) to connect to the
|
||||
* instance identified by app-control.
|
||||
* @param[in] nRetries Number of retries to connect (optional, default 30, minimum 3).
|
||||
* @return Returns a smart pointer to the repository proxy. Disconnection takes place when IObjectDestroy::DestroyObject is
|
||||
* called.
|
||||
*/
|
||||
inline TObjectPtr ConnectToLocalServerRepository(uint32_t uiInstanceID = 0, size_t nRetries = 30)
|
||||
inline TObjectPtr ConnectToLocalServerRepository(size_t nRetries = 30)
|
||||
{
|
||||
com::IClientConnect* pClientConnect = core::GetObject<com::IClientConnect>("ConnectionService");
|
||||
if (!pClientConnect)
|
||||
// This function works with main, external and maintenance applications.
|
||||
const app::IAppContext* pAppContext = core::GetCore<app::IAppContext>();
|
||||
if (!pAppContext) return {};
|
||||
switch (pAppContext->GetContextType())
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cerr << "ERROR: Could not access the connection service." << std::endl;
|
||||
case app::EAppContext::main:
|
||||
case app::EAppContext::external:
|
||||
case app::EAppContext::maintenance:
|
||||
break;
|
||||
default:
|
||||
return {};
|
||||
}
|
||||
|
||||
const sdv::app::IAppConnections* pConnections = core::GetObject<sdv::app::IAppConnections>("AppSettingsService");
|
||||
if (!pConnections) return {};
|
||||
std::string ssConnectionConfig = pConnections->GetConnectionConfig("Default");
|
||||
if (ssConnectionConfig.empty()) return {};
|
||||
|
||||
sdv::core::IRepositoryControl* pRepository = core::GetObject<sdv::core::IRepositoryControl>("RepositoryService");
|
||||
if (!pRepository) return {};
|
||||
auto tConnectSvcID = pRepository->CreateObject("ClientConnectService", "ClientDefault", ssConnectionConfig);
|
||||
if (!tConnectSvcID) return {};
|
||||
|
||||
sdv::TInterfaceAccessPtr ptrConnectSvc = core::GetObject(tConnectSvcID);
|
||||
sdv::com::IClientConnect* pClientConnect = ptrConnectSvc.GetInterface<sdv::com::IClientConnect>();
|
||||
if (!pClientConnect)
|
||||
{
|
||||
pRepository->DestroyObject("ClientDefault");
|
||||
return {};
|
||||
}
|
||||
|
||||
// Connect the client to the server and return the server repository interface.
|
||||
std::string ssConnectString = R"code([Client]
|
||||
Type = "Local"
|
||||
)code";
|
||||
if (uiInstanceID)
|
||||
ssConnectString += "Instance = " + std::to_string(uiInstanceID) + R"code(
|
||||
)code";
|
||||
try
|
||||
{
|
||||
// Try to connect (30 times with 1 second in between).
|
||||
size_t nCnt = 0;
|
||||
sdv::TObjectPtr ptrRepository;
|
||||
while (!ptrRepository && nCnt < nRetries)
|
||||
sdv::TObjectPtr ptrRemoteRepo;
|
||||
while (!ptrRemoteRepo && nCnt < std::max(nRetries, static_cast<size_t>(3u)))
|
||||
{
|
||||
nCnt++;
|
||||
ptrRepository = pClientConnect->Connect(ssConnectString);
|
||||
if (!ptrRepository)
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
if (pClientConnect->IsConnected() || pClientConnect->Connect())
|
||||
{
|
||||
ptrRemoteRepo = pClientConnect->GetRemoteRepository();
|
||||
break;
|
||||
}
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(1000));
|
||||
}
|
||||
|
||||
// Return the result
|
||||
return ptrRepository;
|
||||
return ptrRemoteRepo;
|
||||
}
|
||||
catch (const XAccessDenied& /*rExcept*/)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Access denied trying to connect to a local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
|
||||
app::GetAppInstanceID() << "." << std::endl;
|
||||
return {};
|
||||
}
|
||||
catch (const XNotFound& /*rExcept*/)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " not found." << std::endl;
|
||||
app::GetAppInstanceID() << " not found." << std::endl;
|
||||
return {};
|
||||
}
|
||||
catch (const XInvalidState& rExcept)
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "The local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << " is in an invalid state: " << rExcept.what() <<
|
||||
app::GetAppInstanceID() << " is in an invalid state: " << rExcept.what() <<
|
||||
std::endl;
|
||||
return {};
|
||||
}
|
||||
@@ -312,12 +863,11 @@ Type = "Local"
|
||||
{
|
||||
if (!app::ConsoleIsSilent())
|
||||
std::cout << "Timeout occurred trying to connect to a local repository with server instance ID#" <<
|
||||
(uiInstanceID?uiInstanceID : app::GetAppInstanceID()) << "." << std::endl;
|
||||
app::GetAppInstanceID() << "." << std::endl;
|
||||
return {};
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace core
|
||||
} // namespace com
|
||||
} // namespace sdv
|
||||
|
||||
#endif // !defined LOCAL_SERVICE_ACCESS_H
|
||||
@@ -435,12 +435,14 @@ namespace sdv
|
||||
* @tparam TInfoConstruct The type of the variables that are provided to the constructor function of the parameter
|
||||
* information.
|
||||
* @param[in] rtVar Reference to the parameter variable.
|
||||
* @param[in] bReadOnly When set, the parameter is read-only (even when writable) and will not be initialized.
|
||||
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable
|
||||
* parameters.
|
||||
* @param[in] tConstruct The construct function arguments.
|
||||
*/
|
||||
template <typename... TInfoConstruct>
|
||||
CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
|
||||
CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct);
|
||||
|
||||
/**
|
||||
* @brief Set a value. Overload of CParamGuardian::Set.
|
||||
@@ -993,7 +995,7 @@ namespace sdv
|
||||
} \
|
||||
std::vector<std::shared_ptr<sdv::CSdvParamInfo>> vecParamInfo; \
|
||||
[[maybe_unused]] uint32_t uiFlags = 0; \
|
||||
[[maybe_unused]] std::string ssGroup; \
|
||||
[[maybe_unused]] std::string ssGroup; \
|
||||
[[maybe_unused]] bool bLockable = false;
|
||||
|
||||
/**
|
||||
@@ -1107,8 +1109,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, unit_string, ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
unit_string, ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1126,7 +1129,7 @@ namespace sdv
|
||||
* @param description_string The description of the parameter.
|
||||
*/
|
||||
#define SDV_PARAM_NUMBER_ENTRY(var, name_string, default_val, low_limit, high_limit, unit_string, description_string) \
|
||||
{ \
|
||||
{ \
|
||||
auto prLowLimit = sdv::internal::SLowerLimit() low_limit; \
|
||||
sdv::any_t anyLower; \
|
||||
if (prLowLimit.second != sdv::internal::ELimitType::no_limit) anyLower = prLowLimit.first; \
|
||||
@@ -1144,8 +1147,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, \
|
||||
name_string, default_val, anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
anyLower, prLowLimit.second != sdv::internal::ELimitType::up_to_limit, anyUpper, \
|
||||
prHighLimit.second != sdv::internal::ELimitType::up_to_limit, unit_string, ssGroup, description_string, \
|
||||
uiFlags); \
|
||||
if (ptrParamInfo)vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
@@ -1181,8 +1185,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, pattern_string, unit_string, ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
pattern_string, unit_string, ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1213,8 +1218,9 @@ namespace sdv
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, bLockable, true, name_string, \
|
||||
default_val, sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
|
||||
std::shared_ptr<sdv::CSdvParamInfo> ptrParamInfo = pObject->RegisterParameter(pObject->var, \
|
||||
uiFlags & static_cast<uint32_t>(::sdv::EParamFlags::read_only), bLockable, true, name_string, default_val, \
|
||||
sdv::internal::GetLabelMapHelper().GetLabelMap<TEnum>(), ssGroup, description_string, uiFlags); \
|
||||
if (ptrParamInfo) vecParamInfo.push_back(std::move(ptrParamInfo)); \
|
||||
}
|
||||
|
||||
@@ -1238,11 +1244,12 @@ namespace sdv
|
||||
std::vector<std::shared_ptr<sdv::CSdvParamInfo>> vecParamInfoMember; \
|
||||
if constexpr (bStatic) \
|
||||
{ \
|
||||
vecParamInfoMember = sdv::internal::SMemberMap<decltype(member)>::BuildStatic(); \
|
||||
vecParamInfoMember = sdv::internal::SMemberMap<std::decay_t<decltype(member)>>::BuildStatic(); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
auto ptrMemberMap = std::make_shared<sdv::internal::SMemberMap<decltype(member)>>(pObject->member, pObject); \
|
||||
auto ptrMemberMap = \
|
||||
std::make_shared<sdv::internal::SMemberMap<std::decay_t<decltype(member)>>>(pObject->member, pObject); \
|
||||
if (ptrMemberMap) \
|
||||
{ \
|
||||
ptrMemberMap->BuildMap(); \
|
||||
@@ -1388,13 +1395,15 @@ namespace sdv
|
||||
* @tparam TVar Type of the variable.
|
||||
* @tparam TConstruct The arguments for the parameter info construct function.
|
||||
* @param[in] rtVar Reference to the parameter.
|
||||
* @param[in] bReadOnly When set, the parameter is read only and will not be initialized.
|
||||
* @param[in] bLockable When set, the parameter is lockable. Only use with writable parameters.
|
||||
* @param[in] bAutoDirty When set, the parameter dirty flag is detected automatically. Only use with writable parameters.
|
||||
* @param[in] tConstruct The construct function arguments.
|
||||
* @return Smart pointer to the parameter information structure.
|
||||
*/
|
||||
template <typename TVar, typename... TConstruct>
|
||||
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty, TConstruct... tConstruct);
|
||||
std::shared_ptr<CSdvParamInfo> RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
|
||||
TConstruct... tConstruct);
|
||||
|
||||
/**
|
||||
* @brief Register a member parameter map into this parameter map.
|
||||
|
||||
@@ -412,13 +412,14 @@ namespace sdv
|
||||
|
||||
template <typename TVar>
|
||||
template <typename... TInfoConstruct>
|
||||
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bLockable, bool bAutoDirty, TInfoConstruct... tConstruct) :
|
||||
inline CParamValue<TVar>::CParamValue(TVar& rtVar, bool bReadOnly, bool bLockable, bool bAutoDirty,
|
||||
TInfoConstruct... tConstruct) :
|
||||
CParamGuardian(bLockable, bAutoDirty, rtVar, tConstruct...), m_rtVar(rtVar)
|
||||
{
|
||||
// Assign the default value
|
||||
if constexpr (!CSdvParamInfo::TypeIsReadOnly<TVar>())
|
||||
{
|
||||
m_rtVar = DefaultVal().get<TVar>();
|
||||
if (!bReadOnly) m_rtVar = DefaultVal().get<TVar>();
|
||||
UpdateDirty(DefaultVal());
|
||||
ResetDirty();
|
||||
}
|
||||
@@ -678,10 +679,10 @@ namespace sdv
|
||||
}
|
||||
|
||||
template <typename TVar, typename... TConstruct>
|
||||
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bLockable, bool bAutoDirty,
|
||||
TConstruct... tConstruct)
|
||||
inline std::shared_ptr<CSdvParamInfo> CSdvParamMap::RegisterParameter(TVar& rtVar, bool bReadOnly, bool bLockable,
|
||||
bool bAutoDirty, TConstruct... tConstruct)
|
||||
{
|
||||
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bLockable, bAutoDirty, tConstruct...);
|
||||
auto ptrParam = std::make_shared<internal::CParamValue<TVar>>(rtVar, bReadOnly, bLockable, bAutoDirty, tConstruct...);
|
||||
m_vecParamMapRegistration.push_back(SParamRegistration(ptrParam));
|
||||
return ptrParam;
|
||||
}
|
||||
|
||||
@@ -32,6 +32,7 @@
|
||||
#include <functional>
|
||||
#include <chrono>
|
||||
#include <queue>
|
||||
#include <list>
|
||||
|
||||
namespace serdes
|
||||
{
|
||||
@@ -378,7 +379,25 @@ namespace sdv
|
||||
|
||||
inline CRawDataBypass& GetRawDataBypass()
|
||||
{
|
||||
#if defined __GNUC__ && defined _WIN32
|
||||
// https://dev.azure.com/SW4ZF/AZP-431_DivDI_Vehicle_API/_workitems/edit/610009
|
||||
// In MINGW GCC implementation of thread_local, there is an issue with complex classes being used after the destruction.
|
||||
// This is caused by an architectural bug (https://github.com/msys2/MINGW-packages/issues/2519) causing the emutls (GCC
|
||||
// Emulated TLS) managing the memory allocation to be executed before the __cxa_thread_exit, the thread cleanup callback
|
||||
// of Windows. The solution is to use trivial data only (pointer, reference, integers, etc.). A workaround is
|
||||
// implemented to use a reference of the permission list and map instead of an instance to the list and map.
|
||||
static auto fnCreateBypass = []() -> CRawDataBypass&
|
||||
{
|
||||
static std::mutex mtx;
|
||||
static std::list<CRawDataBypass> lstRawDataBypasses;
|
||||
std::unique_lock<std::mutex> lock(mtx);
|
||||
lstRawDataBypasses.resize(lstRawDataBypasses.size() + 1);
|
||||
return lstRawDataBypasses.back();
|
||||
};
|
||||
thread_local static CRawDataBypass& bypass = fnCreateBypass();
|
||||
#else
|
||||
thread_local static CRawDataBypass bypass;
|
||||
#endif
|
||||
return bypass;
|
||||
}
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
#include <cctype>
|
||||
#include <stdlib.h>
|
||||
#include <functional>
|
||||
#include <sstream>
|
||||
|
||||
#ifdef _WIN32
|
||||
// Resolve conflict
|
||||
@@ -59,6 +60,8 @@
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
|
||||
#include "simple_toml.h"
|
||||
|
||||
namespace sdv
|
||||
{
|
||||
/**
|
||||
@@ -148,7 +151,36 @@ namespace sdv{
|
||||
{
|
||||
/**
|
||||
* @brief The SDV core loader
|
||||
*/
|
||||
* @details The SDV core loader class searches for the core library and does the first startup. The core library uses
|
||||
* the following environment variables to identify its location:
|
||||
* - SDV_FRAMEWORK_RUNTIME directs to the Vehicle API core location.
|
||||
* - SDV_COMPONENT_INSTALL directs to the location of the component installations.
|
||||
* - SDV_FRAMEWORK_DEV_TOOLS directs to the location of the development tools used during the build process of SDV
|
||||
* components.
|
||||
* - SDV_FRAMEWORK_DEV_INCLUDE directs to the header file location to allow building components for use with the
|
||||
* Vehicle API framework.
|
||||
*
|
||||
* The SDV core loader supports different core stacks to coexist. For this there is a location procedure for the core
|
||||
* systems:
|
||||
* 1. Check for a "sdv_core_reloc.toml" file that contain one or more paths to the core system. The paths defined in the
|
||||
* file override the global environment variables for this application and all child applications.
|
||||
* 2. Check for the environment variables. If the SDV_FRAMEWORK_RUNTIM variable is set, it is used to extract all other
|
||||
* variables as well, if not set.
|
||||
* 3. If no variable is set, use the location of the EXE as core location. This might work in some situations if the
|
||||
* path variable has been set properly.
|
||||
*
|
||||
* If none of the above strategies work, the core cannot be loaded.
|
||||
*
|
||||
* The "sdv_core_reloc.toml" file has the following format:
|
||||
* @code
|
||||
* [CoreLocation]
|
||||
* Version = 100 # Version; currently supported 100 for version 1.0
|
||||
* Runtime = "<core runtime directory>"
|
||||
* Install = "<component install directory>" # Typically identical to runtime directory
|
||||
* DevTools = "<development tools directory>" # Typically identical to runtime directory
|
||||
* Include = "<include directory>" # Typically in the include subdirectory
|
||||
* @endcode
|
||||
*/
|
||||
class CSDVCoreLoader
|
||||
{
|
||||
public:
|
||||
@@ -189,77 +221,50 @@ namespace sdv{
|
||||
{
|
||||
if (m_bInit) return; // Prevent trying to load again.
|
||||
m_bInit = true;
|
||||
bool bRelocFileError = false;
|
||||
std::string ssRelocFileInfo = "";
|
||||
std::string ssEnvironmentInfo = "";
|
||||
|
||||
// Check for the executable directory
|
||||
std::filesystem::path pathCoreLib;
|
||||
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
|
||||
pathCoreLib = GetExecDirectory() / "core_services.sdv";
|
||||
// Step 1: check for the "sdv_core_reloc.toml"
|
||||
ProcessRelocationFile();
|
||||
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
|
||||
{
|
||||
// Check for the library in the relocation directory
|
||||
auto relocFolder = GetRelocationPath();
|
||||
if (!relocFolder.empty())
|
||||
{
|
||||
auto coreLibFolder = std::filesystem::path(relocFolder) / "core_services.sdv";
|
||||
if (coreLibFolder.is_relative())
|
||||
coreLibFolder = (GetExecDirectory() / coreLibFolder).lexically_normal();
|
||||
|
||||
if (std::filesystem::exists(coreLibFolder))
|
||||
pathCoreLib = coreLibFolder;
|
||||
}
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
bRelocFileError = true; // we found the file but not the core library, we must run into an error
|
||||
ssRelocFileInfo = "Error: Invalid \"sdv_core_reloc.toml\" file found (but no core library), it contains: " + relocFolder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (pathCoreLib.empty())
|
||||
{
|
||||
// Step 2: check for environment variables (either set globally or overwritten by the sdv_core_reloc.toml).
|
||||
#ifdef _WIN32
|
||||
std::wstring ssPathCoreTemp(32768, '\0');
|
||||
GetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
|
||||
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
std::wstring ssPathCoreTemp(32768, '\0');
|
||||
GetEnvironmentVariable(
|
||||
L"SDV_FRAMEWORK_RUNTIME", ssPathCoreTemp.data(), static_cast<DWORD>(ssPathCoreTemp.size()));
|
||||
ssPathCoreTemp.resize(wcsnlen(ssPathCoreTemp.c_str(), ssPathCoreTemp.size()));
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
#else
|
||||
std::string ssPathCoreTemp = std::getenv("SDV_FRAMEWORK_RUNTIME") ? std::getenv("SDV_FRAMEWORK_RUNTIME") : "";
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
std::string ssPathCoreTemp = std::getenv("SDV_FRAMEWORK_RUNTIME") ? std::getenv("SDV_FRAMEWORK_RUNTIME") : "";
|
||||
if (!ssPathCoreTemp.empty())
|
||||
{
|
||||
m_pathCoreLib = std::filesystem::path(ssPathCoreTemp) / "core_services.sdv";
|
||||
#endif
|
||||
if (pathCoreLib.is_relative())
|
||||
pathCoreLib = (GetExecDirectory() / pathCoreLib).lexically_normal();
|
||||
if (m_pathCoreLib.is_relative())
|
||||
m_pathCoreLib = (GetExecDirectory() / m_pathCoreLib).lexically_normal();
|
||||
|
||||
if (!pathCoreLib.empty())
|
||||
ssEnvironmentInfo = "System environment path: " + pathCoreLib.generic_string();
|
||||
}
|
||||
}
|
||||
|
||||
// Depend on system path to find the library
|
||||
if (pathCoreLib.empty())
|
||||
pathCoreLib = "core_services.sdv";
|
||||
|
||||
// Open the library only if there is no or a valid 'sdv_core_reloc.toml' file
|
||||
if (!bRelocFileError)
|
||||
// Step 3: check for the executable directory or otherwise check globally
|
||||
if (m_pathCoreLib.empty())
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "core_services.sdv"))
|
||||
m_pathCoreLib = GetExecDirectory() / "core_services.sdv";
|
||||
else
|
||||
m_pathCoreLib = "core_services.sdv";
|
||||
}
|
||||
|
||||
ssEnvironmentInfo = "System environment path: " + m_pathCoreLib.generic_string();
|
||||
|
||||
#ifdef _WIN32
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(pathCoreLib.native().c_str()));
|
||||
SetErrorMode(SEM_FAILCRITICALERRORS);
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(LoadLibraryW(m_pathCoreLib.native().c_str()));
|
||||
#elif defined __unix__
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(pathCoreLib.native().c_str(), RTLD_LAZY));
|
||||
m_tModule = reinterpret_cast<core::TModuleID>(dlopen(m_pathCoreLib.native().c_str(), RTLD_LAZY));
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!m_tModule)
|
||||
{
|
||||
@@ -275,16 +280,12 @@ namespace sdv{
|
||||
#else
|
||||
#error OS is not supported!
|
||||
#endif
|
||||
if (ssRelocFileInfo.empty() && ssEnvironmentInfo.empty())
|
||||
std::cerr << "No environment variable set and no realocation file found." << std::endl;
|
||||
if (!ssRelocFileInfo.empty())
|
||||
std::cerr << ssRelocFileInfo << std::endl;
|
||||
if (!ssEnvironmentInfo.empty())
|
||||
std::cerr << ssEnvironmentInfo << std::endl;
|
||||
|
||||
std::cerr << "Could not load \"core_services.sdv\" library";
|
||||
if (!ssError.empty()) std::cerr << ": " << ssError;
|
||||
std::cerr << std::endl;
|
||||
m_ssErrMsg = "Could not load \"core_services.sdv\" library";
|
||||
if (!ssError.empty())
|
||||
m_ssErrMsg += ": " + ssError;
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -301,7 +302,8 @@ namespace sdv{
|
||||
#endif
|
||||
if (!fnSDVCore)
|
||||
{
|
||||
std::cerr << "The library \"core_services.sdv\" doesn't expose the SDVCore function." << std::endl;
|
||||
m_ssErrMsg = "The library \"core_services.sdv\" doesn't expose the SDVCore function.";
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -311,7 +313,8 @@ namespace sdv{
|
||||
m_pCore = fnSDVCore();
|
||||
if (!m_pCore)
|
||||
{
|
||||
std::cerr << "The library \"core_services.sdv\" doesn't provide a valid interface." << std::endl;
|
||||
m_ssErrMsg = "The library \"core_services.sdv\" doesn't provide a valid interface.";
|
||||
std::cerr << m_ssErrMsg << std::endl;
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -321,7 +324,6 @@ namespace sdv{
|
||||
*/
|
||||
operator TInterfaceAccessPtr() const { return m_pCore; }
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Get the directory of the executable.
|
||||
* @return Path to the directory.
|
||||
@@ -346,86 +348,170 @@ namespace sdv{
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the folder path in the file 'sdv_core_reloc.toml'.
|
||||
* @return Path content, empty string if not found.
|
||||
*/
|
||||
static std::string GetRelocationPath()
|
||||
* @brief Get the path to the core library.
|
||||
* @return Returns a reference to the path to the core library.
|
||||
*/
|
||||
const std::filesystem::path& GetCoreLibPath() const
|
||||
{
|
||||
if (std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml"))
|
||||
{
|
||||
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
|
||||
std::string ssLine;
|
||||
while (std::getline(fstream, ssLine))
|
||||
{
|
||||
size_t nPos = 0;
|
||||
auto fnSkipWhitespace = [&]() { while (std::isspace(ssLine[nPos])) nPos++; };
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] == '#') continue; // Rest of the line is comments
|
||||
if (ssLine.substr(nPos, 9) != "directory") continue; // not the keq of interest: skip line
|
||||
nPos += 9;
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] != '=')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting assignment character '=' following"
|
||||
" keyword 'directory'." << std::endl;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
fnSkipWhitespace();
|
||||
if (ssLine[nPos] != '\"')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
|
||||
" a string begin'." << std::endl;
|
||||
break;
|
||||
}
|
||||
nPos++;
|
||||
size_t nStart = nPos;
|
||||
while (nPos < ssLine.length() && ssLine[nPos] != '\"')
|
||||
{
|
||||
// Check for escape character
|
||||
if (ssLine[nPos] == '\\') nPos++;
|
||||
|
||||
// Skip character
|
||||
nPos++;
|
||||
}
|
||||
if (nPos >= ssLine.length() || ssLine[nPos] != '\"')
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting double quote character '\"' indicating"
|
||||
" a string end'." << std::endl;
|
||||
break;
|
||||
}
|
||||
std::string ssDirectory = ssLine.substr(nStart, nPos - nStart);
|
||||
while (ssDirectory.empty())
|
||||
{
|
||||
std::cout << "Error in \"sdv_core_reloc.toml\": expecting a valid value following the assignment"
|
||||
" of the 'directory' key." << std::endl;
|
||||
break;
|
||||
}
|
||||
|
||||
return ssDirectory;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
return m_pathCoreLib;
|
||||
}
|
||||
|
||||
bool m_bInit = false; ///< Is the loader initialized?
|
||||
core::TModuleID m_tModule = 0; ///< Module ID
|
||||
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
|
||||
/**
|
||||
* @brief Has loaded successfully?
|
||||
* @return Returns whether loading was successful.
|
||||
*/
|
||||
bool HasLoaded() const
|
||||
{
|
||||
return m_bInit && m_tModule && m_pCore;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Get the error message if loading was unsuccessful.
|
||||
* @return Returns the a reference to the string containing the error message or an empty string if not available.
|
||||
*/
|
||||
const std::string& GetErrorMsg() const
|
||||
{
|
||||
return m_ssErrMsg;
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* @brief Check for the 'sdv_core_reloc.toml' file containing the information about core relocation.
|
||||
* @details Set the environment variables following the information from the core relocation file.
|
||||
*/
|
||||
static void ProcessRelocationFile()
|
||||
{
|
||||
if (!std::filesystem::exists(GetExecDirectory() / "sdv_core_reloc.toml")) return;
|
||||
|
||||
std::ifstream fstream(GetExecDirectory() / "sdv_core_reloc.toml");
|
||||
if (!fstream.is_open()) return;
|
||||
|
||||
std::stringstream sstreamContent;
|
||||
sstreamContent << fstream.rdbuf();
|
||||
fstream.close();
|
||||
|
||||
try
|
||||
{
|
||||
sdv::toml::simple_parser::CParser parser(sstreamContent.str());
|
||||
if (parser.Root().GetDirect("CoreLocation.Version").GetValue<uint32_t>() != SDVFrameworkInterfaceVersion)
|
||||
{
|
||||
std::cerr << "Invalid version in sdv_core_reloc.toml" << std::endl;
|
||||
return; // Version not supported
|
||||
}
|
||||
|
||||
const auto& sRuntimeNode = parser.Root().GetDirect("CoreLocation.Runtime");
|
||||
if (sRuntimeNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathRuntime = sRuntimeNode.GetValue<std::string>();
|
||||
if (pathRuntime.is_relative())
|
||||
pathRuntime = (GetExecDirectory() / pathRuntime).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_RUNTIME", pathRuntime.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_RUNTIME=") + pathRuntime.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_RUNTIME", pathRuntime.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sInstallNode = parser.Root().GetDirect("CoreLocation.Install");
|
||||
if (sInstallNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathInstall = sInstallNode.GetValue<std::string>();
|
||||
if (pathInstall.is_relative())
|
||||
pathInstall = (GetExecDirectory() / pathInstall).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_COMPONENT_INSTALL", pathInstall.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_COMPONENT_INSTALL=") + pathInstall.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_COMPONENT_INSTALL", pathInstall.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sDevToolsNode = parser.Root().GetDirect("CoreLocation.DevTools");
|
||||
if (sDevToolsNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathDevTools = sDevToolsNode.GetValue<std::string>();
|
||||
if (pathDevTools.is_relative())
|
||||
pathDevTools = (GetExecDirectory() / pathDevTools).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_TOOLS=") + pathDevTools.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_DEV_TOOLS", pathDevTools.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
|
||||
const auto& sIncludeNode = parser.Root().GetDirect("CoreLocation.Include");
|
||||
if (sIncludeNode)
|
||||
{
|
||||
// Note: since the system might load multiple executables and the path is relative to this executable,
|
||||
// but maybe not to another executable, create an absolute path before assigning the environment
|
||||
// variable.
|
||||
std::filesystem::path pathInclude = sIncludeNode.GetValue<std::string>();
|
||||
if (pathInclude.is_relative())
|
||||
pathInclude = (GetExecDirectory() / pathInclude).lexically_normal();
|
||||
#ifdef _WIN32
|
||||
// NOTE: In windows there are two environment variables which need to be updated.
|
||||
std::ignore = SetEnvironmentVariable(L"SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.native().c_str());
|
||||
std::ignore = _wputenv((std::wstring(L"SDV_FRAMEWORK_DEV_INCLUDE=") + pathInclude.native()).c_str());
|
||||
#elif defined __unix__
|
||||
std::ignore = setenv("SDV_FRAMEWORK_DEV_INCLUDE", pathInclude.generic_u8string().c_str(), 1);
|
||||
#else
|
||||
#error The OS is not supported!
|
||||
#endif
|
||||
}
|
||||
}
|
||||
catch (const std::exception&)
|
||||
{}
|
||||
}
|
||||
|
||||
bool m_bInit = false; ///< Is the loader initialized?
|
||||
core::TModuleID m_tModule = 0; ///< Module ID
|
||||
IInterfaceAccess* m_pCore = nullptr; ///< Pointer to the core services.
|
||||
std::filesystem::path m_pathCoreLib; ///< Path to the core library.
|
||||
std::string m_ssErrMsg; ///< Error message for failed loading.
|
||||
};
|
||||
} // namespace internal
|
||||
|
||||
#ifndef NO_SDV_CORE_FUNC
|
||||
/**
|
||||
* @brief Access to the core.
|
||||
* @return Smart pointer to the core services interface.
|
||||
* @brief Access to the core loader.
|
||||
* @return Reference to the one core loader instance.
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetCore()
|
||||
inline internal::CSDVCoreLoader& GetCoreLoader()
|
||||
{
|
||||
static internal::CSDVCoreLoader core;
|
||||
core.Load();
|
||||
return core;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to the core interfaces.
|
||||
* @return Smart pointer to the core services interfaces.
|
||||
*/
|
||||
inline TInterfaceAccessPtr GetCore()
|
||||
{
|
||||
return GetCoreLoader();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Access to specific interface of the core.
|
||||
* @tparam TInterface Type of interface to return.
|
||||
|
||||
@@ -546,10 +546,10 @@ namespace sdv
|
||||
if (m_ptrValue) m_ptrValue->Receive(anyVal);
|
||||
}
|
||||
|
||||
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
|
||||
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
|
||||
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding an receive subscription.
|
||||
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of a callback function.
|
||||
CDispatchService& m_rDispatch; ///< Reference to the dispatch service.
|
||||
std::function<void(any_t)> m_funcSignalReceive; ///< Receive signal data - callback function.
|
||||
IInterfaceAccess* m_pSubscription = nullptr; ///< Cookie received by adding a subscription.
|
||||
std::unique_ptr<CValueAssignmentHelper> m_ptrValue; ///< Value to update instead of callback func.
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
1010
export/support/simple_toml.h
Normal file
1010
export/support/simple_toml.h
Normal file
File diff suppressed because it is too large
Load Diff
@@ -11,12 +11,14 @@
|
||||
* Erik Verhoeven - initial API and implementation
|
||||
********************************************************************************/
|
||||
|
||||
#ifndef SDV_CONFIG_H
|
||||
#define SDV_CONFIG_H
|
||||
#ifndef SDV_TOML_H
|
||||
#define SDV_TOML_H
|
||||
|
||||
#include <charconv>
|
||||
#include "../interfaces/toml.h"
|
||||
#include "interface_ptr.h"
|
||||
#include "local_service_access.h"
|
||||
#include "interface_ptr.h"
|
||||
|
||||
namespace sdv::toml
|
||||
{
|
||||
@@ -82,6 +84,18 @@ namespace sdv::toml
|
||||
*/
|
||||
ENodeType GetType() const;
|
||||
|
||||
/**
|
||||
* @brief Get the index of this node within the parent collection.
|
||||
* @return The index of the node within the parent collection node or npos when no parent is available.
|
||||
*/
|
||||
uint32_t GetIndex() const;
|
||||
|
||||
/**
|
||||
* @brief Is the node defined as inline node?
|
||||
* @return The inline flag.
|
||||
*/
|
||||
bool IsInline() const;
|
||||
|
||||
/**
|
||||
* @brief Return any associated comment text for this node.
|
||||
* @return The node comment or an empty string when there is not comment for this node.
|
||||
@@ -132,6 +146,12 @@ namespace sdv::toml
|
||||
*/
|
||||
virtual void Clear();
|
||||
|
||||
/**
|
||||
* @brief Format the node automatically, remove redundant whitespace.
|
||||
* @param[in] bRemoveComments When set, the comments are removed from the node.
|
||||
*/
|
||||
void AutomaticFormat(bool bRemoveComments);
|
||||
|
||||
/**
|
||||
* @brief Get the TOML string from this node including all children.
|
||||
* @return The TOML string.
|
||||
@@ -228,23 +248,29 @@ namespace sdv::toml
|
||||
*/
|
||||
CNode GetDirect(const sdv::u8string& rssNode) const;
|
||||
|
||||
/**
|
||||
* @brief Return the node name for a node in the collection. If the collection is an array, provides the index between
|
||||
* square brackets.
|
||||
* @param[in] nIndex Index to return the node name for.
|
||||
* @return Name of the node or an empty string if the index is larger than the amount of nodes in the collection.
|
||||
*/
|
||||
std::string GetNodeNameByIndex(size_t nIndex) const;
|
||||
|
||||
/**
|
||||
* @brief Insert a value node before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since values are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
|
||||
* Otherwise the name must be unique within this collection.
|
||||
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
|
||||
* @return Returns the node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNode InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue);
|
||||
CNode InsertValue(const std::string& rssInsertBefore, const std::string& rssName, const sdv::any_t& ranyValue);
|
||||
|
||||
/**
|
||||
* @brief Add a value node to the collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] ranyValue The value to assign to the node. The value also determines the type of value node.
|
||||
@@ -254,20 +280,18 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert an array collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Since arrays are presented as inline node, they
|
||||
* will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new value node. If this collection is an array, the name is ignored.
|
||||
* Otherwise the name must be unique within this collection.
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNodeCollection InsertArray(size_t nIndex, const std::string& rssName);
|
||||
CNodeCollection InsertArray(const std::string& rssInsertBefore, const std::string& rssName);
|
||||
|
||||
/**
|
||||
* @brief Add an array collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new array collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @return Returns the collection node when successfully added or an empty node when not.
|
||||
@@ -276,22 +300,20 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert a table collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Tables can be inserted as inline node, in which
|
||||
* case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
* as inline collection if the this collection is also inline, as standard when not.
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not.
|
||||
*/
|
||||
CNodeCollection InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
|
||||
CNodeCollection InsertTable(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
|
||||
|
||||
/**
|
||||
* @brief Add a table collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] rssName Reference to the name of the new table collection node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
@@ -302,12 +324,12 @@ namespace sdv::toml
|
||||
|
||||
/**
|
||||
* @brief Insert a table array collection before the provided position.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
|
||||
* if not existing already, and adding a table to the array.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Table arrays can be inserted as inline node, in
|
||||
* which case they will be inserted before any standard node (table or table array if defined as standard node).
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
|
||||
* ignored. Otherwise the name must be unique within this collection.
|
||||
* @param[in] bFavorInline When set, the node will be added as inline collection node. When not, the node will be inserted
|
||||
@@ -315,12 +337,10 @@ namespace sdv::toml
|
||||
* @return Returns the collection node when successfully inserted or an empty node when not. The collection node represents
|
||||
* a table collection.
|
||||
*/
|
||||
CNodeCollection InsertTableArray(size_t nIndex, const std::string& rssName, bool bFavorInline = false);
|
||||
CNodeCollection InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName, bool bFavorInline = false);
|
||||
|
||||
/**
|
||||
* @brief Add a table array collection to this collection.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @remarks A table array is an array with table inside. Inserting a table array node can also be done by creating an array,
|
||||
* if not existing already, and adding a table to the array.
|
||||
* @param[in] rssName Reference to the name of the new table array node. If this collection is an array, the name is
|
||||
@@ -335,10 +355,10 @@ namespace sdv::toml
|
||||
/**
|
||||
* @brief Insert a TOML string to the collection. All nodes specified in the TOML will be added in the collection except
|
||||
* when the nodes already exist. Comment and whitespace are preserved when possible.
|
||||
* @remarks The actual position depends on the type of node and the order the nodes are stored. Inline nodes come before
|
||||
* standard nodes.
|
||||
* @param[in] nIndex The index before which to insert the node. Can be larger than the count value as well as
|
||||
* sdv::toml::npos when adding the node at the end.
|
||||
* @remarks In TOML, inline nodes are located before standard nodes. Dependable on the nodes defined in the TOML they
|
||||
* might be transferred to inline or they might be inserted at a different location.
|
||||
* @param[in] rssInsertBefore Name of the node to insert the value before. In case of an array, can be an index between
|
||||
* square brackets. Can be empty, causing the node to be inserted at the end.
|
||||
* @param[in] rssTOML Reference to the TOML string containing the nodes. The TOML string can be empty, which is not an
|
||||
* error. If required the TOML nodes are converted to inline nodes.
|
||||
* @param[in] bAllowPartial When set, duplicate nodes (already present in this collection) will be ignored and do not
|
||||
@@ -346,7 +366,7 @@ namespace sdv::toml
|
||||
* @return Returns 1 if the complete TOMl could be inserted, 0 if no TOML could be inserted or -1 when the TOML could be
|
||||
* partially inserted.
|
||||
*/
|
||||
int InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial = false);
|
||||
int InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML, bool bAllowPartial = false);
|
||||
|
||||
/**
|
||||
* @brief Add a TOML string to this collection. All nodes specified in the TOML will be added in the collection except
|
||||
@@ -372,16 +392,11 @@ namespace sdv::toml
|
||||
class CTOMLParser : public CNodeCollection
|
||||
{
|
||||
public:
|
||||
/**
|
||||
* @brief Default constructor.
|
||||
*/
|
||||
CTOMLParser() = default;
|
||||
|
||||
/**
|
||||
* @brief Constructor providing automatic processing.
|
||||
* @param[in] rssConfig Reference to the configuration.
|
||||
*/
|
||||
CTOMLParser(const std::string& rssConfig);
|
||||
CTOMLParser(const std::string& rssConfig = "");
|
||||
|
||||
/**
|
||||
* @brief Process a configuration. This will clear any previous configuration.
|
||||
@@ -414,6 +429,52 @@ namespace sdv::toml
|
||||
ITOMLParser* m_pParser = nullptr; ///< Pointer to the parser interface.
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare flags
|
||||
*/
|
||||
enum class ECompareFlags : uint32_t
|
||||
{
|
||||
compare_ignore_whitespace = 1, ///< Compare, but ignore whitespace
|
||||
compare_ignore_comments = 2, ///< Compare, but ignore comments
|
||||
compare_ignore_inline = 8, ///< Compare, but ignore inline or explicit
|
||||
compare_ignore_all = 255, ///< Compare with all ignore flags
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Compare result
|
||||
*/
|
||||
enum class ECompareResult : int32_t
|
||||
{
|
||||
compare_identical = 0, ///< The comparison resulted into identical TOML strings
|
||||
compare_different = 1, ///< The comparison resulted into different TOML strings
|
||||
compare_error = -1 ///< The comparison could not be done due to a failure
|
||||
};
|
||||
|
||||
/// Internal namespace
|
||||
namespace internal
|
||||
{
|
||||
/**
|
||||
* @brief Compare the content of the node with the content of another node.
|
||||
* @attention This function changes the nodes dependable on the provided flags.
|
||||
* @param[in] rnode1 First node interface to compare with the second node.
|
||||
* @param[in] rnode2 Second node interface to compare with the first node.
|
||||
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
|
||||
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
|
||||
} // namespace internal;
|
||||
|
||||
/**
|
||||
* @brief Compare the content of TOML string with the content of another TOML string.
|
||||
* @param[in] rssToml1 Reference to the first TOML string to compare with the second TOML string.
|
||||
* @param[in] rssToml2 Reference to the second TOML string to compare with the first TOML string.
|
||||
* @param[in] uiCompareFlags Zero or more flags from ECompareFlags.
|
||||
* @return The comparison result.
|
||||
*/
|
||||
ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
|
||||
uint32_t uiCompareFlags = static_cast<uint32_t>(ECompareFlags::compare_ignore_all));
|
||||
|
||||
inline CNode::CNode(const TInterfaceAccessPtr& rptrNode)
|
||||
{
|
||||
m_pNodeInfo = rptrNode.GetInterface<INodeInfo>();
|
||||
@@ -461,6 +522,16 @@ namespace sdv::toml
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetType() : ENodeType::node_invalid;
|
||||
}
|
||||
|
||||
inline uint32_t CNode::GetIndex() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetIndex() : npos;
|
||||
}
|
||||
|
||||
inline bool CNode::IsInline() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->IsInline() : true;
|
||||
}
|
||||
|
||||
inline std::string CNode::GetComment() const
|
||||
{
|
||||
if (!m_pNodeInfo) return {};
|
||||
@@ -527,7 +598,9 @@ namespace sdv::toml
|
||||
{
|
||||
INodeUpdate* pNodeUpdate = m_ptrNode.GetInterface<INodeUpdate>();
|
||||
if (!pNodeUpdate) return false;
|
||||
return pNodeUpdate->DeleteNode();
|
||||
bool bRet = pNodeUpdate->DeleteNode();
|
||||
Clear(); // Not valid any more.
|
||||
return bRet;
|
||||
}
|
||||
|
||||
inline void CNode::Clear()
|
||||
@@ -536,6 +609,11 @@ namespace sdv::toml
|
||||
m_pNodeInfo = nullptr;
|
||||
}
|
||||
|
||||
inline void CNode::AutomaticFormat(bool bRemoveComments)
|
||||
{
|
||||
if (m_pNodeInfo) m_pNodeInfo->AutomaticFormat(bRemoveComments);
|
||||
}
|
||||
|
||||
inline sdv::u8string CNode::GetTOML() const
|
||||
{
|
||||
return m_pNodeInfo ? m_pNodeInfo->GetTOML() : sdv::u8string();
|
||||
@@ -605,76 +683,86 @@ namespace sdv::toml
|
||||
return m_pCollection ? CNode(m_pCollection->GetNodeDirect(rssNode)) : CNode();
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::InsertValue(size_t nIndex, const std::string& rssName, const sdv::any_t& ranyValue)
|
||||
inline std::string CNodeCollection::GetNodeNameByIndex(size_t nIndex) const
|
||||
{
|
||||
if (!m_pCollection) return {};
|
||||
if (nIndex >= m_pCollection->GetCount()) return {};
|
||||
if (GetType() == ENodeType::node_array) return "[" + std::to_string(nIndex) + "]";
|
||||
TInterfaceAccessPtr ptrNode = m_pCollection->GetNode(static_cast<uint32_t>(nIndex));
|
||||
const auto* pAccess = ptrNode.GetInterface<INodeInfo>();
|
||||
if (!pAccess) return {};
|
||||
return pAccess->GetName();
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::InsertValue(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
const sdv::any_t& ranyValue)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNode(pInsert->InsertValue(static_cast<uint32_t>(nIndex), rssName, ranyValue));
|
||||
return CNode(pInsert->InsertValue(rssInsertBefore, rssName, ranyValue));
|
||||
}
|
||||
|
||||
inline CNode CNodeCollection::AddValue(const std::string& rssName, const sdv::any_t& ranyValue)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNode(pInsert->InsertValue(npos, rssName, ranyValue));
|
||||
return CNode(pInsert->InsertValue("", rssName, ranyValue));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertArray(size_t nIndex, const std::string& rssName)
|
||||
inline CNodeCollection CNodeCollection::InsertArray(const std::string& rssInsertBefore, const std::string& rssName)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertArray(static_cast<uint32_t>(nIndex), rssName));
|
||||
return CNodeCollection(pInsert->InsertArray(rssInsertBefore, rssName));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddArray(const std::string& rssName)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertArray(npos, rssName));
|
||||
return CNodeCollection(pInsert->InsertArray("", rssName));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertTable(size_t nIndex, const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
inline CNodeCollection CNodeCollection::InsertTable(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTable(static_cast<uint32_t>(nIndex), rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTable(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddTable(const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTable(npos, rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTable("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::InsertTableArray(size_t nIndex, const std::string& rssName,
|
||||
inline CNodeCollection CNodeCollection::InsertTableArray(const std::string& rssInsertBefore, const std::string& rssName,
|
||||
bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTableArray(static_cast<uint32_t>(nIndex), rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTableArray(rssInsertBefore, rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline CNodeCollection CNodeCollection::AddTableArray(const std::string& rssName, bool bFavorInline /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return {};
|
||||
return CNodeCollection(pInsert->InsertTableArray(npos, rssName,
|
||||
bFavorInline ? INodeCollectionInsert::EInsertPreference::prefer_inline :
|
||||
INodeCollectionInsert::EInsertPreference::prefer_standard));
|
||||
return CNodeCollection(pInsert->InsertTableArray("", rssName, bFavorInline ? EInsertPreference::prefer_inline :
|
||||
EInsertPreference::prefer_standard));
|
||||
}
|
||||
|
||||
inline int CNodeCollection::InsertTOML(size_t nIndex, const std::string& rssTOML, bool bAllowPartial /*= false*/)
|
||||
inline int CNodeCollection::InsertTOML(const std::string& rssInsertBefore, const std::string& rssTOML,
|
||||
bool bAllowPartial /*= false*/)
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return 0;
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(static_cast<uint32_t>(nIndex), rssTOML, !bAllowPartial);
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(rssInsertBefore, rssTOML, !bAllowPartial);
|
||||
switch (eRet)
|
||||
{
|
||||
case INodeCollectionInsert::EInsertResult::insert_success:
|
||||
@@ -691,7 +779,7 @@ namespace sdv::toml
|
||||
{
|
||||
INodeCollectionInsert* pInsert = m_ptrNode.GetInterface<INodeCollectionInsert>();
|
||||
if (!pInsert) return 0;
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML(npos, rssTOML, !bAllowPartial);
|
||||
INodeCollectionInsert::EInsertResult eRet = pInsert->InsertTOML("", rssTOML, !bAllowPartial);
|
||||
switch (eRet)
|
||||
{
|
||||
case INodeCollectionInsert::EInsertResult::insert_success:
|
||||
@@ -746,6 +834,59 @@ namespace sdv::toml
|
||||
m_ptrParserUtil.Clear();
|
||||
}
|
||||
|
||||
namespace internal
|
||||
{
|
||||
inline ECompareResult CompareNodes(CNode& rnode1, CNode& rnode2,
|
||||
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
|
||||
{
|
||||
if (!rnode1 || !rnode2) return ECompareResult::compare_error;
|
||||
|
||||
// Format the nodes when ignore whitespace and/or comments
|
||||
bool bIgnoreComments = uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_comments);
|
||||
bool bIgnoreWhitespace = bIgnoreComments ||
|
||||
(uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_whitespace));
|
||||
if (bIgnoreWhitespace)
|
||||
{
|
||||
INodeInfo* pNodeInfo1 = rnode1.GetInterface().GetInterface<INodeInfo>();
|
||||
if (!pNodeInfo1) return ECompareResult::compare_error;
|
||||
pNodeInfo1->AutomaticFormat(bIgnoreComments);
|
||||
INodeInfo* pNodeInfo2 = rnode2.GetInterface().GetInterface<INodeInfo>();
|
||||
if (!pNodeInfo2) return ECompareResult::compare_error;
|
||||
pNodeInfo2->AutomaticFormat(bIgnoreComments);
|
||||
}
|
||||
|
||||
// Convert to standard if ignoring inline
|
||||
INodeCollectionConvert* pConvert1 = rnode1.GetInterface().GetInterface<INodeCollectionConvert>();
|
||||
INodeCollectionConvert* pConvert2 = rnode2.GetInterface().GetInterface<INodeCollectionConvert>();
|
||||
if (pConvert1 && pConvert2 && uiCompareFlags & static_cast<uint32_t>(ECompareFlags::compare_ignore_inline))
|
||||
{
|
||||
// Making inline nodes as standard, might only change the upper node.
|
||||
// Making standard nodes inline, will have all child nodes be made inline as well, because inline nodes can only
|
||||
// have inline nodes.
|
||||
pConvert1->MakeInline();
|
||||
pConvert2->MakeInline();
|
||||
}
|
||||
|
||||
// Generate the TOMLs and compare
|
||||
return rnode1.GetTOML() == rnode2.GetTOML() ? ECompareResult::compare_identical : ECompareResult::compare_different;
|
||||
}
|
||||
} // namespace internal
|
||||
|
||||
inline ECompareResult Compare(const std::string& rssToml1, const std::string& rssToml2,
|
||||
uint32_t uiCompareFlags /*= static_cast<uint32_t>(ECompareFlags::compare_ignore_all)*/)
|
||||
{
|
||||
try
|
||||
{
|
||||
CTOMLParser parser1(rssToml1);
|
||||
CTOMLParser parser2(rssToml2);
|
||||
return internal::CompareNodes(parser1, parser2, uiCompareFlags);
|
||||
}
|
||||
catch (const sdv::toml::XTOMLParseException&)
|
||||
{
|
||||
return ECompareResult::compare_error;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
#endif // !defined SDV_CONFIG_H
|
||||
#endif // !defined SDV_TOML_H
|
||||
Reference in New Issue
Block a user