© nikkytok/Shutterstock.com
Fußball-Matchmaking mit Android Things und Google Nearby

Tor! Oder doch nicht?


Adrenalin, rasender Puls, Euphorie. Der Sieg beim Kickern wurde hart erkämpft, aber schon nach kurzer Zeit hinterfragen die schlechten Verlierer, ob der Sieg wirklich so glorreich war und ob das Spiel überhaupt stattgefunden hat. Hier kommt die Kickchain mit ihren Geschwistern ins Spiel.

Unsere Kollegen haben im Rahmen eines Hackathons die Kickchain [1], eine Blockchain für Kickerergebnisse, ins Leben gerufen. Wir fühlten uns verpflichtet, dafür zu sorgen, dass die Ergebnisse vollautomatisiert darin abgelegt werden. Eine Blockchain ohne Blöcke macht schließlich wenig Sinn, oder? In diesem Artikel werden wir darüber berichten, wie aus dem krachenden Einschlagen des Balls ins Tor ein Block in der Blockchain wird (Abb. 1).

dierkes_androidthings_1.tif_fmt1.jpgAbb. 1: Die zwei Erzfeinde während des Matchmakings am Kickertisch

Wir haben unseren Kicker für die Cloudifizierung mit einem Raspberry ausgestattet, an dem zwei Lichtschranken befestigt sind. Sie sind für das Messen der Tore verantwortlich. Der Raspberry dient außerdem als Matchmaking-Server. Für die mobilen Endgeräte haben wir eine App entwickelt, die einem klassischen Multiplayer-Client ähnelt. Ein Smartphone kann entweder ein Spiel erstellen oder einem Spiel beitreten. Der Raspberry nimmt dabei die Rolle des Spielservers ein. Der Besitzer der Lobby kann anschließend das Spiel starten und alle Spieler begeben sich zum Kickertisch. Nachdem auf einer Seite das zehnte Tor gefallen ist, wendet sich der Raspberry an das API-Gateway, um das Spiel zu speichern. Zusätzlich autorisiert das API-Gateway Spieler und liefert nützliche Statistiken. Letztere können die Clients anzeigen.

dierkes_androidthings_2.tif_fmt1.jpgAbb. 2: Architekturdiagramm aller Kickchain-Komponenten

Die Kickchain

Die Kickchain ist eine Blockchain-basierte Anwendung, die Ergebnisse der Kickerspiele speichert. Die Spiele finden zwischen zwei Teams statt. Jedes Spiel ist also eine Transaktion zwischen zwei Parteien. Diese Spiele bzw. Transaktionen werden über das Kickway-Gateway an einen Kickchain-Server übermittelt. Dieser kümmert sich darum, diese Spiele an die Blockchain zu hängen und die Änderungen mit den weiteren Servern der Kickchain auszutauschen. Die Daten werden über mehrere Knoten verteilt, die miteinander vernetzt sind. So sind die Spieldaten auf beliebig vielen Servern verteilt und dadurch vor Veränderungen missgünstiger Mitspieler geschützt.

dierkes_androidthings_3.tif_fmt1.jpgAbb. 3: Architekturdiagramm der verteilten Blockchain Nodes

Spieldaten

Das Kickchain API bietet zwei öffentliche Methoden an: eine, um die gesamte Kickchain abzurufen und eine, um neue Spiele hinzuzufügen. Daneben gibt es noch weitere Methoden für die Kommunikation der Kickchain-Server untereinander.

Listing 1

{ "name": "Kickchain", "chain": [ { "header": { "index": 0, "timestamp": null, "transactionHash": "4f53cda18c2baa0c0354bb5f9a3ecbe5ed12ab4d8e11ba873c2f11161202b945", "previousHash": null, "proof": 100 }, "content": [] }, { "header": { "index": 1, "timestamp": "2018-09-28T11:37:20.511Z", "transactionHash": "e4a61578b40d48965909d05b4f7409f920dc11535bcd948ea477e2c18a619b48", "previousHash": "ae428540ff24893d664b7216eb94f89682274280be890a567d01224e7b8123ce", "proof": 40663 }, "content": [ { "team1": { "players": [ "Alice", "Bob" ] }, "team2": { "players": [ "Eve", "Mallory" ] }, "score": { "goals1": 10, "goals2": 1 } } ] } ] }

Das Bootiful Kickway

Das Kickway [2] ist eine Spring-Boot-Anwendung, die als API-Gateway für die Kickchain fungiert. Sie ist die Hüterin der Kickchain, da diese über keinerlei Authentifizierung verfügt. Das Kickway speichert die Hardware-IDs der Android-Geräte zu den Spielernamen. Das verhindert, dass ein Spieler im Namen eines anderen Ergebnisse in die Blockchain schreibt. Ein Spieler wird durch den Raspberry autorisiert, wenn er ein Spiel erstellen oder einem beitreten möchte. Außerdem bietet das Kickway einen Endpunkt für Statistiken an, der einerseits die Top-10-Spieler eines bestimmten Modus und andererseits spezifische Metriken zu einem Spieler liefert. Abschließend werden die Spiele über das Kickway in der Kickchain gespeichert. In einer weiteren Version des API-Gateways sollen ein Elo-System [3] und eine Spielhistorie implementiert werden. Das Elo-System soll einen direkten Vergleich zwischen Spielern ermöglichen. Durch die Spielhistorie soll nachvollziehbar werden, in welcher Reihenfolge die Tore gefallen sind.

Reactive Android

Viele Android-Anwendungen sind konzeptionell für das reaktive Paradigma geschaffen. Alle Funktionen gehen von einer Nutzeraktion oder der Antwort eines Fremdsystems aus. In unseren Anwendungen sind das zum einen die Benutzeraktionen wie ein Klick auf einen Button und zum anderen eingehende Nearby-Nachrichten oder Änderungen eines GPIO-Zustands. Leider stehen einem Android-Entwickler nur begrenzte Hardwareressourcen zur Verfügung, weswegen die Geschwindigkeit ein großer Faktor ist. RxJava ist dafür, durch den non-blocking Ansatz, eine große Hilfe und bringt viele bereits implementierte Operatoren mit. Kombiniert mit Android-spezifischen Erweiterungen wie RxAndroid [4], RxBinding [5] und AutoDispose [6] lassen sich viele Abläufe einfacher, lesbarer und performanter umsetzen, als es mit Boardmitteln möglich ist.

Eine Einführung in RxJava2

Im reaktiven Paradigma wird alles als Stream dargestellt. Dafür bietet RxJava2 die Datentypen Observable, Flowable, Single, Completeable und Maybe an. An dieser Stelle werden wir uns auf das Observable fokussieren, das wir zur simplen Veranschaulichung einem asynchronen Java-8-Stream gleichsetzen. In reaktiven Streams gibt es immer mindestens einen Publisher, beliebige Operatoren und abschließend einen Subscriber.

In den folgenden Codebeispielen ist der Publisher das kickprotocol und der Subscriber die Methodenreferenz auf die println-Funktion. Jedes createGame-Event-Element wird nun auf der Konsole ausgegeben.

kickprotocol.createGameMessageEvents.subscribe(::println)

Die Events können im Zuge des Streams durch die Operatoren manipuliert werden. Es folgt ein Beispiel, in dem die Endpunkt-ID aus dem Event extrahiert wird.

kickprotocol.createGameMessageEvents .map { it.endpointId } .subscribe(::println)

Non-blocking Streams

Eine Kerneigenschaft von reaktiven Implementationen ist, dass sie nicht blockieren. Das bedeutet: Kein Thread hält beim Warten auf den Abschluss einer Operation einen anderen Thread von der Arbeit ab. Eine Methode, die beispielsweise auf eine Ressource des Betriebssystems zugreift, kehrt nach diesem Aufruf sofort zurück und kann so direkt weitere Aufgaben verrichten. Das Warten auf die Ressource wird nun in einer Event-Loop durch eine Bibliothek wie RxJava2, Reactor, RxJs oder Akka erledigt. Dieses Modell erlaubt, deutlich mehr Aufgaben nebenläufig zu erledigen, als das herkömmliche Multi-Thread-Modell.

dierkes_androidthings_4.tif_fmt1.jpgAbb. 4: Das Event-Loop-Modell [7]

Reaktive Android-Erweiterungen

Für die Entwicklung speziell auf Android haben wir zusätzlich die eingangs erwähnten Bibliotheken RxAndroid, RxBinding und AutoDispose verwendet. RxAndroid bietet Erweiterungen, die es erlauben, mit dem Threading-Modell von Android zu arbeiten. Die Bibliothek bietet einen Scheduler [8] für den Main Thread von Android an.

AutoDispose ...

Neugierig geworden? Wir haben diese Angebote für dich:

Angebote für Gewinner-Teams

Wir bieten Lizenz-Lösungen für Teams jeder Größe: Finden Sie heraus, welche Lösung am besten zu Ihnen passt.

Das Library-Modell:
IP-Zugang

Das Company-Modell:
Domain-Zugang