fix: rsync real-time output + refresh button
- Use read() + poll() instead of fgets() to handle rsync \r progress - rsync uses \r for in-place progress updates, fgets() blocked on \n - Added poll() with 200ms timeout for non-blocking read - Added refresh button (view-refresh icon) in snapshot sidebar header - Fixed duplicate build_menu/build_toolbar calls
This commit is contained in:
+10
-2
@@ -142,8 +142,6 @@ void MainWindow::build_ui() {
|
||||
gtk_container_add(GTK_CONTAINER(window_), vbox);
|
||||
|
||||
build_menu();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar_, FALSE, FALSE, 0);
|
||||
|
||||
build_toolbar();
|
||||
gtk_box_pack_start(GTK_BOX(vbox), toolbar_, FALSE, FALSE, 0);
|
||||
|
||||
@@ -157,11 +155,21 @@ void MainWindow::build_ui() {
|
||||
|
||||
GtkWidget* left_header = gtk_box_new(GTK_ORIENTATION_HORIZONTAL, 6);
|
||||
gtk_widget_set_margin_start(left_header, 8);
|
||||
gtk_widget_set_margin_end(left_header, 4);
|
||||
gtk_widget_set_margin_top(left_header, 6);
|
||||
gtk_widget_set_margin_bottom(left_header, 6);
|
||||
GtkWidget* left_title = gtk_label_new(NULL);
|
||||
gtk_label_set_markup(GTK_LABEL(left_title), "<b>Snapshots</b>");
|
||||
gtk_widget_set_halign(left_title, GTK_ALIGN_START);
|
||||
gtk_box_pack_start(GTK_BOX(left_header), left_title, TRUE, TRUE, 0);
|
||||
|
||||
GtkWidget* refresh_btn = gtk_button_new_from_icon_name("view-refresh", GTK_ICON_SIZE_MENU);
|
||||
gtk_widget_set_tooltip_text(refresh_btn, "Refresh snapshot list");
|
||||
g_signal_connect(refresh_btn, "clicked", G_CALLBACK(+[](GtkWidget*, gpointer d) {
|
||||
static_cast<MainWindow*>(d)->refresh_snapshot_list();
|
||||
}), this);
|
||||
gtk_box_pack_end(GTK_BOX(left_header), refresh_btn, FALSE, FALSE, 0);
|
||||
|
||||
gtk_box_pack_start(GTK_BOX(left_box), left_header, FALSE, FALSE, 0);
|
||||
gtk_box_pack_start(GTK_BOX(left_box), gtk_separator_new(GTK_ORIENTATION_HORIZONTAL), FALSE, FALSE, 0);
|
||||
|
||||
|
||||
+43
-12
@@ -5,6 +5,7 @@
|
||||
#include <regex>
|
||||
#include <unistd.h>
|
||||
#include <sys/wait.h>
|
||||
#include <poll.h>
|
||||
|
||||
RsyncManager::RsyncManager(Config& config) : config_(config) {}
|
||||
|
||||
@@ -62,22 +63,52 @@ bool RsyncManager::create_snapshot(const std::string& snapshot_name,
|
||||
}
|
||||
|
||||
RsyncProgress prog;
|
||||
char buf[4096];
|
||||
while (fgets(buf, sizeof(buf), pipe)) {
|
||||
int fd = fileno(pipe);
|
||||
char raw[4096];
|
||||
std::string accumulator;
|
||||
|
||||
/* Read raw bytes, split on \r and \n for real-time rsync progress */
|
||||
while (true) {
|
||||
if (cancel_requested_) break;
|
||||
std::string line(buf);
|
||||
|
||||
/* Remove trailing newline */
|
||||
if (!line.empty() && line.back() == '\n') line.pop_back();
|
||||
if (!line.empty() && line.back() == '\r') line.pop_back();
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(log_mutex_);
|
||||
log_buffer_.push_back(line);
|
||||
struct pollfd pfd = {fd, POLLIN, 0};
|
||||
int pret = poll(&pfd, 1, 200);
|
||||
if (pret < 0) break;
|
||||
if (pret == 0) continue;
|
||||
if (!(pfd.revents & POLLIN)) {
|
||||
if (pfd.revents & (POLLHUP | POLLERR)) break;
|
||||
continue;
|
||||
}
|
||||
|
||||
parse_progress_line(line, prog);
|
||||
prog.log_line = line;
|
||||
ssize_t n = read(fd, raw, sizeof(raw) - 1);
|
||||
if (n <= 0) break;
|
||||
raw[n] = '\0';
|
||||
|
||||
accumulator += raw;
|
||||
|
||||
/* Split on \r and \n */
|
||||
size_t pos;
|
||||
while ((pos = accumulator.find_first_of("\r\n")) != std::string::npos) {
|
||||
std::string line = accumulator.substr(0, pos);
|
||||
accumulator.erase(0, pos + 1);
|
||||
|
||||
if (line.empty()) continue;
|
||||
|
||||
{
|
||||
std::lock_guard<std::mutex> lock(log_mutex_);
|
||||
log_buffer_.push_back(line);
|
||||
}
|
||||
|
||||
parse_progress_line(line, prog);
|
||||
prog.log_line = line;
|
||||
if (on_progress) on_progress(prog);
|
||||
}
|
||||
}
|
||||
|
||||
/* Flush remaining */
|
||||
if (!accumulator.empty()) {
|
||||
parse_progress_line(accumulator, prog);
|
||||
prog.log_line = accumulator;
|
||||
if (on_progress) on_progress(prog);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user