Преминете към основното съдържание

Работа с Entrosity Sphere

Entrosity Sphere работи до Entrosity Hub, Axis и Edge на същия хост. Той е по избор за всеки хост: профилът sphere на compose съдържа услугите му, а скриптовете за разгръщане ги стартират само когато deploy/.env съдържа SPHERE_ENABLED=true (Включване на Sphere на хост).

ЧастКъде
Уеб приложение (entrosity-sphere.frontend)https://hub.entrosity.com/sphere/, обслужвано от Caddy от уеб образа
API (entrosity-sphere.backend, образ ghcr.io/entrosity/sphere-backend)https://hub.entrosity.com/sphere/api/…; Caddy премахва /sphere, така че бекендът обслужва /api/v1 (браузъри), /api/connector/v1 (конектори) и /api/releases/v1 (инсталатори на конектора: качване от CI, връзки за изтегляне с изтичащ срок)
Медиен сървър (MediaMTX)Конекторите публикуват на rtsps://media.entrosity.com:8322 (отделно DNS-only име на същия сървър, по-долу); браузърите договарят през https://hub.entrosity.com/sphere/media/… (WHEP) и получават медията на порт 8189 на публичния адрес на сървъра
База данниСобствена база данни в PostgreSQL (sphere), мигрирана от бекенда
ВлизанеEntrosity Hub, продукт sphere

Услуги​

deploy/docker-compose.prod.yml на entrosity-infra, профил sphere:

УслугаОбразКакво прави
sphere-db-initpostgres:18-alpineСъздава базата данни sphere (собственик rmm) веднъж.
sphere-migratesphere-backendИзпълнява migrate up като собственик и разрешава входа sphere_app със SPHERE_APP_DATABASE_PASSWORD.
spheresphere-backendsphere-server serve, една инстанция: конекторите държат WebSocket към нея, а уеб приложението – поток от събития. Публичен API на :8080 зад Caddy; hook-ът на медийния сървър на вътрешния слушател :8084 (Caddy никога не го маршрутизира); метрики на :9094. Проверка на здравето: sphere-server healthcheck. Ограничение на паметта SPHERE_MEMORY (512m), GOMEMLIMIT от SPHERE_GOMEMLIMIT (400MiB).
sphere-mediabluenviron/mediamtx, закрепен по таг и digestМедийният сървър (по-долу). Публикува 8189/udp и 8189/tcp на хоста. Ограничение на паметта SPHERE_MEDIA_MEMORY (1g). Стартира, след като sphere е здрав.

Услугата web (Caddy) обслужва и Sphere:

Път или портОтива към
/sphere/Уеб приложението (от образа sphere-frontend, вграден в уеб образа)
/sphere/api/*sphere:8080, с премахнат /sphere
/sphere/media/*sphere-media:8889 (WHEP), с премахнат /sphere/media; адресите на сесиите на медийния сървър се пренаписват обратно под /sphere/media
:8322 (TCP)Маршрут на ниво 4: Caddy терминира TLS със сертификата на SPHERE_MEDIA_DOMAIN и препраща чист RTSP към sphere-media:8554
SPHERE_MEDIA_DOMAIN (сайт)Съществува само за да може Caddy да получи сертификата на медийния хост (HTTP-01 на порт 80); отговаря с 404. Без Sphere сайтът е заместителят http://media.invalid.

Изпълнимият файл на бекенда е sphere-server:

sphere-server serve run the HTTP API and job workers (default)
sphere-server migrate [cmd] database migrations: up | down [N] | version | force N
(up also sets the sphere_app login password when
SPHERE_APP_DATABASE_PASSWORD is set)
sphere-server healthcheck exit 0 when this host's server is ready (/readyz), for
container health checks
sphere-server version print the version

В Hub продуктът sphere (роли tenant_admin, operator, viewer) се регистрира от миграция 0006 на Hub като изключен и в бета версия и се включва от миграция 0007 (Въвеждане). Hub трябва да знае токена на Sphere: PLATFORM_PRODUCT_TOKENS съдържа sphere:<token> със същата стойност като SPHERE_PLATFORM_TOKEN. В продукция и двете идват от PLATFORM_PRODUCT_TOKEN_SPHERE в deploy/.env.

Справочник на конфигурацията​

Бекендът се конфигурира само чрез променливи на средата SPHERE_* (entrosity-sphere.backend/internal/config). Невалидни стойности спират стартирането със списък на всички проблеми. Разделът RETENTION приема едно или две долни тирета: SPHERE_RETENTION_ALARM_DAYS = SPHERE_RETENTION__ALARM_DAYS.

Сървър​

ПроменливаПо подразбиранеЗначение
SPHERE_ENVdevdev, test или prod. prod отказва примерните тайни за разработка и пише журнала в JSON.
SPHERE_PUBLIC_URLhttp://localhost:8083Публичният адрес на Sphere, включително представката /sphere, която проксито премахва (https://hub.entrosity.com/sphere). Конекторите получават <SPHERE_PUBLIC_URL>/api/connector/v1/ws, а командите за инсталиране, показвани с нови токени за регистриране, го използват като SERVER_URL.
SPHERE_HTTP_ADDR:8083Слушател на API (продукция: :8080).
SPHERE_INTERNAL_ADDR:8084Вътрешен слушател за hook-а за удостоверяване на медийния сървър (POST /media/auth). Никога не го маршрутизирайте публично.
SPHERE_METRICS_ADDR:9094Вътрешен слушател за Prometheus /metrics. Никога не го излагайте публично; празно го изключва.
SPHERE_LOG_LEVELinfodebug, info, warn или error.
SPHERE_CORS_ORIGINShttp://localhost:5177Разрешени произходи (origins) на браузъри, разделени със запетая, без заместващи символи и пътища (продукция: https://hub.entrosity.com).
SPHERE_TRUSTED_PROXIESнямаCIDR или IP адреси, на които е разрешено да задават X-Forwarded-For (продукция: мрежата на compose 172.30.0.0/24).
SPHERE_API_RATE_PER_SECOND, SPHERE_API_RATE_BURST20, 60Ограничение на заявките към уеб API за IP адрес на клиент (офис зад един NAT адрес го споделя).
SPHERE_ENROLL_RATE_PER_MINUTE60Регистрирания на конектори за IP адрес на клиент.
SPHERE_CONNECTOR_DOWNLOAD_URLнямаОткъде може да се изтегли MSI на конектора; показва се с новите токени за регистриране, докато няма съхранено издание на конектора (Издания на конектора).

База данни​

ПроменливаПо подразбиранеЗначение
SPHERE_DATABASE_URLняма (задължителна)URL за връзка. Продукцията се свързва като sphere_app.
SPHERE_DATABASE_ROLEsphere_appРолята, към която пулът превключва след свързване (SET ROLE), така че защитата на ниво ред важи дори при връзка като собственик. Празно, когато входът вече е ролята на приложението и не може да превключва.
SPHERE_DATABASE_MAX_CONNS20Размер на пула.
SPHERE_DATABASE_STATEMENT_TIMEOUT30sГорна граница за всяка заявка.
SPHERE_APP_DATABASE_PASSWORDнямаЧете се от migrate up: разрешава входа sphere_app с тази парола.

Тайни​

ПроменливаЗначение
SPHERE_JWT_SECRETЗадължителна. Поне 32 байта, сурови или base64. Подписва едноминутните токени за потока с обновления на живо (POST /auth/sse-token) и петминутните медийни токени, с които браузърите възпроизвеждат видео. Токените за достъп на потребителите идват от Hub.
SPHERE_JWT_SECRET_OLDПредишната тайна по време на смяна (все още се проверява).
SPHERE_CREDENTIALS_KEYЗадължителна. Точно 32 байта, base64: криптира паролите на видеорекордерите в базата данни (AES-256-GCM; ID на видеорекордера е свързан с шифрования текст, така че шифрован текст, копиран към друг видеорекордер, не се декриптира).
SPHERE_CREDENTIALS_KEY_OLDПредишният ключ по време на смяна: той още декриптира; новите и променените пароли използват текущия ключ.

При SPHERE_ENV=prod стойностите, съдържащи dev-only (примерите за разработка), се отказват.

Пазете ключа за идентификационните данни

Без SPHERE_CREDENTIALS_KEY (или с друг ключ) нито една парола на видеорекордер не може да бъде декриптирана: конекторите не могат да влязат в нито един видеорекордер, докато всички пароли не бъдат въведени отново. Пазете копие на deploy/.env заедно с резервните копия.

Влизане чрез Entrosity Hub​

ПроменливаПо подразбиранеЗначение
SPHERE_PLATFORM_URLняма (задължителна)Публичният произход на Hub (https://hub.entrosity.com): издателят на токените за продукт и мястото, където браузърите влизат.
SPHERE_PLATFORM_INTERNAL_URLняма (задължителна)Вътрешният API на Hub, достъпван директно, а не през проксито (compose: http://platform:8081): ключове за подписване и моментната снимка на достъпа.
SPHERE_PLATFORM_TOKENняма (задължителна)Bearer токенът на Sphere за вътрешния API на Hub, поне 32 знака; sphere:<token> в PLATFORM_PRODUCT_TOKENS на Hub.
SPHERE_PLATFORM_SYNC_INTERVAL30sКолко често Sphere изтегля потребителите, организациите и ролите от Hub (поне 1s).

Медия и потоци​

ПроменливаПо подразбиранеЗначение
SPHERE_MEDIA_PUBLISH_URLrtsp://localhost:8554Къде публикуват конекторите: rtsp(s)://host:port, без път (продукция: rtsps://media.entrosity.com:8322). Изпраща се на конектора с всяко стартиране на поток.
SPHERE_MEDIA_WHEP_URL/sphere/mediaОсновата, от която възпроизвеждат браузърите, <base>/<path>/whep: път в произхода на Sphere или абсолютен URL, без наклонена черта накрая.
SPHERE_MAX_STREAMS_PER_CONNECTOR64Едновременно отворени потоци (на живо и записи) на конектор: капацитетът за качване на обекта. 64 запълват мрежа 8×8.
SPHERE_MAX_MAIN_STREAMS_PER_NVR4Потоци на живо с пълна резолюция на видеорекордер.
SPHERE_MAX_PLAYBACKS_PER_NVR4Възпроизвеждания на записи на видеорекордер (видеорекордерите обслужват малко едновременно).
SPHERE_LIVE_IDLE_GRACE5mКолко дълго продължава подпоток на живо, който никой не гледа, така че връщането към камерата пропуска стартирането във видеорекордера. Продължителност в Go, поне 10s (досега фиксирано 30 секунди).
SPHERE_LIVE_IDLE_GRACE_MAIN2mСъщото за основните потоци. Поне 10s.

Неизползваните потоци струват от капацитета за качване на обекта, докато вървят, и се броят към ограниченията. При достигнато ограничение (SPHERE_MAX_STREAMS_PER_CONNECTOR или SPHERE_MAX_MAIN_STREAMS_PER_NVR) неизползваният поток на живо, който не е гледан най-дълго, се спира, за да освободи място; потоци със зрители никога не се спират, а възпроизвежданията на записи никога не остават неизползвани (спират, когато зрителят им излезе). Само когато никой неизползван поток не може да освободи място, заявката на зрителя връща 409 stream_limit. Конекторът има собствено ограничение (SPHERE_CONNECTOR_MAX_STREAMS, по подразбиране 64; Конектор на Sphere).

Обновявания на конектора​

ПроменливаПо подразбиранеЗначение
SPHERE_RELEASE_SIGNING_KEYнямаПодписва изданията на конектора: ключ Ed25519, base64 на 32-байтовото начално число (seed) или на 64-байтовия частен ключ. Публичната му половина е RELEASE_PUBLIC_KEY, с който се компилират конекторите. Празна стойност изключва качването и самообновяването (качванията връщат 503 releases_disabled). Невалидна стойност спира сървъра.
SPHERE_RELEASE_TOKENнямаBearer токенът на CI за качване на версии на конектора (POST /api/releases/v1/connector), поне 32 знака. Празна стойност: всяко качване връща 401.
SPHERE_CONNECTOR_UPDATE_CHANNELstableДо какво се обновяват конекторите (и какво предлага Изтегляне на конектора): stable (само издания с етикет) или dev (версии за разработка и издания с етикет). Продукционният compose файл задава dev, докато Sphere е в бета.

Вижте Издания на конектора.

Срокове за съхранение​

ПроменливаПо подразбиранеЗначение
SPHERE_RETENTION_ALARM_DAYS365Журнал с аларми.
SPHERE_RETENTION_JOB_DAYS90Приключили задачи на конекторите. Тенантите могат да го заменят (7–730).
SPHERE_RETENTION_AUDIT_DAYS365Одитен журнал. Тенантите могат да го заменят (30–3650).

0 или незададена стойност запазва стойността по подразбиране.

Настройки на хоста​

В продукция файлът на compose фиксира повечето от горните (SPHERE_PUBLIC_URL=https://${PLATFORM_DOMAIN}/sphere, SPHERE_MEDIA_PUBLISH_URL=rtsps://${SPHERE_MEDIA_DOMAIN}:8322, слушателите, доверените проксита). deploy/.env (deploy/.env.prod.example ги изброява) задава останалото:

ПроменливаЗначение
SPHERE_ENABLEDtrue пуска профила sphere. По подразбиране false.
SPHERE_APP_DATABASE_PASSWORDПаролата на входа sphere_app. Задължителна, когато е включен.
SPHERE_JWT_SECRET, SPHERE_JWT_SECRET_OLDКакто по-горе. Първата е задължителна, когато е включен.
SPHERE_CREDENTIALS_KEY, SPHERE_CREDENTIALS_KEY_OLDКакто по-горе. Първият е задължителен, когато е включен.
PLATFORM_PRODUCT_TOKEN_SPHEREТокенът на Sphere в Hub: става SPHERE_PLATFORM_TOKEN и записът sphere: в PLATFORM_PRODUCT_TOKENS на Hub. Задължителен, когато е включен.
SPHERE_MEDIA_DOMAINИмето на медийния хост, към което конекторите публикуват видео (media.entrosity.com): A запис, сочещ директно към този сървър, само DNS (без прокси). Използва се за SPHERE_MEDIA_PUBLISH_URL и се подава на услугата web, която получава сертификата му. Задължителна, когато е включен.
SPHERE_MEDIA_PUBLIC_IPПубличният IP адрес на хоста, който се обявява на браузърите като адрес на медията (webrtcAdditionalHosts). Задължителен, когато е включен.
SPHERE_MAX_STREAMS_PER_CONNECTOR, SPHERE_MAX_MAIN_STREAMS_PER_NVR, SPHERE_MAX_PLAYBACKS_PER_NVRОграничения на потоците (64, 4, 4).
SPHERE_LIVE_IDLE_GRACE, SPHERE_LIVE_IDLE_GRACE_MAINВреме, през което неизползваните потоци продължават (5m, 2m).
SPHERE_RELEASE_SIGNING_KEY, SPHERE_RELEASE_TOKENСамообновяване на конекторите, както по-горе. По избор: празни стойности го изключват (Включване на самообновяването на конекторите).
SPHERE_CONNECTOR_UPDATE_CHANNELКакто по-горе; на хоста по подразбиране dev, докато Sphere е в бета.
SPHERE_CONNECTOR_DOWNLOAD_URL, SPHERE_LOG_LEVELКакто по-горе.
SPHERE_BACKEND_IMAGEПо подразбиране ghcr.io/entrosity/sphere-backend.
SPHERE_MEMORY, SPHERE_GOMEMLIMIT, SPHERE_MEDIA_MEMORYОграничения на паметта: 512m, 400MiB, 1g.

Генериране на тайните​

openssl rand -base64 32 # SPHERE_JWT_SECRET, SPHERE_CREDENTIALS_KEY (exactly 32 bytes)
openssl rand -hex 32 # SPHERE_APP_DATABASE_PASSWORD, PLATFORM_PRODUCT_TOKEN_SPHERE, SPHERE_RELEASE_TOKEN

Ключът за подписване на изданията е двойка ключове: Включване на самообновяването на конекторите.

Паролата за базата данни попада в URL за връзка, затова използвайте стойност без /, + и = (hex). Токенът за продукта трябва да е поне 32 знака.

Портове и защитна стена​

Освен 443, Sphere има нужда от тези портове, отворени за входящи връзки в защитната стена на хоста:

ПортУслугаЗа
80/tcpweb (Caddy)Трябва да достига директно до сървъра на SPHERE_MEDIA_DOMAIN: Caddy получава сертификата на медийния хост с проверката HTTP-01.
8322/tcpweb (Caddy)Конекторите публикуват видео към SPHERE_MEDIA_DOMAIN: RTSP през TLS, терминиран от Caddy със сертификата на това име (конекторът го изпраща като SNI).
8189/udp и 8189/tcpsphere-mediaWebRTC медия към браузърите (за предпочитане UDP, TCP, когато UDP е блокиран).

Браузърите договарят WebRTC през /sphere/media на 443 и след това получават медията на 8189 на адреса SPHERE_MEDIA_PUBLIC_IP. Няма TURN сървър: зрител, чиято мрежа блокира изходящ 8189 (UDP и TCP), не вижда видео.

Зад Cloudflare (или друго прокси)​

hub.entrosity.com е зад проксито на Cloudflare, което препраща HTTP(S) на 443, но не и чист TCP на 8322, нито UDP или TCP на 8189. Затова:

  • Конекторите публикуват видео към отделно име на хост, само DNS, SPHERE_MEDIA_DOMAIN (media.entrosity.com): A запис, сочещ към сървъра, с изключено прокси (сивият облак на Cloudflare), както хоста за файлове. Caddy получава сертификата му през порт 80 и го представя на 8322.
  • Контролната връзка на конектора (WebSocket, задачи, аларми) остава на hub.entrosity.com:443, както и WebRTC договарянето на браузърите (/sphere/media, WHEP), което проксито препраща като всяка HTTPS заявка.
  • WebRTC медията минава директно от SPHERE_MEDIA_PUBLIC_IP на сървъра на 8189 към браузъра, никога през проксито.

Затова публичният IP адрес на сървъра става видим (чрез DNS записа на медийния хост и WebRTC кандидатите), както вече е видим чрез хоста за файлове.

Медийният сървър​

sphere-media изпълнява MediaMTX с deploy/mediamtx.yml:

  • Всяко действие се решава от Sphere: authMethod: http изпраща всяко публикуване и гледане към http://sphere:8084/media/auth. Hook-ът разрешава:
    • публикуване по RTSP с ID на конектора като потребител и ключа му като парола и само под представката на собствения му тенант t/<tenant id>/;
    • гледане по WebRTC (или HLS) с медиен токен, в който е посочен точно този път (като bearer токен, ?jwt= или парола в basic идентификационни данни);
    • нищо друго (API, метриките и pprof на MediaMTX са изключени от hook-а и остават в мрежата на compose или са изключени).
  • Пътища: съществуват само t/<tenant>/live/<camera>/<main|sub> и t/<tenant>/pb/<session>.
  • RTSP на :8554, само TCP (Caddy препраща байтове, не UDP), без криптиране (TLS свършва в Caddy), basic удостоверяване. Конектор, който рестартира поток, поема мястото на предишната си сесия (overridePublisher). Нищо не се записва.
  • WebRTC на :8889 (WHEP, зад Caddy) с медията на :8189 UDP и TCP; обявява се само SPHERE_MEDIA_PUBLIC_IP (webrtcIPsFromInterfaces: false).
  • RTMP, SRT, MoQ, HLS, сървърът за възпроизвеждане и метриките са изключени.

Обновяване на MediaMTX​

Образът е закрепен по таг и digest (bluenviron/mediamtx:1.21.1@sha256:…) и в deploy/docker-compose.prod.yml, и в deploy/docker-compose.yml за разработка. За обновяване:

  1. Прочетете бележките към изданията между двете версии.
  2. Проверете всеки ключ на deploy/mediamtx.yml спрямо справочната конфигурация на новата версия, особено authMethod, authHTTPAddress, authHTTPExclude, rtspTransports, rtspEncryption, rtspAuthMethods, webrtcAdditionalHosts, webrtcIPsFromInterfaces, webrtcLocalUDPAddress, webrtcLocalTCPAddress, webrtcICEServers2, overridePublisher и протоколите, които трябва да останат изключени.
  3. Сменете тага и digest-а в двата файла на compose.
  4. Изпробвайте локално с конектор (симулаторът е достатъчен): поток се публикува през TLS на 8322 на медийния хост, възпроизвежда се в браузъра през /sphere/media, а гледане без токен или с токена на друг път се отказва.

Включване на Sphere на хост​

  1. Създайте A записа на медийния хост само DNS (media.entrosity.com → публичният IP на сървъра, без прокси) и изчакайте да сочи към сървъра: Caddy има нужда от него, за да получи сертификата.
  2. Генерирайте тайните и ги задайте заедно с PLATFORM_PRODUCT_TOKEN_SPHERE, SPHERE_MEDIA_DOMAIN и SPHERE_MEDIA_PUBLIC_IP в deploy/.env.
  3. Отворете 8322/tcp и 8189/udp+tcp в защитната стена на хоста (и 80/tcp към медийния хост).
  4. Задайте SPHERE_ENABLED=true.
  5. Разгърнете (следващото изпълнение на deploy или deploy/scripts/upgrade.sh).

При SPHERE_ENABLED=true deploy/scripts/lib.sh добавя --profile sphere към всяка команда на compose и отказва да работи, докато SPHERE_APP_DATABASE_PASSWORD, SPHERE_JWT_SECRET, SPHERE_CREDENTIALS_KEY, PLATFORM_PRODUCT_TOKEN_SPHERE, SPHERE_MEDIA_DOMAIN или SPHERE_MEDIA_PUBLIC_IP е празна. След това upgrade.sh изтегля образите на Sphere и след Hub изпълнява sphere-migrate, рестартира sphere (и изчаква да стане здрав) и след това sphere-media. Финалната проверка на работния поток deploy чака и /sphere/api/v1/healthz на хостовете със SPHERE_ENABLED=true.

Въвеждане​

Sphere достига до потребителите в четири стъпки:

  1. Регистриран, изключен. Миграция 0006 на Hub регистрира продукта sphere изключен и в бета версия: никой не го вижда.
  2. Разгърнат. Образите sphere-backend и sphere-frontend с таг main съществуват, DNS записът на медийния хост сочи към сървъра, хостът е настроен както по-горе със SPHERE_ENABLED=true и разгръщането е направено.
  3. Включен, в бета версия. Миграция 0007 на Hub включва продукта. Той остава в бета версия: само администраторите на платформата го виждат и отварят и могат да го включват за организации.
  4. Пуснат. Администратор на платформата избира Release to organizations (Продукти в бета версия).
Ред на разгръщането

Работният поток deploy изтегля sphere-backend:main и изгражда уеб образа със sphere-frontend:main при всяко изпълнение, независимо дали хостът включва Sphere. Публикувайте промяната в entrosity-infra, която добавя Sphere, само след като и двата образа са публикувани, иначе всяко разгръщане се проваля (Непрекъснато разгръщане). Миграция 0007 трябва да влезе в издание на Hub, разгърнато след стъпка 2: преди това списъкът с продукти би водил към Sphere, който не отговаря.

Издания на конектора​

Sphere пази инсталаторите на конектора и ги разпространява: CI качва всяка версия, Sphere я подписва, на конекторите, които могат да се обновяват сами, се предлага най-новата, а администраторите на тенанта я изтеглят от Изтегляне на конектора (Конектори → Обновявания).

Включване на самообновяването на конекторите​

  1. Генерирайте веднъж двойката ключове Ed25519 (OpenSSL 3):

    openssl genpkey -algorithm ed25519 -out sphere-release.pem
    openssl pkey -in sphere-release.pem -outform DER | tail -c 32 | base64 # SPHERE_RELEASE_SIGNING_KEY (the seed)
    openssl pkey -in sphere-release.pem -pubout -outform DER | tail -c 32 | base64 # RELEASE_PUBLIC_KEY
    openssl rand -hex 32 # SPHERE_RELEASE_TOKEN

    Пазете началното число (seed) толкова тайно, колкото и другите ключове, и след това изтрийте sphere-release.pem.

  2. В deploy/.env на хоста задайте SPHERE_RELEASE_SIGNING_KEY (началното число) и SPHERE_RELEASE_TOKEN и по желание SPHERE_CONNECTOR_UPDATE_CHANNEL (на хоста по подразбиране dev).

  3. В хранилището entrosity-sphere-connector задайте тайните RELEASE_PUBLIC_KEY (публичният ключ, компилиран в конектора) и SPHERE_RELEASE_TOKEN (същият токен), както и променливата RELEASE_PUBLISH_ENABLED=true. SPHERE_RELEASE_API (променлива) сменя адреса, по подразбиране https://hub.entrosity.com/sphere/api/releases/v1 (Работни потоци на CI).

  4. Разгърнете отново (следващото изпълнение на deploy или deploy/scripts/upgrade.sh). Следващата версия на конектора се качва и предлага.

  5. Конекторите, инсталирани преди това, са компилирани без публичния ключ и не могат да се обновяват сами: инсталирайте новата версия на всеки от тях веднъж, от Изтегляне на конектора (Конектори → Обновявания).

Пазете ключа за подписване

Конекторите приемат само издания, подписани с ключа, който съдържа тяхната версия. С друг ключ (изгубено или сменено начално число) всяко обновяване завършва с signature_invalid, докато всеки конектор не бъде преинсталиран ръчно с версия, съдържаща новия публичен ключ.

Публикуване​

CI качва всеки MSI със scripts/publish-release.sh от хранилището на конектора:

ВерсияНомерКанал
Етикет vX.Y.Z (release.yml)X.Y.Zstable
Етикет vX.Y.Z-suffixX.Y.Z-suffixdev
Всяко качване в main (dev-release.yml)0.0.<build>-dev.<commit>dev
curl -X POST -H "Authorization: Bearer $SPHERE_RELEASE_TOKEN" \
-H "Content-Type: application/octet-stream" --data-binary @sphere-connector.msi \
"https://hub.entrosity.com/sphere/api/releases/v1/connector?version=0.2.0&channel=stable&notes=Release%20v0.2.0"

Тялото е самият MSI (до 64 MiB). Sphere подписва манифеста му (proto.ReleaseManifest, компонент sphere-connector: версия, SHA-256 и размер) с SPHERE_RELEASE_SIGNING_KEY и го съхранява в таблицата connector_releases, като пази най-новите десет издания.

ОтговорЗначение
201Съхранено: {id, version, channel, sha256, size_bytes, created_at}.
401 unauthorizedГрешен или липсващ токен, или SPHERE_RELEASE_TOKEN не е зададен.
409 release_existsТази версия вече е публикувана (скриптът го приема за успех: повторни изпълнения на работен поток).
422 validationНе е семантична версия, канал, различен от stable или dev, или празно тяло или по-голямо от 64 MiB.
503 releases_disabledSPHERE_RELEASE_SIGNING_KEY не е зададен.

Предлагане на обновявания​

Sphere предлага най-новото издание от SPHERE_CONNECTOR_UPDATE_CHANNEL (stable: стабилните издания; dev: dev и стабилните), когато конектор изпрати hello, и на всеки 5 минути (releases.rollout), на онлайн конекторите, които:

  • обявяват възможността update (версии с RELEASE_PUBLIC_KEY);
  • работят с по-стара версия (на конектор, чиято версия не е семантична, например локална версия dev, никога не се предлага обновяване);
  • нямат отворена задача update_agent и не им е предлагана същата версия през последния час (connectors.update_version, connectors.update_requested_at).

Предложението е задача update_agent (изтичане на времето след 30 минути) с връзки за изтегляне, валидни 2 часа, и с инсталатора на текущата версия за връщане назад, ако Sphere още го пази. Какво прави конекторът: Конектор на Sphere → Самообновяване.

Връзките за изтегляне (GET /api/releases/v1/connector/{releaseID}/{file}?t=…) не изискват вход: t е срок на валидност и HMAC с ключ, изведен от ключа за подписване, а грешна или изтекла връзка връща 404. Изтегляне на конектора и новите токени за регистриране получават връзки, валидни един час.

Фонови задачи​

Бекендът изпълнява задачите си в PostgreSQL (River):

ЗадачаКогаКакво
realtime.sweepНа всеки 30 секундиМаркира като офлайн конекторите, мълчали 3 минути (видеорекордерите им стават unknown, потоците им – не на живо); прекратява просрочените задачи на конекторите и изпраща повторно непотвърдените (след 60 секунди).
streams.sweepНа всеки 10 секундиПремахва зрителите без keepalive от 45 секунди; спира потоците на живо, които никой не е гледал през времето им за изчакване (SPHERE_LIVE_IDLE_GRACE, 5 минути, за подпотоците; SPHERE_LIVE_IDLE_GRACE_MAIN, 2 минути, за основните потоци; задача sphere.stream.stop), и възпроизвежданията на записи веднага щом зрителят им изчезне (sphere.playback.stop, без изчакване); забравя спрените потоци след 10 минути.
nvr.reconcileНа всеки 2 минутиИзпраща отново sphere.nvr.apply за видеорекордери, чийто конектор е онлайн, но не държи желаното състояние (свързан, но отчетен като unknown или disconnected или с по-стари идентификационни данни; несвързан, но още влязъл), непроменени от 2 минути и без отворена задача за прилагане.
releases.rolloutНа всеки 5 минутиПредлага най-новото издание на конектора на онлайн конекторите, които се обновяват сами (Предлагане на обновявания). Не прави нищо без SPHERE_RELEASE_SIGNING_KEY.
alarms.partitionsЕжедневноСъздава месечните дялове за аларми два месеца напред.
retention.cleanupЕжедневноВижте Съхранение.

Освен това всеки отчет за състоянието на конектор се сравнява с това, което искат зрителите: поток, който той публикува, но никой не иска (или който е спрян), се спира отново, а желан поток на живо, който не е отчитал 45 секунди, се стартира отново, дори ако е бил на живо (например след рестартиране на конектора). Възпроизвеждане на запис, което вече не отчита, е стигнало края си: то приключва и не се стартира отново.

Колко бързо тръгва камера​

Измерено в продукция на 2026-10-09 (подпотоци, H.265, Dahua): камера, която никой не е гледал, се показва за 4,1–5,3 секунди, а камера, чийто поток още върви – за 1,6–2,8 секунди. Съставните части:

СтъпкаВреме
Конекторът отваря потока във видеорекордера и го публикува (само когато потокът не върви)1,9–2,6 с
Зрителят чака следващия ключов кадър на камерата1–2 с при подразбиращия се за Dahua интервал от 2 секунди
Установяване на WebRTC в браузъраоколо 0,6 с

Какво ги скъсява:

  • Времето за изчакване държи неизползваните потоци включени, така че връщането към камера пропуска стартирането във видеорекордера (SPHERE_LIVE_IDLE_GRACE, SPHERE_LIVE_IDLE_GRACE_MAIN, по-горе).
  • Потокът се смята за пуснат на живо веднага щом задачата за стартиране на конектора успее, а не при следващия му отчет за състоянието. Браузърът подготвя WebRTC връзката (оферта, ICE), докато камерата стартира, а конекторът отваря връзката си с медийния сървър (TCP, TLS), докато видеорекордерът отговаря, а не след това.
  • Оптимизиране за изглед на живо на страницата на видеорекордер скъсява интервала между ключовите кадри на подпотоците на камерите до 1–4 секунди (Видеорекордери).

Жизненият цикъл на потоците в подробности: API на Sphere → Гледане на видео, Протокол на конектора на Sphere.

Съхранение​

Ежедневна задача retention.cleanup изтрива старите данни на порции от 10 000 реда:

ДанниПазят се
Журнал с алармиSPHERE_RETENTION_ALARM_DAYS, за всеки тенант. Алармите се съхраняват в месечни дялове; месецът се изтрива изцяло, след като целият е по-стар от срока, така че алармите се пазят между срока и срока плюс един месец.
Приключили задачи на конекторитеЗамяната на тенанта (settings.retention.job_days, 7–730), иначе SPHERE_RETENTION_JOB_DAYS.
Одитен журналЗамяната на тенанта (settings.retention.audit_days, 30–3650), иначе SPHERE_RETENTION_AUDIT_DAYS.
Токени за регистриране30 дни след изтичането или отмяната им.
Приключили сесии в Hub, използвани step-up токениЕдин час след приключването им; след изтичането им.

Администраторите на тенанта задават замените в настройките на тенанта (PATCH /tenants/{tenantID}, API на Sphere). sphere_retention_rows_deleted_total{category} брои какво е премахнато.

База данни и миграции​

Sphere има собствена база данни. Миграциите са вградени в изпълнимия файл (entrosity-sphere.backend/db/migrations) и се прилагат от migrate up:

МиграцияДобавя
0001_initКопието на Sphere на тенантите, потребителите и ролите от Hub (tenants, users, tenant_memberships, състояние на синхронизацията с Hub, приключили сесии, използвани step-up токени), sites, audit_log само за добавяне, enrollment_tokens, connectors (с курсора за аларми alarms_last_seq), jobs и защита на ниво ред с ролята sphere_app.
0002_videonvrs (криптирани идентификационни данни с версия, желано състояние и отчетено състояние), cameras, streams и stream_viewers, журнала alarms, разделен на месечни дялове, с функциите за дяловете, и saved_views.
0003_view_splitsЗапазените изгледи приемат всички разделяния на мрежата: layout 1, 4, 6, 8, 9, 16, 25, 36 или 64 (преди 1, 4, 9 или 16). При връщане назад новите разделяния стават 9 или 16, като се пазят най-много 16 камери.
0004_connector_releasesconnector_releases (инсталаторите с версия, канал, SHA-256, размер, подпис и бележки; глобални редове, четими от всеки тенант и записвани само от глобални операции) и update_version и update_requested_at на конекторите (последното предложено обновяване).
  • Изолация на тенантите: всяка таблица на тенант има политика за защита на ниво ред; сървърът работи като sphere_app (NOBYPASSRLS). Препратките между таблиците на тенантите са съставни ключове (tenant_id, id), така че препратка между тенанти е невъзможна.
  • Само за добавяне: sphere_app не може да променя или изтрива audit_log (съхранението чисти чрез отделна функция) и може само да потвърждава alarms (може да променя acked_at и acked_by, нищо друго; съхранението изтрива дялове).
  • Паролите на видеорекордерите се съхраняват само криптирани (credentials_enc).
  • Аларми, чието време е извън месечните дялове, попадат в alarms_default и се преместват, когато се създаде дялът за техния месец.

Резервни копия и възстановяване​

deploy/scripts/backup.sh прави дъмп на базата данни sphere, когато тя съществува, до останалите: backups/db/sphere-<timestamp>.dump (pg_dump -Fc, проверен чрез обратно прочитане), изтриван заедно с другите дъмпове след дните за съхранение.

deploy/scripts/restore.sh при SPHERE_ENABLED=true спира sphere и sphere-media, възстановява дъмпа sphere-… от същото изпълнение на резервното копие, ако има такъв (създава наново базата данни и ролята sphere_app), изпълнява sphere-migrate и стартира отново sphere и sphere-media.

Дъмпът съдържа паролите на видеорекордерите, криптирани със SPHERE_CREDENTIALS_KEY: възстановяването изисква същия ключ. Алармите, записани след направата на резервното копие, не са във възстановената база данни и конекторите не ги изпращат отново: те изтриват алармите, след като сървърът ги потвърди.

Наблюдение​

  • GET /healthz (жизненост) и GET /readyz (готовност: базата данни отговаря; показва също дали копието на данните от Hub е актуално, stale след 5 минути, без да се проваля) на слушателя на API. Публично: https://hub.entrosity.com/sphere/api/v1/healthz.
  • Метрики за Prometheus на SPHERE_METRICS_ADDR (:9094), сред тях sphere_ws_connections (свързани конектори), sphere_jobs_total{type,status}, sphere_job_dispatch_seconds, sphere_http_request_duration_seconds, sphere_platform_syncs_total, sphere_platform_sync_age_seconds, sphere_sse_subscribers, sphere_retention_rows_deleted_total, sphere_river_queue_depth и sphere_db_pool_connections.
  • Журналите са в JSON при prod. MediaMTX пише журнал на ниво warn; отказано публикуване или гледане се записва от бекенда на ниво debug (media access refused).

Локална разработка​

Средата за разработка на entrosity-infra пуска Sphere до Hub (Настройка за разработка):

  1. deploy/.env.example има блок за Sphere (SPHERE_* на :8083, hook на :8084, метрики на :9094, тайни за разработка, SPHERE_MEDIA_PUBLISH_URL=rtsp://localhost:8554, SPHERE_PUBLIC_URL=http://localhost:5175/sphere), а PLATFORM_PRODUCT_TOKENS на Hub съдържа токена на sphere.

  2. Създайте базата данни веднъж: docker compose -f deploy/docker-compose.yml exec postgres createdb -U rmm sphere.

  3. Стартирайте медийния сървър – продукционната конфигурация, насочена към бекенда на хоста:

    docker compose -f deploy/docker-compose.yml --profile sphere up -d sphere-media

    Той слуша на 8554 (RTSP, без криптиране), 8889 (WHEP) и 8189 (медия), обявява 127.0.0.1 и пита http://host.docker.internal:8084/media/auth.

  4. В entrosity-sphere.backend: make migrate, след това make dev (API на :8083).

  5. В entrosity-sphere.frontend: неговият сървър за разработка на :5177.

  6. Отворете http://localhost:5175/sphere/. Сървърът за разработка на Hub препраща /sphere/api към :8083 (с премахната представка), /sphere/media към :8889 (като запазва адресите на WHEP сесиите под /sphere/media, както Caddy) и /sphere към :5177.

  7. За видео пуснете конектор със симулатора: sphere-connector enroll --server http://localhost:5175/sphere --token <token>, след това make dev в entrosity-sphere-connector (Изпробване на Sphere със симулатора).