Add statusip.
This commit is contained in:
parent
71c68bddcf
commit
f5bef72217
|
@ -25,5 +25,8 @@ add_executable(statusweather "statusweather.cpp" "helpers.cpp")
|
|||
target_link_libraries(statusweather
|
||||
PRIVATE
|
||||
fmt::fmt restclient-cpp nlohmann_json::nlohmann_json Threads::Threads
|
||||
Boost::program_options
|
||||
)
|
||||
Boost::program_options)
|
||||
|
||||
add_executable(statusip "statusip.cpp" "helpers.cpp")
|
||||
target_link_libraries(statusip
|
||||
PRIVATE fmt::fmt Boost::program_options restclient-cpp)
|
||||
|
|
|
@ -0,0 +1,159 @@
|
|||
// Print yout IP(s) for i3 status bar.
|
||||
/* i3blocks config:
|
||||
* [ip]
|
||||
* command=statusip --url=<URL that returns IP as plain text>
|
||||
* interval=persist
|
||||
* markup=pango
|
||||
*/
|
||||
|
||||
#include "helpers.hpp"
|
||||
|
||||
#include <arpa/inet.h>
|
||||
#include <boost/program_options/options_description.hpp>
|
||||
#include <boost/program_options/parsers.hpp>
|
||||
#include <boost/program_options/variables_map.hpp>
|
||||
#include <fmt/core.h>
|
||||
#include <netdb.h>
|
||||
#include <restclient-cpp/connection.h>
|
||||
#include <restclient-cpp/restclient.h>
|
||||
|
||||
#include <exception>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <string_view>
|
||||
#include <thread>
|
||||
|
||||
std::string get_url(int argc, char *argv[])
|
||||
{
|
||||
namespace po = boost::program_options;
|
||||
|
||||
po::options_description options("Options");
|
||||
// clang-format off
|
||||
options.add_options()
|
||||
("help,h", "Display this help and exit.")
|
||||
("url", po::value<std::string>()->required()->value_name("URL"),
|
||||
"URL that returns your IP address as plain text.");
|
||||
// clang-format on
|
||||
|
||||
po::variables_map vm;
|
||||
po::store(po::command_line_parser(argc, argv).options(options).run(), vm);
|
||||
|
||||
const auto path{[]()
|
||||
{
|
||||
auto path{helpers::get_env("XDG_CONFIG_HOME")};
|
||||
if (path.empty())
|
||||
{
|
||||
path = helpers::get_env("HOME");
|
||||
if (!path.empty())
|
||||
{
|
||||
path += "/.config";
|
||||
}
|
||||
}
|
||||
return path += "/statusip.cfg";
|
||||
}()};
|
||||
std::ifstream configfile(path);
|
||||
po::store(po::parse_config_file(configfile, options, true), vm);
|
||||
configfile.close();
|
||||
|
||||
if (vm.count("help") != 0)
|
||||
{
|
||||
std::cout << options;
|
||||
std::exit(0); // NOLINT(concurrency-mt-unsafe)
|
||||
}
|
||||
po::notify(vm);
|
||||
|
||||
return vm["url"].as<std::string>();
|
||||
}
|
||||
|
||||
std::string format_responses(const std::string_view ipv6,
|
||||
const std::string_view ipv4)
|
||||
{
|
||||
using fmt::format;
|
||||
|
||||
std::string out;
|
||||
|
||||
if (size_t pos{0}; (pos = ipv6.find(':')) != std::string::npos)
|
||||
{
|
||||
for (int n = 0; n < 4; ++n)
|
||||
{
|
||||
pos = ipv6.find(':', pos);
|
||||
++pos;
|
||||
}
|
||||
out += format(R"({:s})"
|
||||
R"(<span color="#aaddaa">{:s}</span>)",
|
||||
ipv6.substr(0, pos), ipv6.substr(pos));
|
||||
}
|
||||
if (ipv4.find('.') != std::string::npos)
|
||||
{
|
||||
(out += " ") += ipv4;
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
std::string get_host(const std::string_view url)
|
||||
{
|
||||
const size_t pos{url.find("//") + 2};
|
||||
return std::string(url.substr(pos, url.find('/', pos) - pos));
|
||||
}
|
||||
|
||||
// Ughf. 🙈 <https://github.com/mrtazz/restclient-cpp/issues/164>
|
||||
std::string get_ipv4(const std::string_view url)
|
||||
{
|
||||
// NOLINTNEXTLINE(concurrency-mt-unsafe)
|
||||
auto *hostent{gethostbyname(get_host(url).data())};
|
||||
// NOLINTNEXTLINE
|
||||
auto *addr = reinterpret_cast<struct in_addr *>(hostent->h_addr_list[0]);
|
||||
return inet_ntoa(addr[0]); // NOLINT
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
using clock = std::chrono::system_clock;
|
||||
using namespace std::chrono_literals;
|
||||
|
||||
try
|
||||
{
|
||||
const auto url{get_url(argc, argv)};
|
||||
std::string ipv6;
|
||||
std::string ipv4;
|
||||
|
||||
while (true)
|
||||
{
|
||||
RestClient::init();
|
||||
RestClient::Connection conn("");
|
||||
// We can't force IPv4 or IPv6?
|
||||
// <https://github.com/mrtazz/restclient-cpp/issues/164>
|
||||
conn.FollowRedirects(true, 5);
|
||||
conn.SetTimeout(120);
|
||||
|
||||
auto response{conn.get(url)};
|
||||
if (response.code == 200)
|
||||
{
|
||||
const auto &body{response.body};
|
||||
ipv6 = body.substr(0, body.find_first_of("\r\n"));
|
||||
}
|
||||
|
||||
RestClient::HeaderFields headers{{"Host", get_host(url)}};
|
||||
conn.SetHeaders(headers);
|
||||
response = conn.get(get_ipv4(url));
|
||||
if (response.code == 200)
|
||||
{
|
||||
const auto &body{response.body};
|
||||
ipv4 = body.substr(0, body.find_first_of("\r\n"));
|
||||
}
|
||||
|
||||
RestClient::disable();
|
||||
|
||||
std::cout << format_responses(ipv6, ipv4) << std::endl;
|
||||
std::this_thread::sleep_until(clock::now() + 30min);
|
||||
}
|
||||
}
|
||||
catch (const std::exception &e)
|
||||
{
|
||||
std::cout << R"(<span color="red">)" << e.what() << "</span>"
|
||||
<< std::endl;
|
||||
return 33;
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue