mirror of
https://github.com/uowuo/abaddon.git
synced 2024-11-10 14:10:10 +00:00
settings, token entry, receive READY
This commit is contained in:
parent
18af78e6af
commit
3c3fe3b9f7
3
.gitignore
vendored
3
.gitignore
vendored
@ -348,3 +348,6 @@ MigrationBackup/
|
|||||||
|
|
||||||
# Ionide (cross platform F# VS Code tools) working folder
|
# Ionide (cross platform F# VS Code tools) working folder
|
||||||
.ionide/
|
.ionide/
|
||||||
|
|
||||||
|
abaddon.ini
|
||||||
|
testdata/
|
||||||
|
@ -143,15 +143,19 @@
|
|||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClCompile Include="abaddon.cpp" />
|
<ClCompile Include="abaddon.cpp" />
|
||||||
<ClCompile Include="components\channels.cpp" />
|
<ClCompile Include="components\channels.cpp" />
|
||||||
|
<ClCompile Include="dialogs\token.cpp" />
|
||||||
<ClCompile Include="discord\discord.cpp" />
|
<ClCompile Include="discord\discord.cpp" />
|
||||||
<ClCompile Include="discord\websocket.cpp" />
|
<ClCompile Include="discord\websocket.cpp" />
|
||||||
|
<ClCompile Include="settings.cpp" />
|
||||||
<ClCompile Include="windows\mainwindow.cpp" />
|
<ClCompile Include="windows\mainwindow.cpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="components\channels.hpp" />
|
<ClInclude Include="components\channels.hpp" />
|
||||||
<ClInclude Include="abaddon.hpp" />
|
<ClInclude Include="abaddon.hpp" />
|
||||||
|
<ClInclude Include="dialogs\token.hpp" />
|
||||||
<ClInclude Include="discord\discord.hpp" />
|
<ClInclude Include="discord\discord.hpp" />
|
||||||
<ClInclude Include="discord\websocket.hpp" />
|
<ClInclude Include="discord\websocket.hpp" />
|
||||||
|
<ClInclude Include="settings.hpp" />
|
||||||
<ClInclude Include="windows\mainwindow.hpp" />
|
<ClInclude Include="windows\mainwindow.hpp" />
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||||
|
@ -30,6 +30,12 @@
|
|||||||
<ClCompile Include="discord\discord.cpp">
|
<ClCompile Include="discord\discord.cpp">
|
||||||
<Filter>Source Files</Filter>
|
<Filter>Source Files</Filter>
|
||||||
</ClCompile>
|
</ClCompile>
|
||||||
|
<ClCompile Include="settings.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
|
<ClCompile Include="dialogs\token.cpp">
|
||||||
|
<Filter>Source Files</Filter>
|
||||||
|
</ClCompile>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
<ItemGroup>
|
<ItemGroup>
|
||||||
<ClInclude Include="windows\mainwindow.hpp">
|
<ClInclude Include="windows\mainwindow.hpp">
|
||||||
@ -47,5 +53,11 @@
|
|||||||
<ClInclude Include="abaddon.hpp">
|
<ClInclude Include="abaddon.hpp">
|
||||||
<Filter>Header Files</Filter>
|
<Filter>Header Files</Filter>
|
||||||
</ClInclude>
|
</ClInclude>
|
||||||
|
<ClInclude Include="settings.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
|
<ClInclude Include="dialogs\token.hpp">
|
||||||
|
<Filter>Header Files</Filter>
|
||||||
|
</ClInclude>
|
||||||
</ItemGroup>
|
</ItemGroup>
|
||||||
</Project>
|
</Project>
|
96
abaddon.cpp
96
abaddon.cpp
@ -1,44 +1,92 @@
|
|||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
#include "discord/discord.hpp"
|
|
||||||
#include "windows/mainwindow.hpp"
|
|
||||||
#include <memory>
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
|
#include "discord/discord.hpp"
|
||||||
|
#include "dialogs/token.hpp"
|
||||||
#include "abaddon.hpp"
|
#include "abaddon.hpp"
|
||||||
|
|
||||||
#ifdef _WIN32
|
#ifdef _WIN32
|
||||||
#pragma comment(lib, "crypt32.lib")
|
#pragma comment(lib, "crypt32.lib")
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
int Abaddon::DoMainLoop() {
|
Abaddon::Abaddon()
|
||||||
m_gtk_app = Gtk::Application::create("com.github.lorpus.abaddon");
|
: m_settings("abaddon.ini") {
|
||||||
|
m_discord.SetAbaddon(this);
|
||||||
MainWindow main;
|
LoadFromSettings();
|
||||||
main.SetAbaddon(this);
|
|
||||||
main.set_title("Abaddon");
|
|
||||||
main.show();
|
|
||||||
|
|
||||||
m_gtk_app->signal_shutdown().connect([&]() {
|
|
||||||
m_discord.Stop();
|
|
||||||
});
|
|
||||||
|
|
||||||
/*sigc::connection draw_signal_handler = main.signal_draw().connect([&](const Cairo::RefPtr<Cairo::Context> &ctx) -> bool {
|
|
||||||
draw_signal_handler.disconnect();
|
|
||||||
|
|
||||||
return false;
|
|
||||||
});*/
|
|
||||||
|
|
||||||
return m_gtk_app->run(main);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Abaddon::StartDiscordThread() {
|
Abaddon::~Abaddon() {
|
||||||
|
m_settings.Close();
|
||||||
|
m_discord.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
int Abaddon::StartGTK() {
|
||||||
|
m_gtk_app = Gtk::Application::create("com.github.lorpus.abaddon");
|
||||||
|
|
||||||
|
m_main_window = std::make_unique<MainWindow>();
|
||||||
|
m_main_window->SetAbaddon(this);
|
||||||
|
m_main_window->set_title("Abaddon");
|
||||||
|
m_main_window->show();
|
||||||
|
m_main_window->UpdateMenuStatus();
|
||||||
|
|
||||||
|
m_gtk_app->signal_shutdown().connect([&]() {
|
||||||
|
StopDiscord();
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!m_settings.IsValid()) {
|
||||||
|
Gtk::MessageDialog dlg(*m_main_window, "The settings file could not be created!", false, Gtk::MESSAGE_ERROR, Gtk::BUTTONS_OK, true);
|
||||||
|
dlg.run();
|
||||||
|
}
|
||||||
|
|
||||||
|
return m_gtk_app->run(*m_main_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Abaddon::LoadFromSettings() {
|
||||||
|
std::string token = m_settings.GetSetting("discord", "token");
|
||||||
|
if (token.size()) {
|
||||||
|
m_discord_token = token;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void Abaddon::StartDiscord() {
|
||||||
m_discord.Start();
|
m_discord.Start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Abaddon::StopDiscord() {
|
||||||
|
m_discord.Stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Abaddon::IsDiscordActive() const {
|
||||||
|
return m_discord.IsStarted();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string Abaddon::GetDiscordToken() const {
|
||||||
|
return m_discord_token;
|
||||||
|
}
|
||||||
|
|
||||||
void Abaddon::ActionConnect() {
|
void Abaddon::ActionConnect() {
|
||||||
if (!m_discord.IsStarted())
|
if (!m_discord.IsStarted())
|
||||||
StartDiscordThread();
|
StartDiscord();
|
||||||
|
m_main_window->UpdateMenuStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Abaddon::ActionDisconnect() {
|
||||||
|
if (m_discord.IsStarted())
|
||||||
|
StopDiscord();
|
||||||
|
m_main_window->UpdateMenuStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
void Abaddon::ActionSetToken() {
|
||||||
|
TokenDialog dlg(*m_main_window);
|
||||||
|
auto response = dlg.run();
|
||||||
|
if (response == Gtk::RESPONSE_OK) {
|
||||||
|
m_discord_token = dlg.GetToken();
|
||||||
|
m_main_window->UpdateMenuStatus();
|
||||||
|
m_settings.SetSetting("discord", "token", m_discord_token);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int main(int argc, char **argv) {
|
int main(int argc, char **argv) {
|
||||||
Abaddon abaddon;
|
Abaddon abaddon;
|
||||||
return abaddon.DoMainLoop();
|
return abaddon.StartGTK();
|
||||||
}
|
}
|
||||||
|
23
abaddon.hpp
23
abaddon.hpp
@ -1,14 +1,33 @@
|
|||||||
#include <gtkmm.h>
|
#include <gtkmm.h>
|
||||||
|
#include <memory>
|
||||||
|
#include <string>
|
||||||
#include "discord/discord.hpp"
|
#include "discord/discord.hpp"
|
||||||
|
#include "windows/mainwindow.hpp"
|
||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
class Abaddon {
|
class Abaddon {
|
||||||
public:
|
public:
|
||||||
int DoMainLoop();
|
Abaddon();
|
||||||
void StartDiscordThread();
|
~Abaddon();
|
||||||
|
|
||||||
|
int StartGTK();
|
||||||
|
void StartDiscord();
|
||||||
|
void StopDiscord();
|
||||||
|
|
||||||
|
void LoadFromSettings();
|
||||||
|
|
||||||
void ActionConnect();
|
void ActionConnect();
|
||||||
|
void ActionDisconnect();
|
||||||
|
void ActionSetToken();
|
||||||
|
|
||||||
|
std::string GetDiscordToken() const;
|
||||||
|
bool IsDiscordActive() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
std::string m_discord_token;
|
||||||
|
|
||||||
Glib::RefPtr<Gtk::Application> m_gtk_app;
|
Glib::RefPtr<Gtk::Application> m_gtk_app;
|
||||||
DiscordClient m_discord;
|
DiscordClient m_discord;
|
||||||
|
SettingsManager m_settings;
|
||||||
|
std::unique_ptr<MainWindow> m_main_window; // wah wah cant create a gtkstylecontext fuck you
|
||||||
};
|
};
|
34
dialogs/token.cpp
Normal file
34
dialogs/token.cpp
Normal file
@ -0,0 +1,34 @@
|
|||||||
|
#include "token.hpp"
|
||||||
|
|
||||||
|
TokenDialog::TokenDialog(Gtk::Window &parent)
|
||||||
|
: Gtk::Dialog("Set Token", parent, true)
|
||||||
|
, m_layout(Gtk::ORIENTATION_VERTICAL)
|
||||||
|
, m_bbox(Gtk::ORIENTATION_HORIZONTAL)
|
||||||
|
, m_ok("OK")
|
||||||
|
, m_cancel("Cancel") {
|
||||||
|
set_default_size(300, 50);
|
||||||
|
|
||||||
|
m_ok.signal_clicked().connect([&]() {
|
||||||
|
m_token = m_entry.get_text();
|
||||||
|
response(Gtk::RESPONSE_OK);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_cancel.signal_clicked().connect([&]() {
|
||||||
|
response(Gtk::RESPONSE_CANCEL);
|
||||||
|
});
|
||||||
|
|
||||||
|
m_bbox.pack_start(m_ok, Gtk::PACK_SHRINK);
|
||||||
|
m_bbox.pack_start(m_cancel, Gtk::PACK_SHRINK);
|
||||||
|
m_bbox.set_layout(Gtk::BUTTONBOX_END);
|
||||||
|
|
||||||
|
m_entry.set_hexpand(true);
|
||||||
|
m_layout.add(m_entry);
|
||||||
|
m_layout.add(m_bbox);
|
||||||
|
get_content_area()->add(m_layout);
|
||||||
|
|
||||||
|
show_all_children();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string TokenDialog::GetToken() {
|
||||||
|
return m_token;
|
||||||
|
}
|
19
dialogs/token.hpp
Normal file
19
dialogs/token.hpp
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include <string>
|
||||||
|
|
||||||
|
class TokenDialog : public Gtk::Dialog {
|
||||||
|
public:
|
||||||
|
TokenDialog(Gtk::Window &parent);
|
||||||
|
std::string GetToken();
|
||||||
|
|
||||||
|
protected:
|
||||||
|
Gtk::Box m_layout;
|
||||||
|
Gtk::Button m_ok;
|
||||||
|
Gtk::Button m_cancel;
|
||||||
|
Gtk::ButtonBox m_bbox;
|
||||||
|
Gtk::Entry m_entry;
|
||||||
|
|
||||||
|
private:
|
||||||
|
std::string m_token;
|
||||||
|
};
|
@ -1,10 +1,18 @@
|
|||||||
|
#include "../abaddon.hpp"
|
||||||
#include "discord.hpp"
|
#include "discord.hpp"
|
||||||
|
#include <cassert>
|
||||||
|
|
||||||
DiscordClient::DiscordClient() {}
|
DiscordClient::DiscordClient() {
|
||||||
|
LoadEventMap();
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordClient::SetAbaddon(Abaddon *ptr) {
|
||||||
|
m_abaddon = ptr;
|
||||||
|
}
|
||||||
|
|
||||||
void DiscordClient::Start() {
|
void DiscordClient::Start() {
|
||||||
if (m_client_connected)
|
assert(!m_client_connected);
|
||||||
throw std::runtime_error("attempt to start client twice consecutively");
|
assert(!m_websocket.IsOpen());
|
||||||
|
|
||||||
m_client_connected = true;
|
m_client_connected = true;
|
||||||
m_websocket.StartConnection(DiscordGateway);
|
m_websocket.StartConnection(DiscordGateway);
|
||||||
@ -13,9 +21,11 @@ void DiscordClient::Start() {
|
|||||||
|
|
||||||
void DiscordClient::Stop() {
|
void DiscordClient::Stop() {
|
||||||
if (!m_client_connected) return;
|
if (!m_client_connected) return;
|
||||||
|
|
||||||
m_heartbeat_waiter.kill();
|
m_heartbeat_waiter.kill();
|
||||||
m_heartbeat_thread.join();
|
m_heartbeat_thread.join();
|
||||||
m_client_connected = false;
|
m_client_connected = false;
|
||||||
|
m_websocket.Stop();
|
||||||
}
|
}
|
||||||
|
|
||||||
bool DiscordClient::IsStarted() const {
|
bool DiscordClient::IsStarted() const {
|
||||||
@ -36,16 +46,33 @@ void DiscordClient::HandleGatewayMessage(nlohmann::json j) {
|
|||||||
HelloMessageData d = m.Data;
|
HelloMessageData d = m.Data;
|
||||||
m_heartbeat_msec = d.HeartbeatInterval;
|
m_heartbeat_msec = d.HeartbeatInterval;
|
||||||
m_heartbeat_thread = std::thread(std::bind(&DiscordClient::HeartbeatThread, this));
|
m_heartbeat_thread = std::thread(std::bind(&DiscordClient::HeartbeatThread, this));
|
||||||
|
SendIdentify();
|
||||||
} break;
|
} break;
|
||||||
case GatewayOp::HeartbeatAck: {
|
case GatewayOp::HeartbeatAck: {
|
||||||
m_heartbeat_acked = true;
|
m_heartbeat_acked = true;
|
||||||
} break;
|
} break;
|
||||||
|
case GatewayOp::Event: {
|
||||||
|
auto iter = m_event_map.find(m.Type);
|
||||||
|
if (iter == m_event_map.end()) {
|
||||||
|
printf("Unknown event %s\n", m.Type.c_str());
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
switch (iter->second) {
|
||||||
|
case GatewayEvent::READY: {
|
||||||
|
HandleGatewayReady(m);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} break;
|
||||||
default:
|
default:
|
||||||
printf("Unknown opcode %d\n", m.Opcode);
|
printf("Unknown opcode %d\n", m.Opcode);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscordClient::HandleGatewayReady(const GatewayMessage &msg) {
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
void DiscordClient::HeartbeatThread() {
|
void DiscordClient::HeartbeatThread() {
|
||||||
while (m_client_connected) {
|
while (m_client_connected) {
|
||||||
if (!m_heartbeat_acked) {
|
if (!m_heartbeat_acked) {
|
||||||
@ -57,13 +84,28 @@ void DiscordClient::HeartbeatThread() {
|
|||||||
HeartbeatMessage msg;
|
HeartbeatMessage msg;
|
||||||
msg.Sequence = m_last_sequence;
|
msg.Sequence = m_last_sequence;
|
||||||
nlohmann::json j = msg;
|
nlohmann::json j = msg;
|
||||||
m_websocket.Send(j.dump());
|
m_websocket.Send(j);
|
||||||
|
|
||||||
if (!m_heartbeat_waiter.wait_for(std::chrono::milliseconds(m_heartbeat_msec)))
|
if (!m_heartbeat_waiter.wait_for(std::chrono::milliseconds(m_heartbeat_msec)))
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void DiscordClient::SendIdentify() {
|
||||||
|
auto token = m_abaddon->GetDiscordToken();
|
||||||
|
assert(token.size());
|
||||||
|
IdentifyMessage msg;
|
||||||
|
msg.Properties.OS = "OpenBSD";
|
||||||
|
msg.Properties.Device = GatewayIdentity;
|
||||||
|
msg.Properties.Browser = GatewayIdentity;
|
||||||
|
msg.Token = token;
|
||||||
|
m_websocket.Send(msg);
|
||||||
|
}
|
||||||
|
|
||||||
|
void DiscordClient::LoadEventMap() {
|
||||||
|
m_event_map["READY"] = GatewayEvent::READY;
|
||||||
|
}
|
||||||
|
|
||||||
void from_json(const nlohmann::json &j, GatewayMessage &m) {
|
void from_json(const nlohmann::json &j, GatewayMessage &m) {
|
||||||
j.at("op").get_to(m.Opcode);
|
j.at("op").get_to(m.Opcode);
|
||||||
m.Data = j.at("d");
|
m.Data = j.at("d");
|
||||||
@ -76,6 +118,22 @@ void from_json(const nlohmann::json &j, HelloMessageData &m) {
|
|||||||
j.at("heartbeat_interval").get_to(m.HeartbeatInterval);
|
j.at("heartbeat_interval").get_to(m.HeartbeatInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void to_json(nlohmann::json &j, const IdentifyProperties &m) {
|
||||||
|
j["$os"] = m.OS;
|
||||||
|
j["$browser"] = m.Browser;
|
||||||
|
j["$device"] = m.Device;
|
||||||
|
}
|
||||||
|
|
||||||
|
void to_json(nlohmann::json &j, const IdentifyMessage &m) {
|
||||||
|
j["op"] = GatewayOp::Identify;
|
||||||
|
j["d"] = nlohmann::json::object();
|
||||||
|
j["d"]["token"] = m.Token;
|
||||||
|
j["d"]["properties"] = m.Properties;
|
||||||
|
|
||||||
|
if (m.LargeThreshold)
|
||||||
|
j["d"]["large_threshold"] = m.LargeThreshold;
|
||||||
|
}
|
||||||
|
|
||||||
void to_json(nlohmann::json &j, const HeartbeatMessage &m) {
|
void to_json(nlohmann::json &j, const HeartbeatMessage &m) {
|
||||||
j["op"] = GatewayOp::Heartbeat;
|
j["op"] = GatewayOp::Heartbeat;
|
||||||
if (m.Sequence == -1)
|
if (m.Sequence == -1)
|
||||||
|
@ -2,13 +2,20 @@
|
|||||||
#include "websocket.hpp"
|
#include "websocket.hpp"
|
||||||
#include <nlohmann/json.hpp>
|
#include <nlohmann/json.hpp>
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
enum class GatewayOp : int {
|
enum class GatewayOp : int {
|
||||||
|
Event = 0,
|
||||||
Heartbeat = 1,
|
Heartbeat = 1,
|
||||||
|
Identify = 2,
|
||||||
Hello = 10,
|
Hello = 10,
|
||||||
HeartbeatAck = 11,
|
HeartbeatAck = 11,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum class GatewayEvent : int {
|
||||||
|
READY,
|
||||||
|
};
|
||||||
|
|
||||||
struct GatewayMessage {
|
struct GatewayMessage {
|
||||||
GatewayOp Opcode;
|
GatewayOp Opcode;
|
||||||
nlohmann::json Data;
|
nlohmann::json Data;
|
||||||
@ -23,6 +30,28 @@ struct HelloMessageData {
|
|||||||
friend void from_json(const nlohmann::json &j, HelloMessageData &m);
|
friend void from_json(const nlohmann::json &j, HelloMessageData &m);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct ReadyEventData {
|
||||||
|
std::string AnalyticsToken; // opt
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IdentifyProperties {
|
||||||
|
std::string OS;
|
||||||
|
std::string Browser;
|
||||||
|
std::string Device;
|
||||||
|
|
||||||
|
friend void to_json(nlohmann::json &j, const IdentifyProperties &m);
|
||||||
|
};
|
||||||
|
|
||||||
|
struct IdentifyMessage : GatewayMessage {
|
||||||
|
std::string Token;
|
||||||
|
IdentifyProperties Properties;
|
||||||
|
bool DoesSupportCompression = false;
|
||||||
|
int LargeThreshold = 0;
|
||||||
|
|
||||||
|
friend void to_json(nlohmann::json &j, const IdentifyMessage &m);
|
||||||
|
};
|
||||||
|
|
||||||
struct HeartbeatMessage : GatewayMessage {
|
struct HeartbeatMessage : GatewayMessage {
|
||||||
int Sequence;
|
int Sequence;
|
||||||
|
|
||||||
@ -49,23 +78,32 @@ private:
|
|||||||
bool terminate = false;
|
bool terminate = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
class Abaddon;
|
||||||
class DiscordClient {
|
class DiscordClient {
|
||||||
public:
|
public:
|
||||||
static const constexpr char *DiscordGateway = "wss://gateway.discord.gg/?v=6&encoding=json";
|
static const constexpr char *DiscordGateway = "wss://gateway.discord.gg/?v=6&encoding=json";
|
||||||
static const constexpr char *DiscordAPI = "https://discord.com/api";
|
static const constexpr char *DiscordAPI = "https://discord.com/api";
|
||||||
|
static const constexpr char *GatewayIdentity = "Discord";
|
||||||
|
|
||||||
public:
|
public:
|
||||||
DiscordClient();
|
DiscordClient();
|
||||||
|
void SetAbaddon(Abaddon *ptr);
|
||||||
void Start();
|
void Start();
|
||||||
void Stop();
|
void Stop();
|
||||||
bool IsStarted() const;
|
bool IsStarted() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void HandleGatewayMessage(nlohmann::json msg);
|
void HandleGatewayMessage(nlohmann::json msg);
|
||||||
|
void HandleGatewayReady(const GatewayMessage &msg);
|
||||||
void HeartbeatThread();
|
void HeartbeatThread();
|
||||||
|
void SendIdentify();
|
||||||
|
|
||||||
|
Abaddon *m_abaddon = nullptr;
|
||||||
|
|
||||||
Websocket m_websocket;
|
Websocket m_websocket;
|
||||||
bool m_client_connected = false;
|
bool m_client_connected = false;
|
||||||
|
std::unordered_map<std::string, GatewayEvent> m_event_map;
|
||||||
|
void LoadEventMap();
|
||||||
|
|
||||||
std::thread m_heartbeat_thread;
|
std::thread m_heartbeat_thread;
|
||||||
int m_last_sequence = -1;
|
int m_last_sequence = -1;
|
||||||
|
@ -10,21 +10,38 @@ void Websocket::StartConnection(std::string url) {
|
|||||||
m_websocket.start();
|
m_websocket.start();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Websocket::Stop() {
|
||||||
|
m_websocket.stop();
|
||||||
|
}
|
||||||
|
|
||||||
|
bool Websocket::IsOpen() const {
|
||||||
|
auto state = m_websocket.getReadyState();
|
||||||
|
return state == ix::ReadyState::Open;
|
||||||
|
}
|
||||||
|
|
||||||
void Websocket::SetJSONCallback(JSONCallback_t func) {
|
void Websocket::SetJSONCallback(JSONCallback_t func) {
|
||||||
m_json_callback = func;
|
m_json_callback = func;
|
||||||
}
|
}
|
||||||
|
|
||||||
void Websocket::Send(const std::string &str) {
|
void Websocket::Send(const std::string &str) {
|
||||||
|
printf("sending %s\n", str.c_str());
|
||||||
m_websocket.sendText(str);
|
m_websocket.sendText(str);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void Websocket::Send(const nlohmann::json &j) {
|
||||||
|
Send(j.dump());
|
||||||
|
}
|
||||||
|
|
||||||
void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) {
|
void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) {
|
||||||
switch (msg->type) {
|
switch (msg->type) {
|
||||||
case ix::WebSocketMessageType::Message:
|
case ix::WebSocketMessageType::Message: {
|
||||||
printf("%s\n", msg->str.c_str());
|
if (msg->str.size() > 1000)
|
||||||
|
printf("%s\n", msg->str.substr(0, 1000).c_str());
|
||||||
|
else
|
||||||
|
printf("%s\n", msg->str.c_str());
|
||||||
auto obj = nlohmann::json::parse(msg->str);
|
auto obj = nlohmann::json::parse(msg->str);
|
||||||
if (m_json_callback)
|
if (m_json_callback)
|
||||||
m_json_callback(obj);
|
m_json_callback(obj);
|
||||||
break;
|
} break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -13,6 +13,9 @@ public:
|
|||||||
using JSONCallback_t = std::function<void(nlohmann::json)>;
|
using JSONCallback_t = std::function<void(nlohmann::json)>;
|
||||||
void SetJSONCallback(JSONCallback_t func);
|
void SetJSONCallback(JSONCallback_t func);
|
||||||
void Send(const std::string &str);
|
void Send(const std::string &str);
|
||||||
|
void Send(const nlohmann::json &j);
|
||||||
|
void Stop();
|
||||||
|
bool IsOpen() const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void OnMessage(const ix::WebSocketMessagePtr &msg);
|
void OnMessage(const ix::WebSocketMessagePtr &msg);
|
||||||
|
23
settings.cpp
Normal file
23
settings.cpp
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
#include "settings.hpp"
|
||||||
|
|
||||||
|
SettingsManager::SettingsManager(std::string filename)
|
||||||
|
: m_filename(filename) {
|
||||||
|
auto rc = m_ini.LoadFile(filename.c_str());
|
||||||
|
m_ok = rc == SI_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string SettingsManager::GetSetting(std::string section, std::string key, std::string fallback) {
|
||||||
|
return m_ini.GetValue(section.c_str(), key.c_str(), fallback.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsManager::SetSetting(std::string section, std::string key, std::string value) {
|
||||||
|
m_ini.SetValue(section.c_str(), key.c_str(), value.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool SettingsManager::IsValid() const {
|
||||||
|
return m_ok;
|
||||||
|
}
|
||||||
|
|
||||||
|
void SettingsManager::Close() {
|
||||||
|
m_ini.SaveFile(m_filename.c_str());
|
||||||
|
}
|
18
settings.hpp
Normal file
18
settings.hpp
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#pragma once
|
||||||
|
#include <string>
|
||||||
|
#include <SimpleIni.h>
|
||||||
|
|
||||||
|
class SettingsManager {
|
||||||
|
public:
|
||||||
|
SettingsManager(std::string filename);
|
||||||
|
|
||||||
|
void Close();
|
||||||
|
std::string GetSetting(std::string section, std::string key, std::string fallback = "");
|
||||||
|
void SetSetting(std::string section, std::string key, std::string value);
|
||||||
|
bool IsValid() const;
|
||||||
|
|
||||||
|
private:
|
||||||
|
bool m_ok;
|
||||||
|
std::string m_filename;
|
||||||
|
CSimpleIniA m_ini;
|
||||||
|
};
|
@ -1,14 +1,21 @@
|
|||||||
#include "mainwindow.hpp"
|
#include "mainwindow.hpp"
|
||||||
#include "../abaddon.hpp"
|
#include "../abaddon.hpp"
|
||||||
|
|
||||||
MainWindow::MainWindow()
|
MainWindow::MainWindow() {
|
||||||
: m_main_box(Gtk::ORIENTATION_VERTICAL) {
|
|
||||||
set_default_size(800, 600);
|
set_default_size(800, 600);
|
||||||
|
|
||||||
|
m_main_box.set_orientation(Gtk::ORIENTATION_VERTICAL);
|
||||||
|
|
||||||
m_menu_discord.set_label("Discord");
|
m_menu_discord.set_label("Discord");
|
||||||
m_menu_discord.set_submenu(m_menu_discord_sub);
|
m_menu_discord.set_submenu(m_menu_discord_sub);
|
||||||
m_menu_discord_connect.set_label("Connect");
|
m_menu_discord_connect.set_label("Connect");
|
||||||
|
m_menu_discord_connect.set_sensitive(false);
|
||||||
|
m_menu_discord_disconnect.set_label("Disconnect");
|
||||||
|
m_menu_discord_disconnect.set_sensitive(false);
|
||||||
|
m_menu_discord_set_token.set_label("Set Token");
|
||||||
m_menu_discord_sub.append(m_menu_discord_connect);
|
m_menu_discord_sub.append(m_menu_discord_connect);
|
||||||
|
m_menu_discord_sub.append(m_menu_discord_disconnect);
|
||||||
|
m_menu_discord_sub.append(m_menu_discord_set_token);
|
||||||
m_menu_discord.set_submenu(m_menu_discord_sub);
|
m_menu_discord.set_submenu(m_menu_discord_sub);
|
||||||
m_menu_bar.append(m_menu_discord);
|
m_menu_bar.append(m_menu_discord);
|
||||||
|
|
||||||
@ -16,6 +23,14 @@ MainWindow::MainWindow()
|
|||||||
m_abaddon->ActionConnect(); // this feels maybe not too smart
|
m_abaddon->ActionConnect(); // this feels maybe not too smart
|
||||||
});
|
});
|
||||||
|
|
||||||
|
m_menu_discord_disconnect.signal_activate().connect([&] {
|
||||||
|
m_abaddon->ActionDisconnect();
|
||||||
|
});
|
||||||
|
|
||||||
|
m_menu_discord_set_token.signal_activate().connect([&] {
|
||||||
|
m_abaddon->ActionSetToken();
|
||||||
|
});
|
||||||
|
|
||||||
m_main_box.add(m_menu_bar);
|
m_main_box.add(m_menu_bar);
|
||||||
|
|
||||||
auto *channel_list = m_channel_list.GetRoot();
|
auto *channel_list = m_channel_list.GetRoot();
|
||||||
@ -26,6 +41,16 @@ MainWindow::MainWindow()
|
|||||||
show_all_children();
|
show_all_children();
|
||||||
}
|
}
|
||||||
|
|
||||||
void MainWindow::SetAbaddon(Abaddon* ptr) {
|
void MainWindow::UpdateMenuStatus() {
|
||||||
|
// Connect
|
||||||
|
std::string token = m_abaddon->GetDiscordToken();
|
||||||
|
bool discord_active = m_abaddon->IsDiscordActive();
|
||||||
|
m_menu_discord_connect.set_sensitive(token.size() > 0 && !discord_active);
|
||||||
|
|
||||||
|
// Disconnect
|
||||||
|
m_menu_discord_disconnect.set_sensitive(discord_active);
|
||||||
|
}
|
||||||
|
|
||||||
|
void MainWindow::SetAbaddon(Abaddon *ptr) {
|
||||||
m_abaddon = ptr;
|
m_abaddon = ptr;
|
||||||
}
|
}
|
||||||
|
@ -7,6 +7,7 @@ class MainWindow : public Gtk::Window {
|
|||||||
public:
|
public:
|
||||||
MainWindow();
|
MainWindow();
|
||||||
void SetAbaddon(Abaddon *ptr);
|
void SetAbaddon(Abaddon *ptr);
|
||||||
|
void UpdateMenuStatus();
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Gtk::Box m_main_box;
|
Gtk::Box m_main_box;
|
||||||
@ -17,6 +18,8 @@ protected:
|
|||||||
Gtk::MenuItem m_menu_discord;
|
Gtk::MenuItem m_menu_discord;
|
||||||
Gtk::Menu m_menu_discord_sub;
|
Gtk::Menu m_menu_discord_sub;
|
||||||
Gtk::MenuItem m_menu_discord_connect;
|
Gtk::MenuItem m_menu_discord_connect;
|
||||||
|
Gtk::MenuItem m_menu_discord_disconnect;
|
||||||
|
Gtk::MenuItem m_menu_discord_set_token;
|
||||||
|
|
||||||
Abaddon *m_abaddon = nullptr;
|
Abaddon *m_abaddon = nullptr;
|
||||||
};
|
};
|
||||||
|
Loading…
Reference in New Issue
Block a user