From d6355efe224c3ad305469c3efd7728a0e1b77199 Mon Sep 17 00:00:00 2001 From: winlin Date: Sun, 18 May 2014 16:15:35 +0800 Subject: [PATCH] support http api json, to PUT/POST, to 0.9.103 --- trunk/src/app/srs_app_config.cpp | 158 ++++++++++++++++++++++++----- trunk/src/app/srs_app_config.hpp | 21 +++- trunk/src/app/srs_app_http.cpp | 40 ++++++++ trunk/src/app/srs_app_http.hpp | 13 ++- trunk/src/app/srs_app_http_api.cpp | 103 +++++++++++++++++++ trunk/src/app/srs_app_http_api.hpp | 23 +++++ trunk/src/app/srs_app_json.cpp | 20 +++- trunk/src/app/srs_app_json.hpp | 1 + trunk/src/app/srs_app_log.cpp | 10 +- trunk/src/app/srs_app_utility.cpp | 10 +- trunk/src/core/srs_core.hpp | 2 +- 11 files changed, 358 insertions(+), 43 deletions(-) diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index be3a7eb3d..a2ef152ad 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -184,6 +184,14 @@ string SrsConfDirective::arg2() return ""; } +void SrsConfDirective::set_arg0(string value) +{ + if (args.size() > 0) { + args[0] = value; + } + args.push_back(value); +} + SrsConfDirective* SrsConfDirective::at(int index) { return directives.at(index); @@ -529,38 +537,23 @@ int SrsConfig::reload() // merge config: srs_log_tank if (!srs_directive_equals(root->get("srs_log_tank"), old_root->get("srs_log_tank"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_tank()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_tank failed. ret=%d", ret); - return ret; - } + if ((ret = force_reload_log_tank()) != ERROR_SUCCESS) { + return ret; } - srs_trace("reload srs_log_tank success."); } // merge config: srs_log_level if (!srs_directive_equals(root->get("srs_log_level"), old_root->get("srs_log_level"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_level()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_level failed. ret=%d", ret); - return ret; - } + if ((ret = force_reload_log_level()) != ERROR_SUCCESS) { + return ret; } - srs_trace("reload srs_log_level success."); } // merge config: srs_log_file if (!srs_directive_equals(root->get("srs_log_file"), old_root->get("srs_log_file"))) { - for (it = subscribes.begin(); it != subscribes.end(); ++it) { - ISrsReloadHandler* subscribe = *it; - if ((ret = subscribe->on_reload_log_file()) != ERROR_SUCCESS) { - srs_error("notify subscribes reload srs_log_file failed. ret=%d", ret); - return ret; - } + if ((ret = force_reload_log_file()) != ERROR_SUCCESS) { + return ret; } - srs_trace("reload srs_log_file success."); } // merge config: pithy_print @@ -593,6 +586,117 @@ int SrsConfig::reload() return ret; } +SrsConfDirective* SrsConfig::get_or_create(SrsConfDirective* node, string name) +{ + srs_assert(node); + + SrsConfDirective* conf = node->get(name); + + if (!conf) { + conf = new SrsConfDirective(); + conf->name = name; + node->directives.push_back(conf); + } + + return conf; +} + +bool SrsConfig::set_log_file(string file) +{ + if (file == get_log_file()) { + return false; + } + + SrsConfDirective* conf = get_or_create(root, "srs_log_file"); + srs_assert(conf); + conf->set_arg0(file); + + return true; +} + +bool SrsConfig::set_log_tank(string tank) +{ + if (get_log_tank_file() && tank != "console") { + return false; + } + if (!get_log_tank_file() && tank == "console") { + return false; + } + + SrsConfDirective* conf = get_or_create(root, "srs_log_tank"); + srs_assert(conf); + conf->set_arg0(tank); + + return true; +} + +bool SrsConfig::set_log_level(string level) +{ + if (level == get_log_level()) { + return false; + } + + SrsConfDirective* conf = get_or_create(root, "srs_log_level"); + srs_assert(conf); + conf->set_arg0(level); + + return true; +} + +int SrsConfig::force_reload_log_file() +{ + int ret = ERROR_SUCCESS; + + std::vector::iterator it; + + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_file()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_file failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_file success."); + + return ret; +} + +int SrsConfig::force_reload_log_tank() +{ + int ret = ERROR_SUCCESS; + + std::vector::iterator it; + + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_tank()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_tank failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_tank success."); + + return ret; +} + +int SrsConfig::force_reload_log_level() +{ + int ret = ERROR_SUCCESS; + + std::vector::iterator it; + + for (it = subscribes.begin(); it != subscribes.end(); ++it) { + ISrsReloadHandler* subscribe = *it; + if ((ret = subscribe->on_reload_log_level()) != ERROR_SUCCESS) { + srs_error("notify subscribes reload srs_log_level failed. ret=%d", ret); + return ret; + } + } + srs_trace("reload srs_log_level success."); + + return ret; +} + int SrsConfig::reload_http_api(SrsConfDirective* old_root) { int ret = ERROR_SUCCESS; @@ -1171,13 +1275,13 @@ int SrsConfig::parse_file(const char* filename) // TODO: check pid. // check log - std::string log_filename = this->get_srs_log_file(); - if (get_srs_log_tank_file() && log_filename.empty()) { + std::string log_filename = this->get_log_file(); + if (get_log_tank_file() && log_filename.empty()) { ret = ERROR_SYSTEM_CONFIG_INVALID; srs_error("must specifies the file to write log to. ret=%d", ret); return ret; } - if (get_srs_log_tank_file()) { + if (get_log_tank_file()) { srs_trace("write log to file %s", log_filename.c_str()); srs_trace("you can: tailf %s", log_filename.c_str()); srs_trace("@see: %s", SRS_WIKI_URL_LOG); @@ -2293,7 +2397,7 @@ string SrsConfig::get_ingest_input_url(SrsConfDirective* ingest) return conf->arg0(); } -string SrsConfig::get_srs_log_file() +string SrsConfig::get_log_file() { srs_assert(root); @@ -2317,7 +2421,7 @@ string SrsConfig::get_ffmpeg_log_dir() return conf->arg0(); } -string SrsConfig::get_srs_log_level() +string SrsConfig::get_log_level() { srs_assert(root); @@ -2329,7 +2433,7 @@ string SrsConfig::get_srs_log_level() return conf->arg0(); } -bool SrsConfig::get_srs_log_tank_file() +bool SrsConfig::get_log_tank_file() { srs_assert(root); diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index a61622be8..4135730b6 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -96,6 +96,7 @@ public: std::string arg0(); std::string arg1(); std::string arg2(); + void set_arg0(std::string value); SrsConfDirective* at(int index); SrsConfDirective* get(std::string _name); SrsConfDirective* get(std::string _name, std::string _arg0); @@ -135,6 +136,20 @@ public: virtual void subscribe(ISrsReloadHandler* handler); virtual void unsubscribe(ISrsReloadHandler* handler); virtual int reload(); +private: + virtual SrsConfDirective* get_or_create(SrsConfDirective* node, std::string name); +public: + /** + * dynamic set the config, for instance, for http api to set, + * @return ture if config changed and need to reload. + */ + virtual bool set_log_file(std::string file); + virtual bool set_log_tank(std::string tank); + virtual bool set_log_level(std::string level); +public: + virtual int force_reload_log_file(); + virtual int force_reload_log_tank(); + virtual int force_reload_log_level(); private: virtual int reload_http_api(SrsConfDirective* old_root); virtual int reload_http_stream(SrsConfDirective* old_root); @@ -231,9 +246,9 @@ public: virtual std::string get_ingest_input_url(SrsConfDirective* ingest); // log section public: - virtual bool get_srs_log_tank_file(); - virtual std::string get_srs_log_level(); - virtual std::string get_srs_log_file(); + virtual bool get_log_tank_file(); + virtual std::string get_log_level(); + virtual std::string get_log_file(); virtual std::string get_ffmpeg_log_dir(); // hls section private: diff --git a/trunk/src/app/srs_app_http.cpp b/trunk/src/app/srs_app_http.cpp index 363cdbf61..4999896dd 100644 --- a/trunk/src/app/srs_app_http.cpp +++ b/trunk/src/app/srs_app_http.cpp @@ -134,6 +134,17 @@ int SrsHttpHandler::do_process_request(SrsSocket* /*skt*/, SrsHttpMessage* /*req return ret; } +int SrsHttpHandler::response_error(SrsSocket* skt, SrsHttpMessage* req, int code, string desc) +{ + std::stringstream ss; + ss << JOBJECT_START + << JFIELD_ERROR(code) << JFIELD_CONT + << JFIELD_STR("desc", desc) + << JOBJECT_END; + + return res_json(skt, req, ss.str()); +} + int SrsHttpHandler::best_match(const char* path, int length, SrsHttpHandlerMatch** ppmatch) { int ret = ERROR_SUCCESS; @@ -566,6 +577,26 @@ u_int8_t SrsHttpMessage::method() return (u_int8_t)_header.method; } +bool SrsHttpMessage::is_http_get() +{ + return _header.method == HTTP_GET; +} + +bool SrsHttpMessage::is_http_put() +{ + return _header.method == HTTP_PUT; +} + +bool SrsHttpMessage::is_http_post() +{ + return _header.method == HTTP_POST; +} + +bool SrsHttpMessage::is_http_delete() +{ + return _header.method == HTTP_DELETE; +} + string SrsHttpMessage::url() { return _uri->get_url(); @@ -592,6 +623,15 @@ string SrsHttpMessage::body() return b; } +char* SrsHttpMessage::body_raw() +{ + if (_body && !_body->empty()) { + return _body->bytes(); + } + + return NULL; +} + int64_t SrsHttpMessage::body_size() { return (int64_t)_body->size(); diff --git a/trunk/src/app/srs_app_http.hpp b/trunk/src/app/srs_app_http.hpp index 331bd40e8..9c54aa1e6 100644 --- a/trunk/src/app/srs_app_http.hpp +++ b/trunk/src/app/srs_app_http.hpp @@ -228,9 +228,15 @@ protected: */ virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); /** - * do the actual process of request. + * do the actual process of request., format as, for example: + * {"code":0, "data":{}} */ virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); + /** + * response error, format as, for example: + * {"code":100, "desc":"description"} + */ + virtual int response_error(SrsSocket* skt, SrsHttpMessage* req, int code, std::string desc); // response writer public: virtual SrsHttpHandler* res_status_line(std::stringstream& ss); @@ -327,10 +333,15 @@ public: public: virtual bool is_complete(); virtual u_int8_t method(); + virtual bool is_http_get(); + virtual bool is_http_put(); + virtual bool is_http_post(); + virtual bool is_http_delete(); virtual std::string url(); virtual std::string path(); virtual std::string query(); virtual std::string body(); + virtual char* body_raw(); virtual int64_t body_size(); virtual int64_t content_length(); virtual SrsHttpHandlerMatch* match(); diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 7ed088219..608d779c2 100644 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -123,6 +123,7 @@ SrsApiV1::SrsApiV1() handlers.push_back(new SrsApiSystemProcStats()); handlers.push_back(new SrsApiMemInfos()); handlers.push_back(new SrsApiAuthors()); + handlers.push_back(new SrsApiConfigs()); } SrsApiV1::~SrsApiV1() @@ -147,6 +148,7 @@ int SrsApiV1::do_process_request(SrsSocket* skt, SrsHttpMessage* req) << JFIELD_STR("self_proc_stats", "the self process stats") << JFIELD_CONT << JFIELD_STR("system_proc_stats", "the system process stats") << JFIELD_CONT << JFIELD_STR("meminfos", "the meminfo of system") << JFIELD_CONT + << JFIELD_STR("configs", "to query or modify the config of srs") << JFIELD_CONT << JFIELD_STR("authors", "the primary authors and contributors") << JOBJECT_END << JOBJECT_END; @@ -154,6 +156,107 @@ int SrsApiV1::do_process_request(SrsSocket* skt, SrsHttpMessage* req) return res_json(skt, req, ss.str()); } +SrsApiConfigs::SrsApiConfigs() +{ + handlers.push_back(new SrsApiConfigsLogs()); +} + +SrsApiConfigs::~SrsApiConfigs() +{ +} + +bool SrsApiConfigs::can_handle(const char* path, int length, const char** /*pchild*/) +{ + return srs_path_equals("/configs", path, length); +} + +int SrsApiConfigs::do_process_request(SrsSocket* skt, SrsHttpMessage* req) +{ + std::stringstream ss; + + ss << JOBJECT_START + << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT + << JFIELD_ORG("urls", JOBJECT_START) + << JFIELD_STR("logs", "the log level, tank and path") + << JOBJECT_END + << JOBJECT_END; + + return res_json(skt, req, ss.str()); +} + +SrsApiConfigsLogs::SrsApiConfigsLogs() +{ +} + +SrsApiConfigsLogs::~SrsApiConfigsLogs() +{ +} + +bool SrsApiConfigsLogs::can_handle(const char* path, int length, const char** /*pchild*/) +{ + return srs_path_equals("/logs", path, length); +} + +bool SrsApiConfigsLogs::is_handler_valid(SrsHttpMessage* req, int& status_code, string& reason_phrase) +{ + if (!req->is_http_get() && !req->is_http_put()) { + status_code = HTTP_MethodNotAllowed; + reason_phrase = HTTP_MethodNotAllowed_str; + + return false; + } + + return SrsHttpHandler::is_handler_valid(req, status_code, reason_phrase); +} + +int SrsApiConfigsLogs::do_process_request(SrsSocket* skt, SrsHttpMessage* req) +{ + int ret = ERROR_SUCCESS; + + if (req->is_http_put()) { + srs_trace("http api PUT logs, req is: %s", req->body().c_str()); + + SrsJsonAny* json = SrsJsonAny::loads(req->body_raw()); + SrsAutoFree(SrsJsonAny, json); + + if (json->is_object()) { + SrsJsonObject* o = json->to_object(); + SrsJsonAny* prop = NULL; + if ((prop = o->ensure_property_string("file")) != NULL && _srs_config->set_log_file(prop->to_str())) { + if ((ret = _srs_config->force_reload_log_file()) != ERROR_SUCCESS) { + return response_error(skt, req, ret, "reload log file failed"); + } + srs_warn("http api reload log file to %s", prop->to_str().c_str()); + } + if ((prop = o->ensure_property_string("tank")) != NULL && _srs_config->set_log_tank(prop->to_str())) { + if ((ret = _srs_config->force_reload_log_tank()) != ERROR_SUCCESS) { + return response_error(skt, req, ret, "reload log tank failed"); + } + srs_warn("http api reload log tank to %s", prop->to_str().c_str()); + } + if ((prop = o->ensure_property_string("level")) != NULL && _srs_config->set_log_level(prop->to_str())) { + if ((ret = _srs_config->force_reload_log_level()) != ERROR_SUCCESS) { + return response_error(skt, req, ret, "reload log level failed"); + } + srs_warn("http api reload log level to %s", prop->to_str().c_str()); + } + } + } + + std::stringstream ss; + ss << JOBJECT_START + << JFIELD_ERROR(ERROR_SUCCESS) << JFIELD_CONT + << JFIELD_ORG("data", JOBJECT_START) + << JFIELD_STR("tank", (_srs_config->get_log_tank_file()? "file":"console")) << JFIELD_CONT + << JFIELD_STR("level", _srs_config->get_log_level()) << JFIELD_CONT + << JFIELD_STR("cwd", _srs_config->cwd()) << JFIELD_CONT + << JFIELD_STR("file", _srs_config->get_log_file()) + << JOBJECT_END + << JOBJECT_END; + + return res_json(skt, req, ss.str()); +} + SrsApiVersion::SrsApiVersion() { } diff --git a/trunk/src/app/srs_app_http_api.hpp b/trunk/src/app/srs_app_http_api.hpp index 760534267..0a3de21d9 100644 --- a/trunk/src/app/srs_app_http_api.hpp +++ b/trunk/src/app/srs_app_http_api.hpp @@ -76,6 +76,29 @@ protected: virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); }; +class SrsApiConfigs : public SrsHttpHandler +{ +public: + SrsApiConfigs(); + virtual ~SrsApiConfigs(); +public: + virtual bool can_handle(const char* path, int length, const char** pchild); +protected: + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); +}; + +class SrsApiConfigsLogs : public SrsHttpHandler +{ +public: + SrsApiConfigsLogs(); + virtual ~SrsApiConfigsLogs(); +public: + virtual bool can_handle(const char* path, int length, const char** pchild); +protected: + virtual bool is_handler_valid(SrsHttpMessage* req, int& status_code, std::string& reason_phrase); + virtual int do_process_request(SrsSocket* skt, SrsHttpMessage* req); +}; + class SrsApiVersion : public SrsHttpHandler { public: diff --git a/trunk/src/app/srs_app_json.cpp b/trunk/src/app/srs_app_json.cpp index e6485540b..557d23bee 100644 --- a/trunk/src/app/srs_app_json.cpp +++ b/trunk/src/app/srs_app_json.cpp @@ -343,7 +343,10 @@ SrsJsonAny* srs_json_parse_tree_nx_json(const nx_json* node) SrsJsonAny* SrsJsonAny::loads(char* str) { - srs_assert(str); + if (!str) { + return NULL; + } + if (strlen(str) == 0) { return NULL; } @@ -430,6 +433,21 @@ SrsJsonAny* SrsJsonObject::get_property(string name) return NULL; } +SrsJsonAny* SrsJsonObject::ensure_property_string(string name) +{ + SrsJsonAny* prop = get_property(name); + + if (!prop) { + return NULL; + } + + if (!prop->is_string()) { + return NULL; + } + + return prop; +} + SrsJsonArray::SrsJsonArray() { marker = SRS_JSON_Array; diff --git a/trunk/src/app/srs_app_json.hpp b/trunk/src/app/srs_app_json.hpp index 7aee140d7..bca97a5b7 100644 --- a/trunk/src/app/srs_app_json.hpp +++ b/trunk/src/app/srs_app_json.hpp @@ -147,6 +147,7 @@ public: public: virtual void set(std::string key, SrsJsonAny* value); virtual SrsJsonAny* get_property(std::string name); + virtual SrsJsonAny* ensure_property_string(std::string name); }; class SrsJsonArray : public SrsJsonAny diff --git a/trunk/src/app/srs_app_log.cpp b/trunk/src/app/srs_app_log.cpp index 6df566178..4465048b4 100644 --- a/trunk/src/app/srs_app_log.cpp +++ b/trunk/src/app/srs_app_log.cpp @@ -88,8 +88,8 @@ int SrsFastLog::initialize() _srs_config->subscribe(this); - log_to_file_tank = _srs_config->get_srs_log_tank_file(); - _level = srs_get_log_level(_srs_config->get_srs_log_level()); + log_to_file_tank = _srs_config->get_log_tank_file(); + _level = srs_get_log_level(_srs_config->get_log_level()); return ret; } @@ -202,7 +202,7 @@ int SrsFastLog::on_reload_log_tank() int ret = ERROR_SUCCESS; bool tank = log_to_file_tank; - log_to_file_tank = _srs_config->get_srs_log_tank_file(); + log_to_file_tank = _srs_config->get_log_tank_file(); if (tank) { return ret; @@ -224,7 +224,7 @@ int SrsFastLog::on_reload_log_level() { int ret = ERROR_SUCCESS; - _level = srs_get_log_level(_srs_config->get_srs_log_level()); + _level = srs_get_log_level(_srs_config->get_log_level()); return ret; } @@ -340,7 +340,7 @@ void SrsFastLog::write_log(int& fd, char *str_log, int size, int level) void SrsFastLog::open_log_file() { - std::string filename = _srs_config->get_srs_log_file(); + std::string filename = _srs_config->get_log_file(); if (filename.empty()) { return; diff --git a/trunk/src/app/srs_app_utility.cpp b/trunk/src/app/srs_app_utility.cpp index d49dfbaa4..deb0f1239 100644 --- a/trunk/src/app/srs_app_utility.cpp +++ b/trunk/src/app/srs_app_utility.cpp @@ -31,15 +31,15 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. int srs_get_log_level(std::string level) { - if ("verbose" == _srs_config->get_srs_log_level()) { + if ("verbose" == _srs_config->get_log_level()) { return SrsLogLevel::Verbose; - } else if ("info" == _srs_config->get_srs_log_level()) { + } else if ("info" == _srs_config->get_log_level()) { return SrsLogLevel::Info; - } else if ("trace" == _srs_config->get_srs_log_level()) { + } else if ("trace" == _srs_config->get_log_level()) { return SrsLogLevel::Trace; - } else if ("warn" == _srs_config->get_srs_log_level()) { + } else if ("warn" == _srs_config->get_log_level()) { return SrsLogLevel::Warn; - } else if ("error" == _srs_config->get_srs_log_level()) { + } else if ("error" == _srs_config->get_log_level()) { return SrsLogLevel::Error; } else { return SrsLogLevel::Trace; diff --git a/trunk/src/core/srs_core.hpp b/trunk/src/core/srs_core.hpp index e04213eff..1676dd465 100644 --- a/trunk/src/core/srs_core.hpp +++ b/trunk/src/core/srs_core.hpp @@ -31,7 +31,7 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // current release version #define VERSION_MAJOR "0" #define VERSION_MINOR "9" -#define VERSION_REVISION "102" +#define VERSION_REVISION "103" #define RTMP_SIG_SRS_VERSION VERSION_MAJOR"."VERSION_MINOR"."VERSION_REVISION // server info. #define RTMP_SIG_SRS_KEY "srs"