Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support include directive for config file #2878

Merged
merged 20 commits into from
Feb 14, 2022
Merged
Show file tree
Hide file tree
Changes from 7 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
108 changes: 91 additions & 17 deletions trunk/src/app/srs_app_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -842,9 +842,9 @@ bool SrsConfDirective::is_stream_caster()
return name == "stream_caster";
}

srs_error_t SrsConfDirective::parse(SrsConfigBuffer* buffer)
srs_error_t SrsConfDirective::parse(SrsConfigBuffer* buffer, SrsConfig* conf)
{
return parse_conf(buffer, parse_file);
return parse_conf(buffer, parse_file, conf);
}

srs_error_t SrsConfDirective::persistence(SrsFileWriter* writer, int level)
Expand Down Expand Up @@ -971,7 +971,7 @@ SrsJsonAny* SrsConfDirective::dumps_arg0_to_boolean()
// LCOV_EXCL_STOP

// see: ngx_conf_parse
srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type)
srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveType type, SrsConfig* conf)
{
srs_error_t err = srs_success;

Expand Down Expand Up @@ -1013,19 +1013,54 @@ srs_error_t SrsConfDirective::parse_conf(SrsConfigBuffer* buffer, SrsDirectiveTy
}

// build directive tree.
SrsConfDirective* directive = new SrsConfDirective();

directive->conf_line = line_start;
directive->name = args[0];
args.erase(args.begin());
directive->args.swap(args);

directives.push_back(directive);

if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_BLOCK_START) {
srs_freep(err);
if ((err = directive->parse_conf(buffer, parse_block)) != srs_success) {
return srs_error_wrap(err, "parse dir");
if (args.at(0) == "include") {
if (args.size() < 2) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "line %d: include is empty directive", buffer->line);
}

for (int i = 1; i < (int)args.size(); i++) {
std::string file = args.at(i);

srs_trace("config parse include %s", file.c_str());
srs_freep(err);
if (type != parse_block) {
if ((err = conf->parse_include_file(file.c_str())) != srs_success) {
return srs_error_wrap(err, "parse file");
}
} else {
if (file.empty()) {
winlinvip marked this conversation as resolved.
Show resolved Hide resolved
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty include config");
}

SrsConfigBuffer* config_buffer = conf->get_buffer_from_include_file(file.c_str());
winlinvip marked this conversation as resolved.
Show resolved Hide resolved

if(config_buffer == NULL) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty include config");
} else {
if ((err = parse_conf(config_buffer, parse_file, conf)) != srs_success) {
srs_freep(config_buffer);

return srs_error_wrap(err, "parse include buffer");
}
}
srs_freep(config_buffer);
}
}
} else {
SrsConfDirective* directive = new SrsConfDirective();

directive->conf_line = line_start;
directive->name = args[0];
args.erase(args.begin());
directive->args.swap(args);

directives.push_back(directive);

if (srs_error_code(err) == ERROR_SYSTEM_CONFIG_BLOCK_START) {
srs_freep(err);
if ((err = directive->parse_conf(buffer, parse_block, conf)) != srs_success) {
return srs_error_wrap(err, "parse dir");
}
}
}
srs_freep(err);
Expand Down Expand Up @@ -2419,6 +2454,45 @@ srs_error_t SrsConfig::parse_file(const char* filename)

return err;
}

srs_error_t SrsConfig::parse_include_file(const char *filename)
{
srs_error_t err = srs_success;

std::string file = filename;

if (file.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty include config");
}

SrsConfigBuffer buffer;
winlinvip marked this conversation as resolved.
Show resolved Hide resolved

if ((err = buffer.fullfill(file.c_str())) != srs_success) {
return srs_error_wrap(err, "buffer fullfil");
}

// Parse root tree from buffer.
if ((err = root->parse(&buffer, this)) != srs_success) {
return srs_error_wrap(err, "parse include buffer");
}

return err;
}

SrsConfigBuffer* SrsConfig::get_buffer_from_include_file(const char* filename)
{
srs_error_t err = srs_success;

SrsConfigBuffer* buffer = new SrsConfigBuffer();

if ((err = buffer->fullfill(filename)) != srs_success) {
srs_freep(buffer);

return NULL;
}

return buffer;
}
// LCOV_EXCL_STOP

srs_error_t SrsConfig::check_config()
Expand Down Expand Up @@ -2955,7 +3029,7 @@ srs_error_t SrsConfig::parse_buffer(SrsConfigBuffer* buffer)
root = new SrsConfDirective();

// Parse root tree from buffer.
if ((err = root->parse(buffer)) != srs_success) {
if ((err = root->parse(buffer, this)) != srs_success) {
return srs_error_wrap(err, "root parse");
}

Expand Down
8 changes: 6 additions & 2 deletions trunk/src/app/srs_app_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,7 +210,7 @@ class SrsConfDirective
// Parse utilities
public:
// Parse config directive from file buffer.
virtual srs_error_t parse(srs_internal::SrsConfigBuffer* buffer);
virtual srs_error_t parse(srs_internal::SrsConfigBuffer* buffer, SrsConfig* conf = NULL);
// Marshal the directive to writer.
// @param level, the root is level0, all its directives are level1, and so on.
virtual srs_error_t persistence(SrsFileWriter* writer, int level);
Expand All @@ -234,7 +234,7 @@ class SrsConfDirective
// 1. read a token(directive args and a ret flag),
// 2. initialize the directive by args, args[0] is name, args[1-N] is args of directive,
// 3. if ret flag indicates there are child-directives, read_conf(directive, block) recursively.
virtual srs_error_t parse_conf(srs_internal::SrsConfigBuffer* buffer, SrsDirectiveType type);
virtual srs_error_t parse_conf(srs_internal::SrsConfigBuffer* buffer, SrsDirectiveType type, SrsConfig* conf);
// Read a token from buffer.
// A token, is the directive args and a flag indicates whether has child-directives.
// @param args, the output directive args, the first is the directive name, left is the args.
Expand Down Expand Up @@ -356,6 +356,10 @@ class SrsConfig
public:
// Parse the config file, which is specified by cli.
virtual srs_error_t parse_file(const char* filename);
// Parse the include config file.
virtual srs_error_t parse_include_file(const char* filename);
// Get buffer from include config file.
virtual srs_internal::SrsConfigBuffer* get_buffer_from_include_file(const char* filename);
// Check the parsed config.
virtual srs_error_t check_config();
protected:
Expand Down
185 changes: 185 additions & 0 deletions trunk/src/utest/srs_utest_config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -50,6 +50,37 @@ MockSrsConfig::~MockSrsConfig()
{
}

SrsConfDirective* MockSrsConfig::get_mock_directive(const string file_name)
{
SrsConfDirective* mock_directive = NULL;

std::vector<SrsConfDirective*>::iterator it;
for (it = mock_directives.begin(); it != mock_directives.end(); ++it) {
SrsConfDirective* directive = *it;
if (directive->name == file_name) {
mock_directive = directive;
}
}

return mock_directive;
}

MockSrsConfigBuffer* MockSrsConfig::get_buffer_from_include_file(const char* filename)
{
MockSrsConfigBuffer* buffer = NULL;

std::string file = filename;
SrsConfDirective* mock_directive = get_mock_directive(file);

if(!mock_directive) {
return NULL;
} else {
buffer = new MockSrsConfigBuffer(mock_directive->arg0());
}

return buffer;
}

srs_error_t MockSrsConfig::parse(string buf)
{
srs_error_t err = srs_success;
Expand All @@ -71,6 +102,48 @@ srs_error_t MockSrsConfig::parse(string buf)
return err;
}

srs_error_t MockSrsConfig::parse_include_file(const char *filename)
{
srs_error_t err = srs_success;

std::string file = filename;

if (file.empty()) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty include config");
}

SrsConfDirective* mock_directive = get_mock_directive(file);

if(!mock_directive) {
return srs_error_new(ERROR_SYSTEM_CONFIG_INVALID, "empty include config");
} else {
MockSrsConfigBuffer buffer(mock_directive->arg0());

// Parse root tree from buffer.
if ((err = root->parse(&buffer, this)) != srs_success) {
return srs_error_wrap(err, "parse include buffer");
}
}

return err;
}

srs_error_t MockSrsConfig::mock_include(const string file_name, const string content)
{
srs_error_t err = srs_success;

SrsConfDirective* mock_directive = get_mock_directive(file_name);

if (!mock_directive) {
mock_directive = new SrsConfDirective();
mock_directive->name = file_name;
mock_directive->args.push_back(content);
mock_directives.push_back(mock_directive);
}

return err;
}

VOID TEST(ConfigTest, CheckMacros)
{
#ifndef SRS_CONSTS_LOCALHOST
Expand Down Expand Up @@ -3622,3 +3695,115 @@ VOID TEST(ConfigMainTest, CheckVhostConfig5)
}
}

VOID TEST(ConfigMainTest, CheckIncludeConfig)
{
srs_error_t err;

if (true) {
MockSrsConfig conf;

conf.mock_include("./conf/include_test/include.conf", "listen 1935;include ./conf/include_test/include_1.conf;");
conf.mock_include("./conf/include_test/include_1.conf", "max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}}");

HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include.conf;"));
winlinvip marked this conversation as resolved.
Show resolved Hide resolved

vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());

EXPECT_FALSE(conf.get_log_tank_file());

EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());

EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}

if (true) {
MockSrsConfig conf;

conf.mock_include("./conf/include_test/include_1.conf", "max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}}");

HELPER_ASSERT_SUCCESS(conf.parse(_MIN_OK_CONF "include ./conf/include_test/include_1.conf;"));

vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());

EXPECT_FALSE(conf.get_log_tank_file());

EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());

EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}

if (true) {
MockSrsConfig conf;

conf.mock_include("./conf/include_test/include_2.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;http_server {enabled on;listen xxx;dir xxx2;}vhost ossrs.net {include ./conf/include_test/include_3.conf;}");
conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");

HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_2.conf;"));

vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());

EXPECT_FALSE(conf.get_log_tank_file());

EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());

EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));
}

if (true) {
MockSrsConfig conf;

conf.mock_include("./conf/include_test/include_3.conf", "hls {enabled on;hls_path xxx;hls_m3u8_file xxx1;hls_ts_file xxx2;hls_fragment 10;hls_window 60;}");
conf.mock_include("./conf/include_test/include_4.conf", "listen 1935;max_connections 1000;daemon off;srs_log_tank console;include ./conf/include_test/include_5.conf;vhost ossrs.net {include ./conf/include_test/include_3.conf;}include ./conf/include_test/include_6.conf;");
conf.mock_include("./conf/include_test/include_5.conf", "http_server {enabled on;listen xxx;dir xxx2;}");
conf.mock_include("./conf/include_test/include_6.conf", "http_api {enabled on;listen xxx;}");

HELPER_ASSERT_SUCCESS(conf.parse("include ./conf/include_test/include_4.conf;"));

vector<string> listens = conf.get_listens();
EXPECT_EQ(1, (int)listens.size());
EXPECT_STREQ("1935", listens.at(0).c_str());

EXPECT_FALSE(conf.get_log_tank_file());

EXPECT_TRUE(conf.get_http_stream_enabled());
EXPECT_STREQ("xxx", conf.get_http_stream_listen().c_str());
EXPECT_STREQ("xxx2", conf.get_http_stream_dir().c_str());

EXPECT_TRUE(conf.get_hls_enabled("ossrs.net"));
EXPECT_STREQ("xxx", conf.get_hls_path("ossrs.net").c_str());
EXPECT_STREQ("xxx1", conf.get_hls_m3u8_file("ossrs.net").c_str());
EXPECT_STREQ("xxx2", conf.get_hls_ts_file("ossrs.net").c_str());
EXPECT_EQ(10*SRS_UTIME_SECONDS, conf.get_hls_fragment("ossrs.net"));
EXPECT_EQ(60*SRS_UTIME_SECONDS, conf.get_hls_window("ossrs.net"));

EXPECT_TRUE(conf.get_http_api_enabled());
EXPECT_STREQ("xxx", conf.get_http_api_listen().c_str());
}
}
7 changes: 7 additions & 0 deletions trunk/src/utest/srs_utest_config.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -32,8 +32,15 @@ class MockSrsConfig : public SrsConfig
public:
MockSrsConfig();
virtual ~MockSrsConfig();
private:
std::vector<SrsConfDirective*> mock_directives;
public:
SrsConfDirective* get_mock_directive(const std::string file_name);
public:
virtual MockSrsConfigBuffer* get_buffer_from_include_file(const char* filename);
virtual srs_error_t parse(std::string buf);
virtual srs_error_t parse_include_file(const char* filename);
virtual srs_error_t mock_include(const std::string file_name, const std::string content);
};

#endif
Expand Down