Merge branch 'rewrite' into main
All checks were successful
continuous-integration/drone/push Build is passing
All checks were successful
continuous-integration/drone/push Build is passing
This commit is contained in:
commit
bca496c87a
|
@ -2,7 +2,7 @@
|
||||||
:doctype: manpage
|
:doctype: manpage
|
||||||
:Author: tastytea
|
:Author: tastytea
|
||||||
:Email: tastytea@tastytea.de
|
:Email: tastytea@tastytea.de
|
||||||
:Date: 2019-12-25
|
:Date: 2019-12-28
|
||||||
:Revision: 0.0.0
|
:Revision: 0.0.0
|
||||||
:man source: mastorss
|
:man source: mastorss
|
||||||
:man manual: General Commands Manual
|
:man manual: General Commands Manual
|
||||||
|
@ -157,15 +157,16 @@ proxy support yet, sorry.
|
||||||
== ERROR CODES
|
== ERROR CODES
|
||||||
|
|
||||||
[cols=">,<"]
|
[cols=">,<"]
|
||||||
|===========================================================
|
|===============================================================================
|
||||||
| Code | Explanation
|
| Code | Explanation
|
||||||
|
|
||||||
| 1 | No profile specified.
|
| 1 | No profile specified.
|
||||||
| 2 | Network error.
|
| 2 | Network error.
|
||||||
| 3 | File error.
|
| 3 | File error.
|
||||||
| 4 | Mastodon API error.
|
| 4 | Mastodon API error.
|
||||||
|
| 5 | JSON error, most likely the file is wrongly formatted.
|
||||||
| 9 | Unknown error.
|
| 9 | Unknown error.
|
||||||
|===========================================================
|
|===============================================================================
|
||||||
|
|
||||||
== DEBUGGING
|
== DEBUGGING
|
||||||
|
|
||||||
|
|
|
@ -74,8 +74,8 @@ std::ostream &operator <<(std::ostream &out, const ProfileData &data)
|
||||||
return out;
|
return out;
|
||||||
}
|
}
|
||||||
|
|
||||||
Config::Config(string profile)
|
Config::Config(string profile_name)
|
||||||
:_profile{move(profile)}
|
: profile{move(profile_name)}
|
||||||
{
|
{
|
||||||
const fs::path filename = get_filename();
|
const fs::path filename = get_filename();
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Config filename is: " << filename;
|
BOOST_LOG_TRIVIAL(debug) << "Config filename is: " << filename;
|
||||||
|
@ -94,7 +94,7 @@ Config::Config(string profile)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fs::path Config::get_filename() const
|
fs::path Config::get_config_dir() const
|
||||||
{
|
{
|
||||||
char *envdir = getenv("XDG_CONFIG_HOME");
|
char *envdir = getenv("XDG_CONFIG_HOME");
|
||||||
fs::path dir;
|
fs::path dir;
|
||||||
|
@ -122,7 +122,12 @@ fs::path Config::get_filename() const
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Created config dir: " << dir;
|
BOOST_LOG_TRIVIAL(debug) << "Created config dir: " << dir;
|
||||||
}
|
}
|
||||||
|
|
||||||
return dir /= "config-" + _profile + ".json";
|
return dir;
|
||||||
|
}
|
||||||
|
|
||||||
|
fs::path Config::get_filename() const
|
||||||
|
{
|
||||||
|
return get_config_dir() /= "config-" + profile + ".json";
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::generate()
|
void Config::generate()
|
||||||
|
@ -131,39 +136,39 @@ void Config::generate()
|
||||||
|
|
||||||
cout << "Instance (domain): ";
|
cout << "Instance (domain): ";
|
||||||
getline(cin, line);
|
getline(cin, line);
|
||||||
data.instance = line;
|
profiledata.instance = line;
|
||||||
|
|
||||||
data.access_token = get_access_token(line);
|
profiledata.access_token = get_access_token(line);
|
||||||
|
|
||||||
cout << "URL of the feed: ";
|
cout << "URL of the feed: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
data.feedurl = line;
|
profiledata.feedurl = line;
|
||||||
|
|
||||||
cout << "Post only titles? [y/n]: ";
|
cout << "Post only titles? [y/n]: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
if (line[0] == 'y')
|
if (line[0] == 'y')
|
||||||
{
|
{
|
||||||
data.titles_only = true;
|
profiledata.titles_only = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data.titles_only = false;
|
profiledata.titles_only = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << "Post titles as cw? [y/n]: ";
|
cout << "Post titles as cw? [y/n]: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
if (line[0] == 'y')
|
if (line[0] == 'y')
|
||||||
{
|
{
|
||||||
data.titles_as_cw = true;
|
profiledata.titles_as_cw = true;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
data.titles_as_cw = false;
|
profiledata.titles_as_cw = false;
|
||||||
}
|
}
|
||||||
|
|
||||||
cout << "Append this string to each post: ";
|
cout << "Append this string to each post: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
data.append = line;
|
profiledata.append = line;
|
||||||
|
|
||||||
cout << "Interval between posts in seconds [30]: ";
|
cout << "Interval between posts in seconds [30]: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
|
@ -171,7 +176,7 @@ void Config::generate()
|
||||||
{
|
{
|
||||||
line = "30";
|
line = "30";
|
||||||
}
|
}
|
||||||
data.interval = static_cast<uint32_t>(stoul(line));
|
profiledata.interval = static_cast<uint32_t>(stoul(line));
|
||||||
|
|
||||||
cout << "Maximum size of posts [500]: ";
|
cout << "Maximum size of posts [500]: ";
|
||||||
std::getline(cin, line);
|
std::getline(cin, line);
|
||||||
|
@ -179,7 +184,7 @@ void Config::generate()
|
||||||
{
|
{
|
||||||
line = "500";
|
line = "500";
|
||||||
}
|
}
|
||||||
data.max_size = stoul(line);
|
profiledata.max_size = stoul(line);
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Generated configuration.";
|
BOOST_LOG_TRIVIAL(debug) << "Generated configuration.";
|
||||||
write();
|
write();
|
||||||
|
@ -220,48 +225,48 @@ string Config::get_access_token(const string &instance) const
|
||||||
|
|
||||||
void Config::parse()
|
void Config::parse()
|
||||||
{
|
{
|
||||||
data.access_token = _json[_profile]["access_token"].asString();
|
profiledata.access_token = _json[profile]["access_token"].asString();
|
||||||
data.append = _json[_profile]["append"].asString();
|
profiledata.append = _json[profile]["append"].asString();
|
||||||
data.feedurl = _json[_profile]["feedurl"].asString();
|
profiledata.feedurl = _json[profile]["feedurl"].asString();
|
||||||
for (const auto &fix : _json[_profile]["fixes"])
|
for (const auto &fix : _json[profile]["fixes"])
|
||||||
{
|
{
|
||||||
data.fixes.push_back(fix.asString());
|
profiledata.fixes.push_back(fix.asString());
|
||||||
}
|
}
|
||||||
data.instance = _json[_profile]["instance"].asString();
|
profiledata.instance = _json[profile]["instance"].asString();
|
||||||
if (!_json[_profile]["interval"].isNull())
|
if (!_json[profile]["interval"].isNull())
|
||||||
{
|
{
|
||||||
data.interval =
|
profiledata.interval =
|
||||||
static_cast<uint32_t>(_json[_profile]["interval"].asUInt64());
|
static_cast<uint32_t>(_json[profile]["interval"].asUInt64());
|
||||||
}
|
}
|
||||||
data.last_guid = _json[_profile]["last_guid"].asString();
|
profiledata.last_guid = _json[profile]["last_guid"].asString();
|
||||||
if (!_json[_profile]["max_size"].isNull())
|
if (!_json[profile]["max_size"].isNull())
|
||||||
{
|
{
|
||||||
data.max_size = _json[_profile]["max_size"].asUInt64();
|
profiledata.max_size = _json[profile]["max_size"].asUInt64();
|
||||||
}
|
}
|
||||||
for (const auto &skip : _json[_profile]["skip"])
|
for (const auto &skip : _json[profile]["skip"])
|
||||||
{
|
{
|
||||||
data.skip.push_back(skip.asString());
|
profiledata.skip.push_back(skip.asString());
|
||||||
}
|
}
|
||||||
data.titles_as_cw = _json[_profile]["titles_as_cw"].asBool();
|
profiledata.titles_as_cw = _json[profile]["titles_as_cw"].asBool();
|
||||||
data.titles_only = _json[_profile]["titles_only"].asBool();
|
profiledata.titles_only = _json[profile]["titles_only"].asBool();
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Read config: " << data;
|
BOOST_LOG_TRIVIAL(debug) << "Read config: " << profiledata;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Config::write()
|
void Config::write()
|
||||||
{
|
{
|
||||||
_json[_profile]["access_token"] = data.access_token;
|
_json[profile]["access_token"] = profiledata.access_token;
|
||||||
_json[_profile]["append"] = data.append;
|
_json[profile]["append"] = profiledata.append;
|
||||||
_json[_profile]["feedurl"] = data.feedurl;
|
_json[profile]["feedurl"] = profiledata.feedurl;
|
||||||
// Leave fixes.
|
// Leave fixes.
|
||||||
_json[_profile]["instance"] = data.instance;
|
_json[profile]["instance"] = profiledata.instance;
|
||||||
_json[_profile]["interval"] = data.interval;
|
_json[profile]["interval"] = profiledata.interval;
|
||||||
_json[_profile]["last_guid"] = data.last_guid;
|
_json[profile]["last_guid"] = profiledata.last_guid;
|
||||||
_json[_profile]["max_size"]
|
_json[profile]["max_size"]
|
||||||
= static_cast<Json::Value::UInt64>(data.max_size);
|
= static_cast<Json::Value::UInt64>(profiledata.max_size);
|
||||||
// Leave skip.
|
// Leave skip.
|
||||||
_json[_profile]["titles_as_cw"] = data.titles_as_cw;
|
_json[profile]["titles_as_cw"] = profiledata.titles_as_cw;
|
||||||
_json[_profile]["titles_only"] = data.titles_only;
|
_json[profile]["titles_only"] = profiledata.titles_only;
|
||||||
|
|
||||||
ofstream file{get_filename().c_str()};
|
ofstream file{get_filename().c_str()};
|
||||||
if (file.good())
|
if (file.good())
|
||||||
|
|
|
@ -18,7 +18,7 @@
|
||||||
#define MASTORSS_CONFIG_HPP
|
#define MASTORSS_CONFIG_HPP
|
||||||
|
|
||||||
#include <boost/filesystem.hpp>
|
#include <boost/filesystem.hpp>
|
||||||
#include <jsoncpp/json/json.h>
|
#include <json/json.h>
|
||||||
|
|
||||||
#include <cstdint>
|
#include <cstdint>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -64,14 +64,16 @@ struct ProfileData
|
||||||
class Config
|
class Config
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
explicit Config(string profile);
|
explicit Config(string profile_name);
|
||||||
|
|
||||||
ProfileData data;
|
const string profile;
|
||||||
|
ProfileData profiledata;
|
||||||
|
|
||||||
void write();
|
void write();
|
||||||
|
[[nodiscard]]
|
||||||
|
fs::path get_config_dir() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
const string _profile;
|
|
||||||
Json::Value _json;
|
Json::Value _json;
|
||||||
|
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
|
|
|
@ -21,9 +21,12 @@
|
||||||
#include <boost/log/trivial.hpp>
|
#include <boost/log/trivial.hpp>
|
||||||
#include <boost/property_tree/xml_parser.hpp>
|
#include <boost/property_tree/xml_parser.hpp>
|
||||||
#include <boost/regex.hpp>
|
#include <boost/regex.hpp>
|
||||||
|
#include <json/json.h>
|
||||||
#include <mastodon-cpp/mastodon-cpp.hpp>
|
#include <mastodon-cpp/mastodon-cpp.hpp>
|
||||||
#include <restclient-cpp/connection.h>
|
#include <restclient-cpp/connection.h>
|
||||||
|
|
||||||
|
#include <algorithm>
|
||||||
|
#include <fstream>
|
||||||
#include <list>
|
#include <list>
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
#include <string>
|
#include <string>
|
||||||
|
@ -33,8 +36,11 @@ namespace mastorss
|
||||||
{
|
{
|
||||||
using boost::regex;
|
using boost::regex;
|
||||||
using boost::regex_replace;
|
using boost::regex_replace;
|
||||||
|
using std::transform;
|
||||||
|
using std::ifstream;
|
||||||
using std::list;
|
using std::list;
|
||||||
using std::istringstream;
|
using std::istringstream;
|
||||||
|
using std::stringstream;
|
||||||
using std::string;
|
using std::string;
|
||||||
using std::move;
|
using std::move;
|
||||||
|
|
||||||
|
@ -45,7 +51,7 @@ bool operator !=(const Item &a, const Item &b)
|
||||||
|
|
||||||
Document::Document(Config &cfg)
|
Document::Document(Config &cfg)
|
||||||
: _cfg{cfg}
|
: _cfg{cfg}
|
||||||
, _profile{cfg.data}
|
, _profiledata{_cfg.profiledata}
|
||||||
{
|
{
|
||||||
RestClient::init();
|
RestClient::init();
|
||||||
|
|
||||||
|
@ -70,20 +76,20 @@ void Document::download(const string &uri)
|
||||||
case 200:
|
case 200:
|
||||||
{
|
{
|
||||||
_raw_doc = response.body;
|
_raw_doc = response.body;
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Downloaded feed: " << _profile.feedurl;
|
BOOST_LOG_TRIVIAL(debug) << "Downloaded feed: " << _profiledata.feedurl;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case 301:
|
case 301:
|
||||||
case 308:
|
case 308:
|
||||||
{
|
{
|
||||||
_profile.feedurl = extract_location(response.headers);
|
_profiledata.feedurl = extract_location(response.headers);
|
||||||
if (_profile.feedurl.empty())
|
if (_profiledata.feedurl.empty())
|
||||||
{
|
{
|
||||||
throw HTTPException{response.code};
|
throw HTTPException{response.code};
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Feed has new location (permanent): "
|
BOOST_LOG_TRIVIAL(debug) << "Feed has new location (permanent): "
|
||||||
<< _profile.feedurl;
|
<< _profiledata.feedurl;
|
||||||
_cfg.write();
|
_cfg.write();
|
||||||
download();
|
download();
|
||||||
break;
|
break;
|
||||||
|
@ -99,7 +105,7 @@ void Document::download(const string &uri)
|
||||||
}
|
}
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Feed has new location (temporary): "
|
BOOST_LOG_TRIVIAL(debug) << "Feed has new location (temporary): "
|
||||||
<< _profile.feedurl;
|
<< _profiledata.feedurl;
|
||||||
download(newuri);
|
download(newuri);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -116,7 +122,7 @@ void Document::download(const string &uri)
|
||||||
|
|
||||||
void Document::download()
|
void Document::download()
|
||||||
{
|
{
|
||||||
download(_profile.feedurl);
|
download(_profiledata.feedurl);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Document::parse()
|
void Document::parse()
|
||||||
|
@ -145,14 +151,14 @@ void Document::parse_rss(const pt::ptree &tree)
|
||||||
{
|
{
|
||||||
guid = rssitem.get<string>("link");
|
guid = rssitem.get<string>("link");
|
||||||
}
|
}
|
||||||
if (guid == _profile.last_guid)
|
if (guid == _profiledata.last_guid)
|
||||||
{
|
{
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool skipthis{false};
|
bool skipthis{false};
|
||||||
string title{rssitem.get<string>("title")};
|
string title{rssitem.get<string>("title")};
|
||||||
for (const auto &skip : _profile.skip)
|
for (const auto &skip : _profiledata.skip)
|
||||||
{
|
{
|
||||||
if (title.substr(0, skip.length()) == skip)
|
if (title.substr(0, skip.length()) == skip)
|
||||||
{
|
{
|
||||||
|
@ -171,11 +177,11 @@ void Document::parse_rss(const pt::ptree &tree)
|
||||||
{
|
{
|
||||||
string desc
|
string desc
|
||||||
{remove_html(rssitem.get<string>("description"))};
|
{remove_html(rssitem.get<string>("description"))};
|
||||||
for (const auto &fix : _profile.fixes)
|
for (const auto &fix : _profiledata.fixes)
|
||||||
{
|
{
|
||||||
desc = regex_replace(desc, regex{fix}, "");
|
desc = regex_replace(desc, regex{fix}, "");
|
||||||
}
|
}
|
||||||
return desc;
|
return add_hashtags(desc);
|
||||||
}();
|
}();
|
||||||
item.guid = move(guid);
|
item.guid = move(guid);
|
||||||
item.link = rssitem.get<string>("link");
|
item.link = rssitem.get<string>("link");
|
||||||
|
@ -184,7 +190,7 @@ void Document::parse_rss(const pt::ptree &tree)
|
||||||
|
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Found GUID: " << item.guid;
|
BOOST_LOG_TRIVIAL(debug) << "Found GUID: " << item.guid;
|
||||||
|
|
||||||
if (_profile.last_guid.empty())
|
if (_profiledata.last_guid.empty())
|
||||||
{
|
{
|
||||||
BOOST_LOG_TRIVIAL(debug) << "This is the first run.";
|
BOOST_LOG_TRIVIAL(debug) << "This is the first run.";
|
||||||
break;
|
break;
|
||||||
|
@ -232,4 +238,45 @@ string Document::extract_location(const RestClient::HeaderFields &headers) const
|
||||||
}
|
}
|
||||||
return location;
|
return location;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string Document::add_hashtags(const string &text)
|
||||||
|
{
|
||||||
|
Json::Value json;
|
||||||
|
const auto filepath = _cfg.get_config_dir() /= "watchwords.json";
|
||||||
|
ifstream file{filepath};
|
||||||
|
if (file.good())
|
||||||
|
{
|
||||||
|
stringstream rawjson;
|
||||||
|
rawjson << file.rdbuf();
|
||||||
|
rawjson >> json;
|
||||||
|
BOOST_LOG_TRIVIAL(debug) << "Read " << filepath;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
throw FileException{"File Not found:"
|
||||||
|
+ (_cfg.get_config_dir() /= "watchwords.json").string()};
|
||||||
|
}
|
||||||
|
|
||||||
|
list<string> watchwords;
|
||||||
|
const auto &tags_profile = json[_cfg.profile]["tags"];
|
||||||
|
const auto &tags_global = json["global"]["tags"];
|
||||||
|
transform(tags_profile.begin(), tags_profile.end(),
|
||||||
|
std::back_inserter(watchwords),
|
||||||
|
[](const Json::Value &value) { return value.asString(); });
|
||||||
|
transform(tags_global.begin(), tags_global.end(),
|
||||||
|
std::back_inserter(watchwords),
|
||||||
|
[](const Json::Value &value) { return value.asString(); });
|
||||||
|
|
||||||
|
string out{text};
|
||||||
|
for (const auto &tag : watchwords)
|
||||||
|
{
|
||||||
|
regex re_tag("([[:space:][:punct:]]|^)("
|
||||||
|
+ tag + ")([[:space:][:punct:]]|$)", regex::icase);
|
||||||
|
out = regex_replace(out, re_tag, "$1#$2$3", boost::format_first_only);
|
||||||
|
}
|
||||||
|
|
||||||
|
return out;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
} // namespace mastorss
|
} // namespace mastorss
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
Config &_cfg;
|
Config &_cfg;
|
||||||
ProfileData &_profile;
|
ProfileData &_profiledata;
|
||||||
string _raw_doc;
|
string _raw_doc;
|
||||||
|
|
||||||
void parse_rss(const pt::ptree &tree);
|
void parse_rss(const pt::ptree &tree);
|
||||||
|
@ -77,6 +77,7 @@ private:
|
||||||
string remove_html(string html) const;
|
string remove_html(string html) const;
|
||||||
[[nodiscard]]
|
[[nodiscard]]
|
||||||
string extract_location(const RestClient::HeaderFields &headers) const;
|
string extract_location(const RestClient::HeaderFields &headers) const;
|
||||||
|
string add_hashtags(const string &text);
|
||||||
};
|
};
|
||||||
} // namespace mastorss
|
} // namespace mastorss
|
||||||
|
|
||||||
|
|
18
src/main.cpp
18
src/main.cpp
|
@ -34,6 +34,7 @@ constexpr int noprofile = 1;
|
||||||
constexpr int network = 2;
|
constexpr int network = 2;
|
||||||
constexpr int file = 3;
|
constexpr int file = 3;
|
||||||
constexpr int mastodon = 4;
|
constexpr int mastodon = 4;
|
||||||
|
constexpr int json = 5;
|
||||||
constexpr int unknown = 9;
|
constexpr int unknown = 9;
|
||||||
} // namespace error
|
} // namespace error
|
||||||
|
|
||||||
|
@ -90,25 +91,25 @@ int main(int argc, char *argv[])
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
const string_view profile{args[1]};
|
const string_view profilename{args[1]};
|
||||||
BOOST_LOG_TRIVIAL(debug) << "Using profile: " << profile;
|
BOOST_LOG_TRIVIAL(debug) << "Using profile: " << profilename;
|
||||||
|
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
Config cfg{profile.data()};
|
Config cfg{profilename.data()};
|
||||||
Document doc{cfg};
|
Document doc{cfg};
|
||||||
doc.parse();
|
doc.parse();
|
||||||
|
|
||||||
MastoAPI masto{cfg.data};
|
MastoAPI masto{cfg.profiledata};
|
||||||
if (!doc.new_items.empty())
|
if (!doc.new_items.empty())
|
||||||
{
|
{
|
||||||
for (const auto &item : doc.new_items)
|
for (const auto &item : doc.new_items)
|
||||||
{
|
{
|
||||||
masto.post_item(item);
|
masto.post_item(item);
|
||||||
cfg.data.last_guid = item.guid;
|
cfg.profiledata.last_guid = item.guid;
|
||||||
if (item != *doc.new_items.rbegin())
|
if (item != *doc.new_items.rbegin())
|
||||||
{ // Don't sleep if this is the last item.
|
{ // Don't sleep if this is the last item.
|
||||||
sleep_for(seconds(cfg.data.interval));
|
sleep_for(seconds(cfg.profiledata.interval));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
cfg.write();
|
cfg.write();
|
||||||
|
@ -134,6 +135,11 @@ int main(int argc, char *argv[])
|
||||||
cerr << e.what() << '\n';
|
cerr << e.what() << '\n';
|
||||||
return error::network;
|
return error::network;
|
||||||
}
|
}
|
||||||
|
catch (const Json::RuntimeError &e)
|
||||||
|
{
|
||||||
|
cerr << "JSON error:\n" << e.what() << '\n';
|
||||||
|
return error::json;
|
||||||
|
}
|
||||||
catch (const runtime_error &e)
|
catch (const runtime_error &e)
|
||||||
{
|
{
|
||||||
cerr << e.what() << '\n';
|
cerr << e.what() << '\n';
|
||||||
|
|
Loading…
Reference in New Issue
Block a user