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:

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

Filecommon/interface/config.h

Classes ConfigContext
ConfigItem
ConfigChoice
ConfigBool
ConfigInt
ConfigDword
ConfigLong64
ConfigUlong64
ConfigString

JSON messages Base message
GetConfigItems
GetConfigItemsResult
ReadConfig
ReadConfigResult
ConfigUpdate
WriteConfig
WriteConfigResult

Examples ConfigContext
Using config
First steps

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();

public:
    ConfigContext(class IDatabase * database, class IInstanceLog * log);
    virtual ~ConfigContext();

    class ITask * CreateInitTask(class IDatabase * database = nullptr);
    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: 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 connectionThe 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 connectionThe 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 * databaseThe IDatabase instance to be used by the config context.
class IInstanceLog * const logThe IInstanceLog instance used for loging purposes.
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.

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 * itemThe config item to write to the database.
const char * valueThe value to write.
bool notifyIf 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:

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 * datasetThe 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 * jsonThe json_io instance to read the config item value from.
dword baseThe base id inside the json to start reading the config item data.
class IJsonApiConnection * const connectionThe 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 * jsonThe json_io instance to write the config item value to.
dword baseThe base id inside the json to start writing the config item data.
char * & convBufA 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 connectionThe 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 * destThe 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: Type need to be one of the followin value (the names of defines for that type is given in brackets):

Parameters

class json_io * jsonThe json_io instance to write the config item type information.
dword baseThe base id inside the json to start writing the config item type information.
char * & convBufA 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
bool unmanagedIf 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
size_t defValThe index of the default value inside the given options array.
const char ** optionsThe 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 * optionThe 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 valueIdxThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
bool defValThe 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 valueThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
int defValThe 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 valueThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
dword defValThe 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 valueThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
long64 defValThe 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 valueThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
ulong64 defValThe 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 valueThe 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 * contextThe ConfigContext instance the item itself will reigster to it.
char * nameThe name of the config item. Must be unique withing the given ConfigContext.
char * defValThe 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 valueThe 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:
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:

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:
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:

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)