mirror of https://github.com/BOINC/boinc.git
- client: support notice feeds from account managers.
Implementation: create a base class PROJ_AM, from which both PROJECT and ACCT_MGR_INFO are derived, with basic stuff like name, URL, and RSS feed list svn path=/trunk/boinc/; revision=22324
This commit is contained in:
parent
027d8e5485
commit
f31e311dd2
|
@ -6401,3 +6401,16 @@ Rom 16 Aug 2010
|
|||
/
|
||||
configure.ac
|
||||
version.h
|
||||
|
||||
David 8 Sept 2010
|
||||
- client: support notice feeds from account managers.
|
||||
Implementation: create a base class PROJ_AM,
|
||||
from which both PROJECT and ACCT_MGR_INFO are derived,
|
||||
with basic stuff like name, URL, and RSS feed list
|
||||
|
||||
client/
|
||||
acct_mgr.cpp,h
|
||||
app_start.cpp
|
||||
client_types.cpp,h
|
||||
cs_notice.cpp,h
|
||||
gui_rpc_server_ops.cpp
|
||||
|
|
|
@ -67,7 +67,7 @@ int ACCT_MGR_OP::do_rpc(
|
|||
|
||||
// if null URL, detach from current AMS
|
||||
//
|
||||
if (!strlen(url) && strlen(gstate.acct_mgr_info.acct_mgr_url)) {
|
||||
if (!strlen(url) && strlen(gstate.acct_mgr_info.master_url)) {
|
||||
msg_printf(NULL, MSG_INFO, "Removing account manager info");
|
||||
gstate.acct_mgr_info.clear();
|
||||
boinc_delete_file(ACCT_MGR_URL_FILENAME);
|
||||
|
@ -87,8 +87,8 @@ int ACCT_MGR_OP::do_rpc(
|
|||
return 0;
|
||||
}
|
||||
|
||||
strlcpy(ami.acct_mgr_url, url, sizeof(ami.acct_mgr_url));
|
||||
strlcpy(ami.acct_mgr_name, "", sizeof(ami.acct_mgr_name));
|
||||
strlcpy(ami.master_url, url, sizeof(ami.master_url));
|
||||
strlcpy(ami.project_name, "", sizeof(ami.project_name));
|
||||
strlcpy(ami.login_name, name.c_str(), sizeof(ami.login_name));
|
||||
strlcpy(ami.password_hash, password_hash.c_str(), sizeof(ami.password_hash));
|
||||
|
||||
|
@ -282,7 +282,7 @@ int ACCT_MGR_OP::parse(FILE* f) {
|
|||
continue;
|
||||
}
|
||||
if (!strcmp(tag, "/acct_mgr_reply")) return 0;
|
||||
if (xp.parse_str(tag, "name", ami.acct_mgr_name, 256)) continue;
|
||||
if (xp.parse_str(tag, "name", ami.project_name, 256)) continue;
|
||||
if (xp.parse_int(tag, "error_num", error_num)) continue;
|
||||
if (xp.parse_string(tag, "error", error_str)) continue;
|
||||
if (xp.parse_double(tag, "repeat_sec", repeat_sec)) continue;
|
||||
|
@ -369,7 +369,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
|
|||
if (error_str.size()) {
|
||||
msg_printf(NULL, MSG_USER_ALERT,
|
||||
"%s %s: %s",
|
||||
gstate.acct_mgr_info.acct_mgr_name,
|
||||
gstate.acct_mgr_info.project_name,
|
||||
_("error"),
|
||||
error_str.c_str()
|
||||
);
|
||||
|
@ -379,7 +379,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
|
|||
} else if (error_num) {
|
||||
msg_printf(NULL, MSG_USER_ALERT,
|
||||
"%s %s: %s",
|
||||
gstate.acct_mgr_info.acct_mgr_name,
|
||||
gstate.acct_mgr_info.project_name,
|
||||
_("error"),
|
||||
boincerror(error_num)
|
||||
);
|
||||
|
@ -411,8 +411,8 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
|
|||
}
|
||||
|
||||
if (sig_ok) {
|
||||
strcpy(gstate.acct_mgr_info.acct_mgr_url, ami.acct_mgr_url);
|
||||
strcpy(gstate.acct_mgr_info.acct_mgr_name, ami.acct_mgr_name);
|
||||
strcpy(gstate.acct_mgr_info.master_url, ami.master_url);
|
||||
strcpy(gstate.acct_mgr_info.project_name, ami.project_name);
|
||||
strcpy(gstate.acct_mgr_info.signing_key, ami.signing_key);
|
||||
strcpy(gstate.acct_mgr_info.login_name, ami.login_name);
|
||||
strcpy(gstate.acct_mgr_info.password_hash, ami.password_hash);
|
||||
|
@ -517,7 +517,7 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
|
|||
//
|
||||
if (global_prefs_xml) {
|
||||
retval = gstate.save_global_prefs(
|
||||
global_prefs_xml, ami.acct_mgr_url, ami.acct_mgr_url
|
||||
global_prefs_xml, ami.master_url, ami.master_url
|
||||
);
|
||||
if (retval) {
|
||||
msg_printf(NULL, MSG_INTERNAL_ERROR, "Can't save global prefs");
|
||||
|
@ -544,15 +544,15 @@ void ACCT_MGR_OP::handle_reply(int http_op_retval) {
|
|||
|
||||
int ACCT_MGR_INFO::write_info() {
|
||||
FILE* p;
|
||||
if (strlen(acct_mgr_url)) {
|
||||
if (strlen(master_url)) {
|
||||
p = fopen(ACCT_MGR_URL_FILENAME, "w");
|
||||
if (p) {
|
||||
fprintf(p,
|
||||
"<acct_mgr>\n"
|
||||
" <name>%s</name>\n"
|
||||
" <url>%s</url>\n",
|
||||
acct_mgr_name,
|
||||
acct_mgr_url
|
||||
project_name,
|
||||
master_url
|
||||
);
|
||||
if (send_gui_rpc_info) fprintf(p," <send_gui_rpc_info/>\n");
|
||||
if (strlen(signing_key)) {
|
||||
|
@ -594,8 +594,8 @@ int ACCT_MGR_INFO::write_info() {
|
|||
}
|
||||
|
||||
void ACCT_MGR_INFO::clear() {
|
||||
strcpy(acct_mgr_name, "");
|
||||
strcpy(acct_mgr_url, "");
|
||||
strcpy(project_name, "");
|
||||
strcpy(master_url, "");
|
||||
strcpy(login_name, "");
|
||||
strcpy(password_hash, "");
|
||||
strcpy(signing_key, "");
|
||||
|
@ -668,8 +668,8 @@ int ACCT_MGR_INFO::init() {
|
|||
continue;
|
||||
}
|
||||
if (!strcmp(tag, "/acct_mgr")) break;
|
||||
else if (xp.parse_str(tag, "name", acct_mgr_name, 256)) continue;
|
||||
else if (xp.parse_str(tag, "url", acct_mgr_url, 256)) continue;
|
||||
else if (xp.parse_str(tag, "name", project_name, 256)) continue;
|
||||
else if (xp.parse_str(tag, "url", master_url, 256)) continue;
|
||||
else if (xp.parse_bool(tag, "send_gui_rpc_info", send_gui_rpc_info)) continue;
|
||||
else if (!strcmp(tag, "signing_key")) {
|
||||
retval = xp.element_contents("</signing_key>", signing_key, sizeof(signing_key));
|
||||
|
@ -695,14 +695,13 @@ int ACCT_MGR_INFO::init() {
|
|||
}
|
||||
|
||||
bool ACCT_MGR_INFO::poll() {
|
||||
if (!using_am()) return false;
|
||||
if (gstate.gui_http.is_busy()) return false;
|
||||
|
||||
if (!strlen(login_name) && !strlen(password_hash)) return false;
|
||||
|
||||
if (gstate.now > next_rpc_time) {
|
||||
next_rpc_time = gstate.now + 86400;
|
||||
gstate.acct_mgr_op.do_rpc(
|
||||
acct_mgr_url, login_name, password_hash, false
|
||||
master_url, login_name, password_hash, false
|
||||
);
|
||||
return true;
|
||||
}
|
||||
|
|
|
@ -28,12 +28,10 @@
|
|||
|
||||
// represents info stored in acct_mgr_url.xml and acct_mgr_login.xml
|
||||
|
||||
struct ACCT_MGR_INFO {
|
||||
struct ACCT_MGR_INFO : PROJ_AM {
|
||||
// the following used to be std::string but there
|
||||
// were mysterious bugs where setting it to "" didn't work
|
||||
//
|
||||
char acct_mgr_name[256];
|
||||
char acct_mgr_url[256];
|
||||
char login_name[256];
|
||||
char password_hash[256];
|
||||
// md5 of password.lowercase(login_name)
|
||||
|
@ -58,6 +56,13 @@ struct ACCT_MGR_INFO {
|
|||
// successfully attached to an account manager
|
||||
bool password_error;
|
||||
|
||||
inline bool using_am() {
|
||||
if (!strlen(master_url)) return false;
|
||||
if (!strlen(login_name)) return false;
|
||||
if (!strlen(password_hash)) return false;
|
||||
return true;
|
||||
}
|
||||
|
||||
ACCT_MGR_INFO();
|
||||
int parse_login_file(FILE*);
|
||||
int write_info();
|
||||
|
@ -66,6 +71,8 @@ struct ACCT_MGR_INFO {
|
|||
bool poll();
|
||||
};
|
||||
|
||||
// stuff after here related to RPCs to account managers
|
||||
|
||||
struct OPTIONAL_BOOL {
|
||||
bool present;
|
||||
bool value;
|
||||
|
@ -80,8 +87,6 @@ struct OPTIONAL_DOUBLE {
|
|||
inline void set(double v) {value=v; present=true;}
|
||||
};
|
||||
|
||||
// stuff after here related to RPCs to account managers
|
||||
|
||||
struct AM_ACCOUNT {
|
||||
std::string url;
|
||||
std::string authenticator;
|
||||
|
|
|
@ -206,7 +206,7 @@ int ACTIVE_TASK::write_app_init_file() {
|
|||
aid.app_version = app_version->version_num;
|
||||
safe_strcpy(aid.app_name, wup->app->name);
|
||||
safe_strcpy(aid.symstore, wup->project->symstore);
|
||||
safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.acct_mgr_url);
|
||||
safe_strcpy(aid.acct_mgr_url, gstate.acct_mgr_info.master_url);
|
||||
if (wup->project->project_specific_prefs.length()) {
|
||||
aid.project_preferences = strdup(wup->project->project_specific_prefs.c_str());
|
||||
}
|
||||
|
|
|
@ -460,14 +460,6 @@ int PROJECT::write_statistics(MIOFILE& out, bool /*gui_rpc*/) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char* PROJECT::get_project_name() {
|
||||
if (strlen(project_name)) {
|
||||
return project_name;
|
||||
} else {
|
||||
return master_url;
|
||||
}
|
||||
}
|
||||
|
||||
const char* PROJECT::get_scheduler_url(int index, double r) {
|
||||
int n = (int) scheduler_urls.size();
|
||||
int ir = (int)(r*n);
|
||||
|
|
|
@ -181,12 +181,26 @@ struct DAILY_STATS {
|
|||
};
|
||||
bool operator < (const DAILY_STATS&, const DAILY_STATS&);
|
||||
|
||||
struct PROJECT {
|
||||
// base class for PROJECT and ACCT_MGR_INFO
|
||||
//
|
||||
struct PROJ_AM {
|
||||
char master_url[256];
|
||||
char project_name[256];
|
||||
// descriptive. not unique
|
||||
std::vector<RSS_FEED> proj_feeds;
|
||||
inline char *get_project_name() {
|
||||
if (strlen(project_name)) {
|
||||
return project_name;
|
||||
} else {
|
||||
return master_url;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
struct PROJECT : PROJ_AM {
|
||||
// the following items come from the account file
|
||||
// They are a function only of the user and the project
|
||||
//
|
||||
char master_url[256];
|
||||
// url of site that contains scheduler tags for this project
|
||||
char authenticator[256];
|
||||
// user's authenticator on this project
|
||||
std::string project_prefs;
|
||||
|
@ -231,8 +245,6 @@ struct PROJECT {
|
|||
//
|
||||
std::vector<std::string> scheduler_urls;
|
||||
// where to find scheduling servers
|
||||
char project_name[256];
|
||||
// descriptive. not unique
|
||||
char symstore[256];
|
||||
// URL of symbol server (Windows)
|
||||
char user_name[256];
|
||||
|
@ -405,7 +417,6 @@ struct PROJECT {
|
|||
~PROJECT(){}
|
||||
void init();
|
||||
void copy_state_fields(PROJECT&);
|
||||
char *get_project_name();
|
||||
int write_account_file();
|
||||
int parse_account(FILE*);
|
||||
int parse_account_file_venue();
|
||||
|
@ -419,9 +430,6 @@ struct PROJECT {
|
|||
int parse_statistics(FILE*);
|
||||
int write_statistics(MIOFILE&, bool gui_rpc=false);
|
||||
int write_statistics_file();
|
||||
|
||||
// feed-related
|
||||
std::vector<RSS_FEED> proj_feeds;
|
||||
};
|
||||
|
||||
struct APP {
|
||||
|
|
|
@ -52,7 +52,7 @@ static bool cmp(NOTICE n1, NOTICE n2) {
|
|||
return (strcmp(n1.guid, n2.guid) > 0);
|
||||
}
|
||||
|
||||
static void project_feed_list_file_name(PROJECT* p, char* buf) {
|
||||
static void project_feed_list_file_name(PROJ_AM* p, char* buf) {
|
||||
char url[256];
|
||||
escape_project_url(p->master_url, url);
|
||||
sprintf(buf, "notices/feeds_%s.xml", url);
|
||||
|
@ -97,7 +97,7 @@ static void write_rss_feed_descs(MIOFILE& fout, vector<RSS_FEED>& feeds) {
|
|||
fout.printf("</rss_feeds>\n");
|
||||
}
|
||||
|
||||
static void write_project_feed_list(PROJECT* p) {
|
||||
static void write_project_feed_list(PROJ_AM* p) {
|
||||
char buf[256];
|
||||
project_feed_list_file_name(p, buf);
|
||||
FILE* f = fopen(buf, "w");
|
||||
|
@ -112,7 +112,7 @@ static void write_project_feed_list(PROJECT* p) {
|
|||
// Add new ones to the project's set,
|
||||
// and remove ones from the project's set that aren't in the list.
|
||||
//
|
||||
void handle_sr_feeds(vector<RSS_FEED>& feeds, PROJECT* p) {
|
||||
void handle_sr_feeds(vector<RSS_FEED>& feeds, PROJ_AM* p) {
|
||||
unsigned int i, j;
|
||||
bool feed_set_changed = false;
|
||||
|
||||
|
@ -658,25 +658,33 @@ void RSS_FEED_OP::handle_reply(int http_op_retval) {
|
|||
|
||||
///////////// RSS_FEEDS ////////////////
|
||||
|
||||
static void init_proj_am(PROJ_AM* p) {
|
||||
FILE* f;
|
||||
MIOFILE fin;
|
||||
char path[256];
|
||||
|
||||
project_feed_list_file_name(p, path);
|
||||
f = fopen(path, "r");
|
||||
if (f) {
|
||||
fin.init_file(f);
|
||||
parse_rss_feed_descs(fin, p->proj_feeds);
|
||||
fclose(f);
|
||||
}
|
||||
}
|
||||
|
||||
// called on startup. Get list of feeds. Read archives.
|
||||
//
|
||||
void RSS_FEEDS::init() {
|
||||
unsigned int i;
|
||||
MIOFILE fin;
|
||||
FILE* f;
|
||||
|
||||
boinc_mkdir(NOTICES_DIR);
|
||||
|
||||
for (i=0; i<gstate.projects.size(); i++) {
|
||||
PROJECT* p = gstate.projects[i];
|
||||
char path[256];
|
||||
project_feed_list_file_name(p, path);
|
||||
f = fopen(path, "r");
|
||||
if (f) {
|
||||
fin.init_file(f);
|
||||
parse_rss_feed_descs(fin, p->proj_feeds);
|
||||
fclose(f);
|
||||
}
|
||||
init_proj_am(p);
|
||||
}
|
||||
if (gstate.acct_mgr_info.using_am()) {
|
||||
init_proj_am(&gstate.acct_mgr_info);
|
||||
}
|
||||
|
||||
update_feed_list();
|
||||
|
@ -705,7 +713,7 @@ RSS_FEED* RSS_FEEDS::lookup_url(char* url) {
|
|||
|
||||
// arrange to fetch the project's feeds
|
||||
//
|
||||
void RSS_FEEDS::trigger_fetch(PROJECT* p) {
|
||||
void RSS_FEEDS::trigger_fetch(PROJ_AM* p) {
|
||||
for (unsigned int i=0; i<p->proj_feeds.size(); i++) {
|
||||
RSS_FEED& rf = p->proj_feeds[i];
|
||||
RSS_FEED* rfp = lookup_url(rf.url);
|
||||
|
@ -715,34 +723,42 @@ void RSS_FEEDS::trigger_fetch(PROJECT* p) {
|
|||
}
|
||||
}
|
||||
|
||||
void RSS_FEEDS::update_proj_am(PROJ_AM* p) {
|
||||
unsigned int j;
|
||||
for (j=0; j<p->proj_feeds.size(); j++) {
|
||||
RSS_FEED& rf = p->proj_feeds[j];
|
||||
RSS_FEED* rfp = lookup_url(rf.url);
|
||||
if (rfp) {
|
||||
rfp->found = true;
|
||||
} else {
|
||||
rf.found = true;
|
||||
strcpy(rf.project_name, p->get_project_name());
|
||||
feeds.push_back(rf);
|
||||
if (log_flags.notice_debug) {
|
||||
msg_printf(0, MSG_INFO,
|
||||
"[notice] adding feed: %s, %.0f sec",
|
||||
rf.url, rf.poll_interval
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// the set of project feeds has changed.
|
||||
// update the master list.
|
||||
//
|
||||
void RSS_FEEDS::update_feed_list() {
|
||||
unsigned int i, j;
|
||||
unsigned int i;
|
||||
for (i=0; i<feeds.size(); i++) {
|
||||
RSS_FEED& rf = feeds[i];
|
||||
rf.found = false;
|
||||
}
|
||||
for (i=0; i<gstate.projects.size(); i++) {
|
||||
PROJECT* p = gstate.projects[i];
|
||||
for (j=0; j<p->proj_feeds.size(); j++) {
|
||||
RSS_FEED& rf = p->proj_feeds[j];
|
||||
RSS_FEED* rfp = lookup_url(rf.url);
|
||||
if (rfp) {
|
||||
rfp->found = true;
|
||||
} else {
|
||||
rf.found = true;
|
||||
strcpy(rf.project_name, p->get_project_name());
|
||||
feeds.push_back(rf);
|
||||
if (log_flags.notice_debug) {
|
||||
msg_printf(0, MSG_INFO,
|
||||
"[notice] adding feed: %s, %.0f sec",
|
||||
rf.url, rf.poll_interval
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
update_proj_am(p);
|
||||
}
|
||||
if (gstate.acct_mgr_info.using_am()) {
|
||||
update_proj_am(&gstate.acct_mgr_info);
|
||||
}
|
||||
vector<RSS_FEED>::iterator iter = feeds.begin();
|
||||
while (iter != feeds.end()) {
|
||||
|
|
|
@ -19,7 +19,7 @@
|
|||
#define _CS_NOTICE_
|
||||
|
||||
// Code related to "notices", which come from
|
||||
// 1) RSS feeds specified by projects
|
||||
// 1) RSS feeds specified by projects and account managers
|
||||
// 2) Scheduler replies (high-priority messages)
|
||||
// 3) the client (MSG_USER_ALERT messages)
|
||||
//
|
||||
|
@ -63,6 +63,7 @@
|
|||
#include "miofile.h"
|
||||
|
||||
#include "gui_http.h"
|
||||
#include "client_types.h"
|
||||
|
||||
#include "notice.h"
|
||||
|
||||
|
@ -120,16 +121,17 @@ extern RSS_FEED_OP rss_feed_op;
|
|||
struct RSS_FEEDS {
|
||||
std::vector<RSS_FEED> feeds;
|
||||
void init();
|
||||
void trigger_fetch(PROJECT*);
|
||||
void trigger_fetch(struct PROJ_AM*);
|
||||
void update_feed_list();
|
||||
RSS_FEED* lookup_url(char*);
|
||||
void update_proj_am(PROJ_AM*);
|
||||
void write_feed_list();
|
||||
};
|
||||
|
||||
extern RSS_FEEDS rss_feeds;
|
||||
|
||||
int parse_rss_feed_descs(MIOFILE& fin, std::vector<RSS_FEED>&);
|
||||
void handle_sr_feeds(std::vector<RSS_FEED>&, struct PROJECT*);
|
||||
void handle_sr_feeds(std::vector<RSS_FEED>&, struct PROJ_AM*);
|
||||
// process the feeds in a scheduler reply
|
||||
|
||||
#endif
|
||||
|
|
|
@ -526,8 +526,8 @@ static void handle_acct_mgr_info(char*, MIOFILE& fout) {
|
|||
"<acct_mgr_info>\n"
|
||||
" <acct_mgr_url>%s</acct_mgr_url>\n"
|
||||
" <acct_mgr_name>%s</acct_mgr_name>\n",
|
||||
gstate.acct_mgr_info.acct_mgr_url,
|
||||
gstate.acct_mgr_info.acct_mgr_name
|
||||
gstate.acct_mgr_info.master_url,
|
||||
gstate.acct_mgr_info.project_name
|
||||
);
|
||||
|
||||
if (strlen(gstate.acct_mgr_info.login_name)) {
|
||||
|
@ -816,13 +816,13 @@ static void handle_acct_mgr_rpc(char* buf, MIOFILE& fout) {
|
|||
}
|
||||
}
|
||||
} else {
|
||||
if (!strlen(gstate.acct_mgr_info.acct_mgr_url)) {
|
||||
if (!strlen(gstate.acct_mgr_info.master_url)) {
|
||||
bad_arg = true;
|
||||
msg_printf(NULL, MSG_INTERNAL_ERROR,
|
||||
"Account manager info missing from config file"
|
||||
);
|
||||
} else {
|
||||
url = gstate.acct_mgr_info.acct_mgr_url;
|
||||
url = gstate.acct_mgr_info.master_url;
|
||||
name = gstate.acct_mgr_info.login_name;
|
||||
password_hash = gstate.acct_mgr_info.password_hash;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue