2 | | |
3 | | To get work, a user goes to a particular Bossa-supplied page. |
4 | | There he sees a list of applications for which tasks are available |
5 | | and for which he is qualified, |
6 | | and links to courses for other applications. |
7 | | Online and offline applications are listed separately. |
8 | | Each application has an estimate of the time or other resources required to complete a job. |
9 | | |
10 | | Selecting an online application invokes the Bossa ''scheduler'' script, |
11 | | which selects a job instance suitable for the user, |
12 | | and redirects to its instance URL. |
13 | | |
14 | | Selecting an offline application invokes the Bossa scheduler, |
15 | | which selects a job and redirects to its instance-start URL. |
16 | | |
17 | | Team administrators are provided with an interface for getting |
18 | | offline jobs for the team. |
19 | | The scheduler allows a team to get instances only for applications |
20 | | for which some team member has the required skill. |
21 | | |
22 | | Users and teams are provided with an interface for seeing |
23 | | a list of pending offline jobs. |
24 | | They can indicate that one of them is completed; |
25 | | this takes them to the instance-complete URL for that job. |
85 | | |
86 | | == Creating a Bossa project == |
87 | | |
88 | | First, [ServerIntro set up a BOINC server] and [MakeProject create a project]. |
89 | | You'll need PHP 5.2 or later (for JSON functions). |
90 | | Say your project is called '''test_project''', your BOINC source directory is '''~/boinc''', |
91 | | and your BOINC projects directory is '''~/projects'''. |
92 | | |
93 | | Create Bossa's database tables as follows: |
94 | | {{{ |
95 | | cd ~/boinc/db |
96 | | mysql test_project < bossa_schema.sql |
97 | | mysql test_project < bossa_constraints.sql |
98 | | }}} |
99 | | |
100 | | Create a Bossa application as follows: |
101 | | {{{ |
102 | | cd ~/projects/test_project/html/ops |
103 | | php bossa_setup_example.php |
104 | | }}} |
105 | | |
106 | | bossa_setup_example.php contains: |
107 | | {{{ |
108 | | $ba = new BossaApp(); |
109 | | $ba->name = 'bossa_test'; |
110 | | $ba->user_friendly_name = 'Simple pattern recognition'; |
111 | | $ba->start_url = 'bossa_example.php'; |
112 | | |
113 | | if ($ba->insert($ba)) { |
114 | | echo "Added application '$ba->name'\n"; |
115 | | } else { |
116 | | echo "Couldn't add '$ba->name': ", mysql_error(), "\n"; |
117 | | } |
118 | | }}} |
119 | | You can edit this to change the application name |
120 | | and front-end script name, if you like. |
121 | | |
122 | | == Adding jobs == |
123 | | |
124 | | Typically you'll add jobs using a script. |
125 | | Here's an example ('''html/ops/bossa_make_jobs_example.php'''): |
126 | | {{{ |
127 | | 1 <?php |
128 | | 2 |
129 | | 3 require_once("../inc/bossa_db.inc"); |
130 | | 4 require_once("../inc/db.inc"); |
131 | | 5 |
132 | | 6 db_init(); |
133 | | 7 |
134 | | 8 function make_jobs() { |
135 | | 9 $appname = 'bossa_test'; |
136 | | 10 $app = BossaApp::lookup_name($appname); |
137 | | 11 if (!$app) { |
138 | | 12 echo "Application $appname not found\n"; |
139 | | 13 exit(1); |
140 | | 14 } |
141 | | 15 $job = new BossaJob; |
142 | | 16 $job->app_id = $app->id; |
143 | | 17 $job->batch = 0; |
144 | | 18 $job->time_estimate = 30; |
145 | | 19 $job->time_limit = 600; |
146 | | 20 $job->nsuccess_needed = 3; |
147 | | 21 for ($i=0; $i<10; $i++) { |
148 | | 22 $job->name = "job_$i"; |
149 | | 23 $info = null; |
150 | | 24 $info->number = $i % 2; |
151 | | 25 $job->info = json_encode($info); |
152 | | 26 if (!$job->insert()) { |
153 | | 27 echo "BossaJob::insert failed: ", mysql_error(), "\n"; |
154 | | 28 exit(1); |
155 | | 29 } |
156 | | 30 } |
157 | | 31 } |
158 | | 32 |
159 | | 33 make_jobs(); |
160 | | 34 echo "All done.\n"; |
161 | | 35 |
162 | | 36 ?> |
163 | | }}} |
164 | | |
165 | | This creates 10 jobs. |
166 | | Each job has an ''info'' field consisting of a JSON-encoded structure |
167 | | consisting of an integer (0 or 1). |
168 | | |
169 | | == Front-end scripts == |
170 | | |
171 | | You develop a '''front-end script''' to show a job instance to a user, |
172 | | and to handle a completed instance. |
173 | | It's handy to put both of these functions in a single file. |
174 | | A front-end script is called with the URL parameter '''bji''' set |
175 | | to a job instance ID. |
176 | | Here's an example ('''html/user/bossa_example.php'''): |
177 | | |
178 | | {{{ |
179 | | 1 <?php |
180 | | 2 |
181 | | 3 require_once("../inc/bossa.inc"); |
182 | | 4 |
183 | | 5 echo "foo"; |
184 | | 6 |
185 | | 7 // Bossa example. |
186 | | 8 // Show the user an image and ask them whether it's a zero or one. |
187 | | 9 |
188 | | 10 function show_job($bj, $bji) { |
189 | | 11 if ($bji->finish_time) { |
190 | | 12 error_page("You already finished this job"); |
191 | | 13 } |
192 | | 14 $info = json_decode($bj->info); |
193 | | 15 $img_url = "http://boinc.berkeley.edu/images/number_".$info->number.".jpg"; |
194 | | 16 echo " |
195 | | 17 <form method=get action=bossa_example.php> |
196 | | 18 <input type=hidden name=bji value=$bji->id> |
197 | | 19 <img src=$img_url> |
198 | | 20 <br> |
199 | | 21 The picture shows a |
200 | | 22 <br><input type=radio name=response value=0> zero |
201 | | 23 <br><input type=radio name=response value=1> one |
202 | | 24 <br><input type=radio name=response value=2 checked> not sure |
203 | | 25 <br><br><input type=submit name=submit value=OK> |
204 | | 26 </form> |
205 | | 27 "; |
206 | | 28 } |
207 | | 29 |
208 | | 30 function handle_job_completion($bj, $bji) { |
209 | | 31 $response = null; |
210 | | 32 $response->number = get_int('response'); |
211 | | 33 $bji->info = json_encode($response); |
212 | | 34 $bji->completed($bj); |
213 | | 35 |
214 | | 36 // show another job immediately |
215 | | 37 // |
216 | | 38 Bossa::show_next_job($bj); |
217 | | 39 } |
218 | | 40 |
219 | | 41 Bossa::script_init($user, $bj, $bji); |
220 | | 42 |
221 | | 43 if ($_GET['submit']) { |
222 | | 44 handle_job_completion($bj, $bji); |
223 | | 45 } else { |
224 | | 46 show_job($bj, $bji); |
225 | | 47 } |
226 | | 48 |
227 | | 49 ?> |
228 | | }}} |
229 | | |
230 | | Line 41:: |
231 | | 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. |
232 | | Line 43:: |
233 | | Branch according to whether we are showing a job or handling the completion of a job. |
234 | | Line 14:: |
235 | | If we're showing a job, decode its ''info'' structure to decide whether to show which picture to show. |
236 | | Lines 17-18:: |
237 | | Task completion will be handled by this script; arrange to pass the job instance ID. |
238 | | Lines 31-33:: |
239 | | Get the user's response, and encode it in JSON. |
240 | | Line 34:: |
241 | | Call a utility function that marks the job instance as completed and updates its database record. |
242 | | Line 38:: |
243 | | Call a utility function that gets another job (if one is available) and shows it to the user. |