Added "deletestreamsource" call that deletes a stream AND the corresponding source file.

This commit is contained in:
Thulinma 2018-05-09 13:39:53 +02:00
parent 31403f2685
commit 7af419fdad
12 changed files with 146 additions and 10 deletions

View file

@ -511,6 +511,81 @@ void Controller::handleAPICommands(JSON::Value & Request, JSON::Value & Response
} }
} }
} }
if (Request.isMember("deletestreamsource")){
//if array, delete all elements
//if object, delete all entries
//if string, delete just the one
if (Request["deletestreamsource"].isString()){
switch (Controller::deleteStream(Request["deletestreamsource"].asStringRef(), Controller::Storage["streams"], true)){
case 0:
Response["deletestreamsource"] = "0: No action taken";
break;
case 1:
Response["deletestreamsource"] = "1: Source file deleted";
break;
case 2:
Response["deletestreamsource"] = "2: Source file and dtsh deleted";
break;
case -1:
Response["deletestreamsource"] = "-1: Stream deleted, source remains";
break;
case -2:
Response["deletestreamsource"] = "-2: Stream and source file deleted";
break;
case -3:
Response["deletestreamsource"] = "-3: Stream, source file and dtsh deleted";
break;
}
}
if (Request["deletestreamsource"].isArray()){
jsonForEach(Request["deletestreamsource"], it){
switch (Controller::deleteStream(it->asStringRef(), Controller::Storage["streams"], true)){
case 0:
Response["deletestreamsource"][it.num()] = "0: No action taken";
break;
case 1:
Response["deletestreamsource"][it.num()] = "1: Source file deleted";
break;
case 2:
Response["deletestreamsource"][it.num()] = "2: Source file and dtsh deleted";
break;
case -1:
Response["deletestreamsource"][it.num()] = "-1: Stream deleted, source remains";
break;
case -2:
Response["deletestreamsource"][it.num()] = "-2: Stream and source file deleted";
break;
case -3:
Response["deletestreamsource"][it.num()] = "-3: Stream, source file and dtsh deleted";
break;
}
}
}
if (Request["deletestreamsource"].isObject()){
jsonForEach(Request["deletestreamsource"], it){
switch (Controller::deleteStream(it.key(), Controller::Storage["streams"], true)){
case 0:
Response["deletestreamsource"][it.key()] = "0: No action taken";
break;
case 1:
Response["deletestreamsource"][it.key()] = "1: Source file deleted";
break;
case 2:
Response["deletestreamsource"][it.key()] = "2: Source file and dtsh deleted";
break;
case -1:
Response["deletestreamsource"][it.key()] = "-1: Stream deleted, source remains";
break;
case -2:
Response["deletestreamsource"][it.key()] = "-2: Stream and source file deleted";
break;
case -3:
Response["deletestreamsource"][it.key()] = "-3: Stream, source file and dtsh deleted";
break;
}
}
}
}
if (Request.isMember("addprotocol")){ if (Request.isMember("addprotocol")){
if (Request["addprotocol"].isArray()){ if (Request["addprotocol"].isArray()){
jsonForEach(Request["addprotocol"], it){ jsonForEach(Request["addprotocol"], it){

View file

@ -293,24 +293,75 @@ namespace Controller {
} }
/// \triggers /// Deletes the stream (name) from the config (out), optionally also deleting the VoD source file if sourceFileToo is true.
/// 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: int deleteStream(const std::string & name, JSON::Value & out, bool sourceFileToo) {
/// ~~~~~~~~~~~~~~~ int ret = 0;
/// streamname if (sourceFileToo){
/// ~~~~~~~~~~~~~~~ std::string cleaned = name;
void deleteStream(const std::string & name, JSON::Value & out) { Util::sanitizeName(cleaned);
std::string strmSource;
if (Util::getStreamStatus(cleaned) != STRMSTAT_OFF){
DTSC::Meta mData = Util::getStreamMeta(cleaned);
if (mData.sourceURI.size()){
strmSource = mData.sourceURI;
}
}
if (!strmSource.size()){
std::string smp = cleaned.substr(0, cleaned.find_first_of("+ "));
if (out.isMember(smp) && out[smp].isMember("source")){
strmSource = out[smp]["source"].asStringRef();
}
}
bool noFile = false;
if (strmSource.size()){
std::string prevInput;
while (true){
std::string oldSrc = strmSource;
JSON::Value inputCapa = Util::getInputBySource(oldSrc, true);
if (inputCapa["name"].asStringRef() == prevInput){break;}
prevInput = inputCapa["name"].asStringRef();
strmSource = inputCapa["source_file"].asStringRef();
if (!strmSource.size()){
noFile = true;
break;
}
Util::streamVariables(strmSource, cleaned, oldSrc);
}
}
if (noFile){
WARN_MSG("Not deleting source for stream %s, since the stream does not have an unambiguous source file.", cleaned.c_str());
}else{
Util::streamVariables(strmSource, cleaned);
if (!strmSource.size()){
FAIL_MSG("Could not delete source for stream %s: unable to detect stream source URI using any method", cleaned.c_str());
}else{
if (unlink(strmSource.c_str())){
FAIL_MSG("Could not delete source %s for %s: %s (%d)", strmSource.c_str(), cleaned.c_str(), strerror(errno), errno);
}else{
++ret;
Log("STRM", "Deleting source file for stream "+cleaned+": "+strmSource);
//Delete dtsh, ignore failures
if (!unlink((strmSource+".dtsh").c_str())){
++ret;
}
}
}
}
}
if (!out.isMember(name)){ if (!out.isMember(name)){
return; return ret;
} }
/*LTS-START*/ /*LTS-START*/
if(Triggers::shouldTrigger("STREAM_REMOVE")){ if(Triggers::shouldTrigger("STREAM_REMOVE")){
if (!Triggers::doTrigger("STREAM_REMOVE", name, name)){ if (!Triggers::doTrigger("STREAM_REMOVE", name, name)){
return; return ret;
} }
} }
/*LTS-END*/ /*LTS-END*/
Log("STRM", std::string("Deleted stream ") + name); Log("STRM", "Deleted stream " + name);
out.removeMember(name); out.removeMember(name);
++ret;
ret *= -1;
if (inputProcesses.count(name)){ if (inputProcesses.count(name)){
pid_t procId = inputProcesses[name]; pid_t procId = inputProcesses[name];
if (Util::Procs::isRunning(procId)){ if (Util::Procs::isRunning(procId)){
@ -318,6 +369,7 @@ namespace Controller {
} }
inputProcesses.erase(name); inputProcesses.erase(name);
} }
return ret;
} }
} //Controller namespace } //Controller namespace

View file

@ -6,7 +6,7 @@ namespace Controller {
bool CheckAllStreams(JSON::Value & data); bool CheckAllStreams(JSON::Value & data);
void CheckStreams(JSON::Value & in, JSON::Value & out); void CheckStreams(JSON::Value & in, JSON::Value & out);
void AddStreams(JSON::Value & in, JSON::Value & out); void AddStreams(JSON::Value & in, JSON::Value & out);
void deleteStream(const std::string & name, JSON::Value & out); int deleteStream(const std::string & name, JSON::Value & out, bool sourceFileToo = false);
struct liveCheck { struct liveCheck {
long long int lastms; long long int lastms;

View file

@ -16,6 +16,7 @@ namespace Mist {
capa["name"] = "AV"; capa["name"] = "AV";
capa["desc"] = "This input uses libavformat to read any type of file. Unfortunately this input cannot be redistributed, but it is a great tool for testing the other file-based inputs against."; capa["desc"] = "This input uses libavformat to read any type of file. Unfortunately this input cannot be redistributed, but it is a great tool for testing the other file-based inputs against.";
capa["source_match"] = "/*"; capa["source_match"] = "/*";
capa["source_file"] = "$source";
capa["priority"] = 1ll; capa["priority"] = 1ll;
capa["codecs"][0u][0u].null(); capa["codecs"][0u][0u].null();
capa["codecs"][0u][1u].null(); capa["codecs"][0u][1u].null();

View file

@ -19,6 +19,7 @@ namespace Mist {
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["source_match"].append("/*.dtsc"); capa["source_match"].append("/*.dtsc");
capa["source_match"].append("dtsc://*"); capa["source_match"].append("dtsc://*");
capa["source_file"] = "$source";
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("H263"); capa["codecs"][0u][0u].append("H263");
capa["codecs"][0u][0u].append("VP6"); capa["codecs"][0u][0u].append("VP6");

View file

@ -12,6 +12,7 @@ namespace Mist{
capa["source_match"].append("/*.mk3d"); capa["source_match"].append("/*.mk3d");
capa["source_match"].append("/*.mks"); capa["source_match"].append("/*.mks");
capa["source_match"].append("/*.webm"); capa["source_match"].append("/*.webm");
capa["source_file"] = "$source";
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["codecs"].append("H264"); capa["codecs"].append("H264");
capa["codecs"].append("HEVC"); capa["codecs"].append("HEVC");

View file

@ -19,6 +19,7 @@ namespace Mist {
capa["name"] = "FLV"; capa["name"] = "FLV";
capa["desc"] = "Allows loading FLV files for Video on Demand."; capa["desc"] = "Allows loading FLV files for Video on Demand.";
capa["source_match"] = "/*.flv"; capa["source_match"] = "/*.flv";
capa["source_file"] = "$source";
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");
capa["codecs"][0u][0u].append("H263"); capa["codecs"][0u][0u].append("H263");

View file

@ -11,6 +11,7 @@ namespace Mist {
capa["name"] = "Folder"; capa["name"] = "Folder";
capa["desc"] = "The folder input will make available all supported files in the given folder as streams under this stream name, in the format STREAMNAME+FILENAME. For example, if your stream is called 'files' and you have a file called 'movie.flv', you could access this file streamed as 'files+movie.flv'. This input does not support subdirectories. To support more complex libraries, look into the documentation for the STREAM_SOURCE trigger."; capa["desc"] = "The folder input will make available all supported files in the given folder as streams under this stream name, in the format STREAMNAME+FILENAME. For example, if your stream is called 'files' and you have a file called 'movie.flv', you could access this file streamed as 'files+movie.flv'. This input does not support subdirectories. To support more complex libraries, look into the documentation for the STREAM_SOURCE trigger.";
capa["source_match"] = "/*/"; capa["source_match"] = "/*/";
capa["source_file"] = "$source/$wildcard";
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["morphic"] = 1ll; capa["morphic"] = 1ll;
} }

View file

@ -17,6 +17,7 @@ namespace Mist {
capa["name"] = "MP3"; capa["name"] = "MP3";
capa["desc"] = "This input allows you to stream MP3 Video on Demand files."; capa["desc"] = "This input allows you to stream MP3 Video on Demand files.";
capa["source_match"] = "/*.mp3"; capa["source_match"] = "/*.mp3";
capa["source_file"] = "$source";
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["codecs"][0u][0u].append("MP3"); capa["codecs"][0u][0u].append("MP3");
timestamp = 0; timestamp = 0;

View file

@ -160,6 +160,7 @@ namespace Mist{
capa["name"] = "MP4"; capa["name"] = "MP4";
capa["desc"] = "This input allows streaming of MP4 files as Video on Demand."; capa["desc"] = "This input allows streaming of MP4 files as Video on Demand.";
capa["source_match"] = "/*.mp4"; capa["source_match"] = "/*.mp4";
capa["source_file"] = "$source";
capa["priority"] = 9ll; capa["priority"] = 9ll;
capa["codecs"][0u][0u].append("HEVC"); capa["codecs"][0u][0u].append("HEVC");
capa["codecs"][0u][0u].append("H264"); capa["codecs"][0u][0u].append("H264");

View file

@ -48,6 +48,7 @@ namespace Mist {
capa["name"] = "OGG"; capa["name"] = "OGG";
capa["desc"] = "This input allows streaming of OGG files as Video on Demand."; capa["desc"] = "This input allows streaming of OGG files as Video on Demand.";
capa["source_match"] = "/*.ogg"; capa["source_match"] = "/*.ogg";
capa["source_file"] = "$source";
capa["codecs"][0u][0u].append("theora"); capa["codecs"][0u][0u].append("theora");
capa["codecs"][0u][1u].append("vorbis"); capa["codecs"][0u][1u].append("vorbis");
capa["codecs"][0u][1u].append("opus"); capa["codecs"][0u][1u].append("opus");

View file

@ -113,6 +113,7 @@ namespace Mist {
capa["name"] = "TS"; capa["name"] = "TS";
capa["desc"] = "This input allows you to stream MPEG2-TS data from static files (/*.ts), streamed files or named pipes (stream://*.ts), streamed over HTTP (http://*.ts, http-ts://*), standard input (ts-exec:*), or multicast/unicast UDP sockets (tsudp://*)."; capa["desc"] = "This input allows you to stream MPEG2-TS data from static files (/*.ts), streamed files or named pipes (stream://*.ts), streamed over HTTP (http://*.ts, http-ts://*), standard input (ts-exec:*), or multicast/unicast UDP sockets (tsudp://*).";
capa["source_match"].append("/*.ts"); capa["source_match"].append("/*.ts");
capa["source_file"] = "$source";
capa["source_match"].append("stream://*.ts"); capa["source_match"].append("stream://*.ts");
capa["source_match"].append("tsudp://*"); capa["source_match"].append("tsudp://*");
capa["source_match"].append("ts-exec:*"); capa["source_match"].append("ts-exec:*");