Files
mila/README.md

4.9 KiB

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, and tpl_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_name to 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-content before state is ready
  • invalid route validation
  • UTF-8 text/template validation
  • file store persistence
  • missing file store state