Montagsmaler – Multiplayer online game running on Amazon Web Services

by Jannik Smidt (js343), Niklas Schildhauer (ns107) and Lucas Crämer (lc028)

Project idea

Montagsmaler is a multiplayer online game for web browsers. The idea is derived from the classic Pictionary game, where players have to guess what one person is painting. Basically, we have built the digital version of it, but with one big difference: Not the players are guessing, the image recognition service from AWS is guessing. The game’s aim is to draw as good as possible so that the computer (an AWS service) can recognize what it is. All players are painting at the same time the same thing and after three rounds they see the paintings and the score they have got for it. 

Goal

At the beginning of the course, neither of us had any experience in cloud development. For this lecture we developed Montagsmaler exclusively from scratch. During the project, we have learned and tested new concepts and deepened our skills in software engineering and cloud computing. This article should give you a brief overview of our app, its challenges and the corresponding solutions during development.

Technical architecture

Cloud-Components

Amazon Cognito

Amazon Cognito is an AWS Service for user identification in the cloud. Cognito offers an API and SDKs for simple implementation for popular tech stacks.
We use Cognito for saving personal user data and handling the registration and authentication of the user accounts in our app. Cognito offers EMail verification for user accounts and state of the art token-based stateless authentication techniques. 

Amazon S3

Amazon S3 is an object storage with a REST API. It offers high scalability, availability and fine granular access control. We use an S3 bucket to store the pictures which are saved during the games.

Amazon Rekognition

Amazon Rekognition is an AWS Service for computer vision tasks. Like Cognito Rekogniton offers an API and SDKs for simple implementation for popular tech stacks. We use Rekognition for labelling the pictures during a game after they were stored in the S3 bucket. These labels are then used to calculate a score for the picture which was submitted. 

Amazon ElastiCache (Redis)

Amazon Rekognition is an AWS Service for Redis. We wanted to use it in our architecture for a redis cluster, but since we do not have permission to start even a single ElastiCache Instance, we could not use it at the end.

Amazon Elastic Container Service

Amazon Elastic Container Service is a highly scalable, container management service that makes it easy to run, stop, and manage containers on a cluster. We have one cluster and this cluster has one Elastic Container Service, which contains the core of our application the Montagsmaler API. Our application is continuously deployed with a Task Definition (more on that in CI-Components). This Task Definition deploys two docker containers. One container contains the Montagsmaler API. The other container contains a redis-server since we could not use the Amazon ElastiCache due to permission restrictions.

Amazon Application Load Balancer

We use an Amazon Application Load Balancer which routes all the traffic to the Elastic Container Service. We currently only have one cluster with one service instance, so it fulfills the role of a reverse proxy as of right now. We can not use TLS encryption since we do not have permission to access the AWS Certificate Manager, which is kind of a bummer since it leads to popular browsers refusing to store the HTTP-only cookie containing the refresh token since we can not enable “SameSite: Secure”, which is required.

Amazon Amplify

Amplify offers two products and functions: the Amplify Framework to create serverless backends and static web hosting. For us the static web hosting was interesting. We used it to host our angular frontend. It’s a simple tool which is connected to our github repository and automatically builds the master branch, when a new commit was made (more in CI-Components).

CI-Components

Github Actions

We use GitHub Actions for “continuous integration” of our application. We have an action which automatically tests and deploys the backend to AWS. This action is triggered on every push or pull request to the master. 

Test

The action runs on a Ubuntu machine with a node installation. First it runs the unit tests and then it runs the e2e tests. If even one test fails the deployment stops and we get a notification via EMail. 

Deploy to AWS

The deployment depends on the successful test. It does also run on a ubuntu machine. It starts with configuring the AWS credentials which are stored in the GitHub Secrets of our repository. Then it logs into the AWS Elastic Container Registry and builds the docker image to push it. On successful build and push the AWS Elastic Container Service Task Definition with the new image is rendered. Here we need an extra step since we do not have proper access to AWS IAM: Usually the URI of the credentials is put into the task definition, but we do not have permission to access this URI and our credentials are only valid for about three hours. That is why we take the credentials here also from GitHub Secrets and then insert them manually into the Task Definition using the shell and inplace substitution with sed. When the Task Definition is ready it is deployed to our AWS Elastic Container Service.

We used amplify’s static web hosting to provide the frontend. It would also have been possible to provide the frontend with an AWS S3 bucket. We chose Amplify because of its simple continuous workflows. Once we connected Amplify to Github, all we had to do was select our project, choose the master branch and adjust the build settings. Now the settings were ready and the frontend will be deployed to the master with every new commit. So the latest version is always hosted on AWS.

Montagsmaler-API

NestJS

The HTTP and Websocket API which forms the core of the application is built with NestJS. NestJS is a framework for building efficient and scalable Node.js server-side applications. It is heavily inspired by the architecture of the popular frontend framework Angular, while also taking lots of ideas from Spring. Like Angular it comes with built-in TypeScript support and it combines elements from Object Oriented Programming, Functional Programming and Functional Reactive Programming. 

It makes heavy use of metaprogramming with TypeScript Decorators to provide an advanced modular architecture with dependency injection with the focus on separation of concerns and high testability. 

NestJS provides full compatibility to popular express middlewares and libraries, but can be configured to use different HTTP Server frameworks at your desire. But it also provides a very rich ecosystem with idiomatic solutions for standard problems regarding configuration, pipes e.g. validation pipes, exception filters, authguards, websocket gateways etc. 

The Game

Lobby

Before you can start the game you have to create a lobby. On creation each a UUID is assigned to each lobby, which players can use to invite their friends via an invitation link. Leaving/joining the lobby broadcasts an event to all lobby members. Initially joining the lobby returns the current state of the lobby. The lobby leader (the player who created the lobby or in the case he/she left the lobby the player who joined after and so on) has the permission to configure and start the game. You can configure a round duration between 30 to 300 seconds and up to 10 rounds. Starting the game broadcasts the LobbyConsumedEvent to all members, which contains data about the configured game so all players can join it. As a side effect it also deletes the lobby from the redis storage and it sets a timer to initialize the game loop. Lobbies get automatically cleaned up after two hours in case they are not started to prevent memory leaks.

Games

Games are driven by the game loop. The game loop emits static events based on the given configuration of the game. Consuming the lobby initializes a not started game. After a specific time is over the game starts by emitting the GameStartedEvent. The following RoundStartedEvent starts the game round. After the configured time the round is ended and the RoundOverEvent with the scores of all submitted images is emitted. Within that time frame one picture can be published by each player: An image of the picture is uploaded to an AWS S3-Bucket and then feeded into the AWS Rekognition API. Depending on the time the player needed to publish and the confidence of the expected label given by the Rekognition API a score for the image is determined. After the score is determined the ImageAddedEvent with the corresponding score and link to the uploaded image is emitted. This process repeats for the configured amount of rounds. After all rounds were played the GameOverEvent is emitted which contains the high score and links to all submitted images with the side effect of deleting the game and the saved events. 

Security

Authentification

Authentication is required for playing the game. The registration requires EMail authentication. 

All requests to the HTTP and Websocket API of the game are protected by validating the access token which is transmitted in form of a signed JWT. The refresh token which is used for refreshing the access token is an HTTP-Only Cookie. That makes it possible to store the access token only in memory on the client. These measures protect against common CSRF and XSS attacks.

The API has a middleware for request rate limiting and players are only able to start one game at the time so they have to wait until the previous game is finished before they can start a new one to protect against denial of service attacks.

The game itself also has more security mechanisms build-in regarding the game logic. Only lobby-leaders are allowed to start the game. The lobby-leader is the player who created the lobby, when he leaves the player who joined first becomes the next lobby-leader and so on. The players who are able to join the game are locked once the lobby is consumed, so players can not join a random game. Players can only submit their pictures within the start and the end of a round. This is ensured by a state machine. More on that in challenges.

Challenges

Distributed Gamestate

In single player games or gameservers which only run on one instance, the question where to store the gamestate does not arise. We however wanted that a player could connect to any server instance behind a load balancer and is still able to connect to any game properly. That is why the game state in the application had to be distributed. Since it is just a game and not a serious business application we do not require any specific delivery guarantees or consistency model for our distributed game state. If one in hundred games crashes due to an irrecoverable inconsistency in the game state we can live with that. What we are concerned about is performance. Latency can significantly impact the gaming experience. That is why one important aspect was low latency. The storage medium should also be able to horizontally scale out in the form of a cluster and it should support some kind of publish and subscribe mechanism which we can leverage to distribute events across the instances. With those requirements the choice fell on redis since it is an in-memory key-value store which focuses on performance and it offers a publish and subscribe mechanism. Redis also supports scaling out with Redis-Cluster. So we were settled on Redis. But there was another elephant in the room. In which way do we save the state on the redis? The game loop emits events which are distributed using build-in redis and publish and subscribe mechanism, which we extended to also save all events in order in a redis sorted set. So all the events of a game are saved in a sorted set per game. The maximum events per game can not get very large since there is a maximum amount of rounds which can be played. So having the game state itself saved in the redis and editing it with every event within a lock seems very expensive compared to just accumulating it from the events in the sorted set, which can be retrieved without any lock in a read only operation, whenever it is needed. That is why we settled on pure event sourcing for the game state. So for example whenever a player tries to submit a picture all the events of the game are retrieved from the sorted set and accumulated to the current game state using the state pattern. If the current state is RoundStarted and the player submits for this specific round and the player has not submitted for this round yet the submission is accepted and the picture is rated which leads to the following ImageAddedEvent. So the state is important for validating client events.

Race Conditions/Locking

Although event sourcing significantly reduced the amount of locks we need within the game logic there is still logic that can lead to race conditions and therefore the need of locks. For example while players are submitting a picture we need a mechanism that protects against a player submitting a picture twice which could be possible within the time frame of the AWS API calls which are used for giving a score to the picture since the ImageAddedEvent is emitted after this process was successful. This is a common race condition which can be prevented by putting a lock around the logic from retrieving the state to emitting the event. For locking we use the popular Redlock algorithm, which has its problems though which can lead to inconsistencies according to an article by Martin Kleppmann:

https://martin.kleppmann.com/2016/02/08/how-to-do-distributed-locking.html

There is optimistic locking built into redis, but only on specific key value pairs using WATCH. This does not offer quite what we want and because as mentioned earlier unlikely inconsistencies are not the end of the world for our project we decided to stick with Redlock.

Serialization

Redis does only offer very primitive basic data types in the form of byte arrays and strings. The higher data types like the redis sorted set are just containers for those primitive data types. That means if you want to store objects in redis you need lots of serialization and deserialization which introduces new problems. One problem is that serialization, especially non-binary serialization, can be quite expensive. We ignored the expense of non-binary serialization in our app for the time being. One more problem, which was more important for us, is that the serialization for redis also introduces higher complexity for the programmer while dealing with the data since there is no (virtual) continuous chunk of memory accross the network and is unlike dealing with your data only within an operating system’s process. This results in no call-by-reference but only call-by-value, so if you introduce for example cyclic dependencies in your data objects you need some kind of special algorithm to deal with it. JavaScript has built- in JSON serialization. The problem with JSON serialization is, that it does not serialize to the actual class instance, but rather a plain JavaScript object which has the same data properties. That means it also deserializes to a plain JavaScript object and not to the class instance it once was and how should it, JavaScript is a prototype-based language and the object prototype is lost in the serialization process. We did not want to have constraints on the objects which are serialized nor annoying manual instantiation of an actual class instance from the object. That is why we created a small library which introduces a TypeScript Class Decorator @Serializable() for the classes you want to serialize and a function which deserializes and instantiates to the actual class instance. This helped to increase productivity while working with redis as an object store. Under the hood it makes use of TypeScript Decorators, ES6 Object functions and an algorithm for dealing with cyclic dependencies.

Websocket Interface

From the beginning it was clear that our application needed a websocket interface for bidirectional communication between client and server. Since NestJS provides Websocket support out of the box with socket.io server under the hood, it was the websocket server of choice. The biggest benefit of using socket.io is backwards compatibility with browsers which do not have native websocket support using a http ajax polling technique as a fallback, if no native websockets are available. In retrospect though I would choose a pure websocket API instead of socket.io since socket.io adds a bunch of overhead, the client on the frontend is pretty old fashioned and websocket support in browsers nowadays is really good. According to caniuse.com almost 98% of users use browsers which support native websockets (29.08.2020).

Nobody in our group had any experience with building a websocket API and even after building the application I am not really sure what is good and a bad practice. I tried implementing it with the events of the game in mind. I found it quite challenging and I do not think the API is particularly well designed, but it works. From doing research online it seemed like there are not a lot of guidelines yet. If anyone has good resources on that feel free to message me since I am genuinely interested. Authentication was another problem. The JWT containing the Access Token is sent as a query parameter of the websocket connection and is verified with every event, which was sent from the client. Authentication in websocket connections is still one of those big question marks in my head regarding Websocket APIs. 

E2E-Testing

End-to-end tests are on top of the testing pyramid (https://martinfowler.com/articles/practical-test-pyramid.html). They are actually meant to test your entire, completely integrated system. In our case the e2e-Test of the Websocket API sets up a full Nest Application and connects to it via the node.js socket.io client in the Jest Testrunner, which then initializes a lobby with two members and goes through a whole game. The problem was that the Jest Tests have a timeout of 10 seconds, which means that a whole normal game can not be played within that time frame. To work around this, the service, which initializes the game loop, gets the value of a second in milliseconds injected in the form of a provider into the constructor. On the standard application this provider returns the constant value of 1000 milliseconds. All the time constants within the class are then calculated based on this constant. In the e2e test this provider is overwritten and the value is set to only 50 milliseconds. Using this trick a whole game can be played out in the e2e test within the time frame of 10 seconds. There were also some other sacrifices made regarding the complete integration: The AWS and Redis Providers are mocked and overwritten in the Nest Application for the e2e test. 

Rekognition Service 

A machine learning algorithm for object recognition in pictures requires the picture to include a background. This led to a problem in our drawing component, because the standard was that the drawing of the user was saved as PNG. This led to the drawing having a transparent background. The AWS Rekognition service identified in these pictures only “black” as an object, because the algorithm only considered the inside of the black lines of the drawing, not viewing it as a whole. To ensure that every picture has a background, the solution was to change the format from PNG to JPEG, because JPEG doesn’t support transparency. The library we used to implement a drawing canvas made it easy to change the format, but the new JPEG pictures were now all black. After some research we realized that the problem was that the previously transparent pixels were now saved as “fully black but transparent” pixels by the canvas. Resulting in the transparent pixel becoming black when turning non-opaque by the JPEG format. The solution to this problem was to manually change the background pixel to white instead of black. This change made us face another problem regarding the canvas visible to the user. The change in pixels resulted in aliasing problems or crashes in the HTML canvas. To avoid this from happening, we copied the existing content of the canvas in a new, invisible canvas, in which we applied the pixel-shift. In that way we ensured that the picture visible to the user receives no change while adding a white background to the copied picture.

Word Similarity

To ensure that the users of our game don’t always receive 0 points for their drawings if the AWS Rekognition service doesn’t identify the correct word, we had the idea to calculate the similarity of the other object names recognized by the service. To calculate the context similarity of words, we used the continuous bag of words model. The idea behind this model, is to calculate a vector representation of each word, based on the previous and following words. We decided to implement the code in python, based on the already existing machine learning libraries gensim and tensorflow. The main problem of this algorithm was its dependency on a very big dataset of text, e.g. a Wikipedia dump. The time it takes the code to load the model of a 4 to 20 GB dataset was too long for the AWS instances. Additionally, we would need an instance with a huge amount of RAM, which we couldn’t afford with the AWS student account.

As insurance that the user receives most of the time points, we hard coded similar words for every word a picture has to be drawn for.

Presentation of the Game

Sketches

Demo

Perfekter Glühwein für Zuhause: Thermometer mit Raspberry Pi und AWS

Abstract

Kein anderes Getränk ist mit Weihnachtsmärkten so verbunden wie Glühwein. Und so trinkt sich der ausschweifende Weihnachtsmarktbesucher im Laufe der Adventszeit von Stand zu Stand bis er schließlich am Ende des Jahres seinen Lieblingsstand gefunden hat. Doch auch daheim kann der perfekte Glühwein gelingen. 

Wir zeigen, wie man sich ein Glühweinthermoter mit Cloudanbindung selber baut, und so perfekten Glühwein und Komfort miteinander kombiniert. Und das ganz ohne gedrängte Weihnachtsmärkte und Mundschutz.

Prost!

Einleitung

Unser dreiköpfiges Team hatte für die Vorlesung Software Development for Cloud Computing das Ziel, die Grundlagen der Entwicklung in einer Cloud Umgebung zu lernen und dabei ein Projekt auf die Beine zu stellen, welches diese Grundlagen in der Praxis umsetzt. Ein interessanter Aspekt der Cloud war für uns dabei die Bereitstellung einer überall erreichbaren Umgebung, über welche wir verschiedene Geräte miteinander kommunizieren lassen können.

Daher kam uns die Idee, ein Thermometer zu bauen, welches mit einem Raspberry Pi verbunden ist und wir die Daten über die Cloud verarbeiten und an ein Smartphone weiterleiten. Darüber soll es möglich sein, die aktuelle Temperatur abzulesen und eine Prognose für die Dauer bis zum Erreichen einer einstellbaren Temperatur zu stellen.

Unser Projekt besteht aus drei logischen Schichten. Unser Sensor stellt ein Raspberry Pi mit angeschlossenem Thermometer dar. Der Sensor dient der Feststellung der Flüssigkeitstemperatur, die wir anschließend in der zweiten Schicht verarbeiten. Unsere zweite Schicht stellt dabei eine EC2 Instanz bei AWS dar. Diese erledigt die Berechnung der Zielzeit und stellt einen Webserver für die dritte Schicht, der Datenanzeige bereit. Die Anzeige stellt Informationen und bietet Möglichkeiten der Steuerung des Systems. Es bestehen also bidirektionale Verbindungen, damit der Benutzer Konfigurationen am System unternehmen kann.

Ablauf

Der grundlegende Ablauf in unserem Projekt sollte also folgendermaßen aussehen:

Im ersten Schritt scannt das Smartphone einen QR-Code auf dem Raspberry Pi, damit die richtige Zuordnung von Raspi und Smartphone in der Cloud später gewährleistet werden kann. Als nächstes beginnt der Raspberry Pi, die Temperatur über das Thermometer auszulesen und schickt diese an die Cloud weiter. Sobald der Nutzer nun seine Zieltemperatur eingegeben hat und die Abfrage gestartet hat, wird dies im vierten Schritt mit der ID des Raspberry Pis an die Cloud übermittelt. Nun kann diese die Daten des Raspis mit der passenden ID verarbeiten, die Zeit errechnen und das Ergebnis an die App weiterleiten.

Backend

In unseren ersten Schritten wollten wir uns mit der Cloud vertraut machen und erste Instanzen darauf laufen lassen. Dabei entschieden wir uns für die Cloud von Amazon Web Services (AWS), da es zu dieser eine gute Dokumentation gibt und sie alle für uns notwendigen Komponenten bereitstellt. Zwar kostet die AWS Cloud im Gegensatz zur IBM Cloud auch für Studenten etwas, aber dies stellte für uns kein Problem dar, da wir von der HdM genug Credits zur Verfügung gestellt bekommen haben.

Bei unserem ersten Versuch, eine EC2 Instanz zu starten, stießen wir aber bereits auf einige Probleme. Der Grund dafür war, dass die AWS Cloud relativ komplex ist und sehr viele Möglichkeiten bietet, die Instanzen zu individualisieren und zu optimieren. Dies ist besonders für Einsteiger zu Beginn relativ überfordernd. Am meisten Probleme hatten wir mit dem Einstellen der Security Groups. Diese sind notwendig, damit der Zugriff auf den Server von außerhalb möglich ist. Erst nachdem wir den Zugriff auch über die verschiedenen Protokolle wie TCP und UDP geöffnet haben, konnten wir auf den Server zugreifen.

Als nächstes mussten wir unseren Raspberry Pi so erweitern, dass er die Temperatur messen kann. Dafür haben wir ein Thermometer gekauft, welches wir mit dem Raspberry Pi verkabeln.

Um nun die Temperatur auch zu verarbeiten, benötigten wir ein Skript auf dem Raspberry Pi. Wir entschieden uns hierbei für Python, stellten aber im Nachhinein fest, dass eine Sprache, welche nativ auf dem Gerät läuft, sich hier besser geeignet hätte. Dies hat damit zu tun, dass der Raspberry Pi in unserem Fall ja nur als Testobjekt fungiert, auf welchem Linux installiert ist. Eigentlich sollte es auch möglich sein, die Aufgabe des Raspberry Pis auf ein embedded System zu übertragen, welches nicht die Möglichkeit hat, Python zu nutzen. Hätten wir dies im Vorhinein beachtet, wäre der Übergang vom Raspberry Pi zu embedded Systems einfacher.

Das Thermometer schreibt die ganze Zeit die aktuelle Temperatur in eine Datei auf dem Raspi. Diese lesen wir mit dem Skript jede Sekunde aus und schicken sie dann gemeinsam mit der ID des Raspis an den Server.

Im weiteren Verlauf des Projekts beschäftigten wir uns mehr mit der Serverseite in der Cloud. Wir entschieden uns für eine Node.js-Lösung, welche in der EC2 Instanz läuft, da Node.js mit get und post requests alle von uns benötigten Kommunikationsmittel zwischen dem Raspberry Pi und dem Smartphone bereitstellt. Auch im Nachhinein erwies sich Node.js als eine gute Wahl, da das Aufsetzen des Webservers keinerlei Probleme bereitet hat und die Kommunikation auch mit dem Python Skript auf dem Raspi einwandfrei geklappt hat.

Unser technischer Ablauf und die Kommunikation unter den Geräten sah nun folgendermaßen aus:

Frontend

Zu Beginn des Projekts bestand unser Frontend nur aus einer Webseite, welche die Temperatur des Thermometers anzeigen sollte. Später erweiterten wir diese mit einem Zeit-Temperatur Graph und einem Thermometer zur Darstellung der Temperatur. Dies ließ sich mit HTML, CSS und etwas JavaScript relativ simpel realisieren. Später wurde diese Ansicht durch eine Android App erweitert. Diese stellt eine mobile Möglichkeit dar, sich über den aktuellen Stand zu informieren. Technisch gesehen handelt es sich hierbei um eine WebView, die die Webseite mobil anzeigt.

Dieser Weg, erst eine leicht wartbare Webseite zu erstellen und diese anschließend per WebView auf dem Smartphone aufzurufen erwies sich als gute Idee. So konnten wir uns erst um die Funktionalität der Geschäftslogik konzentrieren und diese anschließend ohne viel Code auf dem Handy nutzen. Jedoch muss man die Optimierung für verschiedene Geräte dann nicht in der App selbst, sondern in der Website vornehmen, was etwas mühsamer ist als in Java für Android.

Zeitberechnung

Ein zentraler Wunsch war es, eine zeitliche Abschätzung zu erhalten, wann nach aktuellem Temperaturtrend die Zieltemperatur erreicht wird. 

Dafür haben wir zuerst eine Beispielmessung eines Temperaturverlaufs durchgeführt. Eine Analyse verschiedener Trendlinien hat ergeben, dass sich eine quadratische Regression am Besten eignet. Bei der Auswahl haben wir ein besonderes Augenmerk auf die Genauigkeit der Zeitabschätzung nach kurzer Zeit gelegt, sodass wir bereits relativ früh eine gute Abschätzung bekommen. 

Die eigentliche Berechnung erfolgte dann in 3 Schritten. Zuerst wurden die Mittelwerte der Messwerte ermittelt und mit diesen nach den Formeln der quadratischen Regression die Faktoren einer quadratischen Gleichung bestimmt. Anhand dieser konnten wir nun den Schnittpunkt mit der gewünschten Zieltemperatur berechnen. Vorteil dieser Variante ist es, dass wir auch negative Temperaturtrends, sowie andere Zieltemperaturen verarbeiten können. Bei der praktischen Anwendung stellte sich jedoch heraus, dass das System einige Schwachstellen aufweist. So können gleichbleibende Temperaturen, die vor allem in der Anfangsphase einer Erhitzung auftreten, die Berechnung sehr ins Schwanken bringen, sodass manchmal für längere Zeit keine Zielzeit berechnet werden kann. Auch kommt es zu teils starken Schwankungen im Verlauf einer Messung. Diese Probleme können jedoch durch eine Bereinigung der Daten im Voraus gelöst werden.

Fazit

Wir haben im Laufe des Projektes natürlich nicht nur viel Mathe gemacht, sondern auch sehr viel über Cloud Computing gelernt. Für einen Anfänger, der vorher noch nie mit AWS in Kontakt kam, ist der Einstieg ziemlich überfordernd. Es gibt deutlich einsteigerfreundliche IaaS-Anbieter wie z.B. die IBM-Cloud.

Was unseren Server angeht, sind wir auch recht zufrieden mit unserer Wahl von Node.js als Web-Backend. Node.js bietet den Vorteil, dass es sehr einfach ist, einen Webserver aufzusetzen, der auf Anfragen hört und gleichzeitig eine Webseite liefern kann. Braucht man mehr Performance und stellt viele parallele Anfragen an den Server, würde es sich lohnen einen Server in Go aufzusetzen. Dasselbe gilt für unseren Raspberry Pi. Das Python-Skript zu schreiben ging ziemlich schnell, aber auch hier könnte man auf eine performantere Lösung in C++ einsetzen. 

Durch eine erprobte Zielberechnung hat unser Thermometer deutlich an Funktionalität gewonnen und kann für nun für verschiedene Temperaturen eingesetzt werden.

Unser Projekt war ganz klar auf Anfänger ausgerichtet. So wurden bereits genutzte und bekannte Technologien mit neuen Technologien der Cloud kombiniert. Dabei konnte der Funktionsumfang von AWS natürlich nicht vollständig ausgenutzt werden. Jedoch haben wir uns Schritt für Schritt an der Cloud bedient und so einen ersten Einblick in die Welt von IaaS erhalten.

Geschrieben von: Nikolai Thees, Michael Partes & Joshua Gertheiss

Building a Serverless Web Service For Music Fingerprinting

Building serverless architectures is hard. At least it was to me in my first attempt to design a loosely coupled system that should, in the long term, mean a good bye to my all-time aversion towards system maintenance.

Music information retrieval is also hard. It is when you attempt to start to grasp the underlying theoretical framework and submerge yourself into scientific papers which each yield a different approach for extracting some feature out of digital audio signals. It is a long way until MFCC starts to sound natural. I have been there.
Continue reading

Building a fully scalable architecture with AWS

What I learned in building the StateOfVeganism ?

Final setup for the finished project (created with Cloudcraft)

By now, we all know that news and media shape our viewson these discussed topics. Of course, this is different from person to person. Some might be influenced a little more than others, but there always is some opinion communicated.

Considering this, it would be really interesting to see the continuous development of mood communicated towards a specific topic or person in the media.

Continue reading

Continuous Integration with Travis CI and Amazon Webservices

Introduction

In the the course Software Engineering and Management and Interactive Media at Stuttgart Media University, we launched an interactive web application called Emoji College.

www.emoji.college

The following blog entry is a brief description of what is going on in this project. The main focus relies on the implementation of a continuous integration pipeline with TravisCI and hosting with AWS. As newcomers in dealing with AWS services it was not easy for us to get started. We have had to try a lot and have paid too much money for the services. Therefore it is our mission to explain the most important steps during the setup of AWS services easily and mention all the lessons learned. So far, there is no easy and understandable guide as we needed it.

Continue reading