mirror of
https://github.com/celisej567/abaddon.git
synced 2026-09-19 20:11:59 +03:00
add http client and channel reordering (waste of time)
This commit is contained in:
@@ -2,7 +2,8 @@
|
||||
#include "discord.hpp"
|
||||
#include <cassert>
|
||||
|
||||
DiscordClient::DiscordClient() {
|
||||
DiscordClient::DiscordClient()
|
||||
: m_http(DiscordAPI) {
|
||||
LoadEventMap();
|
||||
}
|
||||
|
||||
@@ -27,6 +28,8 @@ void DiscordClient::Stop() {
|
||||
m_heartbeat_thread.join();
|
||||
m_client_connected = false;
|
||||
m_websocket.Stop();
|
||||
|
||||
m_guilds.clear();
|
||||
}
|
||||
|
||||
bool DiscordClient::IsStarted() const {
|
||||
@@ -44,6 +47,58 @@ const UserSettingsData &DiscordClient::GetUserSettings() const {
|
||||
return m_user_settings;
|
||||
}
|
||||
|
||||
std::vector<std::pair<Snowflake, GuildData>> DiscordClient::GetUserSortedGuilds() const {
|
||||
std::vector<std::pair<Snowflake, GuildData>> sorted_guilds;
|
||||
|
||||
if (m_user_settings.GuildPositions.size()) {
|
||||
for (const auto &id : m_user_settings.GuildPositions) {
|
||||
auto &guild = m_guilds.at(id);
|
||||
sorted_guilds.push_back(std::make_pair(id, guild));
|
||||
}
|
||||
} else { // default sort is alphabetic
|
||||
for (auto &it : m_guilds)
|
||||
sorted_guilds.push_back(it);
|
||||
std::sort(sorted_guilds.begin(), sorted_guilds.end(), [&](auto &a, auto &b) -> bool {
|
||||
std::string &s1 = a.second.Name;
|
||||
std::string &s2 = b.second.Name;
|
||||
|
||||
if (s1.empty() || s2.empty())
|
||||
return s1 < s2;
|
||||
|
||||
bool ac[] = {
|
||||
!isalnum(s1[0]),
|
||||
!isalnum(s2[0]),
|
||||
isdigit(s1[0]),
|
||||
isdigit(s2[0]),
|
||||
isalpha(s1[0]),
|
||||
isalpha(s2[0]),
|
||||
};
|
||||
|
||||
if ((ac[0] && ac[1]) || (ac[2] && ac[3]) || (ac[4] && ac[5]))
|
||||
return s1 < s2;
|
||||
|
||||
return ac[0] || ac[5];
|
||||
});
|
||||
}
|
||||
|
||||
return sorted_guilds;
|
||||
}
|
||||
|
||||
void DiscordClient::UpdateSettingsGuildPositions(const std::vector<Snowflake> &pos) {
|
||||
assert(pos.size() == m_guilds.size());
|
||||
nlohmann::json body;
|
||||
body["guild_positions"] = pos;
|
||||
m_http.MakePATCH("/users/@me/settings", body.dump(), [this, pos](const cpr::Response &r) {
|
||||
m_user_settings.GuildPositions = pos;
|
||||
m_abaddon->DiscordNotifyChannelListFullRefresh();
|
||||
});
|
||||
}
|
||||
|
||||
void DiscordClient::UpdateToken(std::string token) {
|
||||
m_token = token;
|
||||
m_http.SetAuth(token);
|
||||
}
|
||||
|
||||
void DiscordClient::HandleGatewayMessage(nlohmann::json j) {
|
||||
GatewayMessage m;
|
||||
try {
|
||||
@@ -57,6 +112,7 @@ void DiscordClient::HandleGatewayMessage(nlohmann::json j) {
|
||||
case GatewayOp::Hello: {
|
||||
HelloMessageData d = m.Data;
|
||||
m_heartbeat_msec = d.HeartbeatInterval;
|
||||
assert(!m_heartbeat_thread.joinable()); // handle reconnects later
|
||||
m_heartbeat_thread = std::thread(std::bind(&DiscordClient::HeartbeatThread, this));
|
||||
SendIdentify();
|
||||
} break;
|
||||
@@ -116,13 +172,12 @@ void DiscordClient::HeartbeatThread() {
|
||||
}
|
||||
|
||||
void DiscordClient::SendIdentify() {
|
||||
auto token = m_abaddon->GetDiscordToken();
|
||||
assert(token.size());
|
||||
assert(m_token.size());
|
||||
IdentifyMessage msg;
|
||||
msg.Properties.OS = "OpenBSD";
|
||||
msg.Properties.Device = GatewayIdentity;
|
||||
msg.Properties.Browser = GatewayIdentity;
|
||||
msg.Token = token;
|
||||
msg.Token = m_token;
|
||||
m_websocket.Send(msg);
|
||||
}
|
||||
|
||||
@@ -345,6 +400,10 @@ void from_json(const nlohmann::json &j, Snowflake &s) {
|
||||
s.m_num = std::stoull(tmp);
|
||||
}
|
||||
|
||||
void to_json(nlohmann::json& j, const Snowflake& s) {
|
||||
j = std::to_string(s);
|
||||
}
|
||||
|
||||
#undef JS_O
|
||||
#undef JS_D
|
||||
#undef JS_N
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
#pragma once
|
||||
#include "websocket.hpp"
|
||||
#include "http.hpp"
|
||||
#include <nlohmann/json.hpp>
|
||||
#include <thread>
|
||||
#include <unordered_map>
|
||||
@@ -21,9 +22,14 @@ struct Snowflake {
|
||||
return m_num < s.m_num;
|
||||
}
|
||||
|
||||
operator uint64_t() const noexcept {
|
||||
return m_num;
|
||||
}
|
||||
|
||||
const static int Invalid = -1;
|
||||
|
||||
friend void from_json(const nlohmann::json &j, Snowflake &s);
|
||||
friend void to_json(nlohmann::json &j, const Snowflake &s);
|
||||
|
||||
private:
|
||||
friend struct std::hash<Snowflake>;
|
||||
@@ -286,6 +292,8 @@ private:
|
||||
|
||||
class Abaddon;
|
||||
class DiscordClient {
|
||||
friend class Abaddon;
|
||||
|
||||
public:
|
||||
static const constexpr char *DiscordGateway = "wss://gateway.discord.gg/?v=6&encoding=json";
|
||||
static const constexpr char *DiscordAPI = "https://discord.com/api";
|
||||
@@ -301,6 +309,10 @@ public:
|
||||
using Guilds_t = std::unordered_map<Snowflake, GuildData>;
|
||||
const Guilds_t &GetGuilds() const;
|
||||
const UserSettingsData &GetUserSettings() const;
|
||||
std::vector<std::pair<Snowflake, GuildData>> GetUserSortedGuilds() const;
|
||||
void UpdateSettingsGuildPositions(const std::vector<Snowflake> &pos);
|
||||
|
||||
void UpdateToken(std::string token);
|
||||
|
||||
private:
|
||||
void HandleGatewayMessage(nlohmann::json msg);
|
||||
@@ -309,6 +321,10 @@ private:
|
||||
void SendIdentify();
|
||||
|
||||
Abaddon *m_abaddon = nullptr;
|
||||
HTTPClient m_http;
|
||||
|
||||
std::string m_token;
|
||||
|
||||
mutable std::mutex m_mutex;
|
||||
|
||||
void StoreGuild(Snowflake id, const GuildData &g);
|
||||
|
||||
53
discord/http.cpp
Normal file
53
discord/http.cpp
Normal file
@@ -0,0 +1,53 @@
|
||||
#include "http.hpp"
|
||||
|
||||
HTTPClient::HTTPClient(std::string api_base)
|
||||
: m_api_base(api_base) {}
|
||||
|
||||
void HTTPClient::SetAuth(std::string auth) {
|
||||
m_authorization = auth;
|
||||
}
|
||||
|
||||
void HTTPClient::MakePATCH(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) {
|
||||
printf("PATCH %s\n", path.c_str());
|
||||
auto url = cpr::Url { m_api_base + path };
|
||||
auto headers = cpr::Header {
|
||||
{ "Authorization", m_authorization },
|
||||
{ "Content-Type", "application/json" },
|
||||
};
|
||||
auto body = cpr::Body { payload };
|
||||
#ifdef USE_LOCAL_PROXY
|
||||
m_futures.push_back(cpr::PatchCallback(
|
||||
std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb),
|
||||
url, headers, body,
|
||||
cpr::Proxies { { "http", "127.0.0.1:8888" }, { "https", "127.0.0.1:8888" } },
|
||||
cpr::VerifySsl { false }));
|
||||
#else
|
||||
m_futures.push_back(cpr::PatchCallback(
|
||||
std::bind(&HTTPClient::OnResponse, this, std::placeholders::_1, cb),
|
||||
url, headers, body));
|
||||
#endif
|
||||
}
|
||||
|
||||
void HTTPClient::MakePOST(std::string path, std::string payload, std::function<void(cpr::Response r)> cb) {
|
||||
printf("POST %s\n", path.c_str());
|
||||
auto url = cpr::Url { m_api_base + path };
|
||||
auto headers = cpr::Header {
|
||||
{ "Authorization", m_authorization },
|
||||
{ "Content-Type", "application/json" },
|
||||
};
|
||||
auto body = cpr::Body { payload };
|
||||
}
|
||||
|
||||
void HTTPClient::CleanupFutures() {
|
||||
for (auto it = m_futures.begin(); it != m_futures.end();) {
|
||||
if (it->wait_for(std::chrono::seconds(0)) == std::future_status::ready)
|
||||
it = m_futures.erase(it);
|
||||
else
|
||||
it++;
|
||||
}
|
||||
}
|
||||
|
||||
void HTTPClient::OnResponse(cpr::Response r, std::function<void(cpr::Response r)> cb) {
|
||||
CleanupFutures();
|
||||
cb(r);
|
||||
}
|
||||
32
discord/http.hpp
Normal file
32
discord/http.hpp
Normal file
@@ -0,0 +1,32 @@
|
||||
#pragma once
|
||||
#include <cpr/cpr.h>
|
||||
#include <functional>
|
||||
#include <future>
|
||||
#include <string>
|
||||
#include <unordered_map>
|
||||
#include <memory>
|
||||
|
||||
template<typename F>
|
||||
void fire_and_forget(F &&func) {
|
||||
auto ptr = std::make_shared<std::future<void>>();
|
||||
*ptr = std::async(std::launch::async, [ptr, func]() {
|
||||
func();
|
||||
});
|
||||
}
|
||||
|
||||
class HTTPClient {
|
||||
public:
|
||||
HTTPClient(std::string api_base);
|
||||
|
||||
void SetAuth(std::string auth);
|
||||
void MakePATCH(std::string path, std::string payload, std::function<void(cpr::Response r)> cb);
|
||||
void MakePOST(std::string path, std::string payload, std::function<void(cpr::Response r)> cb);
|
||||
|
||||
private:
|
||||
void OnResponse(cpr::Response r, std::function<void(cpr::Response r)> cb);
|
||||
void CleanupFutures();
|
||||
|
||||
std::vector<std::future<void>> m_futures;
|
||||
std::string m_api_base;
|
||||
std::string m_authorization;
|
||||
};
|
||||
@@ -35,10 +35,10 @@ void Websocket::Send(const nlohmann::json &j) {
|
||||
void Websocket::OnMessage(const ix::WebSocketMessagePtr &msg) {
|
||||
switch (msg->type) {
|
||||
case ix::WebSocketMessageType::Message: {
|
||||
if (msg->str.size() > 1000)
|
||||
printf("%s\n", msg->str.substr(0, 1000).c_str());
|
||||
else
|
||||
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);
|
||||
if (m_json_callback)
|
||||
m_json_callback(obj);
|
||||
|
||||
Reference in New Issue
Block a user