Mila
Mila is a small Go library for BVK media-complex content exchange.
It implements the HTTP protocol where BVK pushes the currently displayed content state to the media complex:
GET /set-content?route=<R>&str=<S>&tpl_name=<T>
GET /get-content
The library intentionally does not know anything about snapshots, route progress, geolocation, frontend state, or media playback rules. It only parses, validates, stores, logs, and returns BVK content state.
Install
go get gitea.unprism.ru/KRBL/mila
Scope
Mila is a protocol library. It should be embedded into an application service,
for example wn-content, and exposed on the address required by the transport
integration.
Mila does:
- parse
GET /set-content - parse
GET /get-content - validate
route,str, andtpl_name - URL-decode query parameters through Go's standard HTTP parser
- store the latest state in memory or in a JSON file
- return protocol-compatible JSON
- log each HTTP request with method, path, status, remote address, and duration
- call an optional callback after successful
set-content
Mila does not:
- calculate route progress
- work with geolocation or NMEA
- map
tpl_nameto real media playlists - read or write snapshots
- communicate with frontend directly
- decide how content should be rendered
Protocol
The media complex acts as an HTTP server. BVK acts as an HTTP client.
Default address from the PDF:
172.16.16.2:13280
Endpoints:
GET /set-content?route=<R>&str=<S>&tpl_name=<T>
GET /get-content
set-content accepts URL-encoded query parameters:
| Parameter | Required | Meaning |
|---|---|---|
route |
yes | route number, default limit is 1-3 characters |
str |
no | ticker/running text, default limit is 200 characters |
tpl_name |
yes | media content template name, default limit is 200 characters |
get-content response:
{
"route": "3",
"str": "Гостиный двор - Gostiny dvor",
"tpl_name": "Гостиный двор"
}
updated_at is stored internally but is not exposed by /get-content, because
the protocol response should stay strict.
Usage
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) {
// Application-specific integration goes here.
}),
)
srv := &http.Server{
Addr: "0.0.0.0:13280",
Handler: handler,
}
log.Fatal(srv.ListenAndServe())
}
Configuration
Default validation config:
cfg := mila.DefaultConfig()
Which currently means:
mila.Config{
MaxRouteLen: 3,
MaxTextLen: 200,
MaxTemplateLen: 200,
}
The text/template limits should be confirmed with the integrator. The provided PDF has an ambiguous text layer for those values.
Stores
Use MemoryStore when state does not need to survive process restart:
store := mila.NewMemoryStore()
Use FileStore on a device when the latest BVK state should be persisted:
store := mila.NewFileStore("/srv/persistence/client_logs/bvk_content.json")
FileStore writes atomically through a temporary file and keeps an in-memory
copy after the first successful read or write.
Callback
WithOnSet lets the host application react to a valid BVK update:
handler := mila.NewHandler(mila.DefaultConfig(), store,
mila.WithOnSet(func(state mila.ContentState) {
// Example host-side decisions:
// - publish route and ticker to frontend state
// - map state.Template to a local playlist/template
// - write application-specific logs
}),
)
The callback is intentionally synchronous. Keep it fast; if integration work is heavy, push the state into an internal queue.
State Model
{
"route": "3",
"str": "Гостиный двор - Gostiny dvor",
"tpl_name": "Гостиный двор",
"updated_at": "2026-07-12T12:00:00Z"
}
Go type:
type ContentState struct {
Route string `json:"route"`
Text string `json:"str"`
Template string `json:"tpl_name"`
UpdatedAt time.Time `json:"updated_at,omitempty"`
}
Status Codes
| Code | When |
|---|---|
| 200 | valid set-content or ready get-content |
| 400 | invalid request parameters |
| 404 | unknown path |
| 405 | method is not GET |
| 500 | store/internal error |
| 503 | get-content before first state, canceled/deadline context, unavailable dependency |
Error response:
{
"error": "route: must be at most 3 characters"
}
Testing
go test ./...
Current tests cover:
- successful
set-content+get-content get-contentbefore state is ready- invalid route validation
- UTF-8 text/template validation
- file store persistence
- missing file store state