7.6 KiB
Mila
Mila — небольшая Go-библиотека для обмена данными между БВК и медиакомплексом.
Библиотека реализует HTTP-протокол, в котором БВК отправляет в медиакомплекс текущее состояние отображаемого контента:
GET /set-content?route=<R>&str=<S>&tpl_name=<T>
GET /get-content
Mila намеренно не знает ничего про снапшоты, геопозицию, прогресс маршрута, фронтенд, правила воспроизведения медиа и структуру контента White Nights. Она только принимает, валидирует, сохраняет, логирует и возвращает состояние, полученное от БВК.
Установка
go get gitea.unprism.ru/KRBL/mila
Зона Ответственности
Mila — библиотека протокола. Ее нужно встраивать в прикладной сервис, например
в wn-content, и открывать на адресе, который требуется транспортной
интеграцией.
Mila делает:
- разбирает
GET /set-content; - разбирает
GET /get-content; - валидирует
route,strиtpl_name; - декодирует URL-параметры стандартным HTTP-парсером Go;
- хранит последнее состояние в памяти или JSON-файле;
- возвращает JSON, совместимый с протоколом;
- логирует каждый HTTP-запрос: метод, путь, статус, удаленный адрес и время;
- вызывает опциональный callback после успешного
set-content.
Mila не делает:
- не считает прогресс маршрута;
- не работает с геопозицией или NMEA;
- не сопоставляет
tpl_nameс реальными плейлистами; - не читает и не пишет снапшоты;
- не общается с фронтендом напрямую;
- не решает, как именно должен отображаться контент.
Протокол
Медиакомплекс выступает HTTP-сервером. БВК выступает HTTP-клиентом.
Адрес по документу:
172.16.16.2:13280
Ручки:
GET /set-content?route=<R>&str=<S>&tpl_name=<T>
GET /get-content
set-content принимает URL-encoded query-параметры:
| Параметр | Обязательный | Описание |
|---|---|---|
route |
да | номер маршрута, по умолчанию 1-3 символа |
str |
нет | текст бегущей строки, по умолчанию до 200 символов |
tpl_name |
да | название шаблона медиаконтента, по умолчанию до 200 символов |
Ответ get-content:
{
"route": "3",
"str": "Гостиный двор - Gostiny dvor",
"tpl_name": "Гостиный двор"
}
Поле updated_at хранится внутри состояния, но не отдается через
/get-content, потому что ответ должен оставаться строгим относительно
протокола.
Использование
package main
import (
"log"
"net/http"
"gitea.unprism.ru/KRBL/mila"
)
func main() {
store := mila.NewFileStore("/srv/persistence/client_logs/bvk_content.json")
handler := mila.NewHandler(mila.DefaultConfig(), store,
mila.WithOnSet(func(state mila.ContentState) {
// Здесь прикладная интеграция:
// - передать route/str/tpl_name в состояние приложения;
// - сопоставить state.Template с локальным шаблоном;
// - записать дополнительные логи.
}),
)
srv := &http.Server{
Addr: "0.0.0.0:13280",
Handler: handler,
}
log.Fatal(srv.ListenAndServe())
}
Конфигурация
Конфигурация валидации по умолчанию:
cfg := mila.DefaultConfig()
Сейчас это:
mila.Config{
MaxRouteLen: 3,
MaxTextLen: 200,
MaxTemplateLen: 200,
}
Лимиты для str и tpl_name нужно подтвердить у интегратора. В переданном PDF
текстовый слой неоднозначно распознает исходное значение.
Хранилища
MemoryStore подходит, когда состояние не должно переживать рестарт процесса:
store := mila.NewMemoryStore()
FileStore подходит для устройства, если последнее состояние от БВК нужно
сохранять на диске:
store := mila.NewFileStore("/srv/persistence/client_logs/bvk_content.json")
FileStore пишет состояние атомарно через временный файл и держит копию в
памяти после первого успешного чтения или записи.
Callback
WithOnSet позволяет приложению отреагировать на валидное обновление от БВК:
handler := mila.NewHandler(mila.DefaultConfig(), store,
mila.WithOnSet(func(state mila.ContentState) {
// Возможные действия на стороне приложения:
// - опубликовать номер маршрута и бегущую строку;
// - сопоставить state.Template с локальным плейлистом;
// - записать прикладные логи.
}),
)
Callback выполняется синхронно. Его нужно держать быстрым. Если интеграционная логика тяжелая, лучше положить состояние во внутреннюю очередь.
Модель Состояния
{
"route": "3",
"str": "Гостиный двор - Gostiny dvor",
"tpl_name": "Гостиный двор",
"updated_at": "2026-07-12T12:00:00Z"
}
Go-тип:
type ContentState struct {
Route string `json:"route"`
Text string `json:"str"`
Template string `json:"tpl_name"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Коды Ответов
| Код | Когда возвращается |
|---|---|
| 200 | валидный set-content или готовый get-content |
| 400 | невалидные параметры запроса |
| 404 | неизвестный путь |
| 405 | метод не GET |
| 500 | ошибка хранилища или внутренняя ошибка |
| 503 | get-content до первого состояния, отмененный контекст, недоступная зависимость |
Формат ошибки:
{
"error": "route: must be at most 3 characters"
}
Тестирование
go test ./...
Текущие тесты покрывают:
- успешный
set-content+get-content; get-contentдо готовности состояния;- невалидный
route; - UTF-8 и лимиты для текста/шаблона;
- сохранение и чтение через
FileStore; - отсутствие файла состояния в
FileStore.