PDA

Archiv verlassen und diese Seite im Standarddesign anzeigen : Aktuelle Platzierung des Teams im Steckbrief


TiKu
15.02.2007, 03:54
Hi,

es wäre ja an sich ganz cool, in den Steckbriefen der Projekte immer die aktuelle Platzierung unseres Teams anzuzeigen - natürlich automatisiert.
Damit das geht, brauchen wir zunächst einmal ein PHP-Skript (Perl geht sicherlich auch), welches auf dem jeweiligen Projektserver im Verzeichnis /stats/ die Datei db_dump.xml auswertet. Wichtig ist aus dieser Datei folgender Teil:
<enumeration>
<table>team</table>
<filename>team</filename>
<output>
<compression>gzip</compression>
</output>
</enumeration>Er verrät uns den Dateinamen und die Kompressionsmethode der XML-Datei, welche die Teamstatistiken enthält. Hier handelt es sich also um eine GZIP-komprimierte Datei namens team.gz.
Nächster Schritt ist also, diese Datei runterzuladen, zu entpacken und die darin enthaltene XML-Datei zu öffnen. Der Name dieser Datei ist in diesem Fall schlicht "team".
Der Aufbau dieser Datei ist folgender:
<teams>
<team>
<id>TEAMID</id>
...
<total_credit>CREDITS</total_credit>
...
</team>
<team>
<id>TEAMID</id>
...
<total_credit>CREDITS</total_credit>
...
</team>
...
</teams>Am besten wird es sein, alle Team-IDs und die dazugehörigen Credits in eine SQL-Tabelle zu schreiben und dann MySQL die Tabelle nach Credits sortieren zu lassen. Anhand unserer Team-ID sollte sich daraus dann unsere Platzierung ermitteln lassen.

Erstmal bis dahin... Falls jemand Bock hat, so ein Skript zu schreiben: Nur zu. :)


Am Ende soll das mal so laufen, dass auf dem Boot, also unserem Server, ein CronJob läuft, welcher alle 5 Stunden oder so angestoßen wird. Dieser holt sich dann aus einer Liste aller Projekte, an denen wir teilnehmen, die URL jedes einzelnen Projekts, lädt sich jeweils die Teamstatistik runter, wertet sie aus und schreibt unsere Platzierung erstmal irgendwohin. Ist ein Projektserver mal nicht erreichbar oder schlägt das Auslesen der Platzierung anderweitig fehl, wird erstmal die alte Platzierung behalten.
Die Wiki holt sich dann beim Anzeigen des Steckbriefs irgendwie die ermittelte Platzierung und baut sie in den Steckbrief ein. Am elegantesten geht das wahrscheinlich mit AJAX.

TiKu
20.02.2007, 20:04
Hier mal ein Skript, welches eine Projekt-URL nimmt und die komprimierte Datei mit den Team-Stats in das aktuelle Verzeichnis lädt, entpackt und die Team-IDs zusammen mit den Credits ausgibt. Verbesserungsvorschläge sind jederzeit willkommen.


<?php
class xml2Array
{
var $arrOutput = array();
var $resParser;
var $strXmlData;

function parse($strInputXML)
{
$this->resParser = xml_parser_create();
xml_set_object($this->resParser, $this);
xml_set_element_handler($this->resParser, "tagOpen", "tagClosed");

xml_set_character_data_handler($this->resParser, "tagData");

$this->strXmlData = xml_parse($this->resParser, $strInputXML);
if(!$this->strXmlData) {
die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->resParser)), xml_get_current_line_number($this->resParser)));
}

xml_parser_free($this->resParser);
return $this->arrOutput;
}

function tagOpen($parser, $name, $attrs)
{
$tag = array("name" => $name, "attrs" => $attrs);
array_push($this->arrOutput, $tag);
}

function tagData($parser, $tagData)
{
if(trim($tagData)) {
if(isset($this->arrOutput[count($this->arrOutput) - 1]['tagData'])) {
$this->arrOutput[count($this->arrOutput) - 1]['tagData'] .= $tagData;
} else {
$this->arrOutput[count($this->arrOutput) - 1]['tagData'] = $tagData;
}
}
}

function tagClosed($parser, $name)
{
$this->arrOutput[count($this->arrOutput) - 2]['children'][] = $this->arrOutput[count($this->arrOutput) - 1];
array_pop($this->arrOutput);
}
}

class parseTeamStats
{
var $arrOutput = array();
var $resParser;
var $strXmlData;
var $inTeamTag = false;
var $inIDTag = false;
var $currentTeamID = -1;
var $inTotalCreditsTag = false;
var $currentTeamCredits = 0;

function parse($fileName)
{
$this->resParser = xml_parser_create();
xml_set_object($this->resParser, $this);
xml_set_element_handler($this->resParser, "tagOpen", "tagClosed");

xml_set_character_data_handler($this->resParser, "tagData");

$fdSource = fopen($fileName, "r");
if(!is_resource($fdSource)) {
die("Failed to read file " . $fileName);
}

while(!feof($fdSource)) {
$data = fread($fdSource, 4096);
$this->strXmlData = xml_parse($this->resParser, $data, feof($fdSource));
if(!$this->strXmlData) {
die(sprintf("XML error: %s at line %d", xml_error_string(xml_get_error_code($this->resParser)), xml_get_current_line_number($this->resParser)));
}
}

fclose($fdSource);

xml_parser_free($this->resParser);
return $this->arrOutput;
}

function tagOpen($parser, $name, $attrs)
{
if(strcmp($name, "TEAM") == 0) {
$this->inTeamTag = true;
} else if(strcmp($name, "ID") == 0) {
$this->inIDTag = true;
} else if(strcmp($name, "TOTAL_CREDIT") == 0) {
$this->inTotalCreditsTag = true;
}
}

function tagData($parser, $tagData)
{
if($this->inTeamTag) {
if($this->inIDTag) {
// a team ID
if(trim($tagData)) {
$this->currentTeamID = $tagData;
}
} else if($this->inTotalCreditsTag) {
// a team's credits
if(trim($tagData)) {
$this->currentTeamCredits = $tagData;
}
}
}
}

function tagClosed($parser, $name)
{
if(strcmp($name, "TEAM") == 0) {
$this->inTeamTag = false;
// output team data
echo $this->currentTeamID . "&nbsp;&nbsp;&nbsp;&nbsp;" . $this->currentTeamCredits . "<br>";
} else if(strcmp($name, "ID") == 0) {
$this->inIDTag = false;
} else if(strcmp($name, "TOTAL_CREDIT") == 0) {
$this->inTotalCreditsTag = false;
}
}
}

function getTeamStatsTable($projecturl)
{
$fd = fopen($projecturl . "/stats/db_dump.xml", "r");
if(!is_resource($fd)) {
die("Failed to read " . $projecturl . "/stats/db_dump.xml");
}

$contents = fread($fd, 2048);
fclose($fd);

$objXML = new xml2Array();
$arrOutput = $objXML->parse($contents);

$enumToParse = null;
for($i = 0; $i < count($arrOutput); ++$i) {
if(strcmp($arrOutput[$i]["name"], "BOINC_DB_DUMP_SPEC") == 0) {
for($j = 0; $j < count($arrOutput[$i]["children"]); ++$j) {
if(strcmp($arrOutput[$i]["children"][$j]["name"], "ENUMERATION") == 0) {
$enum = $arrOutput[$i]["children"][$j]["children"];
for($k = 0; $k < count($enum); ++$k) {
if((strcmp($enum[$k]["name"], "TABLE") == 0)) {
if(strcmp($enum[$k]["tagData"], "team") == 0) {
// found the enumeration tag for the team table
$enumToParse = $enum;
break;
} else {
// wrong enumeration tag
break;
}
}
}
if($enumToParse != null) {
break;
}
}
}
break;
}
}

if($enumToParse == null) {
die("Could not retrieve location of team table");
}

$teamStatsTable = array("FileName" => null, "CompressedFileName" => null, "Compression" => null);
for($i = 0; $i < count($enumToParse); ++$i) {
if(strcmp($enumToParse[$i]["name"], "FILENAME") == 0) {
$teamStatsTable["FileName"] = $projecturl . "/stats/" . $enumToParse[$i]["tagData"];
$teamStatsTable["CompressedFileName"] = $teamStatsTable["FileName"];
} else if(strcmp($enumToParse[$i]["name"], "OUTPUT") == 0) {
for($j = 0; $j < count($enumToParse[$i]["children"]); ++$j) {
if(strcmp($enumToParse[$i]["children"][$j]["name"], "COMPRESSION") == 0) {
$teamStatsTable["Compression"] = $enumToParse[$i]["children"][$j]["tagData"];
}
}
}
}

if(strcmp($teamStatsTable["Compression"], "gzip") == 0) {
$teamStatsTable["CompressedFileName"] .= ".gz";
}
// TODO: weitere Kompressionen (aktuell nicht genutzt)

return $teamStatsTable;
}

function downloadFile($source, $target)
{
require_once 'HTTP/Client.php';
$http_client = new HTTP_Client();
$http_client->get($source);
$data = $http_client->currentResponse();

$fd = fopen($target, "wb");
if(!is_resource($fd)) {
die("Failed to create file " . $target);
}

fwrite($fd, $data["body"]);
fclose($fd);
}

function extractFile($source, $target)
{
$fdSource = gzopen($source, "rb");
if(!is_resource($fdSource)) {
die("Failed to read file " . $source);
}
$fdTarget = fopen($target, "wb");
if(!is_resource($fdTarget)) {
die("Failed to write file " . $target);
}

while(!feof($fdSource)) {
$data = gzread($fdSource, 4096);
fwrite($fdTarget, $data);
}

gzclose($fdSource);
fclose($fdTarget);
}

$teamStatsTable = getTeamStatsTable("http://www.chess960athome.org");

$localCompressedFile = basename($teamStatsTable["CompressedFileName"]);
if($localCompressedFile == null) {
die("Could not retrieve the team table's filename");
}

$localFile = basename($teamStatsTable["FileName"]);
downloadFile($teamStatsTable["CompressedFileName"], $localCompressedFile);
extractFile($localCompressedFile, $localFile);

$objXML = new parseTeamStats();
$objXML->parse($localFile);
?>

Der nächste Schritt wäre, die Daten in eine SQL-Tabelle zu schreiben.

Twodee
10.08.2007, 09:15
Diesr Ansatz ist echt gut!
Ich werde das als Basis für die nächste Erweiterung in unserer Statistik-Page verwenden.

TiKu
09.02.2008, 23:46
Ich hab den Spaß die letzten Tage endlich mal fertig implementiert. Vom ursprünglichen Plan ist nicht mehr viel übrig geblieben.*buck*

Es läuft jetzt so: Wir haben einen Deal mit BOINCstats, der uns ermöglicht, alle interessanten Statistiken zu unserem Team für jedes Projekt (und auch Combined) sehr effizient zu ermitteln. Diese Möglichkeit werden wir per Cronjob 1x täglich nutzen und die Daten in eine lokale Datenbank schreiben. Weitere Details zur Kooperation mit BOINCstats halten wir auf Bitten von BOINCstats geheim.;) Die Datenquelle ist exklusiv für unser DC-Wiki, eine Veröffentlichung der Details würde bei BOINCstats zuviel Traffic/Serverlast verursachen.
Beim Aufruf eines Wiki-Artikels wird ein Javascript aufgerufen, welches den Artikel nach einem bestimmten Tag scannt. Wird es gefunden, wird per AJAX die aktuelle Position unseres Teams für das angegebene Projekt von einem PHP-Skript auf dem P3D-Server erfragt und nachträglich in den Artikel eingefügt. Dieses PHP-Skript liest die Position einfach aus der Datenbank.

Das System geht wahrscheinlich Anfang kommender Woche vollständig online. Einen ersten Eindruck kann man sich schonmal beim Einstein@Home-Artikel (http://dc.planet3dnow.de/wiki/index.php?title=Einstein%40Home) verschaffen.

Möchte man die aktuelle Position in einen Steckbrief einfügen, nutzt man einfach das Template Steckbrief P3D-Statistik Live, bspw. so:
|-
| {{Steckbrief P3D-Statistik Live|Name=Einstein@Home}}Als Projektname ist der Name zu verwenden unter dem das Projekt bei BOINCstats geführt wird.
Möchte man die Live-Stats außerhalb eines Steckbriefs nutzen (bitte sparsam verwenden!), nutzt man das Template P3D-Statistik Live, bspw. so:
{{P3D-Statistik Live|Name=Einstein@Home}}


Nochmal 1000 Dank an Willy von BOINCstats.*great*


Eine kleine Einschränkung gibt es natürlich: Die Live-Stats sind nur bei Projekten möglich, die bei BOINCstats geführt werden, also z. B. nicht für Folding@Home.

TiKu
10.02.2008, 22:23
Die Livestats sind jetzt fertig und bereits bei allen Steckbriefen (außer Folding natürlich) eingearbeitet. Aktualisiert wird täglich um 03:01.



Copyright © 1999 - 2011 Planet 3DNow!
Rechtliche Hinweise