# TinyAd - dokumentacja wstępna
## Skład zespołu
* **Rafał Kulus**
* Damian Kolaska
* Kamil Przybyła
## Treść zadania
**TinyAd** - System dystrybucji i uruchamiania spotów reklamowych.
https://bitbucket.org/BlueAlien99/tinyad
W systemie pracuje stacja zarządzająca i zbiór (do kilkudziesięciu tysięcy) sterowników paneli reklamowych. Stacja multicastowo dystrybuuje treści i harmonogramy ich wyświetlania. Harmonogram określa okresy wyświetlania i czas przechowywania. Sterowniki unicastowo raportują swój stan i zgłaszają błędy. Błąd w transmisji multicastowej obsługiwany jest retransmisją multi- lub unicastową w zależności od liczby otrzymanych komunikatów NAK. System ma pracować w prywatnej sieci IPv6. Stacja zarządzająca może wysyłać unicastowo ważne treści informacyjne do natychmiastowego wyświetlenia przez wybrane sterowniki. Należy też zaprojektować moduł do Wireshark umożliwiający wyświetlanie i analizę zdefiniowanych komunikatów.
## Format plików
### Konfiguracja dla paneli
`panel_name` i `tags` są opcjonalne i służą do identyfikowania paneli w celu wyświetlenia ważnych treści. Są wysyłane do stacji zarządzającej podczas rejestrowania panelu. Domyślna nazwa i lokalizacja pliku to `./config.lfd`.
```
server_ip=fe80::1234
panel_name=Lobby Front
tags=[oled][huge][orange apricot]
```
### Harmonogram
`expire`, `weekday`, `hour` są opcjonalne. W przypadku braku `expire`, zawartość nigdy nie wygaśnie. W przypadku braku pozostałych dwóch pól, zawartość będzie wyświetlana niezależnie od dnia tygodnia i / lub godziny. Pierwszeństwo ma pierwsza zawartość, która spełnia wszystkie warunki.
```
file=./img.jpg
expire=2021-05-15 1930
weekday=[1][2][3]
hour=[0530-0830][1500-1900]
---
file=./vids/video.mp4
expire=2021-06-30
```
## Interfejs użytkownika
### Stacja zarządzająca
Stacja zarządzająca będzie posiadała prosty CLI.
Dane mogą być podane z pliku:
```
./station < timetable.txt
```
Lub wprowadzone przez użytkownika:
```
./station
$ <command1>
$ <command2>
...
$ <commandN>
```
Dostępne polecenia:
* `schedule ./my_sched.sch`
Spowoduje rozesłanie nowego harmonogramu i wymaganych plików do paneli. `./my_sched.sch` to ścieżka do pliku zawierającego harmonogram.
* `panic ./emergency.mkv --name "Lobby Front"`
* `panic ./emergency.mkv --tags [oled][huge]`
Spowoduje wysłanie ważnych treści; do paneli, których nazwa to `Lobby Front` lub które posiadają co najmniej jeden z podanych tagów. ważne treści; będą wyświetlane tak długo, aż panel nie otrzyma nowego harmonogramu poleceniem `schedule`.
* `bye`
Spowoduje wyłączenie stacji zarządzającej.
* `top 10`
Wyświetlenie 10 ostatnich linii logów o poziomie info lub wyższym.
### Panele
Panele nie będą posiadały interfejsu użytkownika. Wszystkie potrzebne informacje będą wczytywane z prostego pliku konfiguracyjnego.
## Pozostałe założenia funkcjonalne
Proces uruchomienia paneli powinien się ograniczyć tylko i wyłącznie do startu aplikacji klienta, która sama wykona wszystkie wymagane czynności, aby panel mógł zacząć wyświetlać zawartość.
Po udanej rejestracji panelu w stacji zarządzającej, zostanie do niego natychmiastowo wysłany ostatnio użyty harmonogram (jeśli taki istnieje).
## Założenia niefunkcjonalne
Stacje zarządzające i panele powinny sobie radzić ze wszystkimi przewidzianymi błędami, aby zapewnić nieprzerwaną pracę, stabilność i niezawodność, w szczególności błędy transmisji danych nie powinny uniemożliwić poprawnego działania systemu.
## Przypadki użycia
### Rejestracja panelu reklamowego
1. Użytkownik uruchamia panel reklamowy (opcjonalnie podając plik konfiguracyjny)
2. Panel rejestruje się, wysyłając komunikat stacji zarządzającej
3. Panel otrzymuje harmonogram i treści do wyświetlenia
4. Panel wyświetla zlecane treści
### Zarządzanie harmonogramem oraz wyświetlanymi treściami
1. Użytkownik, za pośrednictwem stacji zarządzające, modyfikuje informacje o harmonogramie lub treściach
2. Stacja zarządzająca wysyła aktualne dane do paneli
3. Panele wyświetlają treści zgodnie z otrzymanym harmonogramem
### Zlecenie natychmiastowego wyświetlenia informacji
1. Użytkownik, za pośrednictwem stacji zarządzające, zleca natychmiastowe wyświetlenie informacji podanej podgrupie paneli
2. Stacja zarządzająca wysyła treść do natychmiastowego wyświetlenia
3. Panele wyświetlają żądaną treść, ignorując treści wynikające z harmonogramu
## Obsługa błędów
### Brak harmonogramu / błędny harmonogram
Panel będzie wyświetlał `default content`, w logach zostanie zarejestrowana odpowiednia informacja i będą następowały regularne próby uzyskania harmonogramu.
### Stacja zarządzająca nie odpowiada na komunikat
1. Cykliczne ponawianie komunikatu
2. Zamknięcie aplikacji po wyczerpaniu prób
Konfigurowalne parametry:
```
num_retries = 5 # ilość ponowień komunikatu (-1 = nie przerywaj)
timeout = 30 # odstęp pomiędzy komunikatami w sekundach
```
### Brak pliku konfiguracyjnego
Wyświetlenie odpowiedniej informacji zwrotnej użytkownikowi i zamknięcie aplikacji.
### Błąd transmisji danych
W przypadku gdy w wyniku błędu sieciowego jeden lub więcej pakietów zostanie zagubiony, odbiorca wyśle komunikat z prośbą o ponowne przesłanie brakujących segmentów.
## Środowisko programistyczne
Projekt zostanie zrealizowany na systemie operacyjnym Ubuntu 20.04 LTS, w języku C++17. Do testów zostanie wykorzystana biblioteka GoogleTest, a do debugowania programy gdb, valgrind oraz Wireshark. Do budowania projektu zostaną wykorzystane CMake oraz g\+\+.
Do logowania użyjemy biblioteki Loguru https://github.com/emilk/loguru.
## Architektura
### Stacja zarządzająca

### Panel

**Odbiorca komunikatów**
Odbiera pakiety z gniazda UDP, formuje z nich komunikaty, weryfikuje je, a następnie wysyła do kontrolera.
**Nadawca komunikatów**
Odbiera dane od kontrolera, formuje z nich pakiety i wysyła je przez gniazdo UDP.
**Kontroler**
Główny moduł zarządzający. Koordynuje on pracę reszty modułów, przekierowuje komunikaty, tworzy wątki do
obsługi żądań, przekazuje polecenia do sterownika ekranu.
**Kontroler CLI**
Odbiera polecenia podawane na standardowe wejście.
**Baza danych**
Baza danych przechowująca informacje na temat: harmonogramu, wyświetlanych treści.
Aby nie komplikować niepotrzebnie rozwiązania użyjemy SQLite.
## Przesyłanie danych
### Architektura komunikatów
#### Problemy
* jak obsłużyć komunikaty różnych typów
* aby łatwo obsługiwać współbieżność, należałoby zapewnić bezstanowość komunikacji po stronie serwera
* jak czytać komunikaty o różnych długościach
#### Rozwiązania
* 4 pierwsze bajty -> identyfikator komunikatu (np. MDAT - dane multimedialne)
* w każdym komunikacie do serwera klient podaje czego oczekuje, np. trzeba dosłać fragmenty pliku o nr 3, 5, 13
* czytamy po 4 bajty do momentu aż przeczytamy cały identyfikator, a następnie odczytamy tyle bajtów, ile zajmuje odpowiednia struktura
#### Przykładowy komunikat
```cpp
struct __attribute__ ((__packed__)) Multimedia {
uint8_t tag[4] = "MDAT";
uint8_t data[508];
};
```
### Pliki multimedialne
Pliki multimedialne są zbyt duże, żeby przesyłać je w jednym datagramie. Należy je zatem podzielić. Przesyłając plik w kawałkach, może się okazać, że część pakietów nie dotrze albo pakiety dotrą w innej kolejności. Aby rozwiązać ten problem zamierzamy:
* numerować pakiety
* w każdym pakiecie podawać numer pierwszego i ostatniego pakietu w sekwencji
* w ramach optymalizacji uprzednio podzielić pliki na kawałki i tak przechowywać je w bazie danych
## Sposób testowania
Do testowania wykorzystany zostanie moduł do Wiresharka, za pomocą którego badać będziemy, czy stacja zarządzająca i panele wysyłają odpowiednie komunikaty oraz czy ich zawartość jest zgodna z oczekiwaniami. Na przykład podczas uruchamiania panelu, oczekiwać będziemy, że zostanie wysłany komunikat do stacji zarządzającej, którego zawartość będzie zgodna z konfiguracją panelu, oraz że stacja kontrolna odeśle adekwatną odpowiedź.
Przydatne również mogą okazać się logi stacji zarządzającej, z którym będziemy mogli próbować odczytać jakie akcje stacja wykonuje.
## Sposób demonstracji rezultatów
### Demonstracja działania dystrybucji harmonogramów oraz treści
1. Uruchomienie stacji zarządzającej
2. Podłączenie panelu do działającej stacji zarządzającej
3. Zlecenie przesłania harmonogramu oraz treści, za pośrednictwem interfejsu tekstowego stacji zarządzającej
4. Zaprezentowanie panelu wyświetlającego wskazane treści, zgodnie z harmonogramem
### Demonstracja działania dystrybucji ważnych treści
1. Uruchomienie stacji zarządzającej
2. Podłączenie kilku paneli o różnych nazwach i tagach do działającej stacji zarządzającej
3. Zlecenie wyświetlenia pilnej treści panelowi o wskazanej nazwie
4. Zaprezentowanie panelu wyświetlającego żądaną treść
5. Zlecenie wyświetlenia pilnej treści podzbiorowi paneli o wskazanym tagu
6. Zaprezentowanie paneli wyświetlających żądaną treść
7. Wysłanie żądania wyświetlania treści zgodnie z harmonogramem
8. Pokazanie paneli, wyświetlających treści według harmonogramu
9. Próba zlecenia wyświetlenia ważnej treści nieistniejącemu panelowi
10. Prezentacja informacji o nieistniejącym panelu w interfejsie tekstowym
### Demonstracja działającego mechanizmu wyłączania paneli
1. Uruchomienie stacji zarządzającej
2. Podłączenie kilku paneli do działającej stacji zarządzającej
3. Zlecenie wyświetlenia pilnej treści panelowi o wskazanej nazwie
4. Zaprezentowanie paneli wyświetlających treści
5. Wyłączenie jednego z paneli
6. Zlecenie wyświetlenia pilnej treści wyłączonemu panelowi
7. Prezentacja informacji o nieistniejącym panelu w interfejsie tekstowym oraz pozostałych, działających paneli
## Podział prac w zespole
* **Rafał Kulus** -- warstwa abstrakcji na systemowe gniazda UDP (multicast, unicast), wielowątkowa obsługa żądań
* **Damian Kolaska** -- odbieranie i nadawanie komunikatów, interfejs tekstowy, testy integracyjne
* **Kamil Przybyła** -- moduł do Wiresharka, baza danych
## Harmonogram prac
* Do 27 kwietnia - dokumentacja wstępna
* 19-26 maja - działająca dystrybucja harmonogramów oraz wyświetlanie treści przez panele
* Do 1 czerwca - wysyłanie ważnych treści oraz komunikacja z warstwą składowania danych
* Do 7 czerwca - dokumentacja końcowa