mirror of https://github.com/BOINC/boinc.git
- Initial checkin of Bossa code
svn path=/trunk/boinc/; revision=14716
This commit is contained in:
parent
a323eba986
commit
51286a03dc
|
@ -2,11 +2,16 @@ create table bossa_app (
|
|||
id integer not null auto_increment,
|
||||
create_time integer not null,
|
||||
name varchar(255) not null,
|
||||
user_friendly_name varchar(255) not null,
|
||||
description varchar(255) not null,
|
||||
long_jobs tinyint not null,
|
||||
start_url varchar(255) not null,
|
||||
deprecated tinyint not null,
|
||||
display_script varchar(255) not null,
|
||||
backend_script varchar(255) not null,
|
||||
hidden tinyint not null,
|
||||
min_conf_sum double not null,
|
||||
min_conf_frac double not null,
|
||||
max_instances integer not null,
|
||||
info text,
|
||||
-- app-specific info, JSON
|
||||
primary key(id)
|
||||
);
|
||||
|
||||
|
@ -19,12 +24,10 @@ create table bossa_job (
|
|||
batch integer not null,
|
||||
time_estimate integer not null,
|
||||
time_limit integer not null,
|
||||
more_needed tinyint not null,
|
||||
npending smallint not null,
|
||||
nsuccess smallint not null,
|
||||
nsuccess_needed smallint not null,
|
||||
transition_time double not null,
|
||||
nneeded integer not null,
|
||||
primary key(id)
|
||||
);
|
||||
) engine=InnoDB;
|
||||
|
||||
create table bossa_job_inst (
|
||||
id integer not null auto_increment,
|
||||
|
@ -34,7 +37,7 @@ create table bossa_job_inst (
|
|||
finish_time integer not null,
|
||||
info text,
|
||||
primary key(id)
|
||||
);
|
||||
) engine=InnoDB;
|
||||
|
||||
create table bossa_app_user (
|
||||
app_id integer not null,
|
||||
|
|
|
@ -1,6 +1,11 @@
|
|||
<?
|
||||
|
||||
$project_news = array(
|
||||
array("Feb 11, 2008",
|
||||
"Bulgarian BOINC users:
|
||||
find forums and information in your language at
|
||||
<a href=http://www.boinc-bulgaria.net>BOINC Bulgaria</a>."
|
||||
),
|
||||
array("Feb 7, 2008",
|
||||
"<a href=http://biology.polytechnique.fr/proteinsathome>Proteins@Home</a>
|
||||
has resumed operations.
|
||||
|
|
|
@ -170,6 +170,9 @@ language("Belgium (Dutch/French/English)", array(
|
|||
site("http://www.boinc.be", "www.boinc.be"),
|
||||
site("http://icewolves.plid.be", "IceWolves"),
|
||||
));
|
||||
language("Bulgarian", array(
|
||||
site("http://www.boinc-bulgaria.net", "BOINC Bulgaria")
|
||||
));
|
||||
language("Catalan", array(
|
||||
site("http://www.boinc.cat", "BOINC.cat"),
|
||||
));
|
||||
|
|
|
@ -15,6 +15,9 @@ class Bossa {
|
|||
if ($bji->user_id != $user->id) {
|
||||
error_page("Bad user ID");
|
||||
}
|
||||
if ($bji->finish_time) {
|
||||
error_page("You already finished this job");
|
||||
}
|
||||
$bj = BossaJob::lookup_id($bji->job_id);
|
||||
if (!$bj) {
|
||||
error_page("No such job");
|
||||
|
|
|
@ -22,18 +22,16 @@ class BossaDb extends DbConn {
|
|||
}
|
||||
return $instance;
|
||||
}
|
||||
static function escape_string($string) {
|
||||
$db = self::get();
|
||||
return $db->base_escape_string($string);
|
||||
}
|
||||
}
|
||||
|
||||
class BossaApp {
|
||||
function insert() {
|
||||
function insert($clause) {
|
||||
$db = BossaDb::get();
|
||||
if (!isset($this->long_jobs)) $this->long_jobs = 0;
|
||||
$now = time();
|
||||
$query = "insert into DBNAME.bossa_app (create_time, name, user_friendly_name, long_jobs, start_url) values ($now, '$this->name', '$this->user_friendly_name', $this->long_jobs, '$this->start_url')";
|
||||
$result = $db->do_query($query);
|
||||
if (!$result) return false;
|
||||
$this->id = $db->insert_id();
|
||||
return true;
|
||||
return $db->insert('bossa_app', $clause);
|
||||
}
|
||||
|
||||
static function lookup_name($name) {
|
||||
|
@ -56,7 +54,7 @@ class BossaJob {
|
|||
function insert() {
|
||||
$db = BossaDb::get();
|
||||
$now = time();
|
||||
$query = "insert into DBNAME.bossa_job (create_time, name, app_id, info, batch, time_estimate, time_limit, more_needed, npending, nsuccess, nsuccess_needed) values ($now, '$this->name', $this->app_id, '$this->info', $this->batch, $this->time_estimate, $this->time_limit, 1, 0, 0, $this->nsuccess_needed)";
|
||||
$query = "insert into DBNAME.bossa_job (create_time, name, app_id, info, batch, time_estimate, time_limit, nneeded) values ($now, '$this->name', $this->app_id, '$this->info', $this->batch, $this->time_estimate, $this->time_limit, $this->nneeded)";
|
||||
$result = $db->do_query($query);
|
||||
if (!$result) {
|
||||
echo "$query\n";
|
||||
|
@ -114,8 +112,9 @@ class BossaJobInst {
|
|||
// this query skips jobs for which this user
|
||||
// has already been assigned an instance
|
||||
//
|
||||
// TODO: put the following in a transaction
|
||||
$db = BossaDb::get();
|
||||
$query = "select bossa_job.* from DBNAME.bossa_job left join DBNAME.bossa_job_inst on bossa_job_inst.job_id = bossa_job.id where bossa_job.more_needed<>0 and bossa_job_inst.user_id is null limit 1";
|
||||
$query = "select bossa_job.* from DBNAME.bossa_job left join DBNAME.bossa_job_inst on bossa_job_inst.job_id = bossa_job.id where bossa_job.nneeded>0 and bossa_job_inst.user_id is null limit 1";
|
||||
$result = $db->do_query($query);
|
||||
if (!$result) return null;
|
||||
$job = mysql_fetch_object($result, 'BossaJob');
|
||||
|
@ -130,6 +129,8 @@ class BossaJobInst {
|
|||
echo mysql_error();
|
||||
return null;
|
||||
}
|
||||
|
||||
$job->update("nneeded=nneeded-1");
|
||||
return $ji;
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,40 @@
|
|||
<?php
|
||||
|
||||
// two results are compatible if neither found an ellipse,
|
||||
// or they both did and centers are within 20 pixels
|
||||
//
|
||||
function compare($r1, $r2) {
|
||||
if ($r1->have_ellipse) {
|
||||
if ($r2->have_ellipse) {
|
||||
$dx = ($r1->cx - $r2->cx);
|
||||
$dy = ($r1->cy - $r2->cy);
|
||||
$dsq = $dx*$dx + $dy*$dy;
|
||||
return ($dsq < 400);
|
||||
} else return false;
|
||||
} else {
|
||||
return !$r2->have_ellipse;
|
||||
}
|
||||
}
|
||||
|
||||
// handle a completed job with the given consensus set
|
||||
//
|
||||
function handle_consensus($bj, $c) {
|
||||
$res = $c[0];
|
||||
if ($res->have_ellipse) {
|
||||
$res->cx = 0;
|
||||
$res->cy = 0;
|
||||
foreach ($c as $r) {
|
||||
$res->cx += $r->cx;
|
||||
$res->cy += $r->cy;
|
||||
}
|
||||
$res->cx /= count($c);
|
||||
$res->cy /= count($c);
|
||||
}
|
||||
|
||||
$info = json_decode[$bj->info);
|
||||
$info->result = $res;
|
||||
$i = json_encode($info);
|
||||
$bj->update("info='$i'");
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,26 @@
|
|||
<?php
|
||||
|
||||
// PHP versions of functions in sched/sched_util.C
|
||||
|
||||
function filename_hash($filename, $fanout) {
|
||||
$m = md5($filename);
|
||||
$s = substr($m, 1, 7);
|
||||
sscanf($s, "%x", $n);
|
||||
return sprintf("%x", $n%$fanout);
|
||||
}
|
||||
|
||||
function dir_hier_path($filename, $root, $fanout) {
|
||||
$dir = filename_hash($filename, $fanout);
|
||||
$dirpath = "$root/$dir";
|
||||
if (!is_dir($dirpath)) {
|
||||
mkdir($dirpath);
|
||||
}
|
||||
return "$dirpath/$filename";
|
||||
}
|
||||
|
||||
function dir_hier_url($filename, $base, $fanout) {
|
||||
$dir = filename_hash($filename, $fanout);
|
||||
return "$base/$dir/$filename";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,120 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/bossa_db.inc");
|
||||
require_once("../inc/util_ops.inc");
|
||||
|
||||
function show_bapp($app) {
|
||||
echo "<tr>
|
||||
<td>Name: $app->name<br>Description: $app->description<br>Created: ".date_str($app->create_time)."</td>
|
||||
<td>$app->display_script</td>
|
||||
<td>$app->backend_script</td>
|
||||
<td>
|
||||
";
|
||||
if ($app->hidden) {
|
||||
show_button("bossa_ops.php?action=unhide&app_id=$app->id", "Unhide", "Unhide this app");
|
||||
} else {
|
||||
show_button("bossa_ops.php?action=hide&app_id=$app->id", "Hide", "Hide this app");
|
||||
}
|
||||
}
|
||||
|
||||
function show_apps() {
|
||||
$apps = BossaApp::enum();
|
||||
start_table();
|
||||
row1("Existing apps", 4);
|
||||
table_header("Name/description", "Display script", "Backend script", "");
|
||||
foreach ($apps as $app) {
|
||||
show_bapp($app);
|
||||
}
|
||||
end_table();
|
||||
}
|
||||
|
||||
function add_app_form() {
|
||||
echo "
|
||||
<form action=bossa_ops.php method=get>
|
||||
";
|
||||
start_table();
|
||||
row1("Add app");
|
||||
row2("Name<span class=note><br>Visible to users</span>", "<input name=app_name>");
|
||||
row2("Description<span class=note><br>Visible to users</span>", "<textarea name=description cols=60></textarea>");
|
||||
row2("Display script filename", "<input name=display_script>");
|
||||
row2("Backend script filename", "<input name=backend_script>");
|
||||
row2("Min confidence sum for consensus", "<input name=min_conf_sum>");
|
||||
row2("Min confidence fraction for consensus", "<input name=min_conf_frac>");
|
||||
row2("Max instances", "<input name=max_instances>");
|
||||
row2("", "<input type=submit name=submit value=\"Create app\">");
|
||||
end_table();
|
||||
echo "</form>";
|
||||
}
|
||||
|
||||
function user_settings() {
|
||||
global $user;
|
||||
$flags = $user->bossa->flags;
|
||||
echo "<form action=bossa_ops.php method=get>";
|
||||
start_table();
|
||||
row1("User settings");
|
||||
$x = ($flags&BOLT_FLAGS_SHOW_ALL)?"checked":"";
|
||||
row2("Show hidden apps?", "<input type=checkbox name=show_all $x>");
|
||||
$x = ($flags&BOLT_FLAGS_DEBUG)?"checked":"";
|
||||
row2("Show debugging output?", "<input type=checkbox name=debug $x>");
|
||||
row2("", "<input type=submit name=submit value=\"Update user\">");
|
||||
end_table();
|
||||
echo "</form>";
|
||||
}
|
||||
|
||||
function show_all() {
|
||||
admin_page_head("Bossa app administration");
|
||||
show_apps();
|
||||
echo "<p>";
|
||||
add_app_form();
|
||||
echo "<p>";
|
||||
user_settings();
|
||||
admin_page_tail();
|
||||
}
|
||||
|
||||
$user = get_logged_in_user();
|
||||
|
||||
$submit = get_str('submit', true);
|
||||
if ($submit == 'Create app') {
|
||||
$name = BossaDb::escape_string(get_str('app_name'));
|
||||
$description = BossaDb::escape_string(get_str('description'));
|
||||
$display_script = get_str('display_script');
|
||||
$backend_script = get_str('backend_script');
|
||||
$min_conf_sum = get_str('min_conf_sum');
|
||||
$min_conf_frac = get_str('min_conf_frac');
|
||||
$max_instances = get_str('max_instances');
|
||||
$now = time();
|
||||
BossaApp::insert("(create_time, name, description, display_script, backend_script, min_conf_sum, min_conf_frac, max_instances) values ($now, '$name', '$description', '$display_script', '$backend_script', $min_conf_sum, $min_conf_frac, $max_instances)");
|
||||
Header('Location: bossa_ops.php');
|
||||
exit();
|
||||
} else if ($submit == 'Update user') {
|
||||
$flags = 0;
|
||||
if (get_str('show_all', true)) $flags |= BOLT_FLAGS_SHOW_ALL;
|
||||
if (get_str('debug', true)) $flags |= BOLT_FLAGS_DEBUG;
|
||||
$user->bossa->update("flags=$flags");
|
||||
$user->bossa->flags = $flags;
|
||||
Header('Location: bossa_ops.php');
|
||||
exit();
|
||||
} else {
|
||||
$action = get_str('action', true);
|
||||
if ($action) {
|
||||
$app_id = get_int('app_id');
|
||||
$app = BoltApp::lookup_id($app_id);
|
||||
if (!$app) error_page("no such app");
|
||||
switch ($action) {
|
||||
case 'hide':
|
||||
$app->update("hidden=1");
|
||||
break;
|
||||
case 'unhide':
|
||||
$app->update("hidden=0");
|
||||
break;
|
||||
default:
|
||||
error_page("unknown action $action");
|
||||
}
|
||||
Header('Location: bossa_ops.php');
|
||||
exit();
|
||||
}
|
||||
}
|
||||
|
||||
show_all();
|
||||
|
||||
?>
|
|
@ -1,19 +0,0 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
// Set up Bossa applications.
|
||||
// Customize and rename this file.
|
||||
|
||||
$ba = new BossaApp();
|
||||
$ba->name = 'bossa_test';
|
||||
$ba->user_friendly_name = 'Simple pattern recognition';
|
||||
$ba->start_url = 'bossa_example.php';
|
||||
|
||||
if ($ba->insert($ba)) {
|
||||
echo "Added application '$ba->name'\n";
|
||||
} else {
|
||||
echo "Couldn't add '$ba->name': ", mysql_error(), "\n";
|
||||
}
|
||||
|
||||
?>
|
|
@ -0,0 +1,41 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
var $apps;
|
||||
|
||||
function lookup_app($id) {
|
||||
global $apps;
|
||||
foreach ($apps as $app) {
|
||||
if ($app->id == $id) return $app;
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function handle_job($job) {
|
||||
$app = lookup_app($job->app_id);
|
||||
if (!$app) {
|
||||
echo "Missing app: $job->app_id\n";
|
||||
return;
|
||||
}
|
||||
$instances = BossaJobInst::enum("job_id=$job->id");
|
||||
}
|
||||
|
||||
function do_pass() {
|
||||
$now = time();
|
||||
$jobs = BossaJob::enum("transition_time < $now");
|
||||
foreach ($jobs as $job) {
|
||||
handle_job($job);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
global $apps;
|
||||
$apps = BossaApp::enum();
|
||||
while (1) {
|
||||
do_pass();
|
||||
}
|
||||
}
|
||||
|
||||
main();
|
||||
?>
|
|
@ -0,0 +1,31 @@
|
|||
<?php
|
||||
|
||||
require_once("../inc/util.inc");
|
||||
require_once("../inc/bossa_db.inc");
|
||||
|
||||
function show_app($app) {
|
||||
row2(
|
||||
"$app->name<span class=note><br>$app->description</span>",
|
||||
"<a href=bossa_get_job.php?bossa_app_id=$app->id>Get job</a>"
|
||||
);
|
||||
}
|
||||
|
||||
function show_apps() {
|
||||
$apps = BossaApp::enum();
|
||||
foreach ($apps as $app) {
|
||||
if ($app->hidden) continue;
|
||||
show_app($app);
|
||||
}
|
||||
}
|
||||
|
||||
function main() {
|
||||
page_head("Bossa apps");
|
||||
start_table();
|
||||
show_apps();
|
||||
end_table();
|
||||
page_tail();
|
||||
}
|
||||
|
||||
main();
|
||||
|
||||
?>
|
|
@ -3,42 +3,43 @@
|
|||
require_once("../inc/bossa.inc");
|
||||
|
||||
// Bossa example.
|
||||
// Show the user an image and ask them whether it's a zero or one.
|
||||
// Show the user an image and ask them to click on the ellipse
|
||||
|
||||
function show_job($bj, $bji) {
|
||||
if ($bji->finish_time) {
|
||||
error_page("You already finished this job");
|
||||
}
|
||||
$info = json_decode($bj->info);
|
||||
$img_url = "http://boinc.berkeley.edu/images/number_".$info->number.".jpg";
|
||||
print_r($info);
|
||||
$img_url = $info->url;
|
||||
echo "
|
||||
<form method=get action=bossa_example.php>
|
||||
<input type=hidden name=bji value=$bji->id>
|
||||
<img src=$img_url>
|
||||
Click on the center of the ellipse.
|
||||
If you don't see one, click here:
|
||||
<input type=submit name=submit value=None>
|
||||
<br>
|
||||
The picture shows a
|
||||
<br><input type=radio name=response value=0> zero
|
||||
<br><input type=radio name=response value=1> one
|
||||
<br><input type=radio name=response value=2 checked> not sure
|
||||
<br><br><input type=submit name=submit value=OK>
|
||||
<input type=hidden name=bji value=$bji->id>
|
||||
<input type=hidden name=completion value=1>
|
||||
<input type=image name=pic src=$img_url>
|
||||
</form>
|
||||
";
|
||||
}
|
||||
|
||||
function handle_job_completion($bj, $bji) {
|
||||
$response = null;
|
||||
$response->number = get_int('response');
|
||||
if (get_str('submit', true)) {
|
||||
$response->have_ellipse = 0;
|
||||
} else {
|
||||
$response->have_ellipse = 1;
|
||||
$pic = $_GET['pic'];
|
||||
$response->cx = $pic.x;
|
||||
$response->cy = $pic.y;
|
||||
}
|
||||
$bji->info = json_encode($response);
|
||||
$bji->completed($bj);
|
||||
|
||||
// show another job immediately
|
||||
//
|
||||
Bossa::show_next_job($bj);
|
||||
Bossa::show_next_job($bj); // show another job immediately
|
||||
}
|
||||
|
||||
Bossa::script_init($user, $bj, $bji);
|
||||
|
||||
if (isset($_GET['submit'])) {
|
||||
if (isset($_GET['completion'])) {
|
||||
handle_job_completion($bj, $bji);
|
||||
} else {
|
||||
show_job($bj, $bji);
|
||||
|
|
|
@ -17,7 +17,7 @@ if (!$app) {
|
|||
|
||||
$ji = BossaJobInst::assign($app, $user);
|
||||
if ($ji) {
|
||||
$url = $app->start_url."?bji=$ji->id";
|
||||
$url = $app->display_script."?bji=$ji->id";
|
||||
Header("Location: $url");
|
||||
} else {
|
||||
page_head("No jobs available");
|
||||
|
|
Loading…
Reference in New Issue