Skip to content

Commit

Permalink
add --output json option (taganaka#24)
Browse files Browse the repository at this point in the history
... similar to speedtest-cli --json
  • Loading branch information
mfontani authored and taganaka committed Dec 1, 2019
1 parent 262daf8 commit de90891
Show file tree
Hide file tree
Showing 2 changed files with 83 additions and 17 deletions.
6 changes: 4 additions & 2 deletions CmdOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
#define SPEEDTEST_CMDOPTIONS_H
#include <getopt.h>

enum OutputType { verbose, text };
enum OutputType { verbose, text, json };


typedef struct program_options_t {
Expand Down Expand Up @@ -60,9 +60,11 @@ bool ParseOptions(const int argc, const char **argv, ProgramOptions& options){
options.output_type = OutputType::verbose;
else if (strcmp(optarg, "text") == 0)
options.output_type = OutputType::text;
else if (strcmp(optarg, "json") == 0)
options.output_type = OutputType::json;
else {
std::cerr << "Unsupported output type " << optarg << std::endl;
std::cerr << "Supported output type: default, text" <<std::endl;
std::cerr << "Supported output type: default, text, json" <<std::endl;
return false;
}

Expand Down
94 changes: 79 additions & 15 deletions main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,15 +16,15 @@ void banner(){
void usage(const char* name){
std::cerr << "Usage: " << name << " ";
std::cerr << " [--latency] [--quality] [--download] [--upload] [--share] [--help]\n"
" [--test-server host:port] [--output verbose|text]\n";
" [--test-server host:port] [--output verbose|text|json]\n";
std::cerr << "optional arguments:" << std::endl;
std::cerr << " --help Show this message and exit\n";
std::cerr << " --latency Perform latency test only\n";
std::cerr << " --download Perform download test only. It includes latency test\n";
std::cerr << " --upload Perform upload test only. It includes latency test\n";
std::cerr << " --share Generate and provide a URL to the speedtest.net share results image\n";
std::cerr << " --test-server host:port Run speed test against a specific server\n";
std::cerr << " --output verbose|text Set output type. Default: verbose\n";
std::cerr << " --output verbose|text|json Set output type. Default: verbose\n";
}

int main(const int argc, const char **argv) {
Expand Down Expand Up @@ -55,35 +55,51 @@ int main(const int argc, const char **argv) {
ServerInfo serverInfo;
ServerInfo serverQualityInfo;

if (programOptions.output_type == OutputType::json)
std::cout << "{";

if (!sp.ipInfo(info)){
std::cerr << "Unable to retrieve your IP info. Try again later" << std::endl;
if (programOptions.output_type == OutputType::json)
std::cout << "\"error\":\"unable to retrieve your ip info\"}" << std::endl;
return EXIT_FAILURE;
}

if (programOptions.output_type == OutputType::verbose){
std::cout << "IP: " << info.ip_address
<< " ( " << info.isp << " ) "
<< "Location: [" << info.lat << ", " << info.lon << "]" << std::endl;
} else {
} else if (programOptions.output_type == OutputType::text) {
std::cout << "IP=" << info.ip_address << std::endl;
std::cout << "IP_LAT=" << info.lat << std::endl;
std::cout << "IP_LON=" << info.lon << std::endl;
std::cout << "PROVIDER=" << info.isp << std::endl;
} else if (programOptions.output_type == OutputType::json) {
std::cout << "\"client\":{";
std::cout << "\"ip\":\"" << info.ip_address << "\",";
std::cout << "\"lat\":\"" << info.lat << "\",";
std::cout << "\"lon\":\"" << info.lon << "\",";
std::cout << "\"isp\":\"" << info.isp << "\"";
std::cout << "},";
}

auto serverList = sp.serverList();

if (programOptions.selected_server.empty()){
if (programOptions.output_type == OutputType::verbose)
std::cout << "Finding fastest server... " << std::flush;

if (serverList.empty()){
std::cerr << "Unable to download server list. Try again later" << std::endl;
if (programOptions.output_type == OutputType::json)
std::cout << "\"error\":\"unable to download server list\"}" << std::endl;
return EXIT_FAILURE;
}

if (programOptions.output_type == OutputType::verbose)
std::cout << serverList.size() << " Servers online" << std::endl;
else if (programOptions.output_type == OutputType::json)
std::cout << "\"servers_online\":\"" << serverList.size() << "\",";


serverInfo = sp.bestServer(10, [&programOptions](bool success) {
Expand All @@ -98,11 +114,20 @@ int main(const int argc, const char **argv) {
<< " by " << serverInfo.sponsor
<< " (" << serverInfo.distance << " km from you): "
<< sp.latency() << " ms" << std::endl;
} else {
} else if (programOptions.output_type == OutputType::text) {
std::cout << "TEST_SERVER_HOST=" << serverInfo.host << std::endl;
std::cout << "TEST_SERVER_DISTANCE=" << serverInfo.distance << std::endl;

}
else if (programOptions.output_type == OutputType::json) {
std::cout << "\"server\":{";
std::cout << "\"name\":\"" << serverInfo.name << "\",";
std::cout << "\"sponsor\":\"" << serverInfo.sponsor << "\",";
std::cout << "\"distance\":\"" << serverInfo.distance << "\",";
std::cout << "\"latency\":\"" << sp.latency() << "\",";
std::cout << "\"host\":\"" << serverInfo.host << "\"";
std::cout << "},";
}

} else {

Expand All @@ -116,30 +141,48 @@ int main(const int argc, const char **argv) {

if (programOptions.output_type == OutputType::verbose)
std::cout << "Selected server: " << serverInfo.host << std::endl;
else {
else if (programOptions.output_type == OutputType::text) {
std::cout << "TEST_SERVER_HOST=" << serverInfo.host << std::endl;
}
else if (programOptions.output_type == OutputType::json) {
std::cout << "\"server\":{";
std::cout << "\"host\":\"" << serverInfo.host << "\"";
std::cout << "},";
}
}

if (programOptions.output_type == OutputType::verbose)
std::cout << "Ping: " << sp.latency() << " ms." << std::endl;
else
else if (programOptions.output_type == OutputType::text)
std::cout << "LATENCY=" << sp.latency() << std::endl;
else if (programOptions.output_type == OutputType::json) {
std::cout << "\"ping\":\"";
std::cout << std::fixed;
std::cout << sp.latency() << "\",";
}

long jitter = 0;
if (programOptions.output_type == OutputType::verbose)
std::cout << "Jitter: " << std::flush;
if (sp.jitter(serverInfo, jitter)){
if (programOptions.output_type == OutputType::verbose)
std::cout << jitter << " ms." << std::endl;
else
else if (programOptions.output_type == OutputType::text)
std::cout << "JITTER=" << jitter << std::endl;
else if (programOptions.output_type == OutputType::json) {
std::cout << "\"jitter\":\"";
std::cout << std::fixed;
std::cout << jitter << "\",";
}
} else {
std::cerr << "Jitter measurement is unavailable at this time." << std::endl;
}

if (programOptions.latency)
if (programOptions.latency) {
if (programOptions.output_type == OutputType::json)
std::cout << "\"_\":\"only latency requested\"}" << std::endl;
return EXIT_SUCCESS;
}


if (programOptions.output_type == OutputType::verbose)
Expand All @@ -150,6 +193,8 @@ int main(const int argc, const char **argv) {
std::cout << (success ? '.' : '*') << std::flush;
})){
std::cerr << "Pre-flight check failed." << std::endl;
if (programOptions.output_type == OutputType::json)
std::cout << "\"error\":\"pre-flight check failed\"}" << std::endl;
return EXIT_FAILURE;
}

Expand Down Expand Up @@ -181,21 +226,29 @@ int main(const int argc, const char **argv) {
std::cout << std::fixed;
std::cout << std::setprecision(2);
std::cout << downloadSpeed << " Mbit/s" << std::endl;
} else {
} else if (programOptions.output_type == OutputType::text) {
std::cout << "DOWNLOAD_SPEED=";
std::cout << std::fixed;
std::cout << std::setprecision(2);
std::cout << downloadSpeed << std::endl;
} else if (programOptions.output_type == OutputType::json) {
std::cout << "\"download\":\"";
std::cout << std::fixed;
std::cout << (downloadSpeed*1000*1000) << "\",";
}

} else {
std::cerr << "Download test failed." << std::endl;
if (programOptions.output_type == OutputType::json)
std::cout << "\"error\":\"download test failed\"}" << std::endl;
return EXIT_FAILURE;
}
}

if (programOptions.download)
if (programOptions.download) {
if (programOptions.output_type == OutputType::json)
std::cout << "\"_\":\"only download requested\"}" << std::endl;
return EXIT_SUCCESS;
}

if (programOptions.output_type == OutputType::verbose)
std::cout << "Testing upload speed (" << uploadConfig.concurrency << ") " << std::flush;
Expand All @@ -211,15 +264,21 @@ int main(const int argc, const char **argv) {
std::cout << std::fixed;
std::cout << std::setprecision(2);
std::cout << uploadSpeed << " Mbit/s" << std::endl;
} else {
} else if (programOptions.output_type == OutputType::text) {
std::cout << "UPLOAD_SPEED=";
std::cout << std::fixed;
std::cout << std::setprecision(2);
std::cout << uploadSpeed << std::endl;
} else if (programOptions.output_type == OutputType::json) {
std::cout << "\"upload\":\"";
std::cout << std::fixed;
std::cout << (uploadSpeed*1000*1000) << "\",";
}

} else {
std::cerr << "Upload test failed." << std::endl;
if (programOptions.output_type == OutputType::json)
std::cout << "\"error\":\"upload test failed\"}" << std::endl;
return EXIT_FAILURE;
}

Expand All @@ -229,11 +288,16 @@ int main(const int argc, const char **argv) {
if (sp.share(serverInfo, share_it)) {
if (programOptions.output_type == OutputType::verbose) {
std::cout << "Results image: " << share_it << std::endl;
} else {
} else if (programOptions.output_type == OutputType::text) {
std::cout << "IMAGE_URL=" << share_it << std::endl;
} else if (programOptions.output_type == OutputType::json) {
std::cout << "\"share\":\"" << share_it << "\",";
}
}
}

if (programOptions.output_type == OutputType::json)
std::cout << "\"_\":\"all ok\"}" << std::endl;

return EXIT_SUCCESS;
}
}

0 comments on commit de90891

Please sign in to comment.