Director Console Output
The console output should handle different API Modes.
As the initial design of the Director Console connection did allow various forms of output (in fact: free text with some helper functions) the introduction of another API mode (API mode JSON) did require to change the creation of output.
Output can be send to a console connection (UserAgent socket) or the command is executed in a job
free text (with the use of some helper functions)
Different Message types
Types
UAContext::send_msg
UAContext::info_msg
UAContext::warning_msg
UAContext::error_msg
indicated by a signal packet and than the text packet
see Daemon Protocol
The OutputFormatter
class have been introduced to consolidate the
interface to generate Console output.
The basic idea is to provide an object, array and key-value based interface.
object_key_value
A main member function of OutputFormatter
are the
object_key_value(…) functions, like
void OutputFormatter::object_key_value(const char *key, const char *key_fmt, const char *value, const char *value_fmt, int wrap = -1);
API mode 0 and 1 get the key and value, and write them as defined in the key_fmt and value_fmt strings. If the key_fmt string is not given, the key will not be written. If the value_fmt string is not given, the value will not be written.
In API mode 2 (JSON), OutputFormatter stores the key value pair in its internal JSON object, to delivers it, when the response object is finished. The keys will be transformed to lower case strings.
decoration
Additional output can be created by the
void OutputFormatter::decoration(const char *fmt, ...)
function.
This strings will only be written in API mode 0 and is intended to make
an output prettier.
messages
For messages, the UAContext function should be used:
UAContext::send_msg
UAContext::info_msg
UAContext::warning_msg
UAContext::error_msg
Internally, these redirect to the
void OutputFormatter::message(const char *type, POOL_MEM &message)
function.
API mode 0
packet 1: message is send to the user console
API mode 1
packet 1: message signal is send
packet 2: message is send to the user console
API mode 2:
packet 1: message signal is send (TODO: this might change)
message is stored in the corresponding message object
if an error message is send, the result of the command will switch to error
Objects and Arrays
To structure data, the OutputFormatter
class offers functions:
void object_start(const char *name = NULL);
void object_end(const char *name = NULL);
void array_start(const char *name);
void array_end(const char *name);
These functions define the structure of the reult object in API mode 2, but are ignored in API mode 0 and 1.
named objects
named objects (object_start(NAME))
can be added to objects (named and nameless objects)
nameless objects
nameless objects (object_start(NULL))
can be added to arrays
arrays
arrays (array_start(NAME))
can be added by name to an object
contain nameless objects (object_start(NULL))
Example
ResLocker _{my_config};
ua->send->array_start("storages");
foreach_res(store, R_STORAGE) {
if (acl_access_ok(ua, Storage_ACL, store->name())) {
ua->send->object_start();
ua->send->object_key_value("name", store->name(), "%s\n");
ua->send->object_end();
}
}
ua->send->array_end("storages");
results to
*.api 2
{
"jsonrpc": "2.0",
"id": null,
"result": {
"api": 2
}
}
*.storages
{
"jsonrpc": "2.0",
"id": null,
"result": {
"storages": [
{
"name": "File"
},
{
"name": "myTapeLibrary"
}
]
}
}
Example with 3 level structure
ua->send->array_start("files");
for(int i=0; file[i]; i++) {
ua->send->object_start();
ua->send->object_key_value("Name", "%s=", file[i]->name, "%s");
ua->send->object_key_value("Type", "%s=", file[i]->type, "%s");
decode_stat(file[i]->lstat, &statp, sizeof(statp), LinkFI);
ua->send->object_start("stat");
ua->send->object_key_value("dev", "%s=", statp.st_dev, "%s");
ua->send->object_key_value("ino", "%s=", statp.st_ino, "%s");
ua->send->object_key_value("mode", "%s=", statp.st_mode, "%s");
...
ua->send->object_end("stat");
ua->send->object_end();
}
ua->send->array_end("files");