Skip to content
This repository was archived by the owner on Jul 4, 2025. It is now read-only.

Commit b95b857

Browse files
committed
Add CLI support
1 parent e95ca37 commit b95b857

File tree

5 files changed

+192
-78
lines changed

5 files changed

+192
-78
lines changed

engine/cli/command_line_parser.cc

Lines changed: 14 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -326,14 +326,8 @@ void CommandLineParser::SetupModelCommands() {
326326
void CommandLineParser::SetupConfigsCommands() {
327327
auto config_cmd =
328328
app_.add_subcommand("config", "Subcommands for managing configurations");
329-
config_cmd->usage(
330-
"Usage:\n" + commands::GetCortexBinary() +
331-
" config status for listing all API server configuration.\n" +
332-
commands::GetCortexBinary() +
333-
" config --cors [on/off] to toggle CORS.\n" +
334-
commands::GetCortexBinary() +
335-
" config --allowed_origins [comma separated origin] to set a list of "
336-
"allowed origin");
329+
config_cmd->usage("Usage:\n" + commands::GetCortexBinary() +
330+
" config [option] [value]");
337331
config_cmd->group(kConfigGroup);
338332
auto config_status_cmd =
339333
config_cmd->add_subcommand("status", "Print all configurations");
@@ -344,18 +338,18 @@ void CommandLineParser::SetupConfigsCommands() {
344338
std::stoi(cml_data_.config.apiServerPort));
345339
});
346340

347-
// TODO: this can be improved
348-
std::vector<std::string> avai_opts{"cors", "allowed_origins"};
349-
std::unordered_map<std::string, std::string> description{
350-
{"cors", "[on/off] Toggling CORS."},
351-
{"allowed_origins",
352-
"Allowed origins for CORS. Comma separated. E.g. "
353-
"http://localhost,https://cortex.so"}};
354-
for (const auto& opt : avai_opts) {
355-
std::string option = "--" + opt;
356-
config_cmd->add_option(option, config_update_opts_[opt], description[opt])
357-
->expected(0, 1)
358-
->default_str("*");
341+
for (const auto& [key, opt] : CONFIGURATIONS) {
342+
std::string option = "--" + opt.name;
343+
auto option_cmd =
344+
config_cmd->add_option(option, config_update_opts_[opt.name], opt.desc)
345+
->group(opt.group)
346+
->default_str(opt.default_value);
347+
348+
if (opt.allow_empty) {
349+
option_cmd->expected(0, 1);
350+
} else {
351+
option_cmd->expected(1);
352+
}
359353
}
360354

361355
config_cmd->callback([this, config_cmd] {

engine/cli/commands/config_upd_cmd.cc

Lines changed: 21 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,39 @@
11
#include "config_upd_cmd.h"
22
#include "commands/server_start_cmd.h"
3+
#include "common/api_server_configuration.h"
34
#include "utils/curl_utils.h"
45
#include "utils/logging_utils.h"
56
#include "utils/string_utils.h"
67
#include "utils/url_parser.h"
78

89
namespace {
9-
const std::vector<std::string> config_keys{"cors", "allowed_origins"};
10-
1110
inline Json::Value NormalizeJson(
1211
const std::unordered_map<std::string, std::string> options) {
1312
Json::Value root;
1413
for (const auto& [key, value] : options) {
15-
if (std::find(config_keys.begin(), config_keys.end(), key) ==
16-
config_keys.end()) {
14+
if (CONFIGURATIONS.find(key) == CONFIGURATIONS.end()) {
1715
continue;
1816
}
17+
auto config = CONFIGURATIONS.at(key);
1918

20-
if (key == "cors") {
19+
if (config.accept_value == "[on|off]") {
2120
if (string_utils::EqualsIgnoreCase("on", value)) {
22-
root["cors"] = true;
21+
root[key] = true;
2322
} else if (string_utils::EqualsIgnoreCase("off", value)) {
24-
root["cors"] = false;
23+
root[key] = false;
2524
}
26-
} else if (key == "allowed_origins") {
25+
} else if (config.accept_value == "comma separated") {
2726
auto origins = string_utils::SplitBy(value, ",");
2827
Json::Value origin_array(Json::arrayValue);
2928
for (const auto& origin : origins) {
3029
origin_array.append(origin);
3130
}
3231
root[key] = origin_array;
32+
} else if (config.accept_value == "string") {
33+
root[key] = value;
34+
} else {
35+
CTL_ERR("Not support configuration type: " << config.accept_value
36+
<< " for config key: " << key);
3337
}
3438
}
3539

@@ -50,13 +54,21 @@ void commands::ConfigUpdCmd::Exec(
5054
}
5155
}
5256

57+
auto non_null_opts = std::unordered_map<std::string, std::string>();
58+
for (const auto& [key, value] : options) {
59+
if (value.empty()) {
60+
continue;
61+
}
62+
non_null_opts[key] = value;
63+
}
64+
5365
auto url = url_parser::Url{
5466
.protocol = "http",
5567
.host = host + ":" + std::to_string(port),
5668
.pathParams = {"v1", "configs"},
5769
};
5870

59-
auto json = NormalizeJson(options);
71+
auto json = NormalizeJson(non_null_opts);
6072
if (json.empty()) {
6173
CLI_LOG_ERROR("Invalid configuration options provided");
6274
return;

engine/common/api_server_configuration.h

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,78 @@ enum class ProxyAuthMethod {
2020
AwsSigV4
2121
};
2222

23+
struct ApiConfigurationMetadata {
24+
std::string name;
25+
std::string desc;
26+
std::string group;
27+
std::string accept_value;
28+
std::string default_value;
29+
30+
bool allow_empty = false;
31+
};
32+
33+
static const std::unordered_map<std::string, ApiConfigurationMetadata>
34+
CONFIGURATIONS = {
35+
{"cors",
36+
ApiConfigurationMetadata{
37+
.name = "cors",
38+
.desc = "Cross-Origin Resource Sharing configuration.",
39+
.group = "CORS",
40+
.accept_value = "[on|off]",
41+
.default_value = "on"}},
42+
{"allowed_origins",
43+
ApiConfigurationMetadata{
44+
.name = "allowed_origins",
45+
.desc = "Allowed origins for CORS. Comma separated. E.g. "
46+
"http://localhost,https://cortex.so",
47+
.group = "CORS",
48+
.accept_value = "comma separated",
49+
.default_value = "*",
50+
.allow_empty = true}},
51+
{"proxy_url", ApiConfigurationMetadata{.name = "proxy_url",
52+
.desc = "Proxy URL",
53+
.group = "Proxy",
54+
.accept_value = "string",
55+
.default_value = ""}},
56+
{"proxy_username", ApiConfigurationMetadata{.name = "proxy_username",
57+
.desc = "Proxy Username",
58+
.group = "Proxy",
59+
.accept_value = "string",
60+
.default_value = ""}},
61+
{"proxy_password", ApiConfigurationMetadata{.name = "proxy_password",
62+
.desc = "Proxy Password",
63+
.group = "Proxy",
64+
.accept_value = "string",
65+
.default_value = ""}},
66+
{"verify_proxy_ssl",
67+
ApiConfigurationMetadata{.name = "verify_proxy_ssl",
68+
.desc = "Verify SSL for proxy",
69+
.group = "Proxy",
70+
.accept_value = "[on|off]",
71+
.default_value = "on"}},
72+
{"verify_proxy_host_ssl",
73+
ApiConfigurationMetadata{.name = "verify_proxy_host_ssl",
74+
.desc = "Verify SSL for proxy",
75+
.group = "Proxy",
76+
.accept_value = "[on|off]",
77+
.default_value = "on"}},
78+
{"no_proxy", ApiConfigurationMetadata{.name = "no_proxy",
79+
.desc = "No proxy for hosts",
80+
.group = "Proxy",
81+
.accept_value = "string",
82+
.default_value = ""}},
83+
{"verify_peer_ssl", ApiConfigurationMetadata{.name = "verify_peer_ssl",
84+
.desc = "Verify peer SSL",
85+
.group = "Proxy",
86+
.accept_value = "[on|off]",
87+
.default_value = "on"}},
88+
{"verify_host_ssl", ApiConfigurationMetadata{.name = "verify_host_ssl",
89+
.desc = "Verify host SSL",
90+
.group = "Proxy",
91+
.accept_value = "[on|off]",
92+
.default_value = "on"}},
93+
};
94+
2395
class ApiServerConfiguration {
2496
public:
2597
ApiServerConfiguration(

engine/services/download_service.cc

Lines changed: 46 additions & 47 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,48 @@ cpp::result<void, std::string> ProcessCompletedTransfers(CURLM* multi_handle) {
5252
}
5353
return {};
5454
}
55+
56+
void SetUpProxy(CURL* handle, std::shared_ptr<ConfigService> config_service) {
57+
auto configuration = config_service->GetApiServerConfiguration();
58+
if (configuration.has_value()) {
59+
if (!configuration->proxy_url.empty()) {
60+
auto proxy_url = configuration->proxy_url;
61+
auto verify_proxy_ssl = configuration->verify_proxy_ssl;
62+
auto verify_proxy_host_ssl = configuration->verify_proxy_host_ssl;
63+
64+
auto verify_ssl = configuration->verify_peer_ssl;
65+
auto verify_host_ssl = configuration->verify_host_ssl;
66+
67+
auto proxy_username = configuration->proxy_username;
68+
auto proxy_password = configuration->proxy_password;
69+
70+
CTL_INF("=== Proxy configuration ===");
71+
CTL_INF("Proxy url: " << proxy_url);
72+
CTL_INF("Verify proxy ssl: " << verify_proxy_ssl);
73+
CTL_INF("Verify proxy host ssl: " << verify_proxy_host_ssl);
74+
CTL_INF("Verify ssl: " << verify_ssl);
75+
CTL_INF("Verify host ssl: " << verify_host_ssl);
76+
77+
curl_easy_setopt(handle, CURLOPT_PROXY, proxy_url.c_str());
78+
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, verify_ssl ? 1L : 0L);
79+
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST,
80+
verify_host_ssl ? 2L : 0L);
81+
82+
curl_easy_setopt(handle, CURLOPT_PROXY_SSL_VERIFYPEER,
83+
verify_proxy_ssl ? 1L : 0L);
84+
curl_easy_setopt(handle, CURLOPT_PROXY_SSL_VERIFYHOST,
85+
verify_proxy_host_ssl ? 2L : 0L);
86+
87+
auto proxy_auth = proxy_username + ":" + proxy_password;
88+
curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str());
89+
90+
curl_easy_setopt(handle, CURLOPT_NOPROXY,
91+
configuration->no_proxy.c_str());
92+
}
93+
} else {
94+
CTL_ERR("Failed to get configuration");
95+
}
96+
}
5597
} // namespace
5698

5799
cpp::result<bool, std::string> DownloadService::AddDownloadTask(
@@ -87,7 +129,7 @@ cpp::result<uint64_t, std::string> DownloadService::GetFileSize(
87129
return cpp::fail(static_cast<std::string>("Failed to init CURL"));
88130
}
89131

90-
// TODO: namh add header here
132+
SetUpProxy(curl, config_service_);
91133
curl_easy_setopt(curl, CURLOPT_FOLLOWLOCATION, 1L);
92134
curl_easy_setopt(curl, CURLOPT_NOBODY, 1L);
93135
curl_easy_setopt(curl, CURLOPT_URL, url.c_str());
@@ -190,7 +232,8 @@ cpp::result<bool, std::string> DownloadService::Download(
190232

191233
curl_easy_setopt(curl, CURLOPT_HTTPHEADER, curl_headers);
192234
}
193-
// TODO: namh add proxy setting here
235+
236+
SetUpProxy(curl, config_service_);
194237
curl_easy_setopt(curl, CURLOPT_WRITEFUNCTION, &WriteCallback);
195238
curl_easy_setopt(curl, CURLOPT_WRITEDATA, file);
196239
curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 0L);
@@ -339,7 +382,6 @@ void DownloadService::ProcessTask(DownloadTask& task, int worker_id) {
339382
});
340383
worker_data->downloading_data_map[item.id] = dl_data_ptr;
341384

342-
CTL_ERR("Namh Setup curl");
343385
SetUpCurlHandle(handle, item, file, dl_data_ptr.get());
344386
curl_multi_add_handle(worker_data->multi_handle, handle);
345387
task_handles.push_back(std::make_pair(handle, file));
@@ -410,57 +452,14 @@ cpp::result<void, ProcessDownloadFailed> DownloadService::ProcessMultiDownload(
410452

411453
void DownloadService::SetUpCurlHandle(CURL* handle, const DownloadItem& item,
412454
FILE* file, DownloadingData* dl_data) {
413-
auto configuration = config_service_->GetApiServerConfiguration();
414-
if (configuration.has_value()) {
415-
if (!configuration->proxy_url.empty()) {
416-
auto proxy_url = configuration->proxy_url;
417-
auto verify_proxy_ssl = configuration->verify_proxy_ssl;
418-
auto verify_proxy_host_ssl = configuration->verify_proxy_host_ssl;
419-
420-
auto verify_ssl = configuration->verify_peer_ssl;
421-
auto verify_host_ssl = configuration->verify_host_ssl;
422-
423-
auto proxy_username = configuration->proxy_username;
424-
auto proxy_password = configuration->proxy_password;
425-
426-
CTL_ERR("=== Proxy configuration ===");
427-
CTL_ERR("Proxy url: " << proxy_url);
428-
CTL_ERR("Verify proxy ssl: " << verify_proxy_ssl);
429-
CTL_ERR("Verify proxy host ssl: " << verify_proxy_host_ssl);
430-
CTL_ERR("Verify ssl: " << verify_ssl);
431-
CTL_ERR("Verify host ssl: " << verify_host_ssl);
432-
433-
curl_easy_setopt(handle, CURLOPT_PROXY, proxy_url.c_str());
434-
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYPEER, verify_ssl ? 1L : 0L);
435-
curl_easy_setopt(handle, CURLOPT_SSL_VERIFYHOST,
436-
verify_host_ssl ? 2L : 0L);
437-
438-
curl_easy_setopt(handle, CURLOPT_PROXY_SSL_VERIFYPEER,
439-
verify_proxy_ssl ? 1L : 0L);
440-
curl_easy_setopt(handle, CURLOPT_PROXY_SSL_VERIFYHOST,
441-
verify_proxy_host_ssl ? 2L : 0L);
442-
443-
if (!proxy_username.empty()) {
444-
std::string proxy_auth = proxy_username + ":" + proxy_password;
445-
CTL_ERR("Proxy auth: " << proxy_auth);
446-
curl_easy_setopt(handle, CURLOPT_PROXYUSERPWD, proxy_auth.c_str());
447-
}
448-
449-
curl_easy_setopt(handle, CURLOPT_NOPROXY,
450-
configuration->no_proxy.c_str());
451-
}
452-
} else {
453-
CTL_ERR("Failed to get configuration");
454-
}
455-
455+
SetUpProxy(handle, config_service_);
456456
curl_easy_setopt(handle, CURLOPT_URL, item.downloadUrl.c_str());
457457
curl_easy_setopt(handle, CURLOPT_WRITEFUNCTION, WriteCallback);
458458
curl_easy_setopt(handle, CURLOPT_WRITEDATA, file);
459459
curl_easy_setopt(handle, CURLOPT_FOLLOWLOCATION, 1L);
460460
curl_easy_setopt(handle, CURLOPT_NOPROGRESS, 0L);
461461
curl_easy_setopt(handle, CURLOPT_XFERINFOFUNCTION, ProgressCallback);
462462
curl_easy_setopt(handle, CURLOPT_XFERINFODATA, dl_data);
463-
curl_easy_setopt(handle, CURLOPT_VERBOSE, 1L);
464463

465464
auto headers = curl_utils::GetHeaders(item.downloadUrl);
466465
if (headers) {

0 commit comments

Comments
 (0)