Dane na żywo · usługa publiczna

Mapa alertów — dane na żywo, które inne strony osadzają

Mapa alertów powietrznych, gdzie strona jest tylko częścią produktu. Alerty, ruchome cele, linia frontu i punkty termalne pochodzą z pięciu niezależnych źródeł, odświeżają się na własnych zegarach — 15, 10 i 20 sekund — i wychodzą przez otwarte API JSON oraz widget, który inne strony internetowe umieszczają w swoim ramce.

Kategoria
Dane na żywo · usługa publiczna
Szacowany koszt
od 20 000 €
Odśwież
alerty 15 s · cele 10 s · kanał 20 s
Źródła
pięć, niezależnych od siebie
Stos
PHP 8.3, pracownicy Pythona, SQLite, Leaflet
map.megainet.art
Mapa powiadomień
Strona projektu — map.megainet.art

01Przegląd projektu

Mapa powiadomieńpokazuje, gdzie obecnie jest alarm powietrzny: według obwodu i powiatu, z ruchomymi celami na mapie, linią frontu, punktami termalnymi z satelitów oraz kanałem monitorującym poniżej. Jest czytany przez ludzi, którzy potrzebują odpowiedzi w ciągu sekund, i jest czytany na telefonie, w nocy, przy słabym internecie mobilnym.

Strona jest jednak tylko częścią produktu. Te same dane wychodzą przez otwarte API JSON z kluczami i limitami, oraz przez widget, który inne strony internetowe osadzają w swoim własnym ramce. Zaprojektowaliśmy i zbudowaliśmy to wszystko: zbieracze, magazyn, API, mapę i widget.

02Kontekst i problem

Dane, które odpowiadają na pytanie «czy jest tutaj alarm», nie istnieją w jednym miejscu. Oficjalne alarmy pochodzą według obwodu. Lokalne alarmy dla społeczności pochodzą z innej usługi. Gdzie są cele, jest zapisane, słowami, przez kanały monitorujące. Linia frontu jest publikowana przez projekt mapowy. Pożary są widziane przez satelity. Pięć źródeł, pięć formatów, pięć różnych pomysłów na to, co oznacza «teraz».

Drugim problemem jest cisza. Każde z tych źródeł może przestać działać — kanał milknie, API zaczyna się czasowo wyłączać — a uczciwym trybem awaryjnym jest powiedzenie o tym, a nie rysowanie wczorajszego obrazu. Mapa, która wygląda spokojnie, ponieważ jej źródło umarło, jest gorsza niż brak mapy.

03Cele projektu

  • jedno zdjęcie złożone z pięciu niezależnych źródeł, każde na własnym zegarze odświeżania;
  • odpowiedź w ciągu sekund na telefonie, przy słabym połączeniu, w nocy;
  • dane, które mogą opuścić stronę: otwarte API z kluczami, limitami i taryfami, oraz osadzany widget;
  • trzy języki, ponieważ publiczność nie jest tylko lokalna;
  • źródło, które zamilkło, musi być widoczne jako milczące, a nie jako spokojne;
  • adres serwera nigdy nie powinien docierać do źródeł, które odczytuje.

04Pięć źródeł, jeden obrazek

  • Oficjalne powiadomienia według obwodu — kręgosłup mapy;
  • lokalne powiadomienia dla społeczności i dzielnic, z osobnej usługi;
  • kanały monitorujące w Telegramie — czytaj zarówno z publicznych podglądów, jak i, dla zamkniętych kanałów, przez sam protokół wiadomości;
  • linia frontu, z projektu mapowania, który go publikuje;
  • punkty termalne z satelit NASA — pożary widziane z orbity.

Kolektory działają jako dwóch długożyjących pracowników pod nadzorem systemu, każdy uruchamiany na nowo samodzielnie, i zapisują w lokalnej pamięci. Strona internetowa nigdy nie komunikuje się bezpośrednio ze źródłem: odczytuje to, co kolektory już zapisały, dlatego wolne źródło sprawia, że mapa staje się starsza, a nie niedostępna.

05Cztery pliki zamiast jednej bazy danych

Dane znajdują się w czterech oddzielnych plikach SQLite: dziennik alertów, subskrypcje push i ich stan per region, wydarzenia mapy z kanałem oraz klucze API z ich licznikami. Nie ma wspólnej bazy danych celowo — awaria jednego pliku nie może zablokować innych. Jeśli subskrypcje push są niedostępne, mapa nadal się rysuje; jeśli magazyn kluczy jest zajęty, strona nadal odpowiada.

Te same pliki są zapisywane przez panel sterowania całej grupy — wydawanie klucza, resetowanie stanu alertu — więc każde połączenie otwiera się z czasem oczekiwania. SQLite rezygnuje natychmiast z zajętej bazy danych domyślnie, a «natychmiast» tutaj oznaczałoby stronę błędu, podczas gdy pracownik jedynie zapisywałby wiersz.

06Trzy zegary na jednej stronie

Różne dane starzeją się w różnym tempie, więc odświeżają się w różnym tempie: alerty co 15 sekund, poruszające się cele co 10, kanał co 20. Jeden wspólny interwał byłby błędny w obu kierunkach jednocześnie — zbyt wolny dla celów, marnotrawny dla kanału i niepotrzebne żądanie co kilka sekund dla tysięcy otwartych kart.

Każdy blok ma również własny «ostatnio zaktualizowany». Strona, która cicho się przerysowuje, uczy cię ufać jej dokładnie wtedy, gdy nie powinna być ufana; znacznik czasu, który przestaje się poruszać, jest najszybszym sposobem, aby powiedzieć «ta część jest nieaktualna».

07Otwarte API z kluczami i taryfami

Mapa publikuje to, co wie: aktualne alerty, wydarzenia, punkt analityczny z mapą cieplną «oblast × koszyk czasowy», rytm dnia, typy celów i kierunki. Anonimowi dzwoniący mają skromny limit na minutę; klucz go podnosi, a taryfy rosną w krokach dla tych, którzy na tym budują.

Klucze są wydawane z wspólnego panelu sterowania, nigdy wpisywane ręcznie, a użycie liczone jest na klucz dziennie. Jeden punkt końcowy jest celowo zamknięty dla wszystkich oprócz właściciela klucza — tego, który informuje klucz o jego własnej taryfie, limicie i zużyciu. Wszystko inne jest otwarte, ponieważ mapa publiczna, która ukrywa swoje dane, jest tylko w połowie usługą publiczną.

08Widget, który żyje na stronach innych osób

Widget to część produktu, która opuszcza dom. Dwa stałe rozmiary — pasek statusu i kwadratowy panel — trzy języki, dwa motywy i polityka ramki napisana specjalnie tak, aby osadzenie było dozwolone tutaj i nigdzie indziej na stronie: mapa i widget mogą być osadzone, konto i strony wsparcia nie mogą.

Ponieważ żyje w ramce, widget nie ma własnych ciasteczek i nie wybiera generacji interfejsu: wygląda tak samo dla wszystkich. To jest decyzja, a nie ograniczenie — widget, który renderuje się inaczej w zależności od wcześniejszych wyborów odwiedzającego, byłby niemożliwy do wsparcia na stronie kogoś innego.

09Powiadomienie, które zna Twój region

Subskrypcja jest związana z regionem, a stan każdego regionu jest przechowywany obok subskrypcji. To sprawia, że powiadomienie przychodzi na krawędź — gdy alert w twojej obwodzie zaczyna się lub kończy — zamiast przy każdym odświeżeniu źródła. Różnica to cały produkt: jedno to sygnał, drugie to hałas, który ludzie wyłączają w ciągu dnia.

Istnieje natywna aplikacja oparta na tych samych danych, która komunikuje się z API aplikacji, a nie z stronami internetowymi. Własny punkt końcowy zdrowia odpowiada rejestracji floty, ponieważ sprawdzenie żywotności nie może być droższe niż praca, którą sprawdza.

10Trzy języki, w tym widget

Mapa mówi po ukraińsku, angielsku i rosyjsku, podobnie jak dokumentacja API, strony konta i widget. Nowy ciąg interfejsu jest dodawany do wszystkich trzech jednocześnie, a sprawdzenie liczy brakujące: liczba musi wynosić zero. Półprzetłumaczone interfejsy nie ogłaszają się — cicho pokazują jeden język w innym i wyglądają dobrze dla tego, kto je napisał.

Nazwy regionów to osobna historia: pochodzą z źródeł w swoim własnym zapisie, więc mapa utrzymuje własny słownik, zamiast ufać temu, co przychodzi w strumieniu.

11Czytanie źródeł bez pokazywania swojego adresu

Wszystko, co zbieracze pobierają, przechodzi przez proxy SOCKS5, w tym protokół wiadomości używany do zamkniętych kanałów — proxy tam jest realizowane w kodzie, bez dodatkowych zależności. Adres serwera nigdy nie dociera do źródła, a źródło, które decyduje się zablokować kogoś, blokuje proxy, a nie maszynę, która obsługuje mapę.

Ogranicznik szybkości znajduje się przed API z tego samego powodu w odwrotnej kolejności: publiczny punkt końcowy z danymi na żywo przyciąga skrypty, a limit na klucz na minutę to to, co utrzymuje publiczną usługę użyteczną dla ludzi, dla których została napisana.

12Stos technologiczny

  • PHP 8.3 bez frameworka: mały router, punkty końcowe i renderery;
  • Pracownicy Pythona pod nadzorem systemu — jeden tylko na standardowej bibliotece, jeden mówiący protokołem wiadomości;
  • SQLite, cztery oddzielne pliki, każdy z własnym powodem istnienia;
  • Leafletdla mapy, haszowane zasoby, widget o stałych rozmiarach;
  • powiadomienia webowe z stanem per-region, natywna aplikacja na tych samych danych;
  • wyjście SOCKS5 dla każdego wychodzącego żądania, limity szybkości per-klucz przed API.

13Wynik

Mapa, która odpowiada w ciągu kilku sekund i nadal odpowiada, gdy jedno z pięciu źródeł przestaje działać. Dane, które mogą wykorzystać inne strony: otwarte API z kluczami i taryfami oraz widget w trzech językach i dwóch motywach. Powiadomienia, które uruchamiają się na krawędzi zdarzenia, a nie przy każdym zapytaniu. Natywna aplikacja na tych samych danych oraz panel sterowania, w którym wydawane są klucze i resetowane stany.

14Wnioski

Trzy rzeczy, które zabralibyśmy do każdego projektu z danymi na żywo.Oddziel kolektor od strony: strona internetowa, która pobiera źródło, podczas gdy odwiedzający czeka, to strona, która przestaje działać, gdy źródło przestaje działać.Daj każdemu blokowi własny zegar i własny znacznik czasu: pojedynczy interwał jest błędny w obu kierunkach, a cicha ponowna rysowanie ukrywa przestarzałość.Powiedz, kiedy nie wiesz: pusty blok, który to przyznaje, jest więcej wart niż spokojnie wyglądająca mapa z danymi z wczoraj.

I jedna lekcja dotycząca produktu: w momencie, gdy dane mogą być osadzone gdzie indziej, widget staje się produktem. Potrzebuje stałych rozmiarów, własnej polityki ramkowej i tłumaczeń — tej samej troski co strona główna, a nie pozostałości po niej.

Jeśli masz dane na żywo i potrzebujesz mapy, API i widgetu, które inne strony mogą wykorzystać, to jest rodzaj pracy, którą wykonujemy od początku do końca.