📄 downloads.cc
字号:
} curr_bytesize = new_sz; if (curr_bytesize > 1024 * 1024) snprintf(buf, 64, "%.1fMB", (float)curr_bytesize / (1024*1024)); else snprintf(buf, 64, "%.0fKB", (float)curr_bytesize / 1024); prGot->copy_label(buf); prGot->redraw(); if (total_bytesize == -1) { prBar->showtext(false); prBar->move(1); } else { prBar->showtext(true); double pos = 100.0 * (double)curr_bytesize / total_bytesize; prBar->position(pos); }}static void read_log_cb(int fd_in, void *data){ DLItem *dl_item = (DLItem *)data; int BufLen = 4096; char Buf[BufLen]; ssize_t st; int ret = -1; do { st = read(fd_in, Buf, BufLen); if (st < 0) { if (errno == EAGAIN) { ret = 1; break; } perror("read, "); break; } else if (st == 0) { close(fd_in); remove_fd(fd_in, 1); dl_item->log_done(1); ret = 0; break; } else { dl_item->log_text_add(Buf, st); } } while (1);}void DLItem::father_init(){ close(LogPipe[1]); add_fd(LogPipe[0], 1, read_log_cb, this); // Read // Start the timer after the child is running. // (this makes a big difference with wget) //init_time = time(NULL);}/* * Our wget exited, let's check its status and update the panel. */void DLItem::child_finished(int status){ wget_status(status); if (status == 0) { prButton->label("Done"); prButton->tooltip("Close this information panel"); } else { prButton->label("Close"); prButton->tooltip("Close this information panel"); status_msg("ABORTED"); if (curr_bytesize == 0) { // Update the title prTitle->label(shortname); prTitle->redraw(); } } prButton->activate(); prButton->redraw(); MSG("wget status %d\n", status);}/* * Convert seconds into human readable [hour]:[min]:[sec] string. */void secs2timestr(int et, char *str){ int eh, em, es; eh = et / 3600; em = (et % 3600) / 60; es = et % 60; if (eh == 0) { if (em == 0) snprintf(str, 8, "%ds", es); else snprintf(str, 8, "%dm%ds", em, es); } else { snprintf(str, 8, "%dh%dm", eh, em); }}/* * Update Got, Rate, ~Rate and ETA */void DLItem::update(){ struct stat ss; time_t curr_time; float csec, tsec, rate, _rate = 0; char str[64]; int et; if (updates_done()) return; /* Update curr_size */ if (stat(fullname, &ss) == -1) { MSG("stat, %s\n", strerror(errno)); return; } update_size((int)ss.st_size); /* Get current time */ time(&curr_time); csec = (float) (curr_time - init_time); /* Rate */ if (csec >= 2) { tsec = (float) (curr_time - twosec_time); rate = ((float)(curr_bytesize-twosec_bytesize) / 1024) / tsec; snprintf(str, 64, (rate < 100) ? "%.1fK/s" : "%.0fK/s", rate); prRate->copy_label(str); prRate->redraw(); } /* ~Rate */ if (csec >= 1) { _rate = ((float)(curr_bytesize-init_bytesize) / 1024) / csec; snprintf(str, 64, (_rate < 100) ? "%.1fK/s" : "%.0fK/s", _rate); pr_Rate->copy_label(str); pr_Rate->redraw(); } /* ETA */ if (fork_done()) { updates_done(1); // Last update prETAt->label("Time"); prETAt->tooltip("Download Time"); prETAt->redraw(); secs2timestr((int)csec, str); prETA->copy_label(str); if (total_bytesize == -1) { update_prSize(curr_bytesize); if (wget_status() == 0) status_msg("Done"); } } else { if (_rate > 0 && total_bytesize > 0 && curr_bytesize > 0) { et = (int)((total_bytesize-curr_bytesize) / (_rate * 1024)); secs2timestr(et, str); prETA->copy_label(str); } } prETA->redraw(); /* Update one and two secs ago times and bytesizes */ twosec_time = onesec_time; onesec_time = curr_time; twosec_bytesize = onesec_bytesize; onesec_bytesize = curr_bytesize;}// SIGCHLD -------------------------------------------------------------------/*! SIGCHLD handler */void raw_sigchld(int){ caught_sigchld = 1;}/*! Establish SIGCHLD handler */void est_sigchld(void){ struct sigaction sigact; sigset_t set; (void) sigemptyset(&set); sigact.sa_handler = raw_sigchld; sigact.sa_mask = set; sigact.sa_flags = SA_NOCLDSTOP; if (sigaction(SIGCHLD, &sigact, NULL) == -1) { perror("sigaction"); exit(1); }}/* * Timeout function to check wget's exit status. */void cleanup_cb(void *data){ DLItemList *list = (DLItemList *)data; sigprocmask(SIG_BLOCK, &mask_sigchld, NULL); if (caught_sigchld) { /* Handle SIGCHLD */ int i, status; for (i = 0; i < list->num(); ++i) { if (!list->get(i)->fork_done() && waitpid(list->get(i)->pid(), &status, WNOHANG) > 0) { list->get(i)->child_finished(status); list->get(i)->fork_done(1); } } caught_sigchld = 0; } sigprocmask(SIG_UNBLOCK, &mask_sigchld, NULL); repeat_timeout(1.0,cleanup_cb,data);}/* * Timeout function to update the widget indicators, * also remove widgets marked "done". */void update_cb(void *data){ static int cb_used = 0; DLItemList *list = (DLItemList *)data; /* Update the widgets and remove the ones marked as done */ for (int i = 0; i < list->num(); ++i) { if (!list->get(i)->widget_done()) { list->get(i)->update(); } else if (list->get(i)->fork_done()) { // widget_done and fork_done avoid a race condition. dl_win->del(i); --i; } cb_used = 1; } if (cb_used && list->num() == 0) exit(0); repeat_timeout(1.0,update_cb,data);}// DLWin ---------------------------------------------------------------------/* * Read a single line from a socket and store it in a GString. */static ssize_t readline(int socket, GString ** msg){ ssize_t st; gchar buf[16384], *aux; /* can't use fread() */ do st = read(socket, buf, 16384); while (st < 0 && errno == EINTR); if (st == -1) MSG("readline, %s\n", strerror(errno)); if (st > 0) { aux = g_strndup(buf, (guint)st); g_string_assign(*msg, aux); g_free(aux); } else { g_string_assign(*msg, ""); } return st;}/* * Make a new name and place it in 'dl_dest'. */static void make_new_name(gchar **dl_dest, const gchar *url){ GString *gstr = g_string_new(*dl_dest); gint idx = gstr->len; if (gstr->str[idx - 1] != '/'){ g_string_append_c(gstr, '/'); ++idx; } /* Use a mangled url as name */ g_string_append(gstr, url); for ( ; idx < gstr->len; ++idx) if (!isalnum(gstr->str[idx])) gstr->str[idx] = '_'; /* free memory */ g_free(*dl_dest); *dl_dest = gstr->str; g_string_free(gstr, FALSE);}/* * Callback function for the request socket. * Read the request, parse and start a new download. */static void read_req_cb(int req_fd, void *){ GString *tag; struct sockaddr_un clnt_addr; int new_socket; socklen_t csz; struct stat sb; char *cmd = NULL, *url = NULL, *dl_dest = NULL; DLAction action = DL_ABORT; /* compiler happiness */ /* Initialize the value-result parameter */ csz = sizeof(struct sockaddr_un); /* accept the request */ do { new_socket = accept(req_fd, (struct sockaddr *) &clnt_addr, &csz); } while (new_socket == -1 && errno == EINTR); if (new_socket == -1) { MSG("accept, %s fd=%d\n", strerror(errno), req_fd); return; } //sigprocmask(SIG_BLOCK, &blockSC, NULL); tag = g_string_new(NULL); readline(new_socket, &tag); close(new_socket); _MSG("Received tag={%s}\n", tag->str); if ((cmd = a_Dpip_get_attr(tag->str, (size_t)tag->len, "cmd")) == NULL) { MSG("Failed to parse 'cmd' in %s\n", tag->str); goto end; } if (strcmp(cmd, "DpiBye") == 0) { MSG("got DpiBye, ignoring...\n"); goto end; } if (strcmp(cmd, "download") != 0) { MSG("unknown command: '%s'. Aborting.\n", cmd); goto end; } if (!(url = a_Dpip_get_attr(tag->str,(size_t)tag->len, "url"))){ MSG("Failed to parse 'url' in %s\n", tag->str); goto end; } if (!(dl_dest = a_Dpip_get_attr(tag->str,(size_t)tag->len,"destination"))){ MSG("Failed to parse 'destination' in %s\n", tag->str); goto end; } /* 'dl_dest' may be a directory */ if (stat(dl_dest, &sb) == 0 && S_ISDIR(sb.st_mode)) make_new_name(&dl_dest, url); action = dl_win->check_filename(&dl_dest); if (action != DL_ABORT) { // Start the whole thing whithin FLTK. dl_win->add(dl_dest, url, action); } else if (dl_win->num() == 0) { exit(0); }end: g_free(cmd); g_free(url); g_free(dl_dest); g_string_free(tag, TRUE);}/* * Callback for close window request (WM or EscapeKey press) */static void dlwin_esc_cb(Widget *, void *){ char *msg = "There are running downloads.\n" "ABORT them and EXIT anyway?"; if (dl_win && dl_win->num_running() > 0) { int ch = fltk::choice(msg, "Yes", "*No", "Cancel"); if (ch != 0) return; } /* abort each download properly */ dl_win->abort_all();}/* * Add a new download request to the main window and * fork a child to do the job. */void DLWin::add(const char *full_filename, const char *url, DLAction action){ DLItem *dl_item = new DLItem(full_filename, url, action); mDList->add(dl_item); //mPG->add(*dl_item->get_widget()); mPG->insert(*dl_item->get_widget(), 0); _MSG("Child index = %d\n", mPG->find(dl_item->get_widget())); // Start the child process pid_t f_pid = fork(); if (f_pid == 0) { /* child */ dl_item->child_init(); _exit(EXIT_FAILURE); } else if (f_pid < 0) { perror("fork, "); exit(1); } else { /* father */ dl_win->show(); dl_item->pid(f_pid); dl_item->father_init(); }}/* * Decide what to do whe the filename already exists. * (renaming takes place here when necessary) */DLAction DLWin::check_filename(char **p_fullname){ struct stat ss; char *msg; int ch; DLAction ret = DL_ABORT; if (stat(*p_fullname, &ss) == -1) return DL_NEWFILE; msg = g_strdup_printf( "The file:\n %s (%d Bytes)\nalready exists. What do we do?", *p_fullname, (int)ss.st_size); ch = fltk::choice(msg, "Rename", "Continue", "Abort"); g_free(msg); MSG("Choice %d\n", ch); if (ch == 0) { const char *p; p = fltk::file_chooser("Enter a new name:", NULL, *p_fullname); if (p) { g_free(*p_fullname); *p_fullname = g_strdup(p); ret = check_filename(p_fullname); } } else if (ch == 1) { ret = DL_CONTINUE; } return ret;}/* * Add a new download request to the main window and * fork a child to do the job. */void DLWin::del(int n_item){ DLItem *dl_item = mDList->get(n_item); // Remove the widget from the scroll group mPG->remove(dl_item->get_widget()); // Resize the scroll group mPG->resize(mWin->w(), 1); mDList->del(n_item); delete(dl_item);}/* * Return number of entries */int DLWin::num(){ return mDList->num();}/* * Return number of running downloads */int DLWin::num_running(){ int i, nr; for (i = nr = 0; i < mDList->num(); ++i) if (!mDList->get(i)->fork_done()) ++nr; return nr;}/* * Set a callback function for the request socket */void DLWin::listen(int req_fd){ add_fd(req_fd, 1, read_req_cb, NULL); // Read}/* * Abort each download properly, and let the main cycle exit */void DLWin::abort_all(){ for (int i = 0; i < mDList->num(); ++i) mDList->get(i)->abort_dl();}/* * Create the main window and an empty list of requests. */DLWin::DLWin(int ww, int wh) { // Init an empty list for the download requests mDList = new DLItemList(); // Create the empty main window mWin = new Window(ww, wh, "Downloads:"); mWin->begin(); mScroll = new ScrollGroup(0,0,ww,wh); mScroll->begin(); mPG = new PackedGroup(0,0,ww,wh); mPG->end(); //mPG->spacing(10); mScroll->end(); mWin->resizable(mWin); mWin->end(); mWin->callback(dlwin_esc_cb, NULL); mWin->show(); // Set SIGCHLD handlers sigemptyset(&mask_sigchld); sigaddset(&mask_sigchld, SIGCHLD); est_sigchld(); // Set the cleanup timeout add_timeout(1.0, cleanup_cb, mDList); // Set the update timeout add_timeout(1.0, update_cb, mDList);}// ---------------------------------------------------------------------------//int main(int argc, char **argv)int main(){ int ww = 420, wh = 85; lock(); // Create the download window dl_win = new DLWin(ww, wh); // Start listening to the request socket dl_win->listen(STDIN_FILENO); MSG("started...\n"); return run();}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -