mastobotmon/src/mastobotmon.cpp

229 lines
8.0 KiB
C++
Raw Permalink Normal View History

2018-02-27 23:38:05 +01:00
/* This file is part of mastobotmon.
* Copyright © 2018 tastytea <tastytea@tastytea.de>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, version 3.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <iostream>
#include <string>
2018-03-02 08:48:02 +01:00
#include <cstring>
2018-02-27 23:38:05 +01:00
#include <cstdint>
2018-02-28 06:23:42 +01:00
#include <vector>
2018-03-02 06:11:18 +01:00
#include <chrono>
#include <ctime>
#include <sstream>
#include <iomanip> // get_time
2018-03-07 11:41:16 +01:00
#include <fstream>
#include <regex>
2018-04-11 15:58:42 +02:00
#include <memory>
2018-03-07 09:21:13 +01:00
#include <jsoncpp/json/json.h>
2018-04-11 16:52:48 +02:00
#include <mastodon-cpp/easy/entities/account.hpp>
#include <mastodon-cpp/easy/entities/notification.hpp>
2018-02-27 23:38:05 +01:00
#include "version.hpp"
#include "mastobotmon.hpp"
using std::cout;
using std::cerr;
using std::cin;
using std::string;
2018-03-02 06:11:18 +01:00
using std::uint16_t;
2018-04-11 16:52:48 +02:00
using Mastodon::Easy;
using std::chrono::system_clock;
2018-02-27 23:38:05 +01:00
2018-03-07 18:33:13 +01:00
Json::Value config; // Declared in mastobotmon.hpp
2018-04-11 16:52:48 +02:00
const bool write_mentions(const string &straccount, std::vector<std::shared_ptr<Easy::Notification>> &mentions)
2018-03-07 11:41:16 +01:00
{
2018-03-07 18:33:13 +01:00
const string filepath = config["data_dir"].asString() + "/mentions_" + straccount + ".csv";
2018-03-07 11:41:16 +01:00
const std::regex restrip("<[^>]*>");
std::ofstream outfile(filepath, std::ios::app);
if (outfile.is_open())
{
string output;
2018-04-11 16:52:48 +02:00
for (std::shared_ptr<Easy::Notification> &mention : mentions)
2018-03-07 11:41:16 +01:00
{
2018-04-11 16:52:48 +02:00
output = mention->status().account().acct() + ';';
output += Easy::strtime_utc(mention->status().created_at(), "%T") + ';';
2018-04-11 16:52:48 +02:00
output += mention->status().content() + ';';
output += mention->status().url() + '\n';
2018-03-07 11:41:16 +01:00
output = std::regex_replace(output, restrip, "");
outfile.write(output.c_str(), output.length());
}
outfile.close();
2018-03-07 18:33:13 +01:00
cout << "New mentions in: " << filepath << '\n';
2018-03-07 11:41:16 +01:00
return true;
}
2018-03-07 18:33:13 +01:00
cerr << "Error writing file: " << filepath << '\n';
2018-03-07 11:41:16 +01:00
return false;
}
2018-04-11 16:52:48 +02:00
const bool write_statistics(const string &straccount, Easy::Account &account_entity)
2018-03-15 14:35:58 +01:00
{
const string filepath = config["data_dir"].asString() + "/statistics_" + straccount + ".csv";
std::ofstream outfile(filepath, std::ios::app);
if (outfile.is_open())
{
string output;
std::chrono::time_point<std::chrono::system_clock> now = std::chrono::system_clock::now();
std::time_t now_t = std::chrono::system_clock::to_time_t(now);
std::tm now_tm = *std::localtime(&now_t);
std::stringstream ss;
ss << std::put_time(&now_tm, "%Y-%m-%dT%T");
output = ss.str() + ';';
2018-04-11 16:57:55 +02:00
output += std::to_string(account_entity.statuses_count()) + ';';
output += std::to_string(account_entity.followers_count()) + '\n';
2018-03-15 14:35:58 +01:00
outfile.write(output.c_str(), output.length());
outfile.close();
return true;
}
cerr << "Error writing file: " << filepath << '\n';
return false;
}
2018-02-27 23:38:05 +01:00
int main(int argc, char *argv[])
{
2018-03-07 11:41:16 +01:00
uint16_t mainret = 0;
2018-03-07 18:33:13 +01:00
if (!read_config())
2018-02-27 23:38:05 +01:00
{
return 1;
}
2018-03-02 08:48:02 +01:00
if (argc > 1)
{
if ((std::strncmp(argv[1], "add", 3)) == 0)
{
2018-03-07 18:33:13 +01:00
add_account();
2018-03-02 08:48:02 +01:00
}
}
2018-04-11 15:58:42 +02:00
std::vector<std::shared_ptr<Account>> accounts;
2018-02-28 06:23:42 +01:00
2018-03-07 18:33:13 +01:00
for (auto it = config["accounts"].begin(); it != config["accounts"].end(); ++it)
2018-02-27 23:38:05 +01:00
{
// Construct an Account object for every account and store it in a vector
2018-03-07 09:21:13 +01:00
string instance = it.name();
2018-02-28 06:23:42 +01:00
instance = instance.substr(instance.find('@') + 1);
2018-04-11 15:58:42 +02:00
std::shared_ptr<Account> acc(std::make_shared<Account>(instance, (*it)["access_token"].asString()));
//Account *acc = new Account(instance, (*it)["access_token"].asString());
acc->set_useragent("mastobotmon/" + string(global::version));
2018-03-07 09:21:13 +01:00
acc->set_minutes((*it)["minutes"].asUInt());
2018-03-07 11:41:16 +01:00
if (!(*it)["last_mention"].empty())
{
acc->set_last_mention_id((*it)["last_mention"].asUInt64());
}
2018-04-11 15:58:42 +02:00
accounts.push_back(acc);
2018-02-28 06:23:42 +01:00
}
2018-03-07 18:33:13 +01:00
if (config["mode"] == "cron")
2018-02-28 06:23:42 +01:00
{
2018-04-11 15:58:42 +02:00
for (std::shared_ptr<Account> &acc : accounts)
2018-02-28 06:23:42 +01:00
{
std::string answer;
2018-04-11 15:58:42 +02:00
uint16_t ret = acc->get(Mastodon::API::v1::accounts_verify_credentials, answer);
if (ret == 0)
{
2018-04-11 15:58:42 +02:00
if (!acc->get_header("X-RateLimit-Remaining").empty() &&
std::stoi(acc->get_header("X-RateLimit-Remaining")) < 2)
{
cerr << "ERROR: Reached limit of API calls.\n";
cerr << "Counter will reset at " << acc->get_header("X-RateLimit-Reset")
<< '\n';
return 2;
}
2018-04-11 16:52:48 +02:00
Easy::Account account_entity(answer);
const string id = std::to_string(account_entity.id());
const string straccount = account_entity.acct() + "@" + acc->get_instance();
write_statistics(straccount, account_entity);
Account::parametermap parameters(
{
{ "id", { id } },
{ "limit", { "1" } }
});
ret = acc->get(Mastodon::API::v1::accounts_id_statuses, parameters, answer);
if (ret == 0)
{
const Easy::Status status(answer);
2018-03-02 06:11:18 +01:00
const auto now = std::chrono::system_clock::now();
const auto last = status.created_at();
2018-03-02 06:11:18 +01:00
auto elapsed = std::chrono::duration_cast<std::chrono::minutes>(now - last);
2018-04-11 15:58:42 +02:00
if (elapsed.count() > acc->get_minutes())
2018-03-02 06:11:18 +01:00
{
2018-03-02 14:08:49 +01:00
uint16_t minutes = elapsed.count();
std::uint8_t hours = 0;
std:: uint8_t days = 0;
while (minutes >= 1440)
{
minutes -= 1440;
days += 1;
}
while (minutes >= 60)
{
minutes -= 60;
hours += 1;
}
cout << "ALERT: " << account_entity.acct() << " is inactive since ";
2018-03-02 14:08:49 +01:00
if (days > 0)
{
cout << std::to_string(days) << " days, ";
}
if (hours > 0)
{
cout << std::to_string(hours) << " hours and ";
}
cout << std::to_string(minutes) << " minutes.\n";
2018-03-02 06:11:18 +01:00
}
2018-03-07 11:41:16 +01:00
2018-04-11 15:58:42 +02:00
ret = acc->get_mentions(answer);
2018-03-07 11:41:16 +01:00
if (ret == 0)
{
2018-04-11 16:52:48 +02:00
std::vector<std::shared_ptr<Easy::Notification>> notifications;
for (const string &str : Easy::json_array_to_vector(answer))
{
notifications.push_back(std::make_shared<Easy::Notification>(str));
}
if (!notifications.empty())
2018-03-07 11:41:16 +01:00
{
2018-04-11 16:52:48 +02:00
const std::uint64_t lastid = notifications[0]->id();
2018-04-11 15:58:42 +02:00
acc->set_last_mention_id(lastid);
2018-03-07 18:33:13 +01:00
config["accounts"][straccount]["last_mention"] = lastid;
2018-04-11 16:52:48 +02:00
write_mentions(straccount, notifications);
2018-03-07 11:41:16 +01:00
}
}
}
}
2018-02-28 06:23:42 +01:00
if (ret != 0)
{
cerr << "Error: " << ret << '\n';
2018-03-07 11:41:16 +01:00
mainret = ret;
}
2018-02-28 06:23:42 +01:00
}
2018-02-27 23:38:05 +01:00
}
2018-03-07 18:33:13 +01:00
if (!write_config())
2018-03-07 11:41:16 +01:00
{
cerr << "Couldn't write config file\n";
}
return mainret;
2018-02-27 23:38:05 +01:00
}