From 7d6fce4cf49c20ea3bafcda062fe1f7759261db6 Mon Sep 17 00:00:00 2001 From: David Anderson Date: Tue, 13 May 2003 18:55:07 +0000 Subject: [PATCH] tentative projects svn path=/trunk/boinc/; revision=1187 --- Makefile.in | 2 +- checkin_notes | 42 +++++++++++++++ client/account.C | 84 +++++++++++++---------------- client/account.h | 3 -- client/client_state.C | 2 - client/client_state.h | 4 +- client/client_types.C | 45 ++++++++++++++-- client/client_types.h | 7 +-- client/cs_scheduler.C | 11 ++-- client/file_names.C | 52 ++---------------- client/main.C | 42 ++++++++++++--- client/scheduler_op.C | 91 ++++++++++++++++++++------------ client/scheduler_op.h | 1 + client/ss_logic.C | 4 +- client/win/wingui.cpp | 10 ++-- client/win/wingui_mainwindow.cpp | 2 + doc/client_app.html | 9 ++++ doc/client_app_graphic.html | 14 +++++ lib/filesys.C | 16 ++++++ lib/filesys.h | 2 + todo | 69 +++++++++++++++++++----- 21 files changed, 336 insertions(+), 176 deletions(-) create mode 100644 doc/client_app.html create mode 100644 doc/client_app_graphic.html diff --git a/Makefile.in b/Makefile.in index 4c7969367b..b8cf305efe 100644 --- a/Makefile.in +++ b/Makefile.in @@ -56,7 +56,7 @@ ARCHIVE_TARGETS = \ mac_build/boinc.pbproj/*.pbxproj mac_build/*.lproj/*.nib/*.* \ mac_build/*.lproj/*.strings \ win_build/*.* win_build/*/*.dsp win_build/*/*.rct \ - INSTALL LICENSE configure \ + INSTALL LICENSE configure todo checkin_notes \ *.in *.sub *.guess tar: diff --git a/checkin_notes b/checkin_notes index 50788aa16e..ba6920232a 100755 --- a/checkin_notes +++ b/checkin_notes @@ -4101,3 +4101,45 @@ Erik May 8 2003 lib/ Makefile.in app_ipc.C,h + +Erik May 13 2003 + - Added a notion of "tentative" project. + This means that the (URL, account ID) pair hasn't been verified, + i.e. we haven't fetched the master page, found a scheduler, + and done a scheduler op that verified the account ID. + If anything fails for a tentative project, call project_add_failed(). + in the cmdline version this prints an error message, + deletes all evidence of the project, and exits. + TODO: implement for GUI + - Make write_account_file() into a member function of PROJECT. + - Got rid of CLIENT_STATE::change_project(). + The user must detach and attach. + - CLIENT_STATE::quit_project() now takes a PROJECT*, not an int. + Need to change the GUI code. + - got rid of separate WIN_32 implementations of + make_project_dir(), remove_project_dir(), make_slot_dir(). + THIS IS THE WRONG LEVEL FOR PLATFORM-DEPENDENT CODE! + Instead, added boinc_mkdir() and boinc_rmdir() + - added implementation docs for screensaver logic + - test_uc.php: wait for a second before running client. + On fast computers the client runs before feeder has seeded shmem. + + client/ + account.C,h + client_state.C,h + client_types.C,h + cs_scheduler.C + file_names.C + main.C + scheduler_op.C,h + ss_logic.C + win/ + wingui.cpp + wingui_mainwindow.cpp + doc/ + client_app.html + client_app_graphic.html + lib/ + filesys.C,y + test/ + test_uc.php diff --git a/client/account.C b/client/account.C index 51d6607b92..e77fe66d21 100644 --- a/client/account.C +++ b/client/account.C @@ -26,34 +26,6 @@ #include "account.h" -int write_account_file( - char* master_url, char* authenticator, char* project_prefs -) { - char path[256]; - FILE* f; - int retval; - - get_account_filename(master_url, path); - f = fopen(TEMP_FILE_NAME, "w"); - if (!f) return ERR_FOPEN; - - fprintf(f, - "\n" - " %s\n" - " %s\n", - master_url, - authenticator - ); - if (project_prefs) { - fprintf(f, "%s", project_prefs); - } - fprintf(f, "\n"); - fclose(f); - retval = boinc_rename(TEMP_FILE_NAME, path); - if (retval) return ERR_RENAME; - return 0; -} - int CLIENT_STATE::parse_account_files() { DIRREF dir; char name[256]; @@ -87,17 +59,19 @@ int CLIENT_STATE::add_project(char* master_url, char* authenticator) { // create project state // - retval = write_account_file(master_url, authenticator); + project = new PROJECT; + strcpy(project->master_url, master_url); + strcpy(project->authenticator, authenticator); + project->tentative = true; + retval = project->write_account_file(); if (retval) return retval; + get_account_filename(master_url, path); f = fopen(path, "r"); if (!f) return ERR_FOPEN; - project = new PROJECT; retval = project->parse_account(f); fclose(f); - if(retval) { - return retval; - } + if (retval) return retval; // remove any old files // @@ -109,6 +83,13 @@ int CLIENT_STATE::add_project(char* master_url, char* authenticator) { return 0; } +#if 0 +// Wrong approach. +// The user must detach and reattach. +// In any case the following has a major bug: +// the call to remove_project_dir() won't work because +// it gets the new, not the old, project URL +// int CLIENT_STATE::change_project( int index, char* master_url, char* authenticator ) { @@ -121,7 +102,7 @@ int CLIENT_STATE::change_project( // if (lookup_project(master_url)) return -1; - // delete old file + // delete old account file // project = projects[index]; get_account_filename(project->master_url, path); @@ -147,33 +128,42 @@ int CLIENT_STATE::change_project( } return 0; } +#endif -int CLIENT_STATE::quit_project(int index) { - PROJECT* project = NULL; +// TODO: see if any activities are in progress for this project, and stop them +// +int CLIENT_STATE::quit_project(PROJECT* project) { + PROJECT* p; vector ::iterator iter; - int curindex = 0; + char path[256]; + int retval; // find project and remove it from the vector + // for (iter = projects.begin(); iter != projects.end(); iter++) { - if (curindex == index) { - project = *iter; + p = *iter; + if (p == project) { projects.erase(iter); break; } - curindex++; } - if (project == NULL) return -1; - // delete file - char path[256]; - int retval; + // delete account file + // get_account_filename(project->master_url, path); retval = file_delete(path); -// delete project; //also somewhere else? - + // if tentative, there are no activities so we can safely delete everything + // + if (project->tentative) { + // remove project directory and its contents + // + remove_project_dir(*project); + delete project; + } else { #ifdef _WIN32 - AfxMessageBox("Please restart the client to complete the quit.", MB_OK, 0); + AfxMessageBox("Please restart the client to complete the quit.", MB_OK, 0); #endif + } return 0; } diff --git a/client/account.h b/client/account.h index bedbd85d70..95d104cfee 100644 --- a/client/account.h +++ b/client/account.h @@ -1,9 +1,6 @@ #ifndef _ACCOUNT_ #define _ACCOUNT_ -extern int write_account_file( - char* master_url, char* authenticator, char* project_prefs=0 -); extern int add_new_project(); extern int parse_account_files(); diff --git a/client/client_state.C b/client/client_state.C index 27d386ade8..a14d954ad2 100644 --- a/client/client_state.C +++ b/client/client_state.C @@ -488,13 +488,11 @@ int CLIENT_STATE::check_suspend_activities() { if (should_suspend) { if (!activities_suspended) { - if (log_flags.task_debug) printf("SUSPENDING ACTIVITIES\n"); active_tasks.suspend_all(); show_message(NULL, susp_msg, MSG_INFO); } } else { if (activities_suspended) { - if (log_flags.task_debug) printf("UNSUSPENDING ACTIVITIES\n"); active_tasks.unsuspend_all(); show_message(NULL, "Resuming activity", MSG_INFO); } diff --git a/client/client_state.h b/client/client_state.h index c0f1c18436..a9e2020250 100644 --- a/client/client_state.h +++ b/client/client_state.h @@ -168,8 +168,8 @@ public: int report_result_error(RESULT &res, int err_num, char *err_msg); // flag a result as having an error int add_project(char* master_url, char* authenticator); - int change_project(int index, char* master_url, char* authenticator); - int quit_project(int index); + //int change_project(int index, char* master_url, char* authenticator); + int quit_project(PROJECT*); private: PROJECT* find_project_with_overdue_results(); bool some_project_rpc_ok(); diff --git a/client/client_types.C b/client/client_types.C index c9d64a9e8a..ccda9f404f 100644 --- a/client/client_types.C +++ b/client/client_types.C @@ -57,11 +57,43 @@ PROJECT::PROJECT() { debt_order = 0; master_url_fetch_pending = false; sched_rpc_pending = false; + tentative = false; } PROJECT::~PROJECT() { } +// write account_*.xml file +// +int PROJECT::write_account_file() { + char path[256]; + FILE* f; + int retval; + + get_account_filename(master_url, path); + f = fopen(TEMP_FILE_NAME, "w"); + if (!f) return ERR_FOPEN; + + fprintf(f, + "\n" + " %s\n" + " %s\n", + master_url, + authenticator + ); + if (strlen(project_specific_prefs)) { + fprintf(f, "%s", project_specific_prefs); + } + if (tentative) { + fprintf(f, " \n"); + } + fprintf(f, "\n"); + fclose(f); + retval = boinc_rename(TEMP_FILE_NAME, path); + if (retval) return ERR_RENAME; + return 0; +} + // parse project fields from account_*.xml // int PROJECT::parse_account(FILE* in) { @@ -83,6 +115,10 @@ int PROJECT::parse_account(FILE* in) { else if (parse_double(buf, "", resource_share)) continue; else if (match_tag(buf, "")) continue; else if (match_tag(buf, "")) continue; + else if (match_tag(buf, "")) { + tentative = true; + continue; + } else if (match_tag(buf, "")) { retval = copy_element_contents( in, @@ -243,11 +279,12 @@ void PROJECT::copy_state_fields(PROJECT& p) { safe_strcpy(code_sign_key, p.code_sign_key); } -char *PROJECT::get_project_name() { - if(!strcmp(project_name, "")) - return master_url; - else +char* PROJECT::get_project_name() { + if (strlen(project_name)) { return project_name; + } else { + return master_url; + } } int APP::parse(FILE* in) { diff --git a/client/client_types.h b/client/client_types.h index f13d678e9b..0968712c42 100644 --- a/client/client_types.h +++ b/client/client_types.h @@ -59,7 +59,7 @@ public: // the following items come from client_state.xml // They may depend on the host as well as user and project - // NOTE: if you add anything, add it copy_state_fields() as well!!! + // NOTE: if you add anything, add it to copy_state_fields() also!!! // vector scheduler_urls; // where to find scheduling servers char project_name[256]; // descriptive. not unique @@ -82,8 +82,8 @@ public: // of this project (or zero) bool master_url_fetch_pending; // need to fetch and parse the master URL - bool sched_rpc_pending; - // need to contact the scheduling server for user/project info + bool sched_rpc_pending; // contact scheduling server for preferences + bool tentative; // master URL and account ID not confirmed char code_sign_key[MAX_BLOB_LEN]; // the following items are transient; not saved in state file @@ -95,6 +95,7 @@ public: ~PROJECT(); void copy_state_fields(PROJECT&); char *get_project_name(); + int write_account_file(); int parse_account(FILE*); int parse_state(FILE*); int write_state(FILE*); diff --git a/client/cs_scheduler.C b/client/cs_scheduler.C index 15e57d5b85..38076f99a0 100644 --- a/client/cs_scheduler.C +++ b/client/cs_scheduler.C @@ -396,17 +396,18 @@ int CLIENT_STATE::handle_scheduler_reply( // deal with project preferences (should always be there) // if (sr.project_prefs_xml) { - char path[256]; - - retval = write_account_file( - project->master_url, project->authenticator, sr.project_prefs_xml - ); + strcpy(project->project_specific_prefs, sr.project_prefs_xml); + retval = project->write_account_file(); if (retval) return retval; + +#if 0 + char path[256]; get_account_filename(project->master_url, path); f = fopen(path, "r"); if (!f) return ERR_FOPEN; project->parse_account(f); fclose(f); +#endif } // if the scheduler reply includes a code-signing key, diff --git a/client/file_names.C b/client/file_names.C index 09ee13f48d..25d23d945b 100644 --- a/client/file_names.C +++ b/client/file_names.C @@ -89,55 +89,15 @@ void get_slot_dir(int slot, char* path) { sprintf(path, "%s%s%d", SLOTS_DIR, PATH_SEPARATOR, slot); } -#ifdef _WIN32 - -// Double check permissions for CreateDirectory - -int make_project_dir(PROJECT& p) { - char buf[256],buf2[256]; - - CreateDirectory(PROJECTS_DIR, NULL); - escape_project_url(p.master_url, buf); - sprintf(buf2, "%s%s%s", PROJECTS_DIR, PATH_SEPARATOR, buf); - CreateDirectory(buf2, NULL); - return 0; -} - -int remove_project_dir(PROJECT& p) { - char buf[256],buf2[256]; - - escape_project_url(p.master_url, buf); - sprintf(buf2, "%s%s%s", PROJECTS_DIR, PATH_SEPARATOR, buf); - clean_out_dir(buf2); - RemoveDirectory(buf2); - return 0; -} - -// Returns the location of a numbered slot directory -// -int make_slot_dir(int slot) { - if(slot<0) { - fprintf(stderr, "error: make_slot_dir: negative slot\n"); - return ERR_NEG; - } - char buf[256]; - CreateDirectory(SLOTS_DIR, NULL); - get_slot_dir(slot, buf); - CreateDirectory(buf, NULL); - return 0; -} - -#else - // Create the directory for the project p // int make_project_dir(PROJECT& p) { char buf[256],buf2[256]; - mkdir(PROJECTS_DIR, 0777); + boinc_mkdir(PROJECTS_DIR); escape_project_url(p.master_url, buf); sprintf(buf2, "%s%s%s", PROJECTS_DIR, PATH_SEPARATOR, buf); - mkdir(buf2, 0777); + boinc_mkdir(buf2); return 0; } @@ -147,7 +107,7 @@ int remove_project_dir(PROJECT& p) { escape_project_url(p.master_url, buf); sprintf(buf2, "%s%s%s", PROJECTS_DIR, PATH_SEPARATOR, buf); clean_out_dir(buf2); - // rmdir(buf2); + boinc_rmdir(buf2); return 0; } @@ -159,14 +119,12 @@ int make_slot_dir(int slot) { fprintf(stderr, "error: make_slot_dir: negative slot\n"); return ERR_NEG; } - mkdir(SLOTS_DIR, 0777); + boinc_mkdir(SLOTS_DIR); get_slot_dir(slot, buf); - mkdir(buf, 0777); + boinc_mkdir(buf); return 0; } -#endif - void get_account_filename(char* master_url, char* path) { char buf[256]; escape_project_url(master_url, buf); diff --git a/client/main.C b/client/main.C index f990e7cc9c..2b7e6529ad 100644 --- a/client/main.C +++ b/client/main.C @@ -42,16 +42,42 @@ void create_curtain(){} void delete_curtain(){} +// This gets called when the client fails to add a project +// +void project_add_failed(PROJECT* project) { + if (project->scheduler_urls.size()) { + printf( + "BOINC failed to log in to %s.\n " + "Please check your account ID and try again.\n", + project->master_url + ); + } else { + printf( + "BOINC couldn't get main page for %s.\n" + "Please check the URL and try again.\n", + project->master_url + ); + } + gstate.quit_project(project); + exit(1); +} + // Display a message to the user. // Depending on the priority, the message may be more or less obtrusive // void show_message(PROJECT *p, char* message, int priority) { - const char* proj = p?p->project_name:"BOINC"; + char* x; + + if (p) { + x = p->get_project_name(); + } else { + x = "BOINC"; + } switch (priority) { case MSG_ERROR: - fprintf(stderr, "%s [%s] %s\n", timestamp(), proj, message); + fprintf(stderr, "%s [%s] %s\n", timestamp(), x, message); default: - printf("%s [%s] %s\n", timestamp(), proj, message); + printf("%s [%s] %s\n", timestamp(), x, message); } } @@ -59,19 +85,19 @@ void show_message(PROJECT *p, char* message, int priority) { // and create an account file // int add_new_project() { - char master_url[256]; - char authenticator[256]; + PROJECT project; printf("Enter the URL of the project: "); - scanf("%s", master_url); + scanf("%s", project.master_url); printf( "You should have already registered with the project\n" "and received an account key by email.\n" "Paste the account key here: " ); - scanf("%s", authenticator); + scanf("%s", project.authenticator); - write_account_file(master_url, authenticator); + project.tentative = true; + project.write_account_file(); return 0; } diff --git a/client/scheduler_op.C b/client/scheduler_op.C index 4f22a18a1b..01c1d14ca7 100644 --- a/client/scheduler_op.C +++ b/client/scheduler_op.C @@ -32,12 +32,35 @@ #include "log_flags.h" #include "scheduler_op.h" +extern void project_add_failed(PROJECT*); + SCHEDULER_OP::SCHEDULER_OP(HTTP_OP_SET* h) { state = SCHEDULER_OP_STATE_IDLE; http_op.http_op_state = HTTP_STATE_IDLE; http_ops = h; } +// see if there's a pending master file fetch. start it if so. +// +bool SCHEDULER_OP::check_master_fetch_start() { + int retval; + + project = gstate.next_project_master_pending(); + if (project) { + retval = init_master_fetch(project); + if (retval) { + if (project->tentative) { + project_add_failed(project); + } else { + project->master_fetch_failures++; + backoff(project, "Master file fetch failed\n"); + } + } + return true; + } + return false; +} + // try to get enough work to bring us up to max buffer level // int SCHEDULER_OP::init_get_work() { @@ -55,14 +78,7 @@ int SCHEDULER_OP::init_get_work() { return retval; } } else { - project = gstate.next_project_master_pending(); - if (project) { - retval = init_master_fetch(project); - if (retval) { - sprintf(err_msg, "init_master_fetch failed, error %d\n", retval); - backoff(project, err_msg); - } - } + check_master_fetch_start(); } return 0; @@ -344,26 +360,23 @@ bool SCHEDULER_OP::poll() { // it may be the wrong URL. notify the user // if (project->scheduler_urls.size() == 0) { - sprintf(err_msg, - "Could not contact %s. Make sure this is the correct project URL.", - err_url - ); - show_message(project, err_msg, MSG_ERROR); - project->master_fetch_failures++; - backoff(project, err_msg); + if (project->tentative) { + project_add_failed(project); + } else { + sprintf(err_msg, + "Could not contact any schedulers for %s.", + err_url + ); + show_message(project, err_msg, MSG_ERROR); + project->master_fetch_failures++; + backoff(project, err_msg); + } } - // See if need to read master file for another project + // See if need to read master file for another project; + // if not, we're done for now // - project = gstate.next_project_master_pending(); - if (project) { - retval = init_master_fetch(project); - if (retval) { - project->master_fetch_failures++; - backoff(project, "Master file fetch failed\n"); - err_url = project->master_url; - } - } else { + if (!check_master_fetch_start()) { state = SCHEDULER_OP_STATE_IDLE; if (log_flags.sched_op_debug) { printf("Scheduler_op: return to idle state\n"); @@ -402,8 +415,7 @@ bool SCHEDULER_OP::poll() { } else { scheduler_op_done = true; } - } - else { + } else { scheduler_op_done = true; } } @@ -416,14 +428,27 @@ bool SCHEDULER_OP::poll() { } gstate.handle_scheduler_reply(project, scheduler_url, nresults); - // if we asked for work and didn't get any, - // back off this project + // if this was a tentative project and we didn't get user name, + // the account ID must be bad. Tell the user. // - if (must_get_work && nresults==0) { - backoff(project, "No work from project\n"); + if (project->tentative) { + if (strlen(project->user_name)) { + project->tentative = false; + project->write_account_file(); + } else { + project_add_failed(project); + } } else { - project->nrpc_failures = 0; - project->min_rpc_time = 0; + + // if we asked for work and didn't get any, + // back off this project + // + if (must_get_work && nresults==0) { + backoff(project, "No work from project\n"); + } else { + project->nrpc_failures = 0; + project->min_rpc_time = 0; + } } // if we didn't get all the work we needed, diff --git a/client/scheduler_op.h b/client/scheduler_op.h index 92dd743f6f..935f65137e 100644 --- a/client/scheduler_op.h +++ b/client/scheduler_op.h @@ -87,6 +87,7 @@ struct SCHEDULER_OP { int set_min_rpc_time(PROJECT*); bool update_urls(PROJECT& project, vector &urls); int start_op(PROJECT*); + bool check_master_fetch_start(); void backoff(PROJECT* p, char *error_msg); int start_rpc(); int parse_master_file(vector&); diff --git a/client/ss_logic.C b/client/ss_logic.C index b5e6abe011..4ccc5bbb32 100644 --- a/client/ss_logic.C +++ b/client/ss_logic.C @@ -71,7 +71,7 @@ void SS_LOGIC::poll() { } else { if (time(0)>ack_deadline) { do_boinc_logo_ss = true; - sprintf(ss_msg, "App can't display graphics"); + strcpy(ss_msg, "App can't display graphics"); } } } else { @@ -81,7 +81,7 @@ void SS_LOGIC::poll() { ack_deadline = time(0) + 5; } else { do_boinc_logo_ss = true; - sprintf(ss_msg, "No work available"); + strcpy(ss_msg, "No work available"); } } } diff --git a/client/win/wingui.cpp b/client/win/wingui.cpp index 9bb7fcfe2a..a77dbca3d4 100755 --- a/client/win/wingui.cpp +++ b/client/win/wingui.cpp @@ -23,18 +23,18 @@ #include "wingui_mainwindow.h" void show_message(PROJECT* p, char* message, int priority) { - char proj_name[256]; + char* x; if (p) { - safe_strncpy( proj_name, p->get_project_name(), sizeof(proj_name) ); + x = p->get_project_name(); } else { - safe_strncpy( proj_name, "BOINC", sizeof(proj_name) ); + x = "BOINC"; } if(g_myWnd) { - g_myWnd->MessageUser(proj_name, message, priority); + g_myWnd->MessageUser(x, message, priority); } else { - fprintf(stderr, "%s: %s (priority: %s)\n", proj_name, message, priority); + fprintf(stderr, "%s: %s (priority: %s)\n", x, message, priority); } } diff --git a/client/win/wingui_mainwindow.cpp b/client/win/wingui_mainwindow.cpp index 011ec70ea4..eb710a4059 100755 --- a/client/win/wingui_mainwindow.cpp +++ b/client/win/wingui_mainwindow.cpp @@ -1057,6 +1057,7 @@ void CMainWindow::OnCommandConnectionConnectNow() NetClose(); } +#if 0 ////////// // CMainWindow::OnCommandProjectRelogin // arguments: void @@ -1083,6 +1084,7 @@ void CMainWindow::OnCommandProjectRelogin() gstate.change_project(i, dlg.m_strUrl.GetBuffer(0), dlg.m_strAuth.GetBuffer(0)); } } +#endif ////////// // CMainWindow::OnCommandProjectQuit diff --git a/doc/client_app.html b/doc/client_app.html new file mode 100644 index 0000000000..9a660e62bc --- /dev/null +++ b/doc/client_app.html @@ -0,0 +1,9 @@ +

Core/app interaction (basic)

+ +TO BE WRITTEN. +

+Explain startup files +

+Explain shared memory mechanism in general +

+Explain work-related use of shmem diff --git a/doc/client_app_graphic.html b/doc/client_app_graphic.html new file mode 100644 index 0000000000..08c943fbae --- /dev/null +++ b/doc/client_app_graphic.html @@ -0,0 +1,14 @@ +

Screensaver/core/app interaction (graphics)

+ +TO BE WRITTEN + +

+Explain graphics startup files +

+Explain graphics modes of apps +

+Explain graphics use of shmem +

+Explain screensaver module +

+Explain screensaver logic in core diff --git a/lib/filesys.C b/lib/filesys.C index 1640830caa..d5559fcd25 100755 --- a/lib/filesys.C +++ b/lib/filesys.C @@ -263,6 +263,22 @@ int boinc_rename(char* old, char* newf) { return rename(old, newf); } +int boinc_mkdir(char* name) { +#ifdef _WIN32 + return CreateDirectory(name, NULL); +#else + return mkdir(name, 0777); +#endif +} + +int boinc_rmdir(char* name) { +#ifdef _WIN32 + return RemoveDirectory(name, NULL); +#else + return rmdir(name); +#endif +} + #ifdef _WIN32 void full_path(char* relname, char* path) { _getcwd(path, 256); diff --git a/lib/filesys.h b/lib/filesys.h index d01ea2ccfc..eb63e01d7f 100755 --- a/lib/filesys.h +++ b/lib/filesys.h @@ -42,6 +42,8 @@ extern int boinc_link(char *existing, char *new_link); extern int clean_out_dir(char*); extern int dir_size(char* dirpath, double&); extern int boinc_rename(char* old, char* newf); +extern int boinc_mkdir(char*); +extern int boinc_rmdir(char*); #ifdef _WIN32 extern void full_path(char* relname, char* path); #endif diff --git a/todo b/todo index 5aa90c58b4..90e6289e45 100755 --- a/todo +++ b/todo @@ -1,11 +1,13 @@ ----------------------- BUGS (arranged from high to low priority) ----------------------- +- CPU benchmarks take way too long (linux) - Client treats URL "maggie/ap/" different than URL "maggie/ap", though this isn't really a bug it might be good to fix anyway - global battery/user active prefs are always true in the client -- Client should display "Upload failed" and "Download failed" when failure occurs -- Result status should say "downloading files", "uploading files", etc. +- GUI client should display "Upload failed" and "Download failed" + in transfers tab when failure occurs +- GUI: Result status should say "downloading files", "uploading files", etc. - message window should reposition to bottom when new message - show_message should expect \n, discard it if GUI - Win GUI: line between menus and tabs @@ -19,29 +21,68 @@ BUGS (arranged from high to low priority) run_on_startup hangup_if_dialed - trim leading/trailing spaces from account ID (Win GUI) -- I entered in a wrong URL - there was no obvious feedback that it wasn't correct. - Messages showed up in the messages tab, but I was looking at the progress tab. - Shouldn't the client expect something from the server? If it doesn't get it, - especially on logging in for the first time, you should get an obvious warning. - when i quit a project, I have to exit and restart the client, which is ugly. -- after quitting a project, the project name still showed up in gray in the projects - list - I could right click on it to "relogin" (which did nothing) or "quit project" +- after quitting a project, the project name still showed up in gray + in the projects list - I could right click on it to "relogin" + (which did nothing) or "quit project" which I thought I already did. - consider warning message during windows (and perhaps other platforms) install that checks to see if the BOINC directory already exists, and if so, should the user overwrite it? or upgrade it? -- After running all night (on Win98) I shook the mouse to wake up the blank screen, and - all I saw was the top half of the screen was solid gray, and the bottom half the - bottom half of the astropulse graphics. They weren't moving. The computer was frozen. +- After running all night (on Win98) I shook the mouse to wake up + the blank screen, and all I saw was the top half of the screen + was solid gray, and the bottom half the + bottom half of the astropulse graphics. + They weren't moving. The computer was frozen. I had to ctrl-alt-del to restart. ----------------------- HIGH-PRIORITY (should do for beta test) ----------------------- -On "add project" the core client should immediately attempt to - get project master page and verify user account. - If failure, let user retype URL/ID +"Add project" behavior: + Goal: give user timely feedback if bad project URL or account ID; + don't leave bad project files sitting around + + A project addition is "successful" when + 1) the client fetches the master page, + 2) the master page has at least one scheduler URL + 3) the client contacts a scheduler and gets a user name back. + + The cmdline and GUI clients need to inform the user if a project + add is not successful, since it probably means the master URL + or account ID were typed in wrong. + + A project is "tentative" if the above hasn't happened yet. + This is flagged in the project file () and in memory + + A "failure event" is + - master fetch fails + - master page has no scheduler URLs + - scheduler RPC fails + - scheduler RPC returns no user name + A "success event" is + - scheduler RPC returns user name + + cmdline client + first time (no projects initially) or -add_new_project flag: + new project is tentative (write flag to project file) + if failure event occurs for tentative project: + project_add_fail(PROJECT&) + print "check URL and account ID" message + delete project file + exit + If success event occurs for tentative project + project_add_succeed(PROJECT&) + clear tentative flag, rewrite account file + + GUI client: + first-time dialog or "attach to project" command: + show a modal dialog + ("verifying account" w/ "cancel" button) + project_add_fail(PROJECT&) + replace w/ modal error dialog w/ retry, cancel + project_add_succeed(PROJECT&) Delete files if needed to honor disk usage constraint should include per-result constraints (e.g. giant stderr files)