diff --git a/trunk/src/app/srs_app_config.cpp b/trunk/src/app/srs_app_config.cpp index 8f82544f39..24c70992a8 100644 --- a/trunk/src/app/srs_app_config.cpp +++ b/trunk/src/app/srs_app_config.cpp @@ -47,6 +47,7 @@ using namespace std; #include #include #include +#include using namespace _srs_internal; @@ -332,6 +333,31 @@ int SrsConfDirective::persistence(SrsFileWriter* writer, int level) return ret; } +SrsAmf0StrictArray* SrsConfDirective::dumps_args() +{ + SrsAmf0StrictArray* arr = SrsAmf0Any::strict_array(); + for (int i = 0; i < (int)args.size(); i++) { + string arg = args.at(i); + arr->append(SrsAmf0Any::str(arg.c_str())); + } + return arr; +} + +SrsAmf0Any* SrsConfDirective::dumps_arg0_to_str() +{ + return SrsAmf0Any::str(arg0().c_str()); +} + +SrsAmf0Any* SrsConfDirective::dumps_arg0_to_number() +{ + return SrsAmf0Any::number(::atof(arg0().c_str())); +} + +SrsAmf0Any* SrsConfDirective::dumps_arg0_to_boolean() +{ + return SrsAmf0Any::boolean(arg0() == "on"); +} + // see: ngx_conf_parse int SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type) { @@ -1547,6 +1573,208 @@ int SrsConfig::persistence() return ret; } +int SrsConfig::global_to_json(SrsAmf0Object* obj) +{ + int ret = ERROR_SUCCESS; + + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* dir = root->directives.at(i); + if (dir->is_vhost()) { + continue; + } + + if (dir->name == "listen") { + obj->set(dir->name, dir->dumps_args()); + } else if (dir->name == "pid") { + obj->set(dir->name, dir->dumps_arg0_to_str()); + } else if (dir->name == "chunk_size") { + obj->set(dir->name, dir->dumps_arg0_to_number()); + } else if (dir->name == "ff_log_dir") { + obj->set(dir->name, dir->dumps_arg0_to_str()); + } else if (dir->name == "srs_log_tank") { + obj->set(dir->name, dir->dumps_arg0_to_str()); + } else if (dir->name == "srs_log_level") { + obj->set(dir->name, dir->dumps_arg0_to_str()); + } else if (dir->name == "srs_log_file") { + obj->set(dir->name, dir->dumps_arg0_to_str()); + } else if (dir->name == "max_connections") { + obj->set(dir->name, dir->dumps_arg0_to_number()); + } else if (dir->name == "daemon") { + obj->set(dir->name, dir->dumps_arg0_to_boolean()); + } else if (dir->name == "utc_time") { + obj->set(dir->name, dir->dumps_arg0_to_boolean()); + } else if (dir->name == "pithy_print_ms") { + obj->set(dir->name, dir->dumps_arg0_to_number()); + } else if (dir->name == "heartbeat") { + SrsAmf0Object* sobj = SrsAmf0Any::object(); + for (int j = 0; j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name == "enabled") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } else if (sdir->name == "interval") { + sobj->set(sdir->name, sdir->dumps_arg0_to_number()); + } else if (sdir->name == "url") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "device_id") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "summaries") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } + } + obj->set(dir->name, sobj); + } else if (dir->name == "stats") { + SrsAmf0Object* sobj = SrsAmf0Any::object(); + for (int j = 0; j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name == "network") { + sobj->set(sdir->name, sdir->dumps_arg0_to_number()); + } else if (sdir->name == "disk") { + sobj->set(sdir->name, sdir->dumps_args()); + } + } + obj->set(dir->name, sobj); + } else if (dir->name == "http_api") { + SrsAmf0Object* sobj = SrsAmf0Any::object(); + for (int j = 0; j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name == "enabled") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } else if (sdir->name == "listen") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "crossdomain") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } else if (sdir->name == "raw_api") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } + } + obj->set(dir->name, sobj); + } else if (dir->name == "http_server") { + SrsAmf0Object* sobj = SrsAmf0Any::object(); + for (int j = 0; j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name == "enabled") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } else if (sdir->name == "listen") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "dir") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } + } + obj->set(dir->name, sobj); + } else if (dir->name == "stream_caster") { + SrsAmf0Object* sobj = SrsAmf0Any::object(); + for (int j = 0; j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name == "enabled") { + sobj->set(sdir->name, sdir->dumps_arg0_to_boolean()); + } else if (sdir->name == "caster") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "output") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "listen") { + sobj->set(sdir->name, sdir->dumps_arg0_to_str()); + } else if (sdir->name == "rtp_port_min") { + sobj->set(sdir->name, sdir->dumps_arg0_to_number()); + } else if (sdir->name == "rtp_port_max") { + sobj->set(sdir->name, sdir->dumps_arg0_to_number()); + } + } + obj->set(dir->name, sobj); + } else { + continue; + } + } + + SrsAmf0Object* sobjs = SrsAmf0Any::object(); + int nb_vhosts = 0; + + for (int i = 0; i < (int)root->directives.size(); i++) { + SrsConfDirective* dir = root->directives.at(i); + if (!dir->is_vhost()) { + continue; + } + + nb_vhosts++; + SrsAmf0Object* sobj = SrsAmf0Any::object(); + sobjs->set(dir->arg0(), sobj); + + sobj->set("enabled", SrsAmf0Any::boolean(get_vhost_enabled(dir->name))); + sobj->set("dvr", SrsAmf0Any::boolean(get_dvr_enabled(dir->name))); + sobj->set("http_static", SrsAmf0Any::boolean(get_vhost_http_enabled(dir->name))); + sobj->set("http_remux", SrsAmf0Any::boolean(get_vhost_http_remux_enabled(dir->name))); + sobj->set("hls", SrsAmf0Any::boolean(get_hls_enabled(dir->name))); + sobj->set("hds", SrsAmf0Any::boolean(get_hds_enabled(dir->name))); + sobj->set("http_hooks", SrsAmf0Any::boolean(get_vhost_http_hooks(dir->name))); + sobj->set("exec", SrsAmf0Any::boolean(get_exec_enabled(dir->name))); + sobj->set("bandcheck", SrsAmf0Any::boolean(get_bw_check_enabled(dir->name))); + sobj->set("origin", SrsAmf0Any::boolean(!get_vhost_is_edge(dir->name))); + sobj->set("forward", SrsAmf0Any::boolean(get_forward(dir->name))); + + sobj->set("security", SrsAmf0Any::boolean(get_security_enabled(dir->name))); + sobj->set("refer", SrsAmf0Any::boolean(get_refer(dir->name) || get_refer_play(dir->name) || get_refer_publish(dir->name))); + + sobj->set("mr", SrsAmf0Any::boolean(get_mr_enabled(dir->name))); + sobj->set("min_latency", SrsAmf0Any::boolean(get_realtime_enabled(dir->name))); + sobj->set("gop_cache", SrsAmf0Any::boolean(get_gop_cache(dir->name))); + sobj->set("tcp_nodelay", SrsAmf0Any::boolean(get_tcp_nodelay(dir->name))); + + sobj->set("mix_correct", SrsAmf0Any::boolean(get_mix_correct(dir->name))); + sobj->set("time_jitter", SrsAmf0Any::boolean(get_time_jitter(dir->name) != SrsRtmpJitterAlgorithmOFF)); + sobj->set("atc", SrsAmf0Any::boolean(get_atc(dir->name))); + + bool has_transcode = false; + for (int j = 0; !has_transcode && j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name != "transcode") { + continue; + } + + if (!get_transcode_enabled(sdir)) { + continue; + } + + for (int k = 0; !has_transcode && k < (int)sdir->directives.size(); k++) { + SrsConfDirective* ssdir = sdir->directives.at(k); + if (ssdir->name != "engine") { + continue; + } + + if (get_engine_enabled(ssdir)) { + has_transcode = true; + break; + } + } + } + sobj->set("transcode", SrsAmf0Any::boolean(has_transcode)); + + bool has_ingest = false; + for (int j = 0; !has_ingest && j < (int)dir->directives.size(); j++) { + SrsConfDirective* sdir = dir->directives.at(j); + if (sdir->name != "ingest") { + continue; + } + + if (get_ingest_enabled(sdir)) { + has_ingest = true; + break; + } + } + sobj->set("ingest", SrsAmf0Any::boolean(has_ingest)); + } + + obj->set("nb_vhosts", SrsAmf0Any::number(nb_vhosts)); + obj->set("vhosts", sobjs); + + return ret; +} + +int SrsConfig::vhost_to_json(SrsConfDirective* vhost, SrsAmf0Object* obj) +{ + int ret = ERROR_SUCCESS; + + return ret; +} + string SrsConfig::config() { return config_file; diff --git a/trunk/src/app/srs_app_config.hpp b/trunk/src/app/srs_app_config.hpp index a3fcaa2afb..becc22da02 100644 --- a/trunk/src/app/srs_app_config.hpp +++ b/trunk/src/app/srs_app_config.hpp @@ -31,10 +31,14 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. #include #include +#include #include class SrsFileWriter; +class SrsAmf0Object; +class SrsAmf0StrictArray; +class SrsAmf0Any; namespace _srs_internal { @@ -143,6 +147,16 @@ class SrsConfDirective * @param level, the root is level0, all its directives are level1, and so on. */ virtual int persistence(SrsFileWriter* writer, int level); + /** + * dumps the args[0-N] to array(string). + */ + virtual SrsAmf0StrictArray* dumps_args(); + /** + * dumps arg0 to str, number or boolean. + */ + virtual SrsAmf0Any* dumps_arg0_to_str(); + virtual SrsAmf0Any* dumps_arg0_to_number(); + virtual SrsAmf0Any* dumps_arg0_to_boolean(); // private parse. private: /** @@ -298,6 +312,14 @@ class SrsConfig * persistence current config to file. */ virtual int persistence(); + /** + * dumps the global sections to json. + */ + virtual int global_to_json(SrsAmf0Object* obj); + /** + * dumps the vhost section to json. + */ + virtual int vhost_to_json(SrsConfDirective* vhost, SrsAmf0Object* obj); /** * get the config file path. */ diff --git a/trunk/src/app/srs_app_http_api.cpp b/trunk/src/app/srs_app_http_api.cpp index 2c6eed4e2e..bbbdeb2ccd 100755 --- a/trunk/src/app/srs_app_http_api.cpp +++ b/trunk/src/app/srs_app_http_api.cpp @@ -44,6 +44,7 @@ using namespace std; #include #include #include +#include int srs_api_response_jsonp(ISrsHttpResponseWriter* w, string callback, string data) { @@ -872,6 +873,63 @@ int SrsGoApiRaw::serve_http(ISrsHttpResponseWriter* w, ISrsHttpMessage* r) return srs_api_response_code(w, r, ret); } + // for rpc=config_query, to get the configs of server. + // @param scope the scope to query for config, it can be: + // global, the configs belongs to the root, donot includes any sub directives. + // vhost, the configs for specified vhost by @param vhost. + // @param vhost the vhost name for @param scope is vhost to query config. + // for the default vhost, must be __defaultVhost__ + if (rpc == "config_query") { + std::string scope = r->query_get("scope"); + std::string vhost = r->query_get("vhost"); + if (scope.empty() || (scope != "global" && scope != "vhost")) { + ret = ERROR_SYSTEM_CONFIG_RAW_PARAMS; + srs_error("raw api config_query invalid scope=%s. ret=%d", scope.c_str(), ret); + return srs_api_response_code(w, r, ret); + } + + // config query. + SrsAmf0Object* obj = SrsAmf0Any::object(); + SrsAutoFree(SrsAmf0Object, obj); + + obj->set("code", SrsAmf0Any::number(ERROR_SUCCESS)); + + if (scope == "vhost") { + // query vhost scope. + if (vhost.empty()) { + ret = ERROR_SYSTEM_CONFIG_RAW_PARAMS; + srs_error("raw api config_query vhost invalid vhost=%s. ret=%d", vhost.c_str(), ret); + return ret; + } + + SrsConfDirective* root = _srs_config->get_root(); + SrsConfDirective* conf = root->get("vhost", vhost); + if (!conf) { + ret = ERROR_SYSTEM_CONFIG_RAW_PARAMS; + srs_error("raw api config_query vhost invalid vhost=%s. ret=%d", vhost.c_str(), ret); + return ret; + } + + SrsAmf0Object* data = SrsAmf0Any::object(); + obj->set("vhost", data); + if ((ret = _srs_config->vhost_to_json(conf, data)) != ERROR_SUCCESS) { + srs_error("raw api config_query vhost failed. ret=%d", ret); + return srs_api_response_code(w, r, ret); + } + } else { + SrsAmf0Object* data = SrsAmf0Any::object(); + obj->set("global", data); + + // query global scope. + if ((ret = _srs_config->global_to_json(data)) != ERROR_SUCCESS) { + srs_error("raw api config_query global failed. ret=%d", ret); + return srs_api_response_code(w, r, ret); + } + } + + return srs_api_response(w, r, obj->to_json()); + } + return ret; } diff --git a/trunk/src/protocol/srs_rtmp_amf0.cpp b/trunk/src/protocol/srs_rtmp_amf0.cpp index 78db3c64cb..1f8206f2a0 100644 --- a/trunk/src/protocol/srs_rtmp_amf0.cpp +++ b/trunk/src/protocol/srs_rtmp_amf0.cpp @@ -31,6 +31,7 @@ using namespace std; #include #include #include +#include using namespace _srs_internal; @@ -275,12 +276,58 @@ char* SrsAmf0Any::human_print(char** pdata, int* psize) *pdata = data; } if (psize) { - *psize = str.length(); + *psize = (int)str.length(); } return data; } +string SrsAmf0Any::to_json() +{ + switch (marker) { + case RTMP_AMF0_String: { + return "\"" + to_str() + "\""; + } + case RTMP_AMF0_Boolean: { + return to_boolean()? "true":"false"; + } + case RTMP_AMF0_Number: { + // len(max int64_t) is 20, plus one "+-." + char tmp[22]; + snprintf(tmp, 22, "%f", to_number()); + return tmp; + } + case RTMP_AMF0_Null: { + return "null"; + } + case RTMP_AMF0_Undefined: { + return "null"; + } + case RTMP_AMF0_Object: { + SrsAmf0Object* obj = to_object(); + return obj->to_json(); + } + case RTMP_AMF0_EcmaArray: { + SrsAmf0EcmaArray* arr = to_ecma_array(); + return arr->to_json(); + } + case RTMP_AMF0_StrictArray: { + SrsAmf0StrictArray* arr = to_strict_array(); + return arr->to_json(); + } + case RTMP_AMF0_Date: { + // TODO: FIXME: support amf0 data to json. + return "null"; + } + case RTMP_AMF0_Invalid: + default: { + break; + } + } + + return "null"; +} + SrsAmf0Any* SrsAmf0Any::str(const char* value) { return new SrsAmf0String(value); @@ -742,6 +789,27 @@ SrsAmf0Any* SrsAmf0Object::copy() return copy; } +string SrsAmf0Object::to_json() +{ + stringstream ss; + + ss << SRS_JOBJECT_START; + + for (int i = 0; i < properties->count(); i++) { + std::string name = this->key_at(i); + SrsAmf0Any* any = this->value_at(i); + + ss << SRS_JFIELD_NAME(name) << any->to_json(); + if (i < properties->count() - 1) { + ss << SRS_JFIELD_CONT; + } + } + + ss << SRS_JOBJECT_END; + + return ss.str(); +} + void SrsAmf0Object::clear() { properties->clear(); @@ -943,6 +1011,27 @@ SrsAmf0Any* SrsAmf0EcmaArray::copy() return copy; } +string SrsAmf0EcmaArray::to_json() +{ + stringstream ss; + + ss << SRS_JOBJECT_START; + + for (int i = 0; i < properties->count(); i++) { + std::string name = this->key_at(i); + SrsAmf0Any* any = this->value_at(i); + + ss << SRS_JFIELD_NAME(name) << any->to_json(); + if (i < properties->count() - 1) { + ss << SRS_JFIELD_CONT; + } + } + + ss << SRS_JOBJECT_END; + + return ss.str(); +} + void SrsAmf0EcmaArray::clear() { properties->clear(); @@ -1118,6 +1207,27 @@ SrsAmf0Any* SrsAmf0StrictArray::copy() return copy; } +string SrsAmf0StrictArray::to_json() +{ + stringstream ss; + + ss << SRS_JARRAY_START; + + for (int i = 0; i < (int)properties.size(); i++) { + SrsAmf0Any* any = properties[i]; + + ss << any->to_json(); + + if (i < (int)properties.size() - 1) { + ss << SRS_JFIELD_CONT; + } + } + + ss << SRS_JARRAY_END; + + return ss.str(); +} + void SrsAmf0StrictArray::clear() { properties.clear(); @@ -1125,7 +1235,7 @@ void SrsAmf0StrictArray::clear() int SrsAmf0StrictArray::count() { - return properties.size(); + return (int)properties.size(); } SrsAmf0Any* SrsAmf0StrictArray::at(int index) diff --git a/trunk/src/protocol/srs_rtmp_amf0.hpp b/trunk/src/protocol/srs_rtmp_amf0.hpp index 6b697c9aca..959bc1a527 100644 --- a/trunk/src/protocol/srs_rtmp_amf0.hpp +++ b/trunk/src/protocol/srs_rtmp_amf0.hpp @@ -272,6 +272,12 @@ class SrsAmf0Any * @remark user must free the data returned or output by pdata. */ virtual char* human_print(char** pdata, int* psize); +// json +public: + /** + * convert the amf0 stuff to json. + */ + virtual std::string to_json(); // create AMF0 instance. public: /** @@ -351,6 +357,12 @@ class SrsAmf0Object : public SrsAmf0Any virtual int read(SrsStream* stream); virtual int write(SrsStream* stream); virtual SrsAmf0Any* copy(); +// json +public: + /** + * convert the amf0 object to json. + */ + virtual std::string to_json(); // properties iteration public: /** @@ -434,6 +446,12 @@ class SrsAmf0EcmaArray : public SrsAmf0Any virtual int read(SrsStream* stream); virtual int write(SrsStream* stream); virtual SrsAmf0Any* copy(); +// json +public: + /** + * convert the amf0 ecma array to json. + */ + virtual std::string to_json(); // properties iteration public: /** @@ -515,6 +533,12 @@ class SrsAmf0StrictArray : public SrsAmf0Any virtual int read(SrsStream* stream); virtual int write(SrsStream* stream); virtual SrsAmf0Any* copy(); +// json +public: + /** + * convert the amf0 strict array to json. + */ + virtual std::string to_json(); // properties iteration public: /**