-
Notifications
You must be signed in to change notification settings - Fork 1
/
Copy pathmain.cpp
131 lines (117 loc) · 4.45 KB
/
main.cpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
#include "cpr/status_codes.h"
#include <cpr/api.h>
#include <cpr/response.h>
#include <sstream>
#include <stdexcept>
#include <string>
#include <expected>
#include <tgbotxx/tgbotxx.hpp>
#include <cpr/cpr.h>
#include <nlohmann/json.hpp>
#include <csignal>
using namespace tgbotxx;
class WeatherBot : public Bot {
public:
WeatherBot(const std::string &token, const std::string &weatherApiKey)
: Bot(token), m_weatherApiKey(weatherApiKey) {}
private:
std::string m_weatherApiKey;
inline static const std::string WEATHER_API_ENDPOINT = "https://api.weatherapi.com/v1";
inline static const std::map<std::string, std::string> WEATHER_STATUS_EMOTICONS = {
{"sun", "🌞"},
{"rain", "🌧"},
{"cloud", "☁"},
{"clear", "🌅"},
{"overcast", "🌫️"},
{"mist", "🌁"}
};
protected:
nl::json getCurrentWeatherInfo(const std::string &cityName) {
std::ostringstream oss{};
oss << WEATHER_API_ENDPOINT << "/current.json?key=" << m_weatherApiKey << "&q=" << cityName;
cpr::Response res = cpr::Get(cpr::Url{oss.str()});
switch (res.status_code) {
case cpr::status::HTTP_OK:
case cpr::status::HTTP_BAD_REQUEST:
return nl::json::parse(res.text);
default: {
nl::json err;
err["error"]["message"] = "Failed to get weather info";
return err;
}
}
}
private:
void onStart() override {
// Drop pending updates
api()->deleteWebhook(true);
// Register my commands
Ptr<BotCommand> startCmd(new BotCommand());
startCmd->command = "/start";
startCmd->description = "Start interacting with the bot";
api()->setMyCommands({startCmd});
std::cout << "Bot " << api()->getMe()->username << " Started\n";
}
void onStop() override {
std::cout << "\nStopping Bot. Please wait...\n";
}
void onNonCommandMessage(const Ptr<Message> &message) override try {
std::string cityName = message->text;
nl::json info = getCurrentWeatherInfo(cityName);
if (info.contains("error")) {
api()->sendMessage(message->chat->id, info["error"]["message"]);
} else {
std::string name = info["location"]["name"];
std::string region = info["location"]["region"];
std::string country = info["location"]["country"];
std::string localtime = info["location"]["localtime"];
std::string condition = info["current"]["condition"]["text"];
int humidity = info["current"]["humidity"];
float wind_kph = info["current"]["wind_kph"];
std::time_t lastUpdatedTime = info["current"]["last_updated_epoch"];
int temp_c = info["current"]["temp_c"];
float temp_f = info["current"]["temp_f"];
std::string emoticon = "🌍";
for (const auto &[key, value]: WEATHER_STATUS_EMOTICONS) {
if (StringUtils::toLower(condition).find(key) != std::string::npos) {
emoticon = value;
break;
}
}
std::ostringstream oss{};
oss << "------ 🌡️ " << temp_c << " °C (" << temp_f << " °F) " << condition << " " << emoticon << " ------\n"
<< "* Humidity: " << humidity << '\n'
<< "* Wind (kph): " << wind_kph << '\n'
<< "* Name: " << name << '\n'
<< "* Country: " << country << '\n'
<< "* Region: " << region << '\n'
<< "* Local Time: " << localtime << '\n'
<< "* Updated On: " << DateTimeUtils::toString(lastUpdatedTime) << '\n'
<< "------------------------------------------------------\n";
api()->sendMessage(message->chat->id, oss.str());
}
} catch (const std::exception &e) {
std::cerr << e.what() << std::endl;
}
void onCommand(const Ptr<Message> &message) override {
if (message->text == "/start") {
api()->sendMessage(message->chat->id, "Welcome to WeatherBot! Please send a city name to get weather information.");
}
}
};
int main(int argc, const char *argv[]) {
if (argc < 3) {
std::cerr << "Usage:\nweather_bot \"BOT_TOKEN\" \"WEATHER_API_KEY\"\n";
return EXIT_FAILURE;
}
static std::unique_ptr<WeatherBot> BOT;
std::signal(SIGINT, [](int) { // Graceful Bot exit on CTRL+C
if (BOT) {
BOT->stop();
}
std::exit(EXIT_SUCCESS);
});
BOT = std::make_unique<WeatherBot>(argv[1], argv[2]);
BOT->start();
return EXIT_SUCCESS;
}