Implemented triggers.
Merged from code by Wouter Spruit, with additions by yours truly.
This commit is contained in:
parent
eb6b98b219
commit
279add438a
18 changed files with 597 additions and 6 deletions
|
@ -1,4 +1,5 @@
|
|||
/// \page api API calls
|
||||
/// \brief Listing of all controller API calls.
|
||||
/// The controller listens for commands through a JSON-based API. This page describes the API in full.
|
||||
///
|
||||
/// A default interface implementing this API as a single HTML page is included in the controller itself. This default interface will be send for invalid API requests, and is thus triggered by default when a browser attempts to access the API port directly.
|
||||
|
@ -20,7 +21,9 @@
|
|||
///
|
||||
/// You may also include a `"callback"` or `"jsonp"` HTTP variable, to trigger JSONP compatibility mode. JSONP is useful for getting around the cross-domain scripting protection in most modern browsers. Developers creating non-JavaScript applications will most likely not want to use JSONP mode, though nothing is stopping you if you really want to.
|
||||
///
|
||||
/// \brief Listing of all controller API calls.
|
||||
|
||||
|
||||
|
||||
|
||||
/// \file controller.cpp
|
||||
/// Contains all code for the controller executable.
|
||||
|
@ -47,6 +50,7 @@
|
|||
#include "controller_connectors.h"
|
||||
#include "controller_statistics.h"
|
||||
/*LTS-START*/
|
||||
#include <mist/triggers.h>
|
||||
#include "controller_updater.h"
|
||||
#include "controller_limits.h"
|
||||
#include "controller_uplink.h"
|
||||
|
@ -132,6 +136,12 @@ void statusMonitor(void * np){
|
|||
}
|
||||
|
||||
///\brief The main entry point for the controller.
|
||||
///
|
||||
/// \triggers
|
||||
/// The `"SYSTEM_STOP"` trigger is global, and is ran when the controller shuts down. If cancelled, the controller does not shut down and will attempt to re-open the API socket. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// shutdown reason
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
int main(int argc, char ** argv){
|
||||
|
||||
Controller::Storage = JSON::fromFile("config.json");
|
||||
|
@ -214,6 +224,7 @@ int main(int argc, char ** argv){
|
|||
if (Controller::Storage["config"]["controller"]["username"]){
|
||||
Controller::conf.getOption("username", true)[0u] = Controller::Storage["config"]["controller"]["username"];
|
||||
}
|
||||
Controller::writeConfig();
|
||||
Controller::checkAvailProtocols();
|
||||
createAccount(Controller::conf.getString("account"));
|
||||
|
||||
|
@ -299,6 +310,7 @@ int main(int argc, char ** argv){
|
|||
tthread::thread uplinkThread(Controller::uplinkConnection, 0);/*LTS*/
|
||||
|
||||
//start main loop
|
||||
while (Controller::conf.is_active){/*LTS*/
|
||||
Controller::conf.serveThreadedSocket(Controller::handleAPIConnection);
|
||||
//print shutdown reason
|
||||
std::string shutdown_reason;
|
||||
|
@ -311,9 +323,21 @@ int main(int argc, char ** argv){
|
|||
if (Controller::restarting){
|
||||
shutdown_reason = "update (on request)";
|
||||
}
|
||||
if(Triggers::shouldTrigger("SYSTEM_STOP")){
|
||||
if (!Triggers::doTrigger("SYSTEM_STOP", shutdown_reason)){
|
||||
Controller::conf.is_active = true;
|
||||
Controller::restarting = false;
|
||||
Util::sleep(1000);
|
||||
}else{
|
||||
Controller::conf.is_active = false;
|
||||
Controller::Log("CONF", "Controller shutting down because of "+shutdown_reason);
|
||||
}
|
||||
}else{
|
||||
Controller::conf.is_active = false;
|
||||
Controller::Log("CONF", "Controller shutting down because of "+shutdown_reason);
|
||||
}
|
||||
}//indentation intentionally wrong, to minimize Pro/nonPro diffs
|
||||
/*LTS-END*/
|
||||
Controller::Log("CONF", "Controller shutting down because of "+shutdown_reason);
|
||||
Controller::conf.is_active = false;
|
||||
//join all joinable threads
|
||||
statsThread.join();
|
||||
monitorThread.join();
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include <mist/defines.h>
|
||||
#include "controller_storage.h"
|
||||
#include "controller_connectors.h"
|
||||
#include <mist/triggers.h>
|
||||
|
||||
#include <iostream>
|
||||
#include <unistd.h>
|
||||
|
@ -74,6 +75,16 @@ namespace Controller {
|
|||
///\param p An object containing all protocols.
|
||||
///\param capabilities An object containing the detected capabilities.
|
||||
///\returns True if any action was taken
|
||||
///
|
||||
/// \triggers
|
||||
/// The `"OUTPUT_START"` trigger is global, and is ran whenever a new protocol listener is started. It cannot be cancelled. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// output listener commandline
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// The `"OUTPUT_STOP"` trigger is global, and is ran whenever a protocol listener is terminated. It cannot be cancelled. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// output listener commandline
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
bool CheckProtocols(JSON::Value & p, const JSON::Value & capabilities){
|
||||
std::set<std::string> runningConns;
|
||||
|
||||
|
@ -146,6 +157,7 @@ namespace Controller {
|
|||
Log("CONF", "Stopping connector " + it->first);
|
||||
action = true;
|
||||
Util::Procs::Stop(it->second);
|
||||
Triggers::doTrigger("OUTPUT_STOP",it->first); //LTS
|
||||
}
|
||||
currentConnectors.erase(it);
|
||||
if (!currentConnectors.size()){
|
||||
|
@ -168,6 +180,7 @@ namespace Controller {
|
|||
buildPipedArguments(p, (char **)&argarr, capabilities);
|
||||
// start piped w/ generated args
|
||||
currentConnectors[*runningConns.begin()] = Util::Procs::StartPiped(argarr, &zero, &out, &err);
|
||||
Triggers::doTrigger("OUTPUT_START", *runningConns.begin());//LTS
|
||||
}
|
||||
runningConns.erase(runningConns.begin());
|
||||
}
|
||||
|
|
|
@ -7,6 +7,7 @@
|
|||
#include <mist/defines.h>
|
||||
#include "controller_storage.h"
|
||||
#include "controller_capabilities.h"
|
||||
#include <mist/triggers.h>//LTS
|
||||
|
||||
///\brief Holds everything unique to the controller.
|
||||
namespace Controller {
|
||||
|
@ -75,6 +76,10 @@ namespace Controller {
|
|||
}
|
||||
|
||||
/// Writes the current config to shared memory to be used in other processes
|
||||
/// \triggers
|
||||
/// The `"SYSTEM_START"` trigger is global, and is ran as soon as the server configuration is first stable. It has no payload. If cancelled, the system immediately shuts down again.
|
||||
/// \n
|
||||
/// The `"SYSTEM_CONFIG"` trigger is global, and is ran every time the server configuration is updated. Its payload is the new configuration in JSON format. This trigger cannot be cancelled.
|
||||
void writeConfig(){
|
||||
static JSON::Value writeConf;
|
||||
bool changed = false;
|
||||
|
@ -104,6 +109,83 @@ namespace Controller {
|
|||
memcpy(mistConfOut.mapped, temp.data(), std::min(temp.size(), (size_t)mistConfOut.len));
|
||||
//unlock semaphore
|
||||
configLock.post();
|
||||
}
|
||||
|
||||
/*LTS-START*/
|
||||
static std::map<std::string,IPC::sharedPage> pageForType; //should contain one page for every trigger type
|
||||
char tmpBuf[NAME_BUFFER_SIZE];
|
||||
|
||||
//for all shm pages that hold triggers
|
||||
pageForType.clear();
|
||||
|
||||
if( writeConf["config"]["triggers"].size() ){//if triggers are defined...
|
||||
jsonForEach(writeConf["config"]["triggers"], it){//for all types defined in config
|
||||
snprintf(tmpBuf,NAME_BUFFER_SIZE,SHM_TRIGGER,(it.key()).c_str()); //create page
|
||||
pageForType[it.key()].init(tmpBuf, 8*1024, true, false);// todo: should this be false/why??
|
||||
char * bytePos=pageForType[it.key()].mapped;
|
||||
|
||||
//write data to page
|
||||
jsonForEach(*it, triggIt){ //for all defined
|
||||
unsigned int tmpUrlSize=(*triggIt)[(unsigned int) 0].asStringRef().size();
|
||||
unsigned int tmpStreamNames=0;// (*triggIt)[2ul].packedSize();
|
||||
std::string namesArray="";
|
||||
|
||||
if( (triggIt->size() >= 3) && (*triggIt)[2ul].size()){
|
||||
jsonForEach((*triggIt)[2ul], shIt){
|
||||
unsigned int tmpLen=shIt->asString().size();
|
||||
tmpStreamNames+= 4+tmpLen;
|
||||
//INFO_MSG("adding string: %s len: %d", shIt->asString().c_str() , tmpLen );
|
||||
((unsigned int*)tmpBuf)[0] = tmpLen; //NOTE: namesArray may be replaced by writing directly to tmpBuf.
|
||||
namesArray.append(tmpBuf,4);
|
||||
namesArray.append(shIt->asString());
|
||||
}
|
||||
}
|
||||
unsigned int totalLen=9+tmpUrlSize+tmpStreamNames; //4Btotal len, 4Burl len ,XB tmpurl, 1B sync , XB tmpstreamnames
|
||||
|
||||
if(totalLen > (pageForType[it.key()].len-(bytePos-pageForType[it.key()].mapped)) ){ //check if totalLen fits on the page
|
||||
ERROR_MSG("trigger does not fit on page. size: %d bytes left on page: %d skipping.",totalLen,(pageForType[it.key()].len-(bytePos-pageForType[it.key()].mapped))); //doesnt fit
|
||||
continue;
|
||||
}
|
||||
|
||||
((unsigned int*)bytePos)[0] = totalLen;
|
||||
bytePos+=4;
|
||||
((unsigned int*)bytePos)[0] = tmpUrlSize;
|
||||
bytePos+=4;
|
||||
memcpy(bytePos, (*triggIt)[(unsigned int) 0].asStringRef().data(), (*triggIt)[(unsigned int) 0].asStringRef().size());
|
||||
bytePos+=(*triggIt)[(unsigned int) 0].asStringRef().size();
|
||||
(bytePos++)[0] = (*triggIt)[1ul].asBool() ? '\001' : '\000';
|
||||
if(tmpStreamNames){
|
||||
memcpy(bytePos,namesArray.data(),tmpStreamNames); //contains a string of 4Blen,XBstring pairs
|
||||
bytePos+=tmpStreamNames;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static bool serverStartTriggered;
|
||||
if(!serverStartTriggered){
|
||||
if (!Triggers::doTrigger("SYSTEM_START")){
|
||||
conf.is_active = false;
|
||||
}
|
||||
serverStartTriggered++;
|
||||
}
|
||||
if (Triggers::shouldTrigger("SYSTEM_CONFIG")){
|
||||
std::string payload = writeConf.toString();
|
||||
Triggers::doTrigger("SYSTEM_CONFIG", payload);
|
||||
}
|
||||
/*LTS-END*/
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
/*NOTES:
|
||||
4B size (total size of entry 9B+XB(URL)+ 0..XB(nameArrayLen)) (if 0x00, stop reading)
|
||||
4B url_len
|
||||
XB url
|
||||
1B async
|
||||
for(number of strings)
|
||||
4B stringLen
|
||||
XB string
|
||||
)
|
||||
*/
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@
|
|||
#include "controller_storage.h"
|
||||
#include "controller_statistics.h"
|
||||
#include "controller_limits.h" /*LTS*/
|
||||
#include <mist/triggers.h> //LTS
|
||||
#include <sys/stat.h>
|
||||
#include <map>
|
||||
|
||||
|
@ -155,16 +156,45 @@ namespace Controller {
|
|||
return false;
|
||||
}
|
||||
|
||||
///
|
||||
/// \triggers
|
||||
/// The `"STREAM_ADD"` trigger is stream-specific, and is ran whenever a new stream is added to the server configuration. If cancelled, the stream is not added. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// streamname
|
||||
/// configuration in JSON format
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// The `"STREAM_CONFIG"` trigger is stream-specific, and is ran whenever a stream's configuration is changed. If cancelled, the configuration is not changed. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// streamname
|
||||
/// configuration in JSON format
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
///
|
||||
void AddStreams(JSON::Value & in, JSON::Value & out){
|
||||
//check for new streams and updates
|
||||
jsonForEach(in, jit) {
|
||||
if (out.isMember(jit.key())){
|
||||
if ( !streamsEqual((*jit), out[jit.key()])){
|
||||
/*LTS-START*/
|
||||
if(Triggers::shouldTrigger("STREAM_CONFIG")){
|
||||
std::string payload = jit.key()+"\n"+jit->toString();
|
||||
if (!Triggers::doTrigger("STREAM_CONFIG", payload, jit.key())){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*LTS-END*/
|
||||
out[jit.key()] = (*jit);
|
||||
out[jit.key()]["name"] = jit.key();
|
||||
Log("STRM", std::string("Updated stream ") + jit.key());
|
||||
}
|
||||
}else{
|
||||
/*LTS-START*/
|
||||
if(Triggers::shouldTrigger("STREAM_ADD")){
|
||||
std::string payload = jit.key()+"\n"+jit->toString();
|
||||
if (!Triggers::doTrigger("STREAM_ADD", payload, jit.key())){
|
||||
continue;
|
||||
}
|
||||
}
|
||||
/*LTS-END*/
|
||||
out[jit.key()] = (*jit);
|
||||
out[jit.key()]["name"] = jit.key();
|
||||
Log("STRM", std::string("New stream ") + jit.key());
|
||||
|
@ -255,10 +285,22 @@ namespace Controller {
|
|||
|
||||
}
|
||||
|
||||
/// \triggers
|
||||
/// The `"STREAM_REMOVE"` trigger is stream-specific, and is ran whenever a stream is removed from the server configuration. If cancelled, the stream is not removed. Its payload is:
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
/// streamname
|
||||
/// ~~~~~~~~~~~~~~~
|
||||
void deleteStream(const std::string & name, JSON::Value & out) {
|
||||
if (!out.isMember(name)){
|
||||
return;
|
||||
}
|
||||
/*LTS-START*/
|
||||
if(Triggers::shouldTrigger("STREAM_REMOVE")){
|
||||
if (!Triggers::doTrigger("STREAM_REMOVE", name, name)){
|
||||
return;
|
||||
}
|
||||
}
|
||||
/*LTS-END*/
|
||||
Log("STRM", std::string("Deleted stream ") + name);
|
||||
out.removeMember(name);
|
||||
if (inputProcesses.count(name)){
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue