Finalized error propagation and debug level setting code.

This commit is contained in:
Thulinma 2014-06-05 09:55:30 +02:00
parent 75c5af4575
commit 1174773244
5 changed files with 91 additions and 38 deletions

View file

@ -287,6 +287,7 @@ void createAccount (std::string account){
///\brief The main entry point for the controller. ///\brief The main entry point for the controller.
int main(int argc, char ** argv){ int main(int argc, char ** argv){
Controller::Storage = JSON::fromFile("config.json"); Controller::Storage = JSON::fromFile("config.json");
JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}"); JSON::Value stored_port = JSON::fromString("{\"long\":\"port\", \"short\":\"p\", \"arg\":\"integer\", \"help\":\"TCP port to listen on.\"}");
stored_port["default"] = Controller::Storage["config"]["controller"]["port"]; stored_port["default"] = Controller::Storage["config"]["controller"]["port"];
@ -353,6 +354,18 @@ int main(int argc, char ** argv){
//Input custom config here //Input custom config here
Controller::Storage = JSON::fromFile(Controller::conf.getString("configFile")); Controller::Storage = JSON::fromFile(Controller::conf.getString("configFile"));
{
//spawn thread that reads stderr of process
int pipeErr[2];
if (pipe(pipeErr) >= 0){
dup2(pipeErr[1], STDERR_FILENO);//cause stderr to write to the pipe
close(pipeErr[1]);//close the unneeded pipe file descriptor
tthread::thread msghandler(Controller::handleMsg, (void*)(((char*)0) + pipeErr[0]));
msghandler.detach();
}
}
if (Controller::conf.getOption("debug",true).size() > 1){ if (Controller::conf.getOption("debug",true).size() > 1){
Controller::Storage["config"]["debug"] = Controller::conf.getInteger("debug"); Controller::Storage["config"]["debug"] = Controller::conf.getInteger("debug");
} }

View file

@ -7,6 +7,7 @@
#include <mist/procs.h> #include <mist/procs.h>
#include <mist/timing.h> #include <mist/timing.h>
#include <mist/tinythread.h> #include <mist/tinythread.h>
#include <mist/defines.h>
#include "controller_storage.h" #include "controller_storage.h"
#include "controller_connectors.h" #include "controller_connectors.h"
@ -38,18 +39,28 @@ namespace Controller {
static inline void builPipedPart(JSON::Value & p, char * argarr[], int & argnum, JSON::Value & argset){ static inline void builPipedPart(JSON::Value & p, char * argarr[], int & argnum, JSON::Value & argset){
for (JSON::ObjIter it = argset.ObjBegin(); it != argset.ObjEnd(); ++it){ for (JSON::ObjIter it = argset.ObjBegin(); it != argset.ObjEnd(); ++it){
if (it->second.isMember("option") && p.isMember(it->first)){ if (it->second.isMember("option")){
if (it->second.isMember("type")){ if (p.isMember(it->first)){
if (it->second["type"].asStringRef() == "str" && !p[it->first].isString()){ if (it->second.isMember("type")){
p[it->first] = p[it->first].asString(); if (it->second["type"].asStringRef() == "str" && !p[it->first].isString()){
p[it->first] = p[it->first].asString();
}
if ((it->second["type"].asStringRef() == "uint" || it->second["type"].asStringRef() == "int") && !p[it->first].isInt()){
p[it->first] = p[it->first].asString();
}
} }
if ((it->second["type"].asStringRef() == "uint" || it->second["type"].asStringRef() == "int") && !p[it->first].isInt()){ if (p[it->first].asStringRef().size() > 0){
p[it->first] = JSON::Value(p[it->first].asInt()).asString(); argarr[argnum++] = (char*)(it->second["option"].c_str());
argarr[argnum++] = (char*)(p[it->first].c_str());
}
}else{
if (it->first == "debug"){
static std::string debugLvlStr;
debugLvlStr = JSON::Value((long long)Util::Config::printDebugLevel).asString();
argarr[argnum++] = (char*)(it->second["option"].c_str());
argarr[argnum++] = (char*)debugLvlStr.c_str();
DEVEL_MSG("Setting debug for %s to %s", p["connector"].asStringRef().c_str(), debugLvlStr.c_str());
} }
}
if (p[it->first].asStringRef().size() > 0){
argarr[argnum++] = (char*)(it->second["option"].c_str());
argarr[argnum++] = (char*)(p[it->first].c_str());
} }
} }
} }
@ -73,24 +84,6 @@ namespace Controller {
if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);} if (pipedCapa.isMember("optional")){builPipedPart(p, argarr, argnum, pipedCapa["optional"]);}
} }
void handleMsg(void * err){
char buf[1024];
FILE * output = fdopen((long long int)err, "r");
while (fgets(buf, 1024, output)){
unsigned int i = 0;
while (i < 9 && buf[i] != ' '){
++i;
}
if(i < 9){
buf[i] = 0;
Log(buf,buf+i+1);
}else{
printf("%s\n",buf);
}
}
}
///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary. ///\brief Checks current protocol coguration, updates state of enabled connectors if neccesary.
///\param p An object containing all protocols. ///\param p An object containing all protocols.
///\param capabilities An object containing the detected capabilities. ///\param capabilities An object containing the detected capabilities.
@ -109,14 +102,18 @@ namespace Controller {
long long counter = 0; long long counter = 0;
for (JSON::ArrIter ait = p.ArrBegin(); ait != p.ArrEnd(); ait++){ for (JSON::ArrIter ait = p.ArrBegin(); ait != p.ArrEnd(); ait++){
( *ait).removeMember("online"); std::string prevOnline = ( *ait)["online"].asString();
#define connName (*ait)["connector"].asStringRef() #define connName (*ait)["connector"].asStringRef()
if ( !(*ait).isMember("connector") || connName == ""){ if ( !(*ait).isMember("connector") || connName == ""){
( *ait)["online"] = "Missing connector name";
continue; continue;
} }
if ( !capabilities["connectors"].isMember(connName)){ if ( !capabilities["connectors"].isMember(connName)){
Log("WARN", connName + " connector is enabled but doesn't exist on system! Ignoring connector."); ( *ait)["online"] = "Not installed";
if (( *ait)["online"].asString() != prevOnline){
Log("WARN", connName + " connector is enabled but doesn't exist on system! Ignoring connector.");
}
continue; continue;
} }
@ -126,13 +123,17 @@ namespace Controller {
for (JSON::ObjIter it = connCapa["required"].ObjBegin(); it != connCapa["required"].ObjEnd(); ++it){ for (JSON::ObjIter it = connCapa["required"].ObjBegin(); it != connCapa["required"].ObjEnd(); ++it){
if ( !(*ait).isMember(it->first) || (*ait)[it->first].asStringRef().size() < 1){ if ( !(*ait).isMember(it->first) || (*ait)[it->first].asStringRef().size() < 1){
gotAll = false; gotAll = false;
Log("WARN", connName + " connector is missing required parameter " + it->first + "! Ignoring connector."); ( *ait)["online"] = "Invalid configuration";
if (( *ait)["online"].asString() != prevOnline){
Log("WARN", connName + " connector is missing required parameter " + it->first + "! Ignoring connector.");
}
break; break;
} }
} }
if (!gotAll){continue;} if (!gotAll){continue;}
} }
( *ait).removeMember("online");
/// \todo Check dependencies? /// \todo Check dependencies?
new_connectors[counter] = (*ait).toString(); new_connectors[counter] = (*ait).toString();
@ -164,9 +165,9 @@ namespace Controller {
err = -1; err = -1;
Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err);//redirects output to out. Must make a new pipe, redirect std err Util::Procs::StartPiped(toConn(iter->first), argarr, &zero, &out, &err);//redirects output to out. Must make a new pipe, redirect std err
if(err != -1){ if(err != -1){
//spawn new thread where err is read, it reads err until there is nothing more to be read //spawn thread that reads stderr of process
tthread::thread * msghandler = new tthread::thread(handleMsg, (void*)err); tthread::thread msghandler(Controller::handleMsg, (void*)(((char*)0) + err));
msghandler->detach(); msghandler.detach();
} }
} }
} }

View file

@ -38,5 +38,33 @@ namespace Controller {
File.close(); File.close();
return File.good(); return File.good();
} }
/// Handles output of a Mist application, detecting and catching debug messages.
/// Debug messages are automatically converted into Log messages.
/// Closes the file descriptor on read error.
/// \param err File descriptor of the stderr output of the process to monitor.
void handleMsg(void * err){
char buf[1024];
FILE * output = fdopen((long long int)err, "r");
while (fgets(buf, 1024, output)){
unsigned int i = 0;
while (i < 9 && buf[i] != '|' && buf[i] != 0){
++i;
}
unsigned int j = i;
while (j < 1024 && buf[j] != '\n' && buf[j] != 0){
++j;
}
buf[j] = 0;
if(i < 9){
buf[i] = 0;
Log(buf,buf+i+1);
}else{
printf("%s", buf);
}
}
fclose(output);
close((long long int)err);
}
} }

View file

@ -13,5 +13,7 @@ namespace Controller {
/// Write contents to Filename. /// Write contents to Filename.
bool WriteFile(std::string Filename, std::string contents); bool WriteFile(std::string Filename, std::string contents);
void handleMsg(void * err);
} }

View file

@ -35,6 +35,7 @@ namespace Controller {
///\param name The name of the stream ///\param name The name of the stream
///\param data The corresponding configuration values. ///\param data The corresponding configuration values.
void startStream(std::string name, JSON::Value & data){ void startStream(std::string name, JSON::Value & data){
std::string prevState = data["error"].asStringRef();
data["online"] = (std::string)"Checking..."; data["online"] = (std::string)"Checking...";
data.removeMember("error"); data.removeMember("error");
std::string URL; std::string URL;
@ -45,8 +46,10 @@ namespace Controller {
URL = data["source"].asString(); URL = data["source"].asString();
} }
if (URL == ""){ if (URL == ""){
Log("STRM", "Error for stream " + name + "! Source parameter missing.");
data["error"] = "Stream offline: Missing source parameter!"; data["error"] = "Stream offline: Missing source parameter!";
if (data["error"].asStringRef() != prevState){
Log("STRM", "Error for stream " + name + "! Source parameter missing.");
}
return; return;
} }
if (URL.substr(0, 4) == "push"){ if (URL.substr(0, 4) == "push"){
@ -71,8 +74,10 @@ namespace Controller {
data.removeMember("error"); data.removeMember("error");
struct stat fileinfo; struct stat fileinfo;
if (stat(URL.c_str(), &fileinfo) != 0 || S_ISDIR(fileinfo.st_mode)){ if (stat(URL.c_str(), &fileinfo) != 0 || S_ISDIR(fileinfo.st_mode)){
Log("BUFF", "Warning for VoD stream " + name + "! File not found: " + URL);
data["error"] = "Stream offline: Not found: " + URL; data["error"] = "Stream offline: Not found: " + URL;
if (data["error"].asStringRef() != prevState){
Log("BUFF", "Warning for VoD stream " + name + "! File not found: " + URL);
}
data["online"] = 0; data["online"] = 0;
return; return;
} }
@ -89,8 +94,10 @@ namespace Controller {
} }
if ( !getMeta && data.isMember("meta") && data["meta"].isMember("tracks")){ if ( !getMeta && data.isMember("meta") && data["meta"].isMember("tracks")){
if ( !data["meta"] || !data["meta"]["tracks"]){ if ( !data["meta"] || !data["meta"]["tracks"]){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
data["error"] = "Stream offline: Corrupt file?"; data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
}
data["online"] = 0; data["online"] = 0;
return; return;
} }
@ -118,8 +125,10 @@ namespace Controller {
tmp_cmd[1] = (char*)URL.c_str(); tmp_cmd[1] = (char*)URL.c_str();
data["meta"] = JSON::fromString(Util::Procs::getOutputOf(tmp_cmd)); data["meta"] = JSON::fromString(Util::Procs::getOutputOf(tmp_cmd));
if ( !data["meta"] || !data["meta"].isMember("tracks") || !data["meta"]["tracks"]){ if ( !data["meta"] || !data["meta"].isMember("tracks") || !data["meta"]["tracks"]){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
data["error"] = "Stream offline: Corrupt file?"; data["error"] = "Stream offline: Corrupt file?";
if (data["error"].asStringRef() != prevState){
Log("WARN", "Source file " + URL + " seems to be corrupt.");
}
data["online"] = 0; data["online"] = 0;
return; return;
} }