= Bossa implementation notes = To get work, a user goes to a particular Bossa-supplied page. There he sees a list of applications for which tasks are available and for which he is qualified, and links to courses for other applications. Online and offline applications are listed separately. Each application has an estimate of the time or other resources required to complete a job. Selecting an online application invokes the Bossa ''scheduler'' script, which selects a job instance suitable for the user, and redirects to its instance URL. Selecting an offline application invokes the Bossa scheduler, which selects a job and redirects to its instance-start URL. Team administrators are provided with an interface for getting offline jobs for the team. The scheduler allows a team to get instances only for applications for which some team member has the required skill. Users and teams are provided with an interface for seeing a list of pending offline jobs. They can indicate that one of them is completed; this takes them to the instance-complete URL for that job. == Database tables == Until Bossa has good web-based administration tools, you'll often need to directly examine and modify its MySQL database, using the command-line tool 'mysql' or a web-based interface such as [http://www.phpmyadmin.net/ phpMyAdmin]. The database tables used by Bossa (in addition to BOINC's tables for users, teams, etc.) are as follows: '''bossa_app''': || field name || type || meaning || || id || integer || row ID, assigned by MySQL || || create_time || integer || row creation time || || name || varchar(255) || short name (internal use; no spaces) || || user_friendly_name || varchar(255) || user-visible name (spaces OK) || || long_jobs || tinyint || nonzero if user can have > 1 active job || || start_url || varchar(255) || name (relative to project URL) of start script || || deprecated || tinyint || nonzero if deprecated (don't show) || || info || text || information (typically encoded in JSON) such as the criteria for which users to issue jobs to || '''bossa_job''': || field name || type || meaning || || id || integer || row ID, assigned by MySQL || || create_time || integer || row creation time || || name || varchar(255) || a unique name for this job || || app_id || integer || ID of bossa_app || || info || text || job-specific info (file names etc.) typically JSON-encoded || || batch || integer || batch number (use to group jobs) || || time_estimate || integer || number of seconds this job is likely to take || || time_limit || integer || give up if not completed after this number of seconds || || more_needed || tinyint || nonzero if more completed instances of this job are needed || || npending || integer || number of pending instances || || nsuccess || integer || number of successfully completed instances || || nsuccess_needed || integer || required number of successfully completed instances || '''bossa_job_inst''': || field name || type || meaning || || id || integer || row ID, assigned by MySQL || || create_time || integer || row creation time || || job_id || integer || ID of bossa_job || || user_id || integer || ID of user || || finish_time || integer || time when finished, or zero || || info || text || outcome info (usually JSON-encoded) || '''bossa_app_user''': || app_id || integer || ID of bossa_app || || user_id || integer || ID of user || || info || text || description of the user's skill or ranking at a given app, typically JSON-encoded || == Bossa PHP classes == Bossa provides the following classes (in '''html/inc/bossa.inc''' and '''html/inc/bossa_db.inc'''): '''!BossaApp, !BossaJob, !BossaJobInst''':: These correspond to the above tables, and have fields corresponding to each database field. They offer functions to insert, look up, and modify database rows. '''Bossa''':: Utility functions. == Creating a Bossa project == First, [ServerIntro set up a BOINC server] and [MakeProject create a project]. You'll need PHP 5.2 or later (for JSON functions). Say your project is called '''test_project''', your BOINC source directory is '''~/boinc''', and your BOINC projects directory is '''~/projects'''. Create Bossa's database tables as follows: {{{ cd ~/boinc/db mysql test_project < bossa_schema.sql mysql test_project < bossa_constraints.sql }}} Create a Bossa application as follows: {{{ cd ~/projects/test_project/html/ops php bossa_setup_example.php }}} bossa_setup_example.php contains: {{{ $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"; } }}} You can edit this to change the application name and front-end script name, if you like. == Adding jobs == Typically you'll add jobs using a script. Here's an example ('''html/ops/bossa_make_jobs_example.php'''): {{{ 1 app_id = $app->id; 17 $job->batch = 0; 18 $job->time_estimate = 30; 19 $job->time_limit = 600; 20 $job->nsuccess_needed = 3; 21 for ($i=0; $i<10; $i++) { 22 $job->name = "job_$i"; 23 $info = null; 24 $info->number = $i % 2; 25 $job->info = json_encode($info); 26 if (!$job->insert()) { 27 echo "BossaJob::insert failed: ", mysql_error(), "\n"; 28 exit(1); 29 } 30 } 31 } 32 33 make_jobs(); 34 echo "All done.\n"; 35 36 ?> }}} This creates 10 jobs. Each job has an ''info'' field consisting of a JSON-encoded structure consisting of an integer (0 or 1). == Front-end scripts == You develop a '''front-end script''' to show a job instance to a user, and to handle a completed instance. It's handy to put both of these functions in a single file. A front-end script is called with the URL parameter '''bji''' set to a job instance ID. Here's an example ('''html/user/bossa_example.php'''): {{{ 1 finish_time) { 12 error_page("You already finished this job"); 13 } 14 $info = json_decode($bj->info); 15 $img_url = "http://boinc.berkeley.edu/images/number_".$info->number.".jpg"; 16 echo " 17
18 id> 19 20
21 The picture shows a 22
zero 23
one 24
not sure 25

26
27 "; 28 } 29 30 function handle_job_completion($bj, $bji) { 31 $response = null; 32 $response->number = get_int('response'); 33 $bji->info = json_encode($response); 34 $bji->completed($bj); 35 36 // show another job immediately 37 // 38 Bossa::show_next_job($bj); 39 } 40 41 Bossa::script_init($user, $bj, $bji); 42 43 if ($_GET['submit']) { 44 handle_job_completion($bj, $bji); 45 } else { 46 show_job($bj, $bji); 47 } 48 49 ?> }}} Line 41:: Call a Bossa utility function to look up the job instance and make sure that it was issued to the logged-in user. The job instance, job, and user are returned. Line 43:: Branch according to whether we are showing a job or handling the completion of a job. Line 14:: If we're showing a job, decode its ''info'' structure to decide whether to show which picture to show. Lines 17-18:: Task completion will be handled by this script; arrange to pass the job instance ID. Lines 31-33:: Get the user's response, and encode it in JSON. Line 34:: Call a utility function that marks the job instance as completed and updates its database record. Line 38:: Call a utility function that gets another job (if one is available) and shows it to the user.