173 lines
6.3 KiB
C++
173 lines
6.3 KiB
C++
#include "controller_external_writers.h"
|
|
#include "controller_statistics.h"
|
|
#include "controller_storage.h"
|
|
#include <mist/downloader.h>
|
|
#include <mist/bitfields.h>
|
|
#include <mist/config.h>
|
|
#include <mist/json.h>
|
|
#include <mist/stream.h>
|
|
#include <mist/triggers.h>
|
|
#include <string>
|
|
|
|
namespace Controller{
|
|
// Size of the shared memory page
|
|
static uint64_t pageSize = EXTWRITERS_INITSIZE;
|
|
|
|
/// \brief Writes external writers from the server config to shared memory
|
|
void externalWritersToShm(){
|
|
uint64_t writerCount = Controller::Storage["extwriters"].size();
|
|
IPC::sharedPage writersPage(EXTWRITERS, pageSize, false, false);
|
|
// If we have an existing page, set the reload flag
|
|
if (writersPage.mapped){
|
|
writersPage.master = true;
|
|
Util::RelAccX binAccx = Util::RelAccX(writersPage.mapped, false);
|
|
// Check if we need a bigger page
|
|
uint64_t sizeRequired = binAccx.getOffset() + binAccx.getRSize() * writerCount;
|
|
if (pageSize < sizeRequired){pageSize = sizeRequired;}
|
|
binAccx.setReload();
|
|
}
|
|
// Close & unlink any existing page and create a new one
|
|
writersPage.close();
|
|
writersPage.init(EXTWRITERS, pageSize, true, false);
|
|
Util::RelAccX exwriAccx = Util::RelAccX(writersPage.mapped, false);
|
|
exwriAccx = Util::RelAccX(writersPage.mapped, false);
|
|
exwriAccx.addField("name", RAX_32STRING);
|
|
exwriAccx.addField("cmdline", RAX_256STRING);
|
|
exwriAccx.addField("protocols", RAX_NESTED, RAX_64STRING * writerCount * 8);
|
|
// Set amount of records that can fit and how many will be used
|
|
uint64_t reqCount = (pageSize - exwriAccx.getOffset()) / exwriAccx.getRSize();
|
|
exwriAccx.setRCount(reqCount);
|
|
exwriAccx.setPresent(reqCount);
|
|
exwriAccx.setEndPos(writerCount);
|
|
// Do the same for the nested protocol field
|
|
uint64_t index = 0;
|
|
jsonForEach(Controller::Storage["extwriters"], it){
|
|
std::string name = (*it)[0u].asString();
|
|
std::string cmdline = (*it)[1u].asString();
|
|
exwriAccx.setString("name", name, index);
|
|
exwriAccx.setString("cmdline", cmdline, index);
|
|
// Create nested field for source match
|
|
uint8_t protocolCount = (*it)[2u].size();
|
|
Util::RelAccX protocolAccx = Util::RelAccX(exwriAccx.getPointer("protocols", index), false);
|
|
protocolAccx.addField("protocol", RAX_64STRING);
|
|
protocolAccx.setRCount(protocolCount);
|
|
protocolAccx.setPresent(protocolCount);
|
|
protocolAccx.setEndPos(protocolCount);
|
|
uint8_t binIt = 0;
|
|
jsonForEach((*it)[2u], protIt){
|
|
std::string thisProtocol = (*protIt).asString();
|
|
protocolAccx.setString("protocol", thisProtocol, binIt);
|
|
binIt++;
|
|
}
|
|
index++;
|
|
protocolAccx.setReady();
|
|
}
|
|
exwriAccx.setReady();
|
|
// Leave the page in memory after returning
|
|
writersPage.master = false;
|
|
}
|
|
|
|
/// \brief Adds a new generic writer binary to the server config
|
|
/// The request should contain:
|
|
/// - name: name given to this binary in order to edit/remove it's entry in Mists config
|
|
/// - cmdline: command line including arguments
|
|
/// - supported URL protocols: used to identify for what targets we need to run the executable
|
|
void addExternalWriter(JSON::Value &request){
|
|
std::string name;
|
|
std::string cmdline;
|
|
JSON::Value protocols;
|
|
bool isNew = true;
|
|
if (request.isArray()){
|
|
if(request.size() == 4){
|
|
name = request[0u].asString();
|
|
cmdline = request[1u].asString();
|
|
protocols = request[2u];
|
|
}else{
|
|
ERROR_MSG("Cannot add external writer, as the request contained %u variables. Required variables are: name, cmdline and protocols", request.size());
|
|
return;
|
|
}
|
|
}else{
|
|
name = request["name"].asString();
|
|
cmdline = request["cmdline"].asString();
|
|
protocols = request["protocols"];
|
|
}
|
|
//convert protocols from string to array if needed
|
|
if (protocols.isString()){protocols.append(protocols.asString());}
|
|
if (!name.size()){
|
|
ERROR_MSG("Blank or missing name in request");
|
|
return;
|
|
}
|
|
if (!cmdline.size()){
|
|
ERROR_MSG("Blank or missing cmdline in request");
|
|
return;
|
|
}
|
|
if (!protocols.size()){
|
|
ERROR_MSG("Missing protocols in request");
|
|
return;
|
|
}
|
|
if (name.size() > 31){
|
|
name = name.substr(0, 31);
|
|
WARN_MSG("Maximum name length is 31 characters, truncating name to '%s'", name.c_str());
|
|
}
|
|
if (cmdline.size() > 255){
|
|
cmdline.erase(255);
|
|
WARN_MSG("Maximum cmdline length is 255 characters, truncating cmdline to '%s'", cmdline.c_str());
|
|
}
|
|
jsonForEach(protocols, protIt){
|
|
if ((*protIt).size() > 63){
|
|
(*protIt) = (*protIt).asString().substr(0, 63);
|
|
WARN_MSG("Maximum protocol length is 63 characters, truncating protocol to '%s'", (*protIt).asStringRef().c_str());
|
|
}
|
|
}
|
|
|
|
// Check if we have an existing variable with the same name to modify
|
|
jsonForEach(Controller::Storage["extwriters"], it){
|
|
if ((*it)[0u].asString() == name){
|
|
INFO_MSG("Modifying existing external writer '%s'", name.c_str());
|
|
(*it)[1u] = cmdline;
|
|
(*it)[2u] = protocols;
|
|
isNew = false;
|
|
break;
|
|
}
|
|
}
|
|
// Else push a new custom variable to the list
|
|
if (isNew){
|
|
INFO_MSG("Adding new external writer '%s'", name.c_str());
|
|
JSON::Value thisVar;
|
|
thisVar.append(name);
|
|
thisVar.append(cmdline);
|
|
thisVar.append(protocols);
|
|
Controller::Storage["extwriters"].append(thisVar);
|
|
}
|
|
// Modify shm
|
|
externalWritersToShm();
|
|
}
|
|
|
|
/// \brief Fills output with all defined external writers
|
|
void listExternalWriters(JSON::Value &output){
|
|
output = Controller::Storage["extwriters"];
|
|
}
|
|
|
|
/// \brief Removes the external writer name contained in the request from shm and the sever config
|
|
void removeExternalWriter(const JSON::Value &request){
|
|
std::string name;
|
|
if (request.isString()){
|
|
name = request.asStringRef();
|
|
}else if (request.isArray()){
|
|
name = request[0u].asStringRef();
|
|
}else if (request.isMember("name")){
|
|
name = request["name"].asStringRef();
|
|
}
|
|
if (!name.size()){
|
|
WARN_MSG("Aborting request to remove an external writer, as no name was given");
|
|
return;
|
|
}
|
|
// Modify config
|
|
jsonForEach(Controller::Storage["extwriters"], it){
|
|
if ((*it)[0u].asString() == name){it.remove();}
|
|
}
|
|
// Modify shm
|
|
externalWritersToShm();
|
|
}
|
|
}// namespace Controller
|
|
|