// api-manager.cpp — API Server Boshqaruv Paneli // // O'rnatish: // sudo apt-get install libgtk-3-dev g++ pkg-config // // Build: // make // // Ishga tushurish (ROOT SHART): // sudo ./api-manager #include #include #include #include #include #include #include #include #include #include #include // ───────────────────────────────────────────────────── // GLOBAL WIDGETLAR // ───────────────────────────────────────────────────── static GtkWidget *g_window; static GtkWidget *g_textview; static GtkWidget *g_status_label; static GtkWidget *g_toggle_btn; static GtkWidget *g_port_label; static bool g_busy = false; // ───────────────────────────────────────────────────── // YO'LLAR (root uchun system-wide) // ───────────────────────────────────────────────────── static const std::string CONFIG_DIR = "/etc/api-manager"; static const std::string CODE_FILE = "/etc/api-manager/server.cpp"; static const std::string BIN_FILE = "/usr/local/bin/api-server"; static const std::string SVC_FILE = "/etc/systemd/system/api-server.service"; static const std::string PORT_FILE = "/var/run/api-manager.port"; static const std::string BUILD_LOG = "/var/log/api-manager-build.log"; static const char* SVC_NAME = "api-server"; // ───────────────────────────────────────────────────── // YORDAMCHILAR // ───────────────────────────────────────────────────── void mkdirp(const std::string& p) { mkdir(p.c_str(), 0755); } void ensureDirs() { mkdirp(CONFIG_DIR); } void flushUI() { while (gtk_events_pending()) gtk_main_iteration_do(FALSE); } void setStatus(const std::string& msg, const char* color = nullptr) { if (color) { std::string m = "" + msg + ""; gtk_label_set_markup(GTK_LABEL(g_status_label), m.c_str()); } else { gtk_label_set_text(GTK_LABEL(g_status_label), msg.c_str()); } flushUI(); } // Scrollable matn oynasi (xatolar va log uchun) void showScrollableDialog(const std::string& title, const std::string& text, bool isError = false) { GtkWidget* dlg = gtk_dialog_new_with_buttons( title.c_str(), GTK_WINDOW(g_window), GTK_DIALOG_MODAL, "Yopish", GTK_RESPONSE_CLOSE, NULL); gtk_window_set_default_size(GTK_WINDOW(dlg), 780, 440); GtkWidget* area = gtk_dialog_get_content_area(GTK_DIALOG(dlg)); gtk_container_set_border_width(GTK_CONTAINER(area), 8); GtkWidget* scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_widget_set_size_request(scroll, -1, 380); GtkWidget* tv = gtk_text_view_new(); gtk_text_view_set_editable(GTK_TEXT_VIEW(tv), FALSE); gtk_text_view_set_monospace(GTK_TEXT_VIEW(tv), TRUE); gtk_text_view_set_left_margin(GTK_TEXT_VIEW(tv), 10); gtk_text_view_set_top_margin (GTK_TEXT_VIEW(tv), 6); if (isError) { GtkCssProvider* css = gtk_css_provider_new(); gtk_css_provider_load_from_data(css, "textview text { background-color:#2d1b1b; color:#f38ba8; }", -1, NULL); gtk_style_context_add_provider( gtk_widget_get_style_context(tv), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 2); g_object_unref(css); } gtk_text_buffer_set_text( gtk_text_view_get_buffer(GTK_TEXT_VIEW(tv)), text.c_str(), -1); gtk_container_add(GTK_CONTAINER(scroll), tv); gtk_box_pack_start(GTK_BOX(area), scroll, TRUE, TRUE, 0); gtk_widget_show_all(dlg); gtk_dialog_run(GTK_DIALOG(dlg)); gtk_widget_destroy(dlg); } // ───────────────────────────────────────────────────── // BO'SH PORT TOPISH (3000 dan boshlab ketma-ket) // ───────────────────────────────────────────────────── int findFreePort(int start = 3000) { for (int port = start; port <= 65000; port++) { int s = socket(AF_INET, SOCK_STREAM, 0); if (s < 0) continue; int opt = 1; setsockopt(s, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); sockaddr_in a{}; a.sin_family = AF_INET; a.sin_addr.s_addr = INADDR_ANY; a.sin_port = htons(port); bool isFree = (bind(s, (sockaddr*)&a, sizeof(a)) == 0); close(s); if (isFree) return port; } return -1; } // ───────────────────────────────────────────────────── // XIZMAT HOLATI // ───────────────────────────────────────────────────── bool svcRunning() { return system(("systemctl is-active --quiet " + std::string(SVC_NAME)).c_str()) == 0; } void updatePortLabel(int port = -1) { if (port > 0) { gtk_label_set_text(GTK_LABEL(g_port_label), ("Port: " + std::to_string(port)).c_str()); return; } std::ifstream f(PORT_FILE); if (f.good()) { int p = 0; f >> p; gtk_label_set_text(GTK_LABEL(g_port_label), p > 0 ? ("Port: " + std::to_string(p)).c_str() : "Port: ?"); } else { gtk_label_set_text(GTK_LABEL(g_port_label), "Port: -"); } } void applyToggleStyle(bool running) { GtkCssProvider* css = gtk_css_provider_new(); const char* style = running ? "#toggle_btn { background-image:none; background-color:#c0392b;" "color:white; border-radius:4px; padding:5px 18px; font-weight:bold; }" : "#toggle_btn { background-image:none; background-color:#27ae60;" "color:white; border-radius:4px; padding:5px 18px; font-weight:bold; }"; gtk_css_provider_load_from_data(css, style, -1, NULL); gtk_style_context_add_provider( gtk_widget_get_style_context(g_toggle_btn), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION + 1); g_object_unref(css); } void refreshUI(bool running) { if (running) { gtk_button_set_label(GTK_BUTTON(g_toggle_btn), "⏹ To'xtatish"); updatePortLabel(); } else { gtk_button_set_label(GTK_BUTTON(g_toggle_btn), "▶ Ishga tushurish"); gtk_label_set_text(GTK_LABEL(g_port_label), "Port: -"); } applyToggleStyle(running); } // ───────────────────────────────────────────────────── // KOD MUHARRIRI // ───────────────────────────────────────────────────── std::string getCode() { GtkTextBuffer* buf = gtk_text_view_get_buffer(GTK_TEXT_VIEW(g_textview)); GtkTextIter s, e; gtk_text_buffer_get_bounds(buf, &s, &e); gchar* t = gtk_text_buffer_get_text(buf, &s, &e, FALSE); std::string r(t); g_free(t); return r; } void setCode(const std::string& code) { gtk_text_buffer_set_text( gtk_text_view_get_buffer(GTK_TEXT_VIEW(g_textview)), code.c_str(), -1); } // ───────────────────────────────────────────────────── // STANDART SHABLON // ───────────────────────────────────────────────────── static const char* DEFAULT_TEMPLATE = R"CODE(#include #include #include #include #include #include // ── Har bir HTTP ulanishni bu funksiya qayta ishlaydi ──────────────── void handleClient(int client_fd) { char buf[8192] = {}; read(client_fd, buf, sizeof(buf) - 1); // ================================================================ // SIZNING MANTIQINGIZ SHU YERDA // buf — xom HTTP so'rov matni (GET /path HTTP/1.1\r\n...) // ================================================================ std::string body = "{\"status\":\"ok\",\"message\":\"API ishlayapti!\"}"; // ================================================================ std::ostringstream resp; resp << "HTTP/1.1 200 OK\r\n" << "Content-Type: application/json\r\n" << "Content-Length: " << body.size() << "\r\n" << "Access-Control-Allow-Origin: https://test.anicorex.uz\r\n" << "Connection: close\r\n" << "\r\n" << body; std::string r = resp.str(); send(client_fd, r.c_str(), r.size(), 0); close(client_fd); } int main(int argc, char* argv[]) { // Port yuqoridagi manager tomonidan argument sifatida beriladi int port = (argc > 1) ? std::atoi(argv[1]) : 3000; int server_fd = socket(AF_INET, SOCK_STREAM, 0); if (server_fd < 0) { perror("socket"); return 1; } int opt = 1; setsockopt(server_fd, SOL_SOCKET, SO_REUSEADDR, &opt, sizeof(opt)); sockaddr_in addr{}; addr.sin_family = AF_INET; addr.sin_addr.s_addr = INADDR_ANY; addr.sin_port = htons(port); if (bind(server_fd, (sockaddr*)&addr, sizeof(addr)) < 0) { perror("bind"); return 1; } listen(server_fd, 128); std::cout << "[api-server] Port " << port << " da ishga tushdi\n"; std::cout.flush(); while (true) { int client = accept(server_fd, nullptr, nullptr); if (client >= 0) handleClient(client); } return 0; } )CODE"; // ───────────────────────────────────────────────────── // ASOSIY AMALLAR // ───────────────────────────────────────────────────── void saveCode() { ensureDirs(); std::ofstream f(CODE_FILE); if (!f.is_open()) { setStatus("✗ Faylga yozib bo'lmadi — root huquqi yo'qmi?", "red"); return; } f << getCode(); setStatus("✓ Saqlandi → " + CODE_FILE); } void loadCode() { std::ifstream f(CODE_FILE); if (f.good()) { std::stringstream ss; ss << f.rdbuf(); setCode(ss.str()); } else { setCode(DEFAULT_TEMPLATE); } } // Kompilyatsiya: saqlash → g++ → binarna fayl /usr/local/bin/api-server bool compileCode() { saveCode(); setStatus("🔨 Kompilyatsiya qilinmoqda..."); flushUI(); std::string cmd = "g++ -O2 -std=c++17 -pthread" " -o '" + BIN_FILE + "'" " '" + CODE_FILE + "'" " 2>'" + BUILD_LOG + "'"; int ret = system(cmd.c_str()); if (ret != 0) { std::ifstream log(BUILD_LOG); std::stringstream ss; ss << log.rdbuf(); std::string err = ss.str(); if (err.empty()) err = "(Tafsilot yo'q — qaytish kodi: " + std::to_string(ret) + ")"; showScrollableDialog("🔴 Kompilyatsiya xatosi", err, true); setStatus("✗ Kompilyatsiya muvaffaqiyatsiz!", "red"); return false; } chmod(BIN_FILE.c_str(), 0755); return true; } void startServer() { if (!compileCode()) return; // Bo'sh port topish (3000 → 65000 ketma-ket) setStatus("🔍 Bo'sh port axtarilmoqda..."); flushUI(); int port = findFreePort(3000); if (port < 0) { setStatus("✗ 3000–65000 oralig'ida bo'sh port yo'q!", "red"); return; } // Portni keyingi sessiyalar uchun saqlash { std::ofstream pf(PORT_FILE); pf << port; } // systemd service fayli — system-level (/etc/systemd/system/) std::string svc = "[Unit]\n" "Description=API Server (api-manager)\n" "After=network.target\n\n" "[Service]\n" "Type=simple\n" "ExecStart=" + BIN_FILE + " " + std::to_string(port) + "\n" "Restart=always\n" // ishdan chiqqanda avtomatik qayta yoqadi "RestartSec=3\n" "StandardOutput=journal\n" "StandardError=journal\n\n" "[Install]\n" "WantedBy=multi-user.target\n"; // tizim yuklanganda ham ishlaydi { std::ofstream f(SVC_FILE); f << svc; } setStatus("⚙ Xizmat o'rnatilmoqda..."); flushUI(); (void)system("systemctl daemon-reload"); (void)system(("systemctl enable " + std::string(SVC_NAME)).c_str()); (void)system(("systemctl start " + std::string(SVC_NAME)).c_str()); sleep(1); flushUI(); if (svcRunning()) { setStatus("✓ API server ishga tushdi! → http://localhost:" + std::to_string(port), "#27ae60"); refreshUI(true); updatePortLabel(port); } else { setStatus("✗ Server ishga tushmadi — 📋 Log ni ko'ring.", "red"); refreshUI(false); } } void stopServer() { setStatus("⏸ To'xtatilmoqda..."); flushUI(); (void)system(("systemctl stop " + std::string(SVC_NAME)).c_str()); (void)system(("systemctl disable " + std::string(SVC_NAME)).c_str()); // auto-restart ham o'chadi setStatus("● API server to'xtatildi. Auto-restart o'chirildi."); refreshUI(false); } void showLog() { FILE* p = popen(("journalctl -u " + std::string(SVC_NAME) + " -n 150 --no-pager 2>&1").c_str(), "r"); std::string out; if (p) { char buf[512]; while (fgets(buf, sizeof(buf), p)) out += buf; pclose(p); } if (out.empty()) out = "(Hech qanday log yozuvi topilmadi)"; showScrollableDialog("📋 API Server — journalctl loglari", out); } // ───────────────────────────────────────────────────── // CALLBACK'LAR // ───────────────────────────────────────────────────── void on_save (GtkButton*, gpointer) { saveCode(); } void on_compile(GtkButton*, gpointer) { if (g_busy) return; g_busy = true; gtk_widget_set_sensitive(g_toggle_btn, FALSE); if (compileCode()) setStatus("✓ Kompilyatsiya muvaffaqiyatli!", "#27ae60"); gtk_widget_set_sensitive(g_toggle_btn, TRUE); g_busy = false; } void on_toggle(GtkButton*, gpointer) { if (g_busy) return; g_busy = true; gtk_widget_set_sensitive(g_toggle_btn, FALSE); if (svcRunning()) stopServer(); else startServer(); gtk_widget_set_sensitive(g_toggle_btn, TRUE); g_busy = false; } void on_log(GtkButton*, gpointer) { showLog(); } gboolean on_key_press(GtkWidget*, GdkEventKey* ev, gpointer) { if ((ev->state & GDK_CONTROL_MASK) && ev->keyval == GDK_KEY_s) { saveCode(); return TRUE; } return FALSE; } // ───────────────────────────────────────────────────── // UI QURISH // ───────────────────────────────────────────────────── static void activate(GtkApplication* app, gpointer) { g_window = gtk_application_window_new(app); gtk_window_set_title(GTK_WINDOW(g_window), "API Server Manager"); gtk_window_set_default_size(GTK_WINDOW(g_window), 1000, 720); g_signal_connect(g_window, "key-press-event", G_CALLBACK(on_key_press), NULL); // ── CSS ────────────────────────────────────────── GtkCssProvider* css = gtk_css_provider_new(); gtk_css_provider_load_from_data(css, /* ---- asosiy fon ---- */ "window { background-color: #181825; }" /* ---- kod muharriri ---- */ "textview text {" " font-family: 'Fira Code','Cascadia Code','JetBrains Mono'," " 'DejaVu Sans Mono','Liberation Mono',monospace;" " font-size: 11pt;" " background-color: #1e1e2e;" " color: #cdd6f4;" "}" "textview { background-color: #1e1e2e; }" /* ---- toolbar ---- */ ".toolbar {" " background-color: #181825;" " padding: 4px 6px;" " border-bottom: 1px solid #313244;" "}" /* ---- status bar ---- */ ".statusbar {" " font-size: 9pt; color: #a5adcb;" " padding: 4px 10px;" " border-top: 1px solid #313244;" " background-color: #181825;" "}" /* ---- port etiketi ---- */ ".portlabel {" " font-family: monospace; font-weight: bold;" " color: #a6e3a1; font-size: 10pt;" " padding: 0 10px;" "}", -1, NULL); gtk_style_context_add_provider_for_screen( gdk_screen_get_default(), GTK_STYLE_PROVIDER(css), GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); g_object_unref(css); // ── Tuzilma ────────────────────────────────────── GtkWidget* vbox = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0); gtk_container_add(GTK_CONTAINER(g_window), vbox); // ── Toolbar ────────────────────────────────────── GtkWidget* toolbar = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6); gtk_container_set_border_width(GTK_CONTAINER(toolbar), 5); gtk_style_context_add_class(gtk_widget_get_style_context(toolbar), "toolbar"); gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0); GtkWidget* save_btn = gtk_button_new_with_label("💾 Saqlash"); GtkWidget* compile_btn = gtk_button_new_with_label("🔨 Kompilyatsiya"); GtkWidget* log_btn = gtk_button_new_with_label("📋 Log"); g_toggle_btn = gtk_button_new_with_label("▶ Ishga tushurish"); g_port_label = gtk_label_new("Port: -"); gtk_widget_set_name(g_toggle_btn, "toggle_btn"); gtk_style_context_add_class( gtk_widget_get_style_context(g_port_label), "portlabel"); gtk_box_pack_start(GTK_BOX(toolbar), save_btn, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(toolbar), compile_btn, FALSE, FALSE, 0); gtk_box_pack_start(GTK_BOX(toolbar), log_btn, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX(toolbar), g_toggle_btn, FALSE, FALSE, 0); gtk_box_pack_end (GTK_BOX(toolbar), g_port_label, FALSE, FALSE, 0); g_signal_connect(save_btn, "clicked", G_CALLBACK(on_save), NULL); g_signal_connect(compile_btn, "clicked", G_CALLBACK(on_compile), NULL); g_signal_connect(log_btn, "clicked", G_CALLBACK(on_log), NULL); g_signal_connect(g_toggle_btn, "clicked", G_CALLBACK(on_toggle), NULL); gtk_box_pack_start(GTK_BOX(vbox), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE, 0); // ── Kod muharriri (scrollable) ──────────────────── GtkWidget* scroll = gtk_scrolled_window_new(NULL, NULL); gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll), GTK_POLICY_AUTOMATIC, GTK_POLICY_AUTOMATIC); gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0); g_textview = gtk_text_view_new(); gtk_text_view_set_monospace (GTK_TEXT_VIEW(g_textview), TRUE); gtk_text_view_set_left_margin (GTK_TEXT_VIEW(g_textview), 14); gtk_text_view_set_right_margin (GTK_TEXT_VIEW(g_textview), 14); gtk_text_view_set_top_margin (GTK_TEXT_VIEW(g_textview), 10); gtk_text_view_set_bottom_margin(GTK_TEXT_VIEW(g_textview), 10); gtk_container_add(GTK_CONTAINER(scroll), g_textview); // ── Status bar ──────────────────────────────────── g_status_label = gtk_label_new("Tayyor."); gtk_label_set_xalign(GTK_LABEL(g_status_label), 0.0); gtk_style_context_add_class( gtk_widget_get_style_context(g_status_label), "statusbar"); gtk_box_pack_start(GTK_BOX(vbox), g_status_label, FALSE, FALSE, 0); gtk_widget_show_all(g_window); // ── Boshlang'ich holat ──────────────────────────── loadCode(); bool running = svcRunning(); refreshUI(running); if (running) setStatus("● API server allaqachon ishlamoqda.", "#27ae60"); else setStatus("Tayyor. Kodni yozing va ▶ Ishga tushurish tugmasini bosing."); } // ───────────────────────────────────────────────────── // MAIN // ───────────────────────────────────────────────────── int main(int argc, char* argv[]) { // Root bo'lmasa — dialog ko'rsatib chiqish if (getuid() != 0) { gtk_init(&argc, &argv); GtkWidget* dlg = gtk_message_dialog_new( NULL, GTK_DIALOG_MODAL, GTK_MESSAGE_ERROR, GTK_BUTTONS_OK, "Root huquqi talab qilinadi!\n\n" "Quyidagicha ishga tushiring:\n\n" " sudo ./api-manager"); gtk_window_set_title(GTK_WINDOW(dlg), "Huquq xatosi"); gtk_dialog_run(GTK_DIALOG(dlg)); return 1; } ensureDirs(); // g++ yo'q bo'lsa avtomatik o'rnatish (root bo'lgani uchun to'g'ridan apt) if (system("which g++ >/dev/null 2>&1") != 0) { fprintf(stderr, "[api-manager] g++ topilmadi, o'rnatilmoqda...\n"); (void)system("apt-get install -y g++ 2>&1"); if (system("which g++ >/dev/null 2>&1") != 0) { fprintf(stderr, "[api-manager] XATO: g++ o'rnatib bo'lmadi.\n" "Qo'lda bajaring: apt-get install g++\n"); return 1; } } GtkApplication* app = gtk_application_new( "uz.myapp.api-manager", (GApplicationFlags)0); g_signal_connect(app, "activate", G_CALLBACK(activate), NULL); int rc = g_application_run(G_APPLICATION(app), argc, argv); g_object_unref(app); return rc; }