show_host()   F
last analyzed

Complexity

Conditions 28
Paths > 20000

Size

Total Lines 150
Code Lines 117

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 28
eloc 117
nc 218400
nop 3
dl 0
loc 150
rs 0
c 0
b 0
f 0

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
// This file is part of BOINC.
3
// http://boinc.berkeley.edu
4
// Copyright (C) 2008 University of California
5
//
6
// BOINC is free software; you can redistribute it and/or modify it
7
// under the terms of the GNU Lesser General Public License
8
// as published by the Free Software Foundation,
9
// either version 3 of the License, or (at your option) any later version.
10
//
11
// BOINC is distributed in the hope that it will be useful,
12
// but WITHOUT ANY WARRANTY; without even the implied warranty of
13
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
14
// See the GNU Lesser General Public License for more details.
15
//
16
// You should have received a copy of the GNU Lesser General Public License
17
// along with BOINC.  If not, see <http://www.gnu.org/licenses/>.
18
19
require_once("../inc/credit.inc");
20
require_once("../inc/stats_sites.inc");
21
require_once("../inc/boinc_db.inc");
22
require_once("../inc/user.inc");
23
24
function link_to_results($host) {
25
    if (!$host) return tra("No host");
26
    $config = get_config();
27
    if (!parse_bool($config, "show_results")) return tra("Unavailable");
28
    $nresults = host_nresults($host);
29
    if (!$nresults) return "0";
30
    return "<a href=results.php?hostid=$host->id>$nresults</a>";
31
}
32
33
function sched_log_name($x) {
34
    if ($x == 0) return "NO_SUCH_LOG";
35
    return gmdate('Y-m-d_H/Y-m-d_H:i', $x) . ".txt";
36
}
37
38
function sched_log_link($x) {
39
    if (file_exists("sched_logs")) {
40
        return "<a href=\"../sched_logs/" . sched_log_name($x) . "\">" . time_str($x) . "</a>";
41
    } else {
42
        return time_str($x);
43
    }
44
}
45
46
function location_form($host) {
47
    $none = "selected";
48
    $h=$w=$s=$m="";
49
    if ($host->venue == "home") $h = "selected";
50
    if ($host->venue == "work") $w = "selected";
51
    if ($host->venue == "school") $s = "selected";
52
    $x = "<form action=host_venue_action.php>
53
        <input type=hidden name=hostid value=$host->id>
54
        <select class=\"form-control\" name=venue>
55
        <option value=\"\" $none>---
56
        <option value=home $h>".tra("Home")."
57
        <option value=work $w>".tra("Work")."
58
        <option value=school $s>".tra("School")."
59
        </select>
60
        <p></p>
61
        <input class=\"btn btn-primary btn-sm\" type=submit value=\"".tra("Update location")."\">
62
        </form>
63
    ";
64
    return $x;
65
}
66
67
function cross_project_links($host) {
68
    global $host_sites;
69
    $x = "";
70
    foreach ($host_sites as $h) {
71
        $url = $h[0];
72
        $name = $h[1];
73
        $img = $h[2];
74
        $x .= "<a href=$url".$host->host_cpid."><img class=\"icon\" border=2 src=img/$img alt=\"$name\"></a> ";
75
    }
76
    return $x;
77
}
78
79
// Show full-page description of $host.
80
// If $user is non-null, it's both the owner of the host
81
// and the logged in user (so show some extra fields)
82
//
83
function show_host($host, $user, $ipprivate) {
84
    $config = get_config();
85
    start_table();
86
    row1(tra("Computer information"));
87
    $anonymous = false;
88
    if ($user) {
89
        if ($ipprivate) {
90
            row2(tra("IP address"), "$host->last_ip_addr<br>".tra("(same the last %1 times)", $host->nsame_ip_addr));
91
            if ($host->last_ip_addr != $host->external_ip_addr) {
92
                row2(tra("External IP address"), $host->external_ip_addr);
93
            }
94
        } else {
95
            row2(tra("IP address"), "<a href=show_host_detail.php?hostid=$host->id&ipprivate=1>".tra("Show IP address")."</a>");
96
        }
97
        row2(tra("Domain name"), $host->domain_name);
98
        if ($host->product_name) {
99
            row2(tra("Product name"), $host->product_name);
100
        }
101
        $x = $host->timezone/3600;
102
        if ($x >= 0) $x="+$x";
103
        row2(tra("Local Standard Time"), tra("UTC %1 hours", $x));
104
    } else {
105
        $owner = BoincUser::lookup_id($host->userid);
106
        if ($owner && $owner->show_hosts) {
107
            row2(tra("Owner"), user_links($owner, BADGE_HEIGHT_MEDIUM));
108
        } else {
109
            row2(tra("Owner"), tra("Anonymous"));
110
            $anonymous = true;
111
        }
112
    }
113
    row2(tra("Created"), time_str($host->create_time));
114
    if (!NO_STATS) {
115
        row2(tra("Total credit"), format_credit_large($host->total_credit));
116
        row2(tra("Average credit"), format_credit($host->expavg_credit));
117
        if (!$anonymous) {
118
            row2(tra("Cross project credit"), cross_project_links($host));
119
        }
120
    }
121
    row2(tra("CPU type"), "$host->p_vendor <br> $host->p_model");
122
    row2(tra("Number of cores"), $host->p_ncpus);
123
    $misc = json_decode($host->misc);
124
    row2(tra("Coprocessors"), gpu_desc($misc));
125
    row2(tra("Virtualization"), vbox_desc($misc));
126
    row2(tra("Docker"), docker_desc($misc));
127
    row2(tra("Operating System"), "$host->os_name <br> $host->os_version");
128
    row2(tra("BOINC version"), boinc_version($misc));
129
    $x = $host->m_nbytes/GIGA;
130
    $y = round($x, 2);
131
    row2(tra("Memory"), tra("%1 GB", $y));
132
    if ($host->m_cache > 0) {
133
        $x = $host->m_cache/KILO;
134
        $y = round($x, 2);
135
        row2(tra("Cache"), tra("%1 KB", $y));
136
    }
137
138
    if ($user) {
139
        $x = $host->m_swap/GIGA;
140
        $y = round($x, 2);
141
        row2(tra("Swap space"), tra("%1 GB", $y));
142
        $x = $host->d_total/GIGA;
143
        $y = round($x, 2);
144
        row2(tra("Total disk space"), tra("%1 GB", $y));
145
        $x = $host->d_free/GIGA;
146
        $y = round($x, 2);
147
        row2(tra("Free Disk Space"), tra("%1 GB", $y));
148
    }
149
    $x = $host->p_fpops/1e9;
150
    $y = round($x, 2);
151
    row2(tra("Measured floating point speed"), tra("%1 billion ops/sec", $y));
152
    $x = $host->p_iops/1e9;
153
    $y = round($x, 2);
154
    row2(tra("Measured integer speed"), tra("%1 billion ops/sec", $y));
155
    $x = $host->n_bwup/MEGA;
156
    $y = round($x, 2);
157
    if ($y > 0) {
158
        row2(tra("Average upload rate"), tra("%1 MB/sec", $y));
159
    } else {
160
        row2(tra("Average upload rate"), tra("Unknown"));
161
    }
162
    $x = $host->n_bwdown/MEGA;
163
    $y = round($x, 2);
164
    if ($y > 0) {
165
        row2(tra("Average download rate"), tra("%1 MB/sec", $y));
166
    } else {
167
        row2(tra("Average download rate"), tra("Unknown"));
168
    }
169
170
    // This code is used by Science United,
171
    // which knows about hosts but doesn't compute
172
    if (!NO_COMPUTING) {
173
        $x = $host->avg_turnaround;
174
        if ($x) {
175
            row2(tra("Average turnaround time"), time_diff($x));
176
        }
177
        row2(tra("Application details"),
178
            "<a href=host_app_versions.php?hostid=$host->id>".tra("Show")."</a>"
179
        );
180
        $show_results = parse_bool($config, "show_results");
181
        if ($show_results) {
182
            $nresults = host_nresults($host);
183
            if ($nresults) {
184
                $results = "<a href=results.php?hostid=$host->id>$nresults</a>";
185
            } else {
186
                $results = "0";
187
            }
188
            row2(tra("Tasks"), $results);
189
        }
190
        if (defined('BATCH_ACCEL') && BATCH_ACCEL) {
191
            row2('Low turnaround time?',
192
                $host->error_rate?'yes':'no'
193
            );
194
        }
195
    }
196
197
    if ($user) {
198
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
199
        row2(tra("Last time contacted server"), sched_log_link($host->rpc_time));
200
        row2(tra("Fraction of time BOINC is running"), number_format(100*$host->on_frac, 2)."%");
201
        if ($host->connected_frac > 0) {
202
            row2(tra("While BOINC is running, fraction of time computer has an Internet connection"), number_format(100*$host->connected_frac, 2)."%");
203
        }
204
        row2(tra("While BOINC is running, fraction of time computing is allowed"), number_format(100*$host->active_frac, 2)."%");
205
        row2(tra("While is BOINC running, fraction of time GPU computing is allowed"), number_format(100*$host->gpu_active_frac, 2)."%");
206
        if ($host->cpu_efficiency) {
207
            row2(tra("Average CPU efficiency"), $host->cpu_efficiency);
208
        }
209
        if (!NO_COMPUTING) {
210
            if ($host->duration_correction_factor) {
211
                row2(tra("Task duration correction factor"), $host->duration_correction_factor);
212
            }
213
        }
214
        row2(tra("Location"), location_form($host));
215
        row2(tra("Merge duplicate records of this computer"), "<a class=\"btn btn-primary btn-sm\" href=host_edit_form.php?hostid=$host->id>".tra("Merge")."</a>");
216
        if ($show_results && $nresults == 0) {
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $nresults does not seem to be defined for all execution paths leading up to this point.
Loading history...
Comprehensibility Best Practice introduced by
The variable $show_results does not seem to be defined for all execution paths leading up to this point.
Loading history...
217
            row2('',
218
                button_text(
219
                    sprintf(
220
                        'host_delete.php?hostid=%d%s',
221
                        $host->id,
222
                        url_tokens($user->authenticator)
223
                    ),
224
                    tra("Delete this computer")
225
                )
226
            );
227
        }
228
    } else {
229
        row2(tra("Number of times client has contacted server"), $host->rpc_seqno);
230
        row2(tra("Last contact"), date_str($host->rpc_time));
231
    }
232
    echo "</table>\n";
233
234
}
235
236
// the following is used for list of top hosts
237
//
238
function top_host_table_start($sort_by) {
239
    global $host_sites;
240
    shuffle($host_sites);
241
    start_table('table-striped');
242
    $x = array(
243
        tra("Info"),
244
        tra("Rank"),
245
        tra("Owner"),
246
    );
247
    if (!NO_STATS) {
248
        if ($sort_by == 'total_credit') {
249
            $x[] = "<a href=top_hosts.php?sort_by=expavg_credit>".tra("Avg. credit")."</a>";
250
            $x[] = tra("Total credit");
251
        } else {
252
            $x[] = tra("Recent average credit");
253
            $x[] = "<a href=top_hosts.php?sort_by=total_credit>".tra("Total credit")."</a>";
254
        }
255
    }
256
    $x[] = tra("BOINC version");
257
    $x[] = tra("CPU");
258
    $x[] = tra("GPU");
259
    $x[] = tra("Operating system");
260
    $s = 'style="text-align:right;"';
261
    $a = array("", "", "", $s, $s, "", "", "", "");
262
    row_heading_array($x, $a, "bg-default");
263
}
264
265
function host_nresults($host) {
266
    return BoincResult::count("hostid=$host->id");
267
}
268
269
function vbox_desc($misc) {
270
    if (empty($misc->vbox)) return '---';
271
    $v = $misc->vbox;
272
    return sprintf(
273
        'Virtualbox %s<br>HW acceleration: %s<br>Enabled: %s',
274
        $v->version,
275
        $v->hw_accel?'yes':'no',
276
        $v->hw_accel_enabled?'yes':'no'
277
    );
278
}
279
280
function docker_desc($misc) {
281
    if (empty($misc->docker)) return '---';
282
    $d = $misc->docker;
283
    $x = sprintf('%s version %s',
284
        $d->type==1?"Docker":"Podman",
285
        $d->version
286
    );
287
    if (!empty($d->wsl_distro)) {
288
        if (empty($d->boinc_buda_runner_version)) {
289
            $x .= sprintf(
290
                '<br>WSL distro: %s',
291
                htmlspecialchars($d->wsl_distro)
292
            );
293
        } else {
294
            $x .= sprintf(
295
                '<br>WSL distro: %s ver %d',
296
                htmlspecialchars($d->wsl_distro),
297
                $d->boinc_buda_runner_version
298
            );
299
        }
300
    }
301
    if (!empty($misc->config)) {
302
        $c = $misc->config;
303
        if (!empty($c->dont_use_wsl)) {
304
            $x .= "<br>Config: don't use WSL";
305
        }
306
        if (!empty($c->dont_use_docker)) {
307
            $x .= "<br>Config: don't use Docker";
308
        }
309
    }
310
    return $x;
311
}
312
313
314
// return a human-readable version of the GPU info
315
//
316
function gpu_desc($misc) {
317
    if (empty($misc->gpus)) return '---';
318
    $gpus = [];
319
    foreach ($misc->gpus as $g) {
320
        $x = sprintf(
321
            '%d %s; %dMB RAM',
322
            $g->count, $g->model, $g->ram_mb
323
        );
324
        if (!empty($g->driver_version)) {
325
            $x .= "; Driver: $g->driver_version";
326
        }
327
        if (!empty($g->opencl_version)) {
328
            $x .= "; OpenCL: $g->opencl_version";
329
        }
330
        $gpus[] = $x;
331
    }
332
    return implode('<br>', $gpus);
333
}
334
335
// Given the same string as above, return the BOINC version
336
//
337
function boinc_version($misc) {
338
    if (empty($misc->client_version)) {
339
        return '---';
340
    }
341
    $x = $misc->client_version;
342
    if (!empty($misc->client_brand)) {
343
        $x .= " ($misc->client_brand)";
344
    }
345
    return $x;
346
}
347
348
function cpu_desc($host) {
349
    return "$host->p_vendor<br>$host->p_model<br>".tra("(%1 cores)", $host->p_ncpus)."\n";
350
}
351
352
// If private is true, we're showing the host to its owner,
353
// so it's OK to show the domain name etc.
354
// If private is false, show the owner's name only if they've given permission
355
//
356
function show_host_row($host, $i, $private, $show_owner, $any_product_name) {
357
    $anonymous = false;
358
    if (!$private) {
359
        if ($show_owner) {
360
            $user = BoincUser::lookup_id($host->userid);
361
            if ($user && $user->show_hosts) {
362
            } else {
363
                $anonymous = true;
364
            }
365
        }
366
    }
367
    echo "<tr><td>ID: $host->id
368
        <br><a href=show_host_detail.php?hostid=$host->id>".tra("Details")."</a>
369
    ";
370
    if (!NO_COMPUTING) {
371
        echo "
372
        | <a href=results.php?hostid=$host->id>".tra("Tasks")."</a>
373
        ";
374
    }
375
    if (!NO_STATS) {
376
        if (!$anonymous) {
377
            echo "
378
                <br><nobr><small>".tra("Cross-project stats:")."</small></nobr><br>".cross_project_links($host);
379
        }
380
    }
381
    echo "
382
        </td>
383
    ";
384
    if ($private) {
385
        echo "<td>$host->domain_name</td>\n";
386
        if ($any_product_name) {
387
            echo "<td>$host->product_name</td>\n";
388
        }
389
        echo "<td>$host->venue</td>\n";
390
    } else {
391
        echo "<td>$i</td>\n";
392
        if ($show_owner) {
393
            if ($anonymous) {
394
                echo "<td>".tra("Anonymous")."</td>\n";
395
            } else {
396
                echo "<td>", user_links($user, BADGE_HEIGHT_MEDIUM), "</td>\n";
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $user does not seem to be defined for all execution paths leading up to this point.
Loading history...
397
            }
398
        }
399
    }
400
    $misc = json_decode($host->misc);
401
    if ($show_owner) {
402
        // This is used in the "top computers" display
403
        //
404
        if (!NO_STATS) {
405
            printf("
406
                <td align=right>%s</td>
407
                <td align=right>%s</td>",
408
                format_credit($host->expavg_credit),
409
                format_credit_large($host->total_credit)
410
            );
411
        }
412
        printf("
413
            <td>%s</td>
414
            <td>%s</td>
415
            <td>%s</td>
416
            <td>%s <br> %s</td>",
417
            boinc_version($misc),
418
            cpu_desc($host),
419
            gpu_desc($misc),
420
            $host->os_name, $host->os_version
421
        );
422
    } else {
423
        // This is used to show the computers of a given user
424
        //
425
        if (!NO_STATS) {
426
            printf("
427
                <td align=right>%s</td>
428
                <td align=right>%s</td>",
429
                format_credit($host->expavg_credit),
430
                format_credit_large($host->total_credit)
431
            );
432
        }
433
        printf("
434
            <td>%s</td>
435
            <td>%s</td>
436
            <td>%s</td>
437
            <td>%s<br><small>%s</small></td>
438
            <td>%s</td>
439
            ",
440
            boinc_version($misc),
441
            cpu_desc($host),
442
            gpu_desc($misc),
443
            $host->os_name, $host->os_version,
444
            sched_log_link($host->rpc_time)
445
        );
446
    }
447
448
    echo "</tr>\n";
449
}
450
451
// Logic for deciding whether two host records might actually
452
// be the same machine, based on CPU info
453
//
454
// p_vendor is typically either AuthenticAMD or GenuineIntel.
455
// Over time we've changed the contents of p_model.
456
// Some examples:
457
// Intel(R) Core(TM)2 Duo CPU  E7300  @ 2.66GHz [Family 6 Model 23 Stepping 6]
458
// AMD Athlon(tm) II X2 250 Processor [Family 16 Model 6 Stepping 3]
459
// Intel(R) Xeon(R) CPU X5650 @ 2.67GHz [x86 Family 6 Model 44 Stepping 2]
460
// Intel(R) Core(TM) i5-2500K CPU @ 3.30GHz [Intel64 Family 6 Model 42 Stepping 7]
461
//
462
// in the last 2 cases, let's call x86 and Intel64 the "architecture"
463
//
464
// so, here's the policy:
465
//
466
// if p_ncpus different, return false
467
// if p_vendor different, return false
468
// if both have family/model/stepping info
469
//    if info disagrees, return false
470
//    if both have GHz info, and they disagree, return false
471
//    if both have architecture, and they disagree, return false
472
//    return true
473
// if p_model different, return false
474
// return true
475
//
476
477
// parse p_model to produce the following structure:
478
// x->speed     "3.00GHz" etc. or null
479
// x->arch      "x86" etc. or null
480
// x->info      "Family 6 Model 23 Stepping 6" etc. or null
481
//
482
function parse_model($model) {
483
    $y = explode(" ", $model);
484
    $x = new StdClass;
485
    $x->speed = null;
486
    $x->arch = null;
487
    $x->info = null;
488
    foreach ($y as $z) {
489
        if (strstr($z, "GHz")) $x->speed = $z;
490
        if (strstr($z, "MHz")) $x->speed = $z;
491
    }
492
    $pos1 = strpos($model, '[');
493
    if ($pos1 === false) return $x;
494
    $pos2 = strpos($model, ']');
495
    if ($pos2 === false) return $x;
496
    $a = substr($model, $pos1+1, $pos2-$pos1-1);
497
    $y = explode(" ", $a);
498
    if (count($y) == 0) return $x;
499
    if ($y[0] == "Family") {
500
        $x->info = $a;
501
    } else {
502
        $x->arch = $y[0];
503
        $x->info = substr($a, strlen($y[0])+1);
504
    }
505
    return $x;
506
}
507
508
function cpus_compatible($host1, $host2) {
509
    if ($host1->p_ncpus != $host2->p_ncpus) return false;
510
    if ($host1->p_vendor != $host2->p_vendor) return false;
511
    $x1 = parse_model($host1->p_model);
512
    $x2 = parse_model($host2->p_model);
513
    if ($x1->info && $x2->info) {
514
        if ($x1->info != $x2->info) return false;
515
        if ($x1->speed && $x2->speed) {
516
            if ($x1->speed != $x2->speed) return false;
517
        }
518
        if ($x1->arch && $x2->arch) {
519
            if ($x1->arch != $x2->arch) return false;
520
        }
521
        return true;
522
    }
523
    if ($host1->p_model != $host2->p_model) return false;
524
    return true;
525
}
526
527
// does one host strictly precede the other?
528
//
529
function times_disjoint($host1, $host2) {
530
    if ($host1->rpc_time < $host2->create_time) return true;
531
    if ($host2->rpc_time < $host1->create_time) return true;
532
    return false;
533
}
534
535
function os_compatible($host1, $host2) {
536
    if (strstr($host1->os_name, "Windows") && strstr($host2->os_name, "Windows")) return true;
537
    if (strstr($host1->os_name, "Linux") && strstr($host2->os_name, "Linux")) return true;
538
    if (strstr($host1->os_name, "Darwin") && strstr($host2->os_name, "Darwin")) return true;
539
    if (strstr($host1->os_name, "SunOS") && strstr($host2->os_name, "SunOS")) return true;
540
    if ($host1->os_name == $host2->os_name) return true;
541
    return false;
542
}
543
544
// Return true if it's possible that the two host records
545
// correspond to the same host
546
// NOTE: the cheat-proofing comes from checking
547
// that their time intervals are disjoint.
548
// So the CPU/OS checks don't have to be very strict.
549
//
550
function hosts_compatible($host1, $host2, $show_detail) {
551
    // A host is "new" if it has no credit and no results.
552
    // Skip disjoint-time check if one host or other is new
553
    //
554
    $new1 = !$host1->total_credit && !host_nresults($host1);
555
    $new2 = !$host2->total_credit && !host_nresults($host2);
556
    if (!$new1 && !$new2) {
557
        if (!times_disjoint($host1, $host2)) {
558
            if ($show_detail) {
559
                $c1 = date_str($host1->create_time);
560
                $r1 = date_str($host1->rpc_time);
561
                $c2 = date_str($host2->create_time);
562
                $r2 = date_str($host2->rpc_time);
563
                echo "<br>".tra("Host %1 has overlapping lifetime:", $host2->id)." ($c1 - $r1), ($c2 - $r2)";
564
            }
565
            return false;
566
        }
567
    }
568
    if (!os_compatible($host1, $host2)) {
569
        if ($show_detail) {
570
            echo "<br>".tra("Host %1 has an incompatible OS:", $host2->id)." ($host1->os_name, $host2->os_name)\n";
571
        }
572
        return false;
573
    }
574
    if (!cpus_compatible($host1, $host2)) {
575
        if ($show_detail) {
576
            echo "<br>".tra("Host %1 has an incompatible CPU:", $host2->id)." ($host1->p_vendor $host1->p_model, $host2->p_vendor $host2->p_model)\n";
577
        }
578
        return false;
579
    }
580
    return true;
581
}
582
583
// recompute host's average credit by scanning results.
584
// Could be expensive if lots of results!
585
//
586
function host_update_credit($hostid) {
587
    $total = 0;
588
    $avg = 0;
589
    $avg_time = 0;
590
591
    $results = BoincResult::enum("hostid=$hostid order by received_time");
592
    foreach($results as $result) {
593
        if ($result->granted_credit <= 0) continue;
594
        $total += $result->granted_credit;
595
596
        update_average(
597
            $result->received_time,
598
            $result->sent_time,
599
            $result->granted_credit,
600
            $avg,
601
            $avg_time
602
        );
603
604
        //echo "<br>$avg\n";
605
    }
606
607
    // do a final decay
608
    //
609
    $now = time();
610
    update_average(now, 0, 0, $avg, $avg_time);
611
612
    $host = new BoincHost();
613
    $host->id = hostid;
614
    $host->update("total_credit=$total, expavg_credit=$avg, expavg_time=$now");
615
}
616
617
// decay a host's average credit
618
//
619
function host_decay_credit($host) {
620
    $avg = $host->expavg_credit;
621
    $avg_time = $host->expavg_time;
622
    $now = time();
623
    update_average($now, 0, 0, $avg, $avg_time);
624
    $host->update("expavg_credit=$avg, expavg_time=$now");
625
}
626
627
// if the host hasn't received new credit for ndays,
628
// decay its average and return true
629
//
630
function host_inactive_ndays($host, $ndays) {
631
    $diff = time() - $host->expavg_time;
632
    if ($diff > $ndays*86400) {
633
        host_decay_credit($host);
634
        return true;
635
    }
636
    return false;
637
}
638
639
// invariant: old_host.create_time < new_host.create_time
640
//
641
function merge_hosts($old_host, $new_host) {
642
    if ($old_host->id == $new_host->id) {
643
        return tra("same host");
644
    }
645
    if (!hosts_compatible($old_host, $new_host, false)) {
646
        return tra("Can't merge host %1 into %2 - they're incompatible", $old_host->id, $new_host->id);
647
    }
648
649
    echo "<br>".tra("Merging host %1 into host %2", $old_host->id, $new_host->id)."\n";
650
651
    // decay the average credit of both hosts
652
    //
653
    $now = time();
654
    update_average($now, 0, 0, $old_host->expavg_credit, $old_host->expavg_time);
655
    update_average($now, 0, 0, $new_host->expavg_credit, $new_host->expavg_time);
656
657
    // update the database:
658
    // - add credit from old to new host
659
    // - change results to refer to new host
660
    // - put old host in "zombie" state (userid=0, rpc_seqno=new host ID)
661
    //
662
    $total_credit = $old_host->total_credit + $new_host->total_credit;
663
    $recent_credit = $old_host->expavg_credit + $new_host->expavg_credit;
664
    $result = $new_host->update("total_credit=$total_credit, expavg_credit=$recent_credit, expavg_time=$now");
665
    if (!$result) {
666
        return tra("Couldn't update credit of new computer");
667
    }
668
    $result = BoincResult::update_aux("hostid=$new_host->id where hostid=$old_host->id");
669
    if (!$result) {
670
        return tra("Couldn't update results");
671
    }
672
673
    $result = $old_host->update("total_credit=0, expavg_credit=0, userid=0, rpc_seqno=$new_host->id");
674
    if (!$result) {
675
        return tra("Couldn't retire old computer");
676
    }
677
    echo "<br>".tra("Retired old computer %1", $old_host->id)."\n";
678
    return 0;
679
}
680
681
//////////////// helper functions for hosts_user.php ////////////////
682
683
function link_url($sort, $rev, $show_all) {
684
    global $userid;
685
    $x = $userid ? "&userid=$userid":"";
686
    return "hosts_user.php?sort=$sort&rev=$rev&show_all=$show_all$x";
687
}
688
689
function link_url_rev($actual_sort, $sort, $rev, $show_all) {
690
    if ($actual_sort == $sort) {
691
        $rev = 1 - $rev;
692
    }
693
    return link_url($sort, $rev, $show_all);
694
}
695
696
function more_or_less($sort, $rev, $show_all) {
697
    echo "<p>";
698
    if ($show_all) {
699
        $url = link_url($sort, $rev, 0);
700
        echo tra("Show:")." ".tra("All computers")." &middot; <a href=$url>".tra("Only computers active in past 30 days")."</a>";
701
    } else {
702
        $url = link_url($sort, $rev, 1);
703
        echo tra("Show:")." <a href=$url>".tra("All computers")."</a> &middot; ".tra("Only computers active in past 30 days");
704
    }
705
    echo "<p>";
706
}
707
708
function user_host_table_start(
709
    $private, $sort, $rev, $show_all, $any_product_name
710
) {
711
    start_table('table-striped');
712
    $x = array();
713
    $a = array();
714
715
    $url = link_url_rev($sort, "id", $rev, $show_all);
716
    $x[] = "<a href=$url>".tra("Computer ID")."</a>";
717
    $a[] = '';
718
719
    if ($private) {
720
        $url = link_url_rev($sort, "name", $rev, $show_all);
721
        $x[] = "<a href=$url>".tra("Name")."</a>";
722
        $a[] = null;
723
        $url = link_url_rev($sort, "venue", $rev, $show_all);
724
        if ($any_product_name) {
725
            $x[] = tra("Model");
726
            $a[] = null;
727
        }
728
        $x[] = "<a href=$url>".tra("Location")."</a>";
729
        $a[] = null;
730
    } else {
731
        $x[] = tra("Rank");
732
        $a[] = null;
733
    }
734
    if (!NO_STATS) {
735
        $url = link_url_rev($sort, "expavg_credit", $rev, $show_all);
736
        $x[] = "<a href=$url>".tra("Avg. credit")."</a>";
737
        $a[] = ALIGN_RIGHT;
738
        $url = link_url_rev($sort, "total_credit", $rev, $show_all);
739
        $x[] = "<a href=$url>".tra("Total credit")."</a>";
740
        $a[] = ALIGN_RIGHT;
741
    }
742
    $x[] = tra("BOINC<br>version");
743
    $a[] = null;
744
    $url = link_url_rev($sort, "cpu", $rev, $show_all);
745
    $x[] = "<a href=$url>".tra("CPU")."</a>";
746
    $a[] = null;
747
    $x[] = tra("GPU");
748
    $a[] = null;
749
    $url = link_url_rev($sort, "os", $rev, $show_all);
750
    $x[] = "<a href=$url>".tra("Operating System")."</a>";
751
    $a[] = null;
752
    $url = link_url_rev($sort, "rpc_time", $rev, $show_all);
753
    $x[] = "<a href=$url>".tra("Last contact")."</a>";
754
    $a[] = null;
755
    row_heading_array($x, $a, "bg-default");
756
}
757
758
function show_user_hosts($userid, $private, $show_all, $sort, $rev) {
759
    $desc = false;  // whether the sort order's default is decreasing
760
    switch ($sort) {
761
    case "total_credit": $sort_clause = "total_credit"; $desc = true; break;
762
    case "expavg_credit": $sort_clause = "expavg_credit"; $desc = true; break;
763
    case "name": $sort_clause = "domain_name"; break;
764
    case "id": $sort_clause = "id"; break;
765
    case "cpu": $sort_clause = "p_vendor"; break;
766
    case "os": $sort_clause = "os_name"; break;
767
    case "venue": $sort_clause = "venue"; break;
768
    default:
769
        // default value -- sort by RPC time
770
        $sort = "rpc_time";
771
        $sort_clause = "rpc_time";
772
        $desc = true;
773
    }
774
775
    if ($rev != $desc) {
776
        $sort_clause .= " desc";
777
    }
778
    more_or_less($sort, $rev, $show_all);
779
780
    $now = time();
781
    $old_hosts=0;
782
    $i = 1;
783
    $hosts = BoincHost::enum("userid=$userid order by $sort_clause limit 100");
784
    $any_product_name = false;
785
    foreach ($hosts as $host) {
786
        if ($host->product_name) {
787
            $any_product_name = true;
788
            break;
789
        }
790
    }
791
    user_host_table_start($private, $sort, $rev, $show_all, $any_product_name);
792
    foreach ($hosts as $host) {
793
        $is_old=false;
794
        if (($now - $host->rpc_time) > 30*86400) {
795
            $is_old=true;
796
            $old_hosts++;
797
        }
798
        if (!$show_all && $is_old) continue;
799
        show_host_row($host, $i, $private, false, $any_product_name);
800
        $i++;
801
    }
802
    end_table();
803
804
    if ($old_hosts>0) {
805
        more_or_less($sort, $rev, $show_all);
806
    }
807
808
    if ($private) {
809
        echo "
810
            <a href=merge_by_name.php>".tra("Merge computers by name")."</a>
811
        ";
812
    }
813
}
814
815
// remove user-specific info from a user's hosts
816
//
817
function anonymize_hosts($user) {
818
    $hosts = BoincHost::enum("userid=$user->id");
819
    foreach ($hosts as $h) {
820
        $h->update("domain_name='deleted', last_ip_addr=''");
821
    }
822
}
823
824
825
?>
826