비동기 다운로드 구현 완료

This commit is contained in:
2024-10-19 05:06:21 +09:00
parent b4476c68d7
commit 30569f4472
11 changed files with 170 additions and 116 deletions

5
.gitignore vendored
View File

@@ -1,8 +1,5 @@
build/*
out/
.vs/
.idea/
tmp/
Temp/
config.json
Music
*.info.json

View File

@@ -3,8 +3,7 @@
{
"name": "Linux",
"includePath": [
"${workspaceFolder}/**",
"${workspaceFolder}/include"
"${workspaceFolder}/**"
],
"defines": [
"DDPP_CORO=on"

2
.vscode/launch.json vendored
View File

@@ -5,7 +5,7 @@
"name": "Debug",
"type": "cppdbg",
"request": "launch",
"program": "/home/happytanuki/BumbleCee/build/BumbleCee",
"program": "${workspaceFolder}/build/BumbleCee",
"stopAtEntry": false,
"cwd": "${workspaceFolder}",
"environment": [],

125
.vscode/settings.json vendored
View File

@@ -1,84 +1,81 @@
{
"files.associations": {
"iostream": "cpp",
"any": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"condition_variable": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"optional": "cpp",
"string_view": "cpp",
"random": "cpp",
"*.tcc": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"istream": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"iosfwd": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"system_error": "cpp",
"thread": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp",
"array": "cpp",
"atomic": "cpp",
"bit": "cpp",
"cctype": "cpp",
"charconv": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"concepts": "cpp",
"coroutine": "cpp",
"csignal": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdint": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"map": "cpp",
"algorithm": "cpp",
"numeric": "cpp",
"ratio": "cpp",
"utility": "cpp",
"iomanip": "cpp",
"iosfwd": "cpp",
"limits": "cpp",
"numbers": "cpp",
"cinttypes": "cpp",
"bitset": "cpp",
"set": "cpp",
"regex": "cpp",
"format": "cpp",
"span": "cpp",
"any": "cpp",
"array": "cpp",
"atomic": "cpp",
"strstream": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"bitset": "cpp",
"charconv": "cpp",
"chrono": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"coroutine": "cpp",
"cstdint": "cpp",
"deque": "cpp",
"forward_list": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"vector": "cpp",
"exception": "cpp",
"algorithm": "cpp",
"functional": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"numeric": "cpp",
"optional": "cpp",
"random": "cpp",
"ratio": "cpp",
"source_location": "cpp",
"typeindex": "cpp"
"string_view": "cpp",
"system_error": "cpp",
"tuple": "cpp",
"type_traits": "cpp",
"utility": "cpp",
"fstream": "cpp",
"future": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iostream": "cpp",
"istream": "cpp",
"limits": "cpp",
"mutex": "cpp",
"new": "cpp",
"numbers": "cpp",
"ostream": "cpp",
"ranges": "cpp",
"semaphore": "cpp",
"shared_mutex": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeindex": "cpp",
"typeinfo": "cpp",
"valarray": "cpp",
"variant": "cpp"
}
}

4
.vscode/tasks.json vendored
View File

@@ -8,7 +8,7 @@
"command": "make",
"args": [],
"options": {
"cwd": "/home/happytanuki/BumbleCee/build/"
"cwd": "${workspaceFolder}/build/"
},
"group": {
"kind": "build",
@@ -24,7 +24,7 @@
".."
],
"options": {
"cwd": "/home/happytanuki/BumbleCee/build/"
"cwd": "${workspaceFolder}/build/"
},
"group": {
"kind": "build",

View File

@@ -78,4 +78,6 @@ else()
endif()
target_link_libraries(${BOT_NAME} dpp)
endif()
endif()
set(CMAKE_CXX_FLAGS "-g")

View File

@@ -6,27 +6,40 @@
#include <thread>
#include <condition_variable>
#include <curl/curl.h>
#include <dpp/dpp.h>
#include <MusicQueue.hpp>
#define WORKER_COUNT 5
namespace bumbleBee {
class AsyncDownloadManager {
public:
static void enqueue(std::string query) {
static AsyncDownloadManager dl;
std::thread th(&bumbleBee::AsyncDownloadManager::enqueueAsyncDL, &dl, query);
static AsyncDownloadManager& getInstance(int worker_count, std::weak_ptr<dpp::cluster> bot, std::weak_ptr<bumbleBee::MusicQueue> musicQueue) {
static AsyncDownloadManager dl(worker_count);
dl.bot = bot;
dl.musicQueue = musicQueue;
return dl;
}
void enqueue(std::string query) {
std::thread th(&bumbleBee::AsyncDownloadManager::enqueueAsyncDL, this, query);
th.detach();
}
private:
AsyncDownloadManager(){
for (int i=0; i<WORKER_COUNT; i++) {
std::thread th(&bumbleBee::AsyncDownloadManager::downloadWorker, &(*this));
th.detach();
AsyncDownloadManager(int worker_count){
worker_thread.reserve(worker_count);
terminate = false;
for (int i=0; i<worker_count; i++) {
worker_thread.emplace_back([this](){this->downloadWorker();});
}
}
~AsyncDownloadManager(){
terminate = true;
dlQueueCondition.notify_all();
for (auto& t : worker_thread) {
t.join();
}
}
~AsyncDownloadManager(){}
AsyncDownloadManager(const AsyncDownloadManager& ref) = delete;
AsyncDownloadManager& operator=(const AsyncDownloadManager& ref) = delete;
void enqueueAsyncDL(std::string query);
void downloadWorker();
@@ -34,6 +47,10 @@ private:
std::queue<std::string> downloadQueue;
std::condition_variable dlQueueCondition;
std::mutex dlQueueMutex;
std::weak_ptr<dpp::cluster> bot;
std::weak_ptr<bumbleBee::MusicQueue> musicQueue;
std::vector<std::thread> worker_thread;
bool terminate;
};
}

View File

@@ -27,19 +27,13 @@ public:
* @brief 파괴자
* @details BumbleBee의 모든 Property를 책임지고 파괴합니다
**/
~BumbleBee();
~BumbleBee() {}
/**
* @fn void start()
* @brief 봇 시작
**/
void start();
/**
* @fn bool addCommand(commands::ICommand cmd)
* @brief ICommand 인터페이스에 맞는 커맨드를 추가
* @warning 이 메소드는 start()메소드가 호출되기 전에 호출되어야 함
**/
bool addCommand(commands::ICommand cmd);
/**
* @fn void on_slashcommand(const dpp::slashcommand_t& event)
@@ -53,9 +47,12 @@ public:
* @param event
**/
void on_ready(const dpp::ready_t &event);
private:
/// @brief DPP 기본 클러스터 객체
std::unique_ptr<dpp::cluster> cluster;
std::shared_ptr<dpp::cluster> cluster;
/// @brief 음악 큐
std::shared_ptr<MusicQueue> queue;
private:
/// @brief db 드라이버
sql::Driver* dbDriver;
/// @brief db 접속 URL
@@ -63,9 +60,7 @@ private:
/// @brief db 접속 속성
std::shared_ptr<sql::Properties> dbProperties;
/// @brief Command 목록
std::vector<commands::ICommand> commands;
/// @brief 음악 큐
std::shared_ptr<MusicQueue> queue;
std::vector<std::shared_ptr<commands::ICommand>> commands;
};
}
#endif

View File

@@ -1,25 +1,69 @@
#include <AsyncDownloadManager.hpp>
#include <sstream>
namespace bumbleBee {
void AsyncDownloadManager::enqueueAsyncDL(std::string query) {
dlQueueMutex.lock();
std::lock_guard<std::mutex> lock(dlQueueMutex);
downloadQueue.push(query);
dlQueueMutex.unlock();
dlQueueCondition.notify_one();
}
std::string getResultFromCommand(std::string cmd) {
std::string result;
FILE* stream;
const int maxBuffer = 12; // 버퍼의 크기는 적당하게
char buffer[maxBuffer];
cmd.append(" 2>&1"); // 표준에러를 표준출력으로 redirect
stream = popen(cmd.c_str(), "r"); // 주어진 command를 shell로 실행하고 파이프 연결 (fd 반환)
if (stream) {
while (fgets(buffer, maxBuffer, stream) != NULL) result.append(buffer); // fgets: fd (stream)를 길이 (maxBuffer)만큼 읽어 버퍼 (buffer)에 저장
pclose(stream); // 파이프 닫는 것 잊지 마시고요!
}
return result;
}
void AsyncDownloadManager::downloadWorker() {
std::unique_lock<std::mutex> dlQueueLock(dlQueueMutex);
std::ostringstream tid;
tid << std::this_thread::get_id();
while (true) {
//mutex lock
dlQueueLock.lock();
dlQueueCondition.wait(dlQueueLock, [&]{ return !downloadQueue.empty(); });
system(("./yt-dlp --no-clean-info-json --write-info-json --default-search ytsearch \
--flat-playlist --skip-download --quiet --ignore-errors -f ba* " + downloadQueue.front()).c_str());
std::unique_lock<std::mutex> dlQueueLock(dlQueueMutex);
dlQueueCondition.wait(dlQueueLock, [&]{ return !downloadQueue.empty() || terminate; });
std::string query = downloadQueue.front();
downloadQueue.pop();
dlQueueLock.unlock();
auto cluster = bot.lock();
assert(cluster);
cluster->log(dpp::ll_info, "Enqueuing " + query + " accepted.");
std::string idstring = getResultFromCommand("./yt-dlp --default-search ytsearch --flat-playlist --skip-download --quiet --ignore-errors --print id " + query);
std::queue<std::string> ids;
std::stringstream ss(idstring);
std::string _id;
while (std::getline(ss, _id, '\n')) {
ids.push(_id);
}
if (ids.size() >= 2) {
cluster->log(dpp::ll_info, "Playlist detected.");
while (!ids.empty()) {
cluster->log(dpp::ll_info, "Enqueuing " + ids.front());
enqueue("https://youtu.be/" + ids.front());
ids.pop();
}
break;
}
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + ids.front() + " accepted.");
system(("./yt-dlp -o \"Temp/%(id)s\" --no-clean-info-json --write-info-json --default-search ytsearch \
--flat-playlist --skip-download --quiet --ignore-errors -f ba* https://youtu.be/" + ids.front()).c_str());
cluster->log(dpp::ll_info, "Thread id: " + tid.str() + ": " + ids.front() + " downloaded.");
}
}
}

View File

@@ -2,7 +2,7 @@
namespace bumbleBee{
BumbleBee::BumbleBee(nlohmann::json settings) {
this->cluster = std::make_unique<dpp::cluster>(settings["token"]);
this->cluster = std::make_shared<dpp::cluster>(settings["token"]);
dbDriver = sql::mariadb::get_driver_instance();
this->dbURL = std::make_shared<sql::SQLString>(settings["dbURL"]);
sql::Properties pro({
@@ -16,21 +16,16 @@ BumbleBee::BumbleBee(nlohmann::json settings) {
cluster->on_ready([this](const dpp::ready_t &event){on_ready(event);});
}
BumbleBee::~BumbleBee() {
}
void BumbleBee::start() { this->cluster->start(dpp::st_wait); }
bool BumbleBee::addCommand(commands::ICommand cmd) {
commands.push_back(cmd);
return false;
}
void BumbleBee::on_slashcommand(const dpp::slashcommand_t &event) {
for (auto command : commands)
for (auto alias : command->nameAndAliases)
if (event.command.get_command_name() == alias.name)
(*command)(event);
}
void BumbleBee::on_ready(const dpp::ready_t &event) {
cluster->log(dpp::loglevel::ll_info, "Bot ready.");
}
}

View File

@@ -1,5 +1,7 @@
#include <iostream>
#include <BumbleBee.hpp>
#include <AsyncDownloadManager.hpp>
#include <thread>
int main() {
nlohmann::json configdocument;
@@ -8,5 +10,11 @@ int main() {
bumbleBee::BumbleBee bot(configdocument);
bot.start();
bumbleBee::AsyncDownloadManager& manager = bumbleBee::AsyncDownloadManager::getInstance(5, bot.cluster, bot.queue);
manager.enqueue("https://music.youtube.com/playlist?list=PL5NSTAfQ-wQBqZYMTqxADemyUW8mxJq2h&si=S1OwPaaif_litCqN");
std::thread th([](){sleep(100);});
th.join();
//bot.start();
}