diff --git a/.$SpCloud.drawio.dtmp b/.$SpCloud.drawio.dtmp
deleted file mode 100644
index 7da353a..0000000
--- a/.$SpCloud.drawio.dtmp
+++ /dev/null
@@ -1,181 +0,0 @@
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
-
diff --git a/SpCloud.drawio b/SpCloud.drawio
index a64815b..91ec9e6 100644
--- a/SpCloud.drawio
+++ b/SpCloud.drawio
@@ -1,6 +1,6 @@
-
+
-
+
@@ -68,7 +68,7 @@
-
+
@@ -118,8 +118,8 @@
-
-
+
+
@@ -134,7 +134,7 @@
-
+
@@ -145,8 +145,8 @@
-
-
+
+
@@ -175,6 +175,12 @@
+
+
+
+
+
+
diff --git a/SpCloudMain/Controllers/PublishController.cpp b/SpCloudMain/Controllers/PublishController.cpp
index d098078..7ca47eb 100644
--- a/SpCloudMain/Controllers/PublishController.cpp
+++ b/SpCloudMain/Controllers/PublishController.cpp
@@ -1,10 +1,11 @@
-#include "../httplib.h"
+#include "../httplib.h"
//#include
//#include "Service/AuthorizationService.cpp"
//#include "Service/FileProcessingService.cpp"
#include "../Service/AuthorizationService.cpp"
#include "../Service/FileProcessingService.cpp"
+#include "../Models/App.cpp"
//#include "Service/Logger.cpp"
class PublishController
@@ -20,6 +21,8 @@ private:
Logger& logger_;
+ int last_available_port = 8081;
+
//std::string publish_app_path = "C:/Temps/";// Todo delete if not needed
public:
@@ -29,49 +32,47 @@ public:
}
public:
- void process_publish(const httplib::Request& req, httplib::Response& res)
+ std::string process_publish(const httplib::Request& req, App* app)
{
- //if (this->authorization.is_user_authorized())
- if (true)//Todo change to is user authorized
- {
- const auto& content = req.files.begin()->second.content;
+ const auto& content = req.files.begin()->second.content;
- const auto& filename = this->publish_app_path + req.files.begin()->second.filename;
+ const auto& filename = this->publish_app_path + req.files.begin()->second.filename;
- if (filename.size() >= 4 && filename.substr(filename.size() - 4) == ".rar") {
- if (file_processing->save_file(filename, content)) {
+ if (filename.size() >= 4 && filename.substr(filename.size() - 4) == ".rar") {
+ //if (true) {//TODO UNCOMMIT WHEN STARING TO WRITE PUBLISH PROCESS
+ if (file_processing->save_file(filename, content)) {
- std::string random_string = generate_random_string(20);//TODO VERY IMPORTANT CHANGE THIS RANDOM GENERATING TO GENERATE UNIQUE STRING
+ file_processing->unzip(filename, this->publish_app_path + app->get_user_id());//TODO UNCOMMIT WHEN STARING TO WRITE PUBLISH PROCESS
- file_processing->unzip(filename, this->publish_app_path + random_string);
+ /*check_port_and_increase_if_not_available();
- this->dotnet_publish(this->publish_app_path + random_string);
+ file_processing->adjust_nginx_configuration_and_reloud(app->get_name(), std::to_string(last_available_port));*/
- res.set_content("File uploaded successfully: " + filename, "text/plain");
- }
- else {
- res.status = 500;
- res.set_content("Failed to save file, please ensure you are putting rar file"
- + filename, "text/plain");
- }
+ //file_processing->create_service_file(app->get_name());//TODO UNCOMMIT WHEN STARING TO WRITE PUBLISH PROCESS
+
+ //this->dotnet_publish(this->publish_app_path + app->get_user_id(), last_available_port);//TODO UNCOMMIT WHEN STARING TO WRITE PUBLISH PROCESS
+
+ //Todo introduce old binary file
+
+ file_processing->delete_file(filename);
+
+ return "File uploaded successfully: " + filename;
}
else {
- res.status = 400;
- res.set_content("Invalid file type. Only .rar files are allowed.",
- "text/plain");
+ return "Failed to save file, please ensure you are putting rar file" + filename;
}
}
- else
- {
- //Todo add logging and exiting from function with bead request
+ else {
+ return "Invalid file type. Only .rar files are allowed." + filename;
+
}
}
private:
- void dotnet_publish(const std::string& path)
- {
+ void dotnet_publish(const std::string& path, int port)
+ {//Todo adjust to build setting from mongodb
std::string dll_file_name = file_processing->find_file_by_suffix(path, "exe");
-
+ //Todo introduce deleting old rar file after publishing
size_t pos = dll_file_name.find(".exe");
if (pos != std::string::npos) {
dll_file_name.replace(pos, 4, ".dll");
@@ -84,6 +85,41 @@ private:
commandThread.detach();
}
+ void check_port_and_increase_if_not_available()
+ {
+ while (true)
+ {
+ std::string port_str = std::to_string(last_available_port);
+
+ std::string command = "ss -tuln | grep :" + port_str;
+
+ auto request = std::async(std::launch::async, &PublishController::execute_command, this, command);
+
+ std::string response = request.get();
+
+ if (!response.empty())
+ {
+ last_available_port++;
+ }
+ else
+ {
+ break;
+ }
+ }
+
+ }
+
+ std::string execute_command(const std::string& command) {
+ std::array buffer;
+ std::string result;
+ std::shared_ptr pipe(popen(command.c_str(), "r"), pclose);
+ if (!pipe) throw std::runtime_error("popen() failed!");
+ while (fgets(buffer.data(), buffer.size(), pipe.get()) != nullptr) {
+ result += buffer.data();
+ }
+ return result;
+ }
+
static std::string generate_random_string(size_t length, const std::string& char_set = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789") {
std::random_device rd;
std::mt19937 generator(rd());
diff --git a/SpCloudMain/Models/App.cpp b/SpCloudMain/Models/App.cpp
index 874271b..9ab3f19 100644
--- a/SpCloudMain/Models/App.cpp
+++ b/SpCloudMain/Models/App.cpp
@@ -1,50 +1,29 @@
#include
-
+#ifndef APP_H
+#define APP_H
class App {
private:
- int id;
std::string name;
- std::string authToken;
- bool isBanned;
+ std::string user_id;
+ std::string url;
+ std::string url_on_local_machine;
+ std::string target;
public:
- // Конструктор
- App(int id, const std::string& name, const std::string& authToken, bool isBanned)
- : id(id), name(name), authToken(authToken), isBanned(isBanned) {}
+ App(const std::string& name, const std::string& user_id, const std::string& url,
+ const std::string& url_on_local_machine, const std::string& target)
+ : name(name), user_id(user_id), url(url), url_on_local_machine(url_on_local_machine), target(target) {}
- // Геттеры и сеттеры для Id
- int getId() const {
- return id;
- }
+ std::string get_name() const { return name; }
+ std::string get_user_id() const { return user_id; }
+ std::string get_url() const { return url; }
+ std::string get_url_on_local_machine() const { return url_on_local_machine; }
+ std::string get_target() const { return target; }
- void setId(int id) {
- this->id = id;
- }
-
- // Геттеры и сеттеры для Name
- std::string getName() const {
- return name;
- }
-
- void setName(const std::string& name) {
- this->name = name;
- }
-
- // Геттеры и сеттеры для AuthToken
- std::string getAuthToken() const {
- return authToken;
- }
-
- void setAuthToken(const std::string& authToken) {
- this->authToken = authToken;
- }
-
- // Геттеры и сеттеры для IsBanned
- bool getIsBanned() const {
- return isBanned;
- }
-
- void setIsBanned(bool isBanned) {
- this->isBanned = isBanned;
- }
+ void set_name(const std::string& name) { this->name = name; }
+ void set_user_id(const std::string& user_id) { this->user_id = user_id; }
+ void set_url(const std::string& url) { this->url = url; }
+ void set_url_on_local_machine(const std::string& url_on_local_machine) { this->url_on_local_machine = url_on_local_machine; }
+ void set_target(const std::string& target) { this->target = target; }
};
+#endif // APP_H
diff --git a/SpCloudMain/Service/DiscordService.cpp b/SpCloudMain/Service/DiscordService.cpp
index efaab2b..0ee9cd4 100644
--- a/SpCloudMain/Service/DiscordService.cpp
+++ b/SpCloudMain/Service/DiscordService.cpp
@@ -21,29 +21,6 @@ public:
{
std::string auth_code_processed = extract_code(auth_code);
- //std::string body = "client_id=1273414933874479185&"//Todo delete comments if not needed
- // "client_secret=S_vG4frjlxWoi8mic_GlcxUO0aWxXwRJ&"
- // "grant_type=authorization_code&"
- // "code=" + auth_code_processed + "&"
- // "redirect_uri=https://www.sp-donate.ru/pay/Hepatir";
-
- //httplib::Headers headers = {
- // {"Content-Type", "application/x-www-form-urlencoded"}
- //};
-
- //httplib::Client client("discord.com/api");
- ////// Выполняем простой GET-запрос на http://httpbin.org/get
- ////auto res = client.Get("/get");
- //auto res = client.Post("/oauth2/token", headers, body, "application/x-www-form-urlencoded");
- ////auto res = client_.Post("/oauth2/token", headers, body, "application/x-www-form-urlencoded");
-
- //if (res && res->status == 200) {
- // return res->body;
- //}
- //else {
- // return "Error: ";//Todo write handling this
- //}
-
std::string command = "curl --location https://discord.com/api/oauth2/token "
"--header \"Content-Type: application/x-www-form-urlencoded\" "
"--data-urlencode \"client_id=1273414933874479185\" "
@@ -62,19 +39,6 @@ public:
auto me_request = std::async(std::launch::async, &DiscordService::execute_command, this, command);
- //httplib::Headers headers = {
- // {"Authorization", "Bearer " + access_token}
- //};
-
- //auto res = client_.Get("/users/@me", headers);
-
- //if (res && res->status == 200) {
- // return res->body;
- //}
- //else {
- // return "Error: ";//Todo write handling this
- //}
-
std::string user_id = extract_user_id(me_request.get());
return user_id;
@@ -107,35 +71,16 @@ public:
return result;
}
- //std::string extract_user_id(const std::string& input) {
- // std::string search_pattern = "\"discord_id\":\"";
- // std::size_t start_pos = input.find(search_pattern);
- // if (start_pos == std::string::npos) {
- // throw std::runtime_error("discord_id not found");
- // }
-
- // start_pos += search_pattern.length(); // move to the start of the user_id
- // std::size_t end_pos = input.find("\"", start_pos);
- // if (end_pos == std::string::npos) {
- // throw std::runtime_error("End of discord_id not found");
- // }
-
- // return input.substr(start_pos, end_pos - start_pos);
- //}
-
-
std::string extract_code(const std::string& json_str) {
std::string key = "\"code\":";
size_t start = json_str.find(key);
if (start != std::string::npos) {
start += key.length();
- // Пропускаем любые пробелы или символы ':'
while (start < json_str.length() && (json_str[start] == ' ' || json_str[start] == '\"' || json_str[start] == ':')) {
start++;
}
- // Найти конец строки
size_t end = json_str.find('\"', start);
if (end != std::string::npos) {
return json_str.substr(start, end - start);
@@ -154,6 +99,6 @@ public:
return response.substr(start_pos, end_pos - start_pos);
}
}
- return ""; // Вернуть пустую строку, если токен не найден
+ return "";
}
};
diff --git a/SpCloudMain/Service/FileProcessingService.cpp b/SpCloudMain/Service/FileProcessingService.cpp
index 86b8e54..db6a7d1 100644
--- a/SpCloudMain/Service/FileProcessingService.cpp
+++ b/SpCloudMain/Service/FileProcessingService.cpp
@@ -7,6 +7,7 @@
#include
#include "CommandService.cpp"
#include "Logger.cpp"
+#include
class FileProcessingService
{
Logger& logger_;
@@ -18,6 +19,79 @@ public:
}
+ void adjust_nginx_configuration_and_reloud(const std::string& filename, std::string port)
+ {
+ std::string file_path = "/etc/nginx/nginx.conf";
+
+ std::string new_text =
+ "server {\n"
+ " listen 443 ssl;\n"
+ " server_name " + filename + ".almavid.ru;\n\n"
+ " ssl_certificate /etc/letsencrypt/live/almavid.ru/fullchain.pem;\n"
+ " ssl_certificate_key /etc/letsencrypt/live/almavid.ru/privkey.pem;\n"
+ " ssl_protocols TLSv1 TLSv1.1 TLSv1.2;\n"
+ " ssl_ciphers HIGH:!aNULL:!MD5;\n\n"
+ " client_max_body_size 2G; // Allow file uploads up to 2GB\n\n"
+ " location / {\n"
+ " proxy_pass http://localhost:" + port + ";\n"
+ " proxy_set_header Host $host;\n"
+ " proxy_set_header X-Real-IP $remote_addr;\n"
+ " proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;\n"
+ " proxy_set_header X-Forwarded-Proto $scheme;\n\n"
+ " # Support for WebSocket\n"
+ " proxy_http_version 1.1;\n"
+ " proxy_set_header Upgrade $http_upgrade;\n"
+ " proxy_set_header Connection \"upgrade\";\n"
+ " }\n\n"
+ "}\n";
+
+ std::ofstream file(file_path, std::ios::app);
+
+ if (!file.is_open()) {
+ logger_.log(INFO, "Error: Could not open file " + file_path + strerror(errno) + '\n');
+ return;
+ }
+
+ file << new_text << '\n';
+
+ file.close();
+
+ // Reload Nginx to apply the changes
+ /*int result = std::system("sudo systemctl reload nginx");
+ if (result != 0) {
+ std::cerr << "Error: Failed to reload Nginx" << std::endl;
+ return 1;
+ }*/
+
+ std::string command = "sudo systemctl reload nginx";
+
+ std::thread commandThread(&CommandService::execute_command, command);
+
+ commandThread.join();
+
+ logger_.log(INFO, "Nginx reloaded successfully.");
+ }
+
+ void delete_file(const std::string& file_path) const
+ {
+ try {
+ // Delete the original file
+ if (std::filesystem::exists(file_path)) {
+ std::filesystem::remove(file_path);
+ logger_.log(INFO, "Deleted file: " + file_path);
+ }
+
+ // Delete the directory recursively//Todo test if method will not work
+ /*if (std::filesystem::exists(final_files_directory)) {
+ std::filesystem::remove_all(final_files_directory);
+ logger_.log(INFO, "Deleted directory: " + final_files_directory);
+ }*/
+ }
+ catch (const std::filesystem::filesystem_error& e) {
+ logger_.log(ERROR, "Error during deletion: " + std::string(e.what()));
+ }
+ }
+
bool save_file(const std::string& filename, const std::string& content) {
logger_.log(INFO, "Start saving file method");
@@ -35,6 +109,48 @@ public:
return ofs.good();
}
+ void create_service_file(std::string name)
+ {
+ logger_.log(INFO, "Start create_service_file");
+
+ std::string filename = "/etc/systemd/system/" + name + ".service";
+ std::ofstream serviceFile(filename);
+
+ if (serviceFile.is_open()) {
+ serviceFile << "[Unit]\n";
+ serviceFile << "Description=" << name << " Service\n";
+ serviceFile << "After=network.target\n\n";
+
+ serviceFile << "[Service]\n";
+ serviceFile << "ExecStart=/home/danilt2000/SpCloud/" + name + "/build/ " + name + "\n";
+ //serviceFile << "ExecStart=/home/danilt2000/SpCloud/SpCloudMain/build/SpCloudMain\n";
+ serviceFile << "WorkingDirectory=/home/danilt2000/SpCloud/" + name + "/build\n";
+ //serviceFile << "WorkingDirectory=/home/danilt2000/SpCloud/SpCloudMain/build\n";
+ serviceFile << "Restart=always\n";
+ serviceFile << "User=danilt2000\n";
+ serviceFile << "Environment=PATH=/usr/bin\n";
+ serviceFile << "Environment=NODE_ENV=production\n\n";
+
+ serviceFile << "[Install]\n";
+ serviceFile << "WantedBy=multi-user.target\n";
+
+ std::string command = "sudo systemctl daemon-reload";
+
+ std::thread commandThread(&CommandService::execute_command, command);
+
+ commandThread.join();
+
+ //Todo check service ->sudo systemctl status .service
+
+ serviceFile.close();
+
+ logger_.log(INFO, "Service file " + filename + " created successfully.\n");
+ }
+ else {
+ logger_.log(INFO, "Unable to open file " + filename + " for writing: " + strerror(errno) + "\n");
+ }
+ }
+
void create_directory(const std::string& path) {
std::filesystem::create_directories(path);
}
@@ -60,8 +176,4 @@ public:
}
return ""; //todo add throwing exception
}
-
-/*private:
- std::mutex file_mutex; */// Мьютекс для синхронизации доступа к файлу
-
};
diff --git a/SpCloudMain/Service/MongoDbService.cpp b/SpCloudMain/Service/MongoDbService.cpp
index b107176..0c19abf 100644
--- a/SpCloudMain/Service/MongoDbService.cpp
+++ b/SpCloudMain/Service/MongoDbService.cpp
@@ -86,6 +86,34 @@ public:
return "Success";
}
+ std::string is_app_name_free(std::string name)
+ {
+ std::string json_data = R"({
+ "dataSource": "SpCloudCluster",
+ "database": "SpCloud",
+ "collection": "Apps",
+ "filter": {
+ "name": ")" + name + R"("
+ }
+ })";
+
+ std::string command = "curl --location 'https://eu-central-1.aws.data.mongodb-api.com/app/data-zvcqvrr/endpoint/data/v1/action/findOne' "
+ "--header 'Content-Type: application/json' "
+ "--header 'api-key: Q1NfSCrruUAzsxdrjhZd3sjSwiqbdSFmCLeaCatZiuohUXsvEq9RtEAeG0JL2Jd7' "
+ "--data-raw '" + json_data + "'";
+
+ auto request = std::async(std::launch::async, &MongoDbService::execute_command, this, command);
+
+ std::string response = request.get();
+
+ if (response == "{\"document\":null}")
+ {
+ return "Success";
+ }
+
+ return "App name isn't free please select another one";
+ }
+
std::string add_app(std::string name, std::string user_id, std::string url, std::string url_on_local_mahcine, std::string target)
{
std::string json_data = R"({
diff --git a/SpCloudMain/SpCloudMain.cpp b/SpCloudMain/SpCloudMain.cpp
index 595d2ea..26304f7 100644
--- a/SpCloudMain/SpCloudMain.cpp
+++ b/SpCloudMain/SpCloudMain.cpp
@@ -1,16 +1,12 @@
-// SpCloudMain.cpp : Defines the entry point for the application.
-//
-
-// ReSharper disable CppClangTidyBugproneSuspiciousInclude
+// ReSharper disable CppClangTidyBugproneSuspiciousInclude
#include "SpCloudMain.h"
#include "httplib.h"
#include "Controllers/PublishController.cpp"
#include "Service/DiscordService.cpp"
#include "Service/MongoDbService.cpp"
+#include "Models/App.cpp"
-//#include "Service/AuthorizationService.cpp"
-//#include "Service/FileProcessingService.cpp"
using namespace std;
int main()
@@ -52,19 +48,37 @@ int main()
{
logger.log(INFO, "Start publish from main");
- string is_user_can_publish_response = mongo_service.is_user_can_publish("khBuvDWPHOhPSiQNVQZm9PM0VF29dqAaDBjWX4BnxJKzRvg0Gm");//TODO UNCOMMENT AND FIX
+ std::string user_id = req.get_file_value("UserId").content;
+ std::string name = req.get_file_value("Name").content;
+ ranges::transform(name, name.begin(), [](unsigned char c) { return std::tolower(c); });
+ std::string target = req.get_file_value("Target").content;
+ std::string authorization_token = req.get_header_value("Authorization");
+
+ string is_user_can_publish_response = mongo_service.is_user_can_publish(authorization_token);
if (is_user_can_publish_response != "Success")
{
- res.set_content(is_user_can_publish_response, "text/plain");//Todo add app address showing
+ res.set_content(is_user_can_publish_response, "text/plain");
return;
}
- //publish_controller.process_publish(req, res);//TODO UNCOMMENT AND FIX
+ string is_app_name_response = mongo_service.is_app_name_free(name);
- //mongo_service.add_app("test", "test", "test", "test", "test");//TODO UNCOMMENT AND FIX
+ if (is_app_name_response != "Success")
+ {
+ res.set_content(is_app_name_response, "text/plain");
+ return;
+ }
+
+ App* app = new App(name, user_id, "url", "local_url", target);
+
+ publish_controller.process_publish(req, app);
+
+ //mongo_service.add_app("test", "test", "test", "test", "test");//TODO UNCOMMENT AND FIX
+
+ delete app;
res.set_content("App is running on address ????", "text/plain");//Todo add app address showing
});
@@ -79,27 +93,5 @@ int main()
res.set_content(result, "text/plain");
});
-
- /*httplib::Client cli("https://discord.com/api/oauth2/token");
-
- std::string jsonData = R"({
- "dataSource": "Cluster0",
- "database": "myDatabase",
- "collection": "items",
- "document": {
- "name": "Item Name",
- "value": "Item Value"
- }
- })";
-
- auto res = cli.Post("/app/data-abcde/endpoint/data/v1/action/insertOne", jsonData, "application/json");
-
- if (res && res->status == 200) {
- std::cout << "Success: " << res->body << std::endl;
- }
- else {
- std::cerr << "Error: " << res.error() << std::endl;
- }*/
-
svr.listen("0.0.0.0", 8081);
}