Config
The config library supports Apps to store configuration options in a config database table. To access the config options
from within a JavaScript App, the C++ config library communicates with the JavaScript config library using JSON messages. See the
JS config library documentation for more informations.
The usage of the config library is straight forward and only needs a couple of steps:
- Create instance of ConfigContext.
- Register the config library to the JSON API framework by passing the created instance to RegisterJsonApi(configContextInstance).
- Create the database table used by the config lib by calling CreateInitTask(databaseObject) and exetuting the returned task (don't forget to free it,
after the task is finished).
- Add ConfigItem members to your class and initialize them passing the ConfigContext instance (see the description of the ConfigItems classes
below).
Now the appliction service and the JavaScript app only need to access the items or changed and save them (especially from the JavaScript side). ConfigContext and
the JavaScript config library are handling all of the communication, so there is no need for an app to worry about that.
File information
Classes
ConfigContext
class ConfigContext : public UTask, public UJsonApiContext, public UConfigContextApi {
protected:
virtual void ConfigChanged() {}
virtual void ConfigChangedUnmanaged() {}
virtual bool CanReadConfig(IJsonApiConnection * const connection) { return true; }
virtual bool CanWriteConfig(IJsonApiConnection * const connection) { return true; }
class ITask * UpdateUnmanagedItems();
class ITask * UpdateManagedItems();
public:
ConfigContext(class IDatabase * database, class IInstanceLog * log);
virtual ~ConfigContext();
bool SwitchToFileMode(class IIoMux * iomux, const char * absoluteFileName, bool initFromDatabase = false);
void SwitchToDatabaseMode();
class ITask * CreateInitTask(class IDatabase * database = nullptr, bool readOnly = false);
void ResetChangedFlag();
class ITask * WriteItemValue(ConfigItem * item, const char * value, bool notify);
};
Overview
The ConfigContext is the base class of the config library. It handles the communication with the database as well as with the
JSON API framework. An application only needs to create an instance of ConfigContext and initialize it. To initialize, the
instance must be passed to to RegisterJsonApi() of an existing JsonApiContext instance and the database must be initialized by
executing the task returned by CreateInitTask(). Even if not necessary it is recommended to create a subclass of ConfigContext
to store the config items into that subclass, too. This makes handling and initializing the config items easier as well as get
informed after changes made for the config items.
The ConfigContext stores the configuration inside the database accassable through the given database connection. When initializing running
the task to do so, a table called config will be created with three rows:
- name The name of the config item with a maximum length of 255 chars.
- value The vlaue of the config item. Each item is stored as string with an (in theory) unlimited length. But be aware that each item will stay resident in RAM,
so take care to not hold values to big.
- unmanaged A boolean value to describe if the item is unmanaged or not.
Note that only items will be written to the database, that have a different value than given as the default value. Even if an item had ben changed and set back to
the default value, it is no longer written to the database.
Each config item will be registered to a ConfigContext instance and managed by that instance. That also means that each config item must have a unique name. See the description
of ConfigItem classes below for more details.
Protected functions
ConfigChanged
Will be called after the value of a config item had been changed. Create a class derived from ConfigContext to catch that callback.
ConfigChangedUnmanaged
Will be called after the value of an unmanaged config item had been changed. An unmanaged config item can only be accessed by the C++ side of the library,
but not by the JSON API. So on the JSON API side, that item is read-only. Create a class derived from ConfigContext to catch that callback.
CanReadConfig
Will be called to check, if a given IJsonApiConnection instance has the right to read the config. Create a class derived from ConfigContext and overwrite
the function to add rights management for reading the config.
Parameters
class IJsonApiConnection * const connection | The IJsonApiConnection instance to be checked for the right to read the config. |
Return value
True, if the given connection has the right to read the config. So if true is returned, ConfigContext will send config informations to the connection that asks for them.
False, to deny the access to the config. The default implementation of ConfigContext::CanReadConfig() always returns true.
CanWriteConfig
Will be called to check, if a given IJsonApiConnection instance has the right to write the config. Create a class derived from ConfigContext and overwrite
the function to add rights management for writing the config.
Parameters
class IJsonApiConnection * const connection | The IJsonApiConnection instance to be checked for the right to write the config. |
Return value
True, if the given connection has the right to write the config. So if true is returned, ConfigContext will accept changed config values send via JSON API messages and write
them to the database. False, to deny the access to the config. The default implementation of ConfigContext::CanWriteConfig() always returns true.
Public functions
ConfigContext (Constructor)
The constructor of the class.
Parameters
class IDatabase * database | The IDatabase instance to be used by the config context. |
class IInstanceLog * const log | The IInstanceLog instance used for loging purposes. |
SwitchToFileMode
In standard mode the config library writes values to the database config table. After calling this function, changes are written to a file instead.
The task created with CreateInitTask will also read from this config file and not from the database anymore.
Parameters
class IIoMux * iomux | The IIoMux instance to be used. |
const char * absoluteFileName | The absolute path and filename in which the config will be stored. |
bool initFromDatabase | (Default: false) Set true if the config file shall be created at once and initialized with the current database values. |
Return value
True if the file can be created and written. Otherwise false.
SwitchToDatabaseMode
Switches back to database mode. If you want the current values to be written into the database, you must use UpdateManagedItems and/or UpdateUnmanagedItems.
Parameters
Return value
CreateInitTask
Creates an instance of the task to initialize the database table used by the config context.
Parameters
class IDatabase * database | (Default: nullptr) The IDatabase instance to be used.
If nullptr, the instance passed to the constructor will be used. |
bool readOnly | (Default: false) Set true if the config table is read only (in standby scenarios). |
Return value
The task that must be executed to initialize the config table. Simply call Start(class UTask * user) of that task, passing a user of your choice to that function. Make sure to provide a user parameter. The function Start() without any parameter should not be used.
Remarks
Note that the created ITask instance returned by CreateInitTask() must be freed after the task has finished or failed. If not, the application will
create memory leaks.
ResetChangedFlag
This will reset the changed flag of all items. After calling that, Changed() of each ConfigItem registered to ConfigContext will return false. It will be a good
Idea to call that function in ConfigChanged() and / or ConfigChangedUnmanaged() after handling all changes.
WriteItemValue
Call this function to write a config item to the database. Generally this will be done when items had been changed through the JSON API. But in case of unmanaged
items, this function is the only way to save them.
Parameters
ConfigItem * item | The config item to write to the database. |
const char * value | The value to write. |
bool notify | If true, a changed notification will be send to all open JsonApoContext instances. |
ConfigItem
class ConfigItem : public istd::listElement {
private:
char * name;
protected:
friend class TaskWriteConfig;
friend class TaskWriteConfigUnmanaged;
friend class TaskInitConfig;
friend class ConfigContext;
class IInstanceLog * const log;
bool changed;
bool unmanaged;
virtual void ReadValueFromDataset(class IDataSet * dataset) = 0;
virtual void ReadValueFromJSON(class json_io * json, dword base, class IJsonApiConnection * connection) = 0;
virtual void WriteValueToJSON(class json_io * json, dword base, char * & convBuf, class IJsonApiConnection * connection) = 0;
virtual int WriteValueToString(char * dest) = 0;
virtual void SetWriteValue(const char * value) = 0;
virtual void WriteItemTypeToJSON(class json_io * json, dword base, char * & convBuf) = 0;
public:
ConfigItem(ConfigContext * context, const char * name, bool unmanaged);
virtual ~ConfigItem();
const char * GetName() const { return this->name; }
bool Changed() const { return this->changed; }
virtual bool HasDefaultValue() = 0;
virtual void Reset() = 0;
};
Overview
This is the base class for each config item. Generally there is no need to create an own config item, because the config library provides config items
for the most use cases. But if there is need, an own config item must be derived from ConfigItem. Also, because of the internals, ConfigContext must
be a friend class for the new config item as well (the other classes don't need to, that's only used internally for the ConfigItem base class).
If an app whants to create an own config item class, it needs to provide one of the default data types to ConfigContext anyway. If not, the result of
handling that item on the JSON API side is undefined. Types supported by the ConfigContext are:
- 32bit integers (singed and unsigned)
- 64bit integers (singed and unsigned - but take care with 64bit integers because of the not-that-good support of them on JavaScript).
- bool.
- string (with unlimited length).
- password (which is a string with a flag given on initialization to define it as password. Passwords can only be received from the JSON API
and only in an encrypted way. ConfigContext will not send passwords. Instead an empty string for that items will be send).
- choice (which is a combination of an integer as index and a array with available choices).
Remarks
Don't use ConfigItem direktly (however, because of the pure virutal functions the compiler don't let you do so). Use one of the pre defined ConfigItem
subclasses (as described below) or implement your own to map the data type of your choice the one of the base data types using a subclass of ConfigItem.
When creating a subclass, each functions (except GetName() and Changed()) must be implemented by the subclass!
Protected variables
bool changed
Must be set from within the ReadValue* functions to show whether the value of the item had been changed or not.
bool unmanaged
Defines whether the item is unmanaged or not. An unmanaged item cannot be accessed through the JSON API. It is recommended to not touch this
value in an subclass and only set it using the constructor of ConfigItem.
Protected functions
ReadValueFromDataset
Will be called during loading the data from the database. An derived class should get the value from the "value" field of the dataset (by calling the
datasets functions to get a value by field name, see IDataSet for details) and stores that to an
internal variable in whatever datatype needed. Don't make a copy of the dataset pointer, because it will be released after all data had ben read from
the database. There is no need to control the items name inside the dataset, because ConfigContext will determine the config item the current row in dataset
is for by the config item name of that row.
Parameters
class IDataSet * dataset | The dataset instance holding the row responsible for the item. |
Remarks
Never ever delete the given dataset, store the pointer for later use or call Next() or FetchNextRow() of the dataset instance, or everything will be
screwed up!
ReadValueFromJSON
Will be called during parsing a JSON received from the JSON API. The function need to get the value (depending on the type, see the JSON message description below)
and store it into an internal variable. If the value differes from the previous value, the function must set the changed flag to true.
A subclass of ConfigItem read the value of the datatype needed from the given json_io instance. It must check, if there is data for that item not not get undefined
behaviour. The name for the field is the same as the one for the config value. Only choice type config items are a little bit different. See the JSON describtion below.
Parameters
class json_io * json | The json_io instance to read the config item value from. |
dword base | The base id inside the json to start reading the config item data. |
class IJsonApiConnection * const connection | The IJsonApiConnection instance that sent the data to write. |
WriteValueToJSON
When an JasonApiContext requests the configuration of an application through the JSON API, ConfigContext will call WriteValueToJSON for each config item.
The function need to write their value to the given json_io instance by calling the propriate function for the value to write. The value should be written
using the name of the config item as name for the JSON item to write which get be done using the GetName() function of ConfigItem
(e. g. json->add_usnigned(base, this->GetName(), this->value, convBuf)). Config item that are type of choice item need also to store the choices to them.
See the JSON message description below.
Parameters
class json_io * json | The json_io instance to write the config item value to. |
dword base | The base id inside the json to start writing the config item data. |
char * & convBuf | A pointer to a buffer used by json_io to convert numbers to strings. You only need it if
number values need to be written to the json_io instance. |
class IJsonApiConnection * const connection | The IJsonApiConnection instance that requested the config. |
WriteValueToString
When writing the value to the database, ConfigContext needs it as string (because the values from the config items are stored as strings only to the database).
So for each config item this function will be called so that the function can convert the value to write it into the given buffer (or copy it, if the value of
the item is already in string format).
Parameters
char * dest | The destination buffer to write the value to as string. Dest can also be nullptr. In that case, the function
only should return the length of the string that will be written to the buffer if given in dest. |
Return value
The function must return the length of the string put to dest, also if dest nullptr.
WriteItemTypeToJSON
The JavaScript config library requests all config items registeres to ConfigContext and needs to now what type there are. For this, ConfigContext calls WriteItemTypeToJSON.
A ConfigItem subclass needs the following fields to the given json_io instance:
- name The name of the config item. You can use ConfigItem::GetName() for this.
- type The type of the config item wich must be one of the items listed below.
- password This field must only be added (and then be added with the value true), if the item holds a string password value.
- minVal (For integer types only) The minumum value the item can have.
- maxVal (For integer types only) The maximum value the item can have.
Type need to be one of the followin value (the names of defines for that type is given in brackets):
- BOOL The item is a BOOl type (CFG_TYPE_BOOL)
- INT The item is a signed 32bit integer type (CFG_TYPE_INT)
- DWORD The item is an unsigned 32bit integer type (CFG_TYPE_DWORD)
- LONG64 The item is a signed 64bit integer type (CFG_TYPE_LONG64)
- ULONG64 The item is an unsigned 64bit integer type (CFG_TYPE_ULONG64)
- STRING The item is a string type (CFG_TYPE_STRING)
- CHOICE The item is a choice type (CFG_TYPE_CHOICE)
Parameters
class json_io * json | The json_io instance to write the config item type information. |
dword base | The base id inside the json to start writing the config item type information. |
char * & convBuf | A pointer to a buffer used by json_io to convert numbers to strings. You only need it if
number values need to be written to the json_io instance. |
Public functions
ConfigItem (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
bool unmanaged | If set to true, the item is unmanaged and with this not accassable through the JSON API. |
GetName
Return value
Returns the name of the config item as passed to the constructor.
Changed
Return value
Returns ture, if the item had been changed the last time the config items had been saved using the JSON API. The only good place to call that function
will be within ConfigContext::ConfigChanged() and ConfigContext::ConfigChangedUnmanaged() to figure out, wich item actually had been changed and maybe
nead to lead to additional updates inside the application.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Remarks
ConfigItem itself doesn't have handlig of default value, so it need to be implemented from a subclass.
Reset
Resets the config item and set the value to the default value. Must be implemented by a subclass.
ConfigChoice
class ConfigChoice : public ConfigItem {
public:
ConfigChoice(ConfigContext * context, const char * name, size_t defVal, const char ** options, bool unmanaged = false);
virtual ~ConfigChoice();
int ValueIdx() const { return this->valueIdx; }
const char * Value() const { return (this->valueIdx < this->optionsCount ? this->choiceValues[this->valueIdx] : nullptr); }
void SetValue(const char * option);
void SetValueIdx(size_t valudIdx);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item is for providing a couple of available options and selecting one of them (that can be used e. g. for setting the language for an UI). The choice
options will be passes as an array of string (terminated by a nullptr entry), while the choice itself represents the index inside that array. However, ConfigChoice
will write the choice itself to the database instead of the index. So if there need to localize the options, the application needs to provide some kind of mapping.
Using the options in a way to show them directly inside a UI is not the best idea.
Public functions
ConfigChoice (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
size_t defVal | The index of the default value inside the given options array. |
const char ** options | The options proivided by an array of char pointers terminated by a nullptr entry. ConfigOptions
won't copy that array, so it should be guaranteed that this array exists over the lifetime of the
COnfigOptions instance. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
ValueIdx
Return value
Returns the index of the currently selected option.
Value
Return value
Returns the value of the current selected options. This will be the same as options[ConfigItem::ValuedIdx()].
Remarks
If the current value index is out of range of the options array, nullptr will be returned.
SetValue
Set the current value of ConfigItem by passing a string that also is inside the options array. Calling this function will internally set the
value index to the correct value. If the given option cannot be found, the internal value index will be set to 0.
Parameters
const char * option | The option to set. Must be inside the options array passed to the constructor of ConfigChoice. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
You also should take care the case of the given string, because SetValue() will make a case sensitive compare to each string inside the options array.
SetValueIdx
Will set the internal index to the given value. If the given value is out of range, the internal index will set to 0.
Parameters
size_t valueIdx | The new index to set. |
Remarks
SetValueIdx() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigBool
class ConfigBool : public ConfigItem {
public:
ConfigBool(ConfigContext * context, const char * name, bool defVal, bool unmanaged = false);
virtual ~ConfigBool();
bool Value() const { return this->value; }
void SetValue(bool value);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item will store a simple boolean value.
Public functions
ConfigBool (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
bool defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
Value
Return value
Returns the current value of the config item.
SetValue
Set the value of the config item to the given one.
Parameters
bool value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigInt
class ConfigInt: public ConfigItem {
public:
ConfigInt(ConfigContext * context, const char * name, int defVal, bool unmanaged = false, int minVal = INT32_MIN, int maxVal = INT32_MAX);
virtual ~ConfigInt();
int Value() const { return this->value; }
void SetValue(int value);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item will store a 32bit singed integer.
Public functions
ConfigInt (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
int defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
int minVal | (Default: INT32_MIN) The minimum value that can be set to that item. |
int maxVal | (Default: INT32_MAX) The maximum value that can be set to that item. |
Value
Return value
Returns the current value of the config item.
SetValue
Set the value of the config item to the given one.
Parameters
int value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
If the value passed to SetValue() is less than minVal (given to the constructor), the internal value will be set to minVal. If it is greater than
maxVal, the internal value will be set to maxVal.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigDword
class ConfigDword : public ConfigItem {
public:
ConfigDword(ConfigContext * context, const char * name, dword defVal, bool unmanaged = false, dword minVal = 0, dword maxVal = UINT32_MAX);
virtual ~ConfigDword();
dword Value() const { return this->value; }
void SetValue(dword value);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item will store a 32bit unsinged integer.
Public functions
ConfigDword (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
dword defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
dword minVal | (Default: 0) The minimum value that can be set to that item. |
dword maxVal | (Default: UINT32_MAX) The maximum value that can be set to that item. |
Value
Return value
Returns the current value of the config item.
SetValue
Set the value of the config item to the given one.
Parameters
dword value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
If the value passed to SetValue() is less than minVal (given to the constructor), the internal value will be set to minVal. If it is greater than
maxVal, the internal value will be set to maxVal.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigLong64
class ConfigLong64 : public ConfigItem {
public:
ConfigLong64(ConfigContext * context, const char * name, long64 defVal, bool unmanaged = false, long64 minVal = INT64_MIN, long64 maxVal = INT64_MAX);
virtual ~ConfigLong64();
long64 Value() const { return this->value; }
void SetValue(long64 value);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item will store a 64bit singed integer.
Public functions
ConfigLong64 (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
long64 defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
long64 minVal | (Default: INT64_MIN) The minimum value that can be set to that item. |
long64 maxVal | (Default: INT64_MAX) The maximum value that can be set to that item. |
Value
Return value
Returns the current value of the config item.
SetValue
Set the value of the config item to the given one.
Parameters
long64 value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
If the value passed to SetValue() is less than minVal (given to the constructor), the internal value will be set to minVal. If it is greater than
maxVal, the internal value will be set to maxVal.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigUlong64
class ConfigUlong64 : public ConfigItem {
public:
ConfigUlong64(ConfigContext * context, const char * name, ulong64 defVal, bool unmanaged = false, ulong64 minVal = 0, ulong64 maxVal = UINT64_MAX);
virtual ~ConfigUlong64();
ulong64 Value() const { return this->value; }
void SetValue(ulong64 value);
bool HasDefaultValue() override;
void Reset() override;
};
Overview
This config item will store a 64bit singed integer.
Public functions
ConfigUlong64 (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
ulong64 defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
ulong64 minVal | (Default: 0) The minimum value that can be set to that item. |
ulong64 maxVal | (Default: UINT64_MAX) The maximum value that can be set to that item. |
Value
Return value
Returns the current value of the config item.
SetValue
Set the value of the config item to the given one.
Parameters
ulong64 value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
If the value passed to SetValue() is less than minVal (given to the constructor), the internal value will be set to minVal. If it is greater than
maxVal, the internal value will be set to maxVal.
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
ConfigString
class ConfigString : public ConfigItem {
public:
ConfigString(ConfigContext * context, const char * name, const char * defVal, bool unmanaged = false, bool isPassword = false);
virtual ~ConfigString();
const char * Value() const { return this->value; }
void SetValue(const char * value);
bool HasDefaultValue() override;
void Reset() override;
static void Encrypt(const char * seed, const char * password, char * out, size_t len);
static void Decrypt(const char * seed, const char * password, char * out, size_t len);
};
Overview
This config item will store string value. That also can be a password (of isPassword of the constructor is set to true). In that case, an empty string
instead of the password itself will be send to a JsonApiContext. When setting a new value for that item using the JSON API, the password must be encrypted.
See the JSON messages description below for more details. Gladly, the encryption and decryption part is handled inside the JavaScript config library as
well as inside the C++ library.
Remarks
Note that even passwords must be send by a JsonApiContext in an encrypted format, the password itself will be saved unencrypted to the database. This
is not a big problem, because the database of an application can only be accassed after passing the login-procedure on the JavaScript side. On the linux
(C++) side, the access to the database is also protected by username and password. However, an app is free to encrypt the password itself before sending
it to ConfigContext (or setting it using SetValue() for unmanaged items), which will end up in an encrpyted password inside the databse. In that case,
the app also must decrypt the password when needed.
Public functions
ConfigString (Constructor)
The constructor of the class.
Parameters
ConfigContext * context | The ConfigContext instance the item itself will reigster to it. |
char * name | The name of the config item. Must be unique withing the given ConfigContext. |
char * defVal | The default value for the item. |
bool unmanaged | (Default false) If set to true, the item is unmanaged and with this not accassable through the JSON API. |
bool isPassword | (Default false) If set to true, the item is handled as password string and will not be send to a JsonApiContext. |
Remarks
Note that ConfigString won't make a copy of the default value given in devVal. It will only store the pointer. So an application must guarantee, that the string
passed to the constructor will exist and also not be changed over the lifetime of a ConfigString object.
Value
Return value
Returns the current value of the config item.
Remarks
If the item is defined as password, Value() will return that password in plain text.
SetValue
Set the value of the config item to the given one.
Parameters
ulong64 value | The new value to set. |
Remarks
SetValue() can only be called for items with unmanaged flag set to true. Everything else will lead to an assertion.
Note that this won't affect the internal changed flag.
If the item is defined as password, the password must be set unencrypted here (or Value() will return it encrypted, too).
HasDefaultValue
Return value
Returns true, if the current value of the item equals the default value given on creation, else false.
Reset
Resets the config item and set the value to the default value.
Encrypt
Encrypts a password with a seed and writes the result to an output buffer. The encrypted password can be decrypted with the same seed again.
Parameters
const char * seed | A seed to use. |
const char * password | The clear text password. |
char * out | Output buffer. The buffer should have a size of strlen(password) * 2 + 1. |
size_t len | The length of the output buffer. |
Decrypt
Decrypts a password with a seed and writes the result to an output buffer.
Parameters
const char * seed | A seed to use. |
const char * password | The encrypted password. |
char * out | Output buffer. The buffer should have a size of strlen(password) / 2 + 1. |
size_t len | The length of the output buffer. |
JSON Messages
Overview
Below is the description of the JSON messages the ConfigContext shares with the JavaScript config library. Note that some of the fields are optional end depend on the value
of other fields. You are free to implement your only config javascript library, but note that this messages only will be accepted after sucessfully logging into an appservice
using the AppWebsocket javascript library. See JavaScript config library for details.
The Config protocol supports the AppWebsocket "src" mechanism.
Base message
{
"api": "Config",
"src": string,
"mt": "ConfigMessage"
}
All messages send from and to ConfigContext always have the same header. The property api defines the message as part of the configuration API of the SDK, mt defines the message
itself and will be one of the following values:
Send to ConfigContext
Send from ConfigContext
GetConfigItems
{
"api": "Config",
"mt": "GetConfigItems"
}
Overview
Before reading the current config, the list of available config items should be requested first. This will be done by the GetConfigItems message, which will lead to a
GetConfigItemsResult with the list of config items and details to them.
GetConfigItemsResult
{
"api": "Config",
"mt": "GetConfigItems",
"result": "AccessDenied",
"ConfigItems": [ConfigItemObject]
}
Overview
This will be the answer for a GetConfigItems message. Beside the message base, there will be another property which is either result or ConfigItems.
Fields
result
If the JsonApiContext that sent the GetConfigItems message doens't have the right to read the config, the result property will be set (always with the value "AccessDenied").
In that case, result is the only additional one. If access is allowed, no result property will be sent within that message.
ConfigItems
If the JsonApiContext that has sent the GetConfigItems message has the right to read the config, an array named ConfigItems will be send. This array can be empty (if there
are no config items), or filled with objects descriped in ConfigItemObject providing the informations for an config item.
ConfigItemObject
{
"name": "ConfigItemName",
"type": "TypeOfItem",
"minVal" : Number,
"maxVal" : Number,
"password" : true,
"choices" : [ListOfChoices]
}
name
The name of the config item as defined on the C++ side.
type
The type of the config item. Will be one of the following:
- BOOL A boolean field.
- INT A 32bit singed integer field.
- DWORD A 32bit unsigned integer field.
- LONG64 A 64bit singed integer field.
- ULONG64 A 64bit unsigned integer field.
- STRING A string field.
- CHOICE A choice field.
minVal (optional)
(Only for config item types INT, DWORD, LONG64 and ULONG64) If set, the property defines minimum value accepted by that config item.
maxVal (optional)
(Only for config item types INT, DWORD, LONG64 and ULONG64) If set, the property defines maximum value accepted by that config item.
password (optional)
(Only for config item type STRING) If exists (and in that case always set to true), the string config item is defined as password string. That means,
that ReadConfig and ConfigUpdate never will send the real value for that item (an empty string will be send instead). And when writing a value to that item,
it must be encrypted. That encryption is handled by the JavaScript config library.
choices
(Only for config item type CHOICE) An array with the available choices to choose. Each choice is represented by a string value.
Example message
{
"api": "Config",
"mt": "GetConfigItemsResult",
"ConfigItems": [{
"name" : "maxPlayers",
"type" : "DWORD",
"minVal" : 1,
"maxVal" : 10
},
{
"name" : "teams",
"type" : "CHOICE",
"choices" : ["RedTeam", "BlueTeam", "InnoTeam"]
},
{
"name" : "playerName",
"type" : "STRING"
}]
}
ReadConfig
{
"api": "Config",
"mt": "ReadConfig"
}
Overview
This will request the current configuration which will lead to a ReadConfigResult message.
ReadConfigResult / ConfigUpdate
{
"api": "Config",
"mt": "ReadConfigResult" / "ConfigUpdate"
"ConfigItems" : {
"ItemName" : number,
"ItemName" : true / false,
"ItemName" : "stringValue"
}
}
Overview
This message will be used to send the current configuration after requested (ReadConfigResult) or after the config had been changed on the C++ side (ConfigUpdate). The messages for
ReadConfigResult and ConfigUpdate are the same except the value of the mt property, of course.
ConfigItems
This array holds all config items and their values. Each item will be send by a property with the name of the item and the value. The value type depends of the type of the config item itself:
- INT, DWORD, LONG64, ULONG64: The value as number with the bitwith according the config item type.
- CHOICE: The zero based index inside the array of choices received with the GetConfigItemsResult message.
- BOOL: Simply true or false.
- STRING: The string value of the item.
Example message
{
"api": "Config",
"mt": "ReadConfigResult",
"ConfigItems": {
"maxPlayers" : 5,
"teams" : 2,
"playerName" : "Goldfish"
}
}
WriteConfig
{
"api": "Config",
"mt": "WriteConfig",
"ConfigItems": {
"ItemName": number,
"ItemName": true / false,
"ItemName": "StringValue",
"ItemNamePassword": {
"value": "EncodedValue",
"key": "KeyToDecode"
}
}
}
Overview
With this message, ConfigContext will update the internal config items with the values sent by the message. Each property value that differ from the appropriate config items dfefault value or current value,
will be updated in memory and written to the database.
ConfigItems
This array holds all config items and their values. Each item will be send by a property with the name of the item and the value. The value type depends of the type of the config item itself:
- INT, DWORD, LONG64, ULONG64: The value as number with the bitwith according the config item type.
- CHOICE: The zero based index inside the array of choices received with the GetConfigItemsResult message.
- BOOL: Simply true or false.
- STRING: The string value of the item.
There is one special field for string config items that are defined as password strings. For this items, "Password" must be added to the items name and set as the property that holds an array.
Inside this array, the encrypted string value will be set to the value property, while the key property holds the key needed to decode the string inside value. The encryption must be done by
creating a value for the key and call the decrypt function of appWebsocket with that created key and the string to encode. Both informations (the encrypted string and the key) are used by
ConfigContext do decrypt the password again.
WriteConfigResult
{
"api":"Config",
"mt":"WriteConfigResult",
"result":"ok"
}
Overview
This message will be send as answer to WriteConfig.
result
The result of the WriteConfig message which can be one of the following value:
- ok The config had been sucessfully witten to the database.
- failed Writing the config failed. See the log of the application service for details (logging of config must be enabled).
- AccessDenied The connection does't have the right to write the config.
Code examples
ConfigContext
// A simple class derived from ConfigContext
static const char * team_names[] = { "ReadTeam", "BlueTeam", "InnoTeam", nullptr };
class MyConfig : public ConfigContext() {
private:
class MyApp * myApp;
ConfigInt maxPlayers;
ConfigString playerName;
ConfigChoice teams;
protected:
virtual void ConfigChanged()
{
this->myApp->OnConfigChanged();
}
public:
// Let's assume, that MyApp is derived from JsonApiContext.
MyConfig(class MyApp * userApp, class IDatabase * database, class IInstanceLog * log)
: ConfigContext(database, log),
maxPlayers(this, "maxPlayers", 5, false, 1, 10),
playerName(this, "playerName", "Goldfish"),
teams(this, "teams", 2, team_names)
{
this->myApp = userApp;
this->myApp->RegisterJsonApi(this);
}
ConfigInt & MaxPlayers() { return this->maxPlayers; }
ConfigString & PlayerName() { return this->playerName; }
ConfigChoice & Teams() { return this->teams; }
};
Using config
// Let's assume, that MyApp is derived from JsonApiContext and UTask, already
// created and also has pointers to an already created and initialized IDatabase
// instance as well as valid IInstanceLog instance.
void MyApp::Init()
{
this->config = new MyConfig(this, this->database, this->log);
ITask * initConfigTask = this->config->CreateInitTask();
initConfigTask->Start(this);
}
void MyApp::TaskComplete(ITask * task)
{
delete task;
debug->printf("Config database initialized");
}
void MyApp::OnConfigChanged()
{
debug->printf("Config changed - new values:");
debug->printf(" Max-Players : %u", this->config->MaxPlayers().Value());
debug->printf(" Player-Name : %s", this->config->PlayerName().Value());
debug->printf(" Selected Team : %s", this->config->Teams().Value());
}
First Steps
To use config some preparations in your code needs to be done. The following steps appply
when you use ConfigContext as base class to your instance class and do not use a separate
class for the config. This is a good option in most cases.
- Includes
-
Use config.h as include
#include "common/lib/config.h"
- Definitions in the instance class
-
Use JsonApiContext and ConfigContext as base class
..., public JsonApiContext, public ConfigContext
Define a private function, as initialization complete handler
void ConfigInitComplete(class ITask * task);
Define a UTaskTemplate class so that this handler will be called
class UTaskTemplate<YourApp, class ITask> taskConfigInit;
Define public members for the config parameters, e.g
class ConfigString configParameter;
- Instance Code
-
Initializations in the constructor of the instance class
ConfigContext(0, this),
taskConfigInit(this, &yourApp::ConfigInitComplete),
configParameter(this, "parameter", "")
Call RegisterJsonApi in the instance constructor, so that the Config lib
is known as Api provider
RegisterJsonApi(this);
Start config initialization after database is connected. E.g. in the
DatabaseConnectComplete function
class ITask * task = CreateInitTask(database);
task->Start(&taskConfigInit);
Continue initialization when config init is complete
void YourApp::ConfigInitComplete(class ITask * task)
{
... more init ...
}
Make sure the you instance class is passed as jsonApiContext in the AppWebsocket
constructor
AppWebsocket(webserverPlugin, yourApp, yourApp)