summaryrefslogtreecommitdiff
path: root/src/main.cpp
blob: 3c8f5e70fe6ac5cb5abedd0fe287051dc8a3bbe2 (plain)
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
#include <optional>
#include <pqxx/pqxx>
#include <string>
#include <vector>

#include "api/twitch/helix_client.hpp"
#include "bundle.hpp"
#include "commands/command.hpp"
#include "config.hpp"
#include "handlers.hpp"
#include "irc/client.hpp"
#include "irc/message.hpp"
#include "localization/localization.hpp"
#include "logger.hpp"
#include "stream.hpp"
#include "timer.hpp"

int main(int argc, char *argv[]) {
  bot::log::info("Main", "Starting up...");

  std::optional<bot::Configuration> o_cfg =
      bot::parse_configuration_from_file(".env");

  if (!o_cfg.has_value()) {
    return 1;
  }

  bot::Configuration cfg = o_cfg.value();

  if (cfg.twitch_credentials.client_id.empty() ||
      cfg.twitch_credentials.token.empty()) {
    bot::log::error("Main",
                    "TWITCH_CREDENTIALS.CLIENT_ID and TWITCH_CREDENTIALS.TOKEN "
                    "must be set in environmental file!");
    return 1;
  }

  if (cfg.database.name.empty() || cfg.database.user.empty() ||
      cfg.database.password.empty() || cfg.database.host.empty() ||
      cfg.database.port.empty()) {
    bot::log::error("Main",
                    "DB_NAME, DB_USER, DB_PASSWORD, DB_HOST, DB_PORT "
                    "must be set in environmental file!");
    return 1;
  }

  bot::irc::Client client(cfg.twitch_credentials.client_id,
                          cfg.twitch_credentials.token);
  bot::command::CommandLoader command_loader;
  bot::loc::Localization localization("localization");
  bot::api::twitch::HelixClient helix_client(cfg.twitch_credentials.token,
                                             cfg.twitch_credentials.client_id);

  client.join(client.get_bot_username());

  pqxx::connection conn(GET_DATABASE_CONNECTION_URL(cfg));
  pqxx::work *work = new pqxx::work(conn);

  pqxx::result rows = work->exec(
      "SELECT alias_id FROM channels WHERE opted_out_at is null AND alias_id "
      "!= " +
      std::to_string(client.get_bot_id()));

  std::vector<int> ids;

  for (const auto &row : rows) {
    ids.push_back(row[0].as<int>());
  }

  auto helix_channels = helix_client.get_users(ids);

  // it could be optimized
  for (const auto &helix_channel : helix_channels) {
    auto channel =
        work->exec("SELECT id, alias_name FROM channels WHERE alias_id = " +
                   std::to_string(helix_channel.id));

    if (!channel.empty()) {
      std::string name = channel[0][1].as<std::string>();

      if (name != helix_channel.login) {
        work->exec("UPDATE channels SET alias_name = '" + helix_channel.login +
                   "' WHERE id = " + std::to_string(channel[0][0].as<int>()));
        work->commit();

        delete work;
        work = new pqxx::work(conn);
      }

      client.join(helix_channel.login);
    }
  }

  work->commit();
  delete work;

  conn.close();

  bot::stream::StreamListenerClient stream_listener_client(helix_client, client,
                                                           cfg);

  client.on<bot::irc::MessageType::Privmsg>(
      [&client, &command_loader, &localization, &cfg, &helix_client](
          const bot::irc::Message<bot::irc::MessageType::Privmsg> &message) {
        bot::InstanceBundle bundle{client, helix_client, localization, cfg};

        pqxx::connection conn(GET_DATABASE_CONNECTION_URL(cfg));

        bot::handlers::handle_private_message(bundle, command_loader, message,
                                              conn);

        conn.close();
      });

  client.run();

  std::vector<std::thread> threads;
  threads.push_back(std::thread(bot::create_timer_thread, &client, &cfg));
  threads.push_back(std::thread(&bot::stream::StreamListenerClient::run,
                                &stream_listener_client));

  for (auto &thread : threads) {
    thread.join();
  }

  return 0;
}