diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 27c398ea16..9f5e74504f 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -46,6 +46,7 @@ using namespace std; #include #include #include +#include using namespace _srs_internal; @@ -240,6 +241,97 @@ int SrsConfDirective::parse(SrsConfigBuffer* buffer) return parse_conf(buffer, parse_file); } +int SrsConfDirective::persistence(SrsFileWriter* writer, int level) +{ + int ret = ERROR_SUCCESS; + + static char SPACE = SRS_CONSTS_SP; + static char SEMICOLON = SRS_CONSTS_SE; + static char LF = SRS_CONSTS_LF; + static char LB = SRS_CONSTS_LB; + static char RB = SRS_CONSTS_RB; + static const char* INDENT = " "; + + // for level0 directive, only contains sub directives. + if (level > 0) { + // indent by (level - 1) * 4 space. + for (int i = 0; i < level - 1; i++) { + if ((ret = writer->write((char*)INDENT, 4, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + // directive name. + if ((ret = writer->write((char*)name.c_str(), (int)name.length(), NULL)) != ERROR_SUCCESS) { + return ret; + } + if (!args.empty() && (ret = writer->write((char*)&SPACE, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + + // directive args. + for (int i = 0; i < (int)args.size(); i++) { + std::string& arg = args.at(i); + if ((ret = writer->write((char*)arg.c_str(), (int)arg.length(), NULL)) != ERROR_SUCCESS) { + return ret; + } + if (i < (int)args.size() - 1 && (ret = writer->write((char*)&SPACE, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + // native directive, without sub directives. + if (directives.empty()) { + if ((ret = writer->write((char*)&SEMICOLON, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + } + + // persistence all sub directives. + if (level > 0) { + if (!directives.empty()) { + if ((ret = writer->write((char*)&SPACE, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + if ((ret = writer->write((char*)&LB, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + if ((ret = writer->write((char*)&LF, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + for (int i = 0; i < (int)directives.size(); i++) { + SrsConfDirective* dir = directives.at(i); + if ((ret = dir->persistence(writer, level + 1)) != ERROR_SUCCESS) { + return ret; + } + } + + if (level > 0 && !directives.empty()) { + // indent by (level - 1) * 4 space. + for (int i = 0; i < level - 1; i++) { + if ((ret = writer->write((char*)INDENT, 4, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + if ((ret = writer->write((char*)&RB, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + + if ((ret = writer->write((char*)&LF, 1, NULL)) != ERROR_SUCCESS) { + return ret; + } + } + + + return ret; +} + // see: ngx_conf_parse int SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type) { @@ -1424,7 +1516,31 @@ int SrsConfig::parse_options(int argc, char** argv) int SrsConfig::persistence() { int ret = ERROR_SUCCESS; - // TODO: FIXME: implements it. + + // write to a tmp file, then mv to the config. + std::string path = config_file + ".tmp"; + + // open the tmp file for persistence + SrsFileWriter fw; + if ((ret = fw.open(path)) != ERROR_SUCCESS) { + return ret; + } + + // persistence root directive to writer. + if ((ret = root->persistence(&fw, 0)) != ERROR_SUCCESS) { + ::unlink(path.c_str()); + return ret; + } + + // rename the config file. + if (::rename(path.c_str(), config_file.c_str()) < 0) { + ::unlink(path.c_str()); + + ret = ERROR_SYSTEM_CONFIG_PERSISTENCE; + srs_error("rename config from %s to %s failed. ret=%d", path.c_str(), config_file.c_str(), ret); + return ret; + } + return ret; } diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index 7479c3f248..650033a27c 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -34,6 +34,8 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include +class SrsFileWriter; + namespace _srs_internal { class SrsConfigBuffer; @@ -136,6 +138,11 @@ class SrsConfDirective * parse config directive from file buffer. */ virtual int parse(_srs_internal::SrsConfigBuffer* buffer); + /** + * persistence the directive to writer. + * @param level, the root is level0, all its directives are level1, and so on. + */ + virtual int persistence(SrsFileWriter* writer, int level); // private parse. private: /** diff --git a/trunk/src/kernel/srs_kernel_consts.hpp b/trunk/src/kernel/srs_kernel_consts.hpp index 94d8ef0a3c..8b3b9bdcfb 100644 --- a/trunk/src/kernel/srs_kernel_consts.hpp +++ b/trunk/src/kernel/srs_kernel_consts.hpp @@ -194,6 +194,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define SRS_CONSTS_CR '\r' // 0x0D // LF = #define SRS_CONSTS_LF '\n' // 0x0A +// SP = +#define SRS_CONSTS_SP ' ' // 0x20 +// SE = +#define SRS_CONSTS_SE ';' // 0x3b +// LB = +#define SRS_CONSTS_LB '{' // 0x7b +// RB = +#define SRS_CONSTS_RB '}' // 0x7d /////////////////////////////////////////////////////////// // HTTP consts values diff --git a/trunk/src/kernel/srs_kernel_error.hpp b/trunk/src/kernel/srs_kernel_error.hpp index bb7fddcefb..f9df9d3924 100755 --- a/trunk/src/kernel/srs_kernel_error.hpp +++ b/trunk/src/kernel/srs_kernel_error.hpp @@ -97,6 +97,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #define ERROR_SYSTEM_DIR_EXISTS 1056 #define ERROR_SYSTEM_CREATE_DIR 1057 #define ERROR_SYSTEM_KILL 1058 +#define ERROR_SYSTEM_CONFIG_PERSISTENCE 1059 /////////////////////////////////////////////////////// // RTMP protocol error.