/**************************************************************************
* *
* Copyright (C) 2001 Grub, Inc. *
* File: gui.cpp *
* Authors: Lawrence Kincheloe, Philip McCauley, Patrick McAllister *
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 1, or (at your option) *
* any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the Free Software *
* Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. *
* *
* *
**************************************************************************/
#include "Gui.h"
using namespace std;
struct MemoryStruct {
char *memory;
size_t size;
};
size_t GuiWriteMemoryCallback(void *ptr, size_t size, size_t nmemb, void *data)
{
register int realsize = size * nmemb;
struct MemoryStruct *mem = (struct MemoryStruct *)data;
mem->memory = (char *)realloc(mem->memory, mem->size + realsize + 1);
if (mem->memory)
{
memcpy(&(mem->memory[mem->size]), ptr, realsize);
mem->size += realsize;
mem->memory[mem->size] = 0;
}
return realsize;
}
void gui::end(void) // clean's up gui on exit
{
#ifdef GRUB_UNIX
// clear the window, end the window, clear again
clear();
endwin();
clear();
#endif
// indicated that the GUI is now dead
Crawler_Status_Info.gui_quit = false;
// log out that we are shutting down
CLog(GCLOG_INFO, "(gui) shutting down per request of main thread...");
// exit this thread
#ifdef GRUB_UNIX
pthread_exit(NULL);
#endif
}
gui::gui() {}
gui::~gui()
{
#ifdef GRUB_UNIX
clear();
endwin();
#endif
}
void gui::start()
{
CLog(GCLOG_INFO, "(gui) starting up GUI...");
crawled_urls = 0;
AveragePerHour = 0;
crawled_today = 0;
url_rank_overall = 0;
url_rank_daily = 0;
/* Begin switch statement */
int static_count = 0;
// set up screen and disable echo from keyboard
#ifdef GRUB_UNIX
stdscr = initscr();
noecho();
cbreak();
nodelay(stdscr, TRUE);
init_def_var();
static_setup();
while(true)
{
// check the keyboard for input
check_keyboard();
// you want your machine to be slammed?
// we use a mu sleep via a select here.
struct timeval tv;
tv.tv_sec = 0;
tv.tv_usec = 1000000;
select (0, NULL, NULL, NULL, &tv);
// every so often we clear the whole screen
// just because something else might print to it
static_count++;
if (static_count > 30)
{
clear();
static_count = 0;
}
// check to see if we need to exit
if (Crawler_Status_Info.gui_quit)
{
end();
}
draw();
refresh();
}
#endif
}
void gui::check_keyboard()
{
#ifdef GRUB_UNIX
int key_pressed;
// read in from the keyboard
key_pressed = getch();
// check to see if a key was pressed
if (key_pressed != ERR)
{
switch (key_pressed)
{
case 'q': // tell the coordinator to quit, in turn he will shut us down
CLog(GCLOG_INFO, "(gui) shutting down per keyboard request...");
Crawler_Status_Info.coordinator_quit = true;
//sending singnal to the parent processor to kill the client
kill(Crawler_Status_Info.main_pid, SIGINT);
break;
case '+': // increasing the bandwidth
Config_File_Info.MaxAmountOfBandwidth = Config_File_Info.MaxAmountOfBandwidth +10000;
break;
case '-': // decreasing the bandwidth
if (Config_File_Info.MaxAmountOfBandwidth > 30000)
Config_File_Info.MaxAmountOfBandwidth = Config_File_Info.MaxAmountOfBandwidth -10000;
break;
case '>': // increasing the number of crawlers running
if(Config_File_Info.NumOfCrawlersToRun < 100)
Config_File_Info.NumOfCrawlersToRun = Config_File_Info.NumOfCrawlersToRun + 1;
break;
case '<': // decreasing the number of crawlers running
if(Config_File_Info.NumOfCrawlersToRun > 1)
Config_File_Info.NumOfCrawlersToRun = Config_File_Info.NumOfCrawlersToRun - 1;
break;
default:
break;
}
}
fflush(stdout);
return;
#endif
}
void gui::init_def_var() // initiate default variables
{
#ifdef GRUB_UNIX
curs_set(0);
#endif
(void) time(&start_time);
(void) time(&cpu_time);
(void) time(&cstat_time);
#ifdef GRUB_UNIX
getrusage(RUSAGE_SELF , &cpu_rec_used);
#endif
start_position = 5;
(void) time(&cbar_time);
bar_state = 0;
bar_inc = 0;
}
void gui::gui_uptime()
{
(void) time(¤t_time); //gets current time
total_up_time = current_time - (start_time); //start_time is initalized once, total up time is what it says it is
#ifdef GRUB_UNIX
mvprintw(16, 12, "%3i:%02i:%02i", (int) (total_up_time/3600), (int) ((total_up_time%3600)/60) ,(int) (total_up_time%60));
#endif
}
void gui::draw() //this function does the majority of setting up the gui
{
#ifdef GRUB_UNIX
LINES = 24;
COLS = 79;
#endif
static_setup();
bar(); // handy bar graph
title_bar();
connection_bar();
cstatus(); // client status
cstats(); // client statistics
url_stats(); //url statistics
}
void gui::static_setup()
{
#ifdef GRUB_UNIX
// outside lines for whole pane
mvhline(0, 0, '-', 79);
mvhline(23, 0, '-', 79);
mvvline(0, 0, '|', 23);
mvvline(0, 79, '|', 23);
mvaddch(0, 0, '#');
mvaddch(0, 79,'#');
mvaddch(23, 0, '#');
mvaddch(23, 79,'#');
// 2nd horizontal line from top
mvhline(3, 1, '-', 79);
mvaddch(3, 0, '#');
mvaddch(3, 79, '#');
// 3rd horizontal line from top
mvhline(13, 1 , '-', 79);
mvaddch(13, 0, '#');
mvaddch(13, 79, '#');
// 4th horizontal line from top
mvhline(15, 1,'-', 79);
mvaddch(15, 0, '#');
mvaddch(15, 79, '#');
// 1st vertical line in bottom pane (in middle)
mvvline(13, 22, '|', 10);
mvaddch(13, 22, '#');
mvaddch(15, 22, '#');
mvaddch(23, 22, '#');
// 2nd vertical line in bottom pane (in middle)
mvvline(13, 49, '|', 10);
mvaddch(13, 49, '#');
mvaddch(15, 49, '#');
mvaddch(23, 49, '#');
mvaddstr(1,2, "Grub Distributed Network Crawling Agent"); //prints title
string versionstring = "Version ";
versionstring += VERSION;
mvaddstr(1, 45, versionstring.c_str()); //prints version
mvaddstr(2,2, "Tech Support Available: http://www.grub.org or Email us at support@grub.org");
mvaddstr(11, 2, "Current Connection Status:");
mvaddstr(14, 2, "Client Status");
mvaddstr(16, 2, "Uptime:");
mvaddstr(17, 2, "Max Crawlers:");
mvaddstr(18, 2, "Engaged:");
mvaddstr(19, 2, "B/W Limit:");
mvaddstr(20, 2, "B/W Usage:");
mvaddstr(21, 2, "Host Protect:");
mvaddstr(14, 24, "URL Stats - This Run");
mvaddstr(16, 24, "# Total URLs:");
mvaddstr(17, 24, "# Updated:");
mvaddstr(18, 24, "# Unchanged:");
mvaddstr(19, 24, "# No Crawls:");
mvaddstr(20, 24, "# Redirected:");
mvaddstr(21, 24, "# Host Down:");
mvaddstr(22, 24, "# Not Found:");
mvaddstr(16, 51, "# URLs Crawled:");
mvaddstr(17, 51, "# Crawled Today:");
mvaddstr(18, 51, "# Per Hour Today:");
mvaddstr(19, 51, "Overall Ranking:");
mvaddstr(20, 51, "Today's Ranking:");
#endif
}
void gui::cstatus()
{
gui_uptime(); //maybe edit later when update scheme is clear
#ifdef GRUB_UNIX
mvprintw( 17, 16, "%5i ", Config_File_Info.NumOfCrawlersToRun);
mvprintw( 18, 16, "%5i ", Crawler_Status_Info.engaged);
mvprintw( 19, 12, "%5iKbps ", Config_File_Info.MaxAmountOfBandwidth/1000);
mvprintw( 20, 12, "%5iKbps ", Crawler_Status_Info.usage);
if (Crawler_Status_Info.host_protect)
{
mvprintw( 21, 18, "YES");
}
else
{
mvprintw( 21, 18, " ");
mvprintw( 21, 19, "NO");
}
#endif
}
void gui::url_stats()
{
#ifdef GRUB_UNIX
int total_urls = 0;
int updated_urls_percentage = 0;
int redirect_urls_percentage = 0;
int down_urls_percentage = 0;
int unchanged_urls_percentage = 0;
int not_found_urls_percentage = 0;
int no_crawl_urls_percentage = 0;
total_urls = Crawler_Status_Info.unchanged_urls + Crawler_Status_Info.updated_urls + Crawler_Status_Info.redirect_urls;
total_urls += Crawler_Status_Info.down_urls + Crawler_Status_Info.not_found_urls + Crawler_Status_Info.no_crawl_urls;
if (total_urls > 10)
{
updated_urls_percentage = (Crawler_Status_Info.updated_urls*100)/total_urls;
redirect_urls_percentage = (Crawler_Status_Info.redirect_urls*100)/total_urls;
down_urls_percentage = (Crawler_Status_Info.down_urls*100)/total_urls;
unchanged_urls_percentage = (Crawler_Status_Info.unchanged_urls*100)/total_urls;
not_found_urls_percentage = (Crawler_Status_Info.not_found_urls*100)/total_urls;
no_crawl_urls_percentage = (Crawler_Status_Info.no_crawl_urls*100)/total_urls;
}
else
{
updated_urls_percentage = 0;
redirect_urls_percentage = 0;
down_urls_percentage = 0;
unchanged_urls_percentage = 0;
not_found_urls_percentage = 0;
no_crawl_urls_percentage = 0;
}
mvprintw( 16, 38, "%7i/%%%%", total_urls);
mvprintw( 17, 38, "%7i/%2i", Crawler_Status_Info.updated_urls, updated_urls_percentage);
mvprintw( 18, 38, "%7i/%2i", Crawler_Status_Info.unchanged_urls, unchanged_urls_percentage);
mvprintw( 19, 38, "%7i/%2i", Crawler_Status_Info.no_crawl_urls, no_crawl_urls_percentage);
mvprintw( 20, 38, "%7i/%2i", Crawler_Status_Info.redirect_urls, redirect_urls_percentage);
mvprintw( 21, 38, "%7i/%2i", Crawler_Status_Info.down_urls, down_urls_percentage);
mvprintw( 22, 38, "%7i/%2i", Crawler_Status_Info.not_found_urls, not_found_urls_percentage);
#endif
}
void gui::cstats()
{
#ifdef GRUB_UNIX
char url_rank_overall_temp[3]; //used for suffix on ranking
char url_rank_daily_temp[3]; //'th', 'st','rd', and such
mvprintw(14, 51, "Client Statistics (ID %d)", Config_File_Info.ClientID);
switch(url_rank_overall % 10)
{
case 1:
strcpy(url_rank_overall_temp , "st");
break;
case 2:
strcpy(url_rank_overall_temp , "nd");
break;
case 3:
strcpy(url_rank_overall_temp , "rd");
break;
default:
strcpy(url_rank_overall_temp , "th");
break;
}
switch(url_rank_daily % 10)
{
case 1:
strcpy(url_rank_daily_temp , "st");
break;
case 2:
strcpy(url_rank_daily_temp , "nd");
break;
case 3:
strcpy(url_rank_daily_temp , "rd");
break;
default:
strcpy(url_rank_daily_temp , "th");
break;
}
switch(url_rank_daily % 100)
{
case 11:
strcpy(url_rank_daily_temp, "th");
break;
case 12:
strcpy(url_rank_daily_temp, "th");
break;
case 13:
strcpy(url_rank_daily_temp, "th");
break;
default:
break;
}
switch(url_rank_overall % 100)
{
case 11:
strcpy(url_rank_overall_temp, "th");
break;
case 12:
strcpy(url_rank_overall_temp, "th");
break;
case 13:
strcpy(url_rank_overall_temp, "th");
break;
default:
break;
}
mvprintw(16, 69, "%9i", Crawler_Status_Info.HistoricURLs);
mvprintw(17, 69, "%9i", Crawler_Status_Info.TodaysURLs);
mvprintw(18, 69, "%9i", Crawler_Status_Info.TodaysURLs/24);
mvprintw(19, 67, "%9i", Crawler_Status_Info.OverallURLRank);
mvaddstr(19, 76, url_rank_overall_temp);
mvprintw(20, 67, "%9i", Crawler_Status_Info.DailyURLRank);
mvaddstr(20, 76, url_rank_daily_temp);
#endif
}
void gui::title_bar()
{
// gets current time
(void) time(¤t_time);
//gets month
tm_pointer = localtime(¤t_time);
switch(tm_pointer->tm_mon)
{
case 0:
strcpy(month, "Jan");
break;
case 1:
strcpy(month , "Feb");
break;
case 2:
strcpy(month , "Mar");
break;
case 3:
strcpy(month , "Apr");
break;
case 4:
strcpy(month , "May");
break;
case 5:
strcpy(month , "June");
break;
case 6:
strcpy(month , "July");
break;
case 7:
strcpy(month , "Aug");
break;
case 8:
strcpy(month , "Sept");
break;
case 9:
strcpy(month , "Oct");
break;
case 10:
strcpy(month , "Nov");
break;
case 11:
strcpy(month , "Dec");
break;
default:
strcpy(month , "Def");
break;
}
#ifdef GRUB_UNIX
//prints date
mvprintw(1 , 64, "%4s %2d, %4d" , month, tm_pointer->tm_mday, tm_pointer->tm_year+1900);
#endif
}
void gui::connection_bar()
{
#ifdef GRUB_UNIX
char *rl_bar_animation[2] = {" ------------ ", " <=========== "};
char *lr_bar_animation[2] = {" ------------ ", " ===========> "};
switch(bar_state) // bar_state needs to be 0 to start out with
{
case 2: // From CLIENT to SERVER
mvprintw(11 , 30, "SERVER");
mvprintw(11 , 36, rl_bar_animation[bar_inc]);
mvprintw(11 , 50, "CLIENT");
mvprintw(11 , 56, rl_bar_animation[0]);
mvprintw(11 , 70, "website");
break;
case 1: // From WEBSITE to CLIENT
mvprintw(11, 30 , "server");
mvprintw(11, 36 , rl_bar_animation[0]);
mvprintw(11, 50 , "CLIENT");
mvprintw(11, 56 , rl_bar_animation[bar_inc]);
mvprintw(11, 70 , "WEBSITE");
break;
case 0: // From SERVER to CLIENT
mvprintw(11, 30 , "SERVER");
mvprintw(11, 36 , lr_bar_animation[bar_inc]);
mvprintw(11, 50 , "CLIENT");
mvprintw(11, 56 , rl_bar_animation[0]);
mvprintw(11, 70 , "website");
break;
}
// animate the whole run one way before flipping state
bar_inc++;
if (bar_inc == 2)
{
bar_inc = 0;
bar_state = Crawler_Status_Info.current_action;
}
//if else prints BW or bw depending on value in bandwidth_limit
if(!Crawler_Status_Info.bandwidth_limit)
{
mvprintw(12 ,52 , "bw");
}
else
{
mvprintw(12 ,52 , "BW");
}
#endif
}
void gui::bar() //makes progress bar //note: start position initialized in init_def_var
{
#ifdef GRUB_UNIX
float graph;
float graph_width = COLS - 8;
mvaddstr(start_position-1, 3, "URL Set Completion ("); //title for bar
printw("%i URLS)",(int)Crawler_Status_Info.max_url); //prints total # urls
if (Crawler_Status_Info.max_url <= Crawler_Status_Info.current_url)
{
Crawler_Status_Info.max_url = Crawler_Status_Info.current_url; //catches idiots
}
if (graph_width < -2)
{
graph_width = 0; //catches idiots
}
if (Crawler_Status_Info.max_url < 1) Crawler_Status_Info.max_url = 500; // an idiot wrote this code
graph = graph_width*(Crawler_Status_Info.current_url/Crawler_Status_Info.max_url); //stars in bar
mvaddch(start_position, 3, '[');
for (int t=(int)graph; t<=graph_width; t++)
{
mvaddch( start_position, t+4, '-'); //prints -'s across bar
}
if (!(graph <= 0))
{
for (int t=0; t<=graph; t++)
{
mvaddch( start_position, t+4, '#' ); //prints out one pound sign
}
}
mvaddch( start_position, (int)graph_width+5, ']'); // prints out bracket
mvaddch( start_position+2, 3, '['); //prints out bracket
graph = graph_width/10; // can pre-define graph and sets it up
move(start_position+1,4); // moves the curser each time
for (int t = 0; t <= 100; )
{
addch('|');
t+=10;
move(start_position+1,(int)((t/10)*graph)+4);
}
move(start_position+2,4);
if (graph_width >= 34)
{
for (int t = 0; t < 100; )
{
printw("%i" ,t);
t+=10;
move(start_position+2, (int)((t/10)*graph)+4);
}
}
move(start_position+2, (int)(10*graph+2));
printw("%i" , 100);
mvaddch(start_position+2,(int)graph_width+5,']');
#endif
}