Протокол на агента и конектора
Описва съобщенията, които се обменят по WebSocket между бекенда и агентите/конекторите. Типовете на Go се намират в entrosity-shared-go/proto и са единственият източник на истина; този документ описва предназначението и машините на състоянията.
Транспорт
- URL:
wss://<server>/api/agent/v1/ws(агенти) или/api/connector/v1/ws(конектори). - Заглавка
Authorization: Bearer <agent_key>;X-RMM-Version: <semver>. Без заглавкаOrigin: надгражданията на връзката, инициирани от браузър, се отказват. - Текстови рамки, по един JSON плик (envelope) на рамка, максимум 1 MB. По-големите полезни товари (payload), например пълната инвентаризация, се изпращат по HTTPS чрез
POST /inventory. - Сървърът изпраща WebSocket ping на всеки 30 s; връзката се смята за прекъсната след 2 пропуснати pong.
- Клиентът се свързва отново с експоненциално нарастващо изчакване
1s → 2s → … → 5 min+ 20 % случайно отклонение (jitter). След 10 поредни неуспеха агентът преминава към HTTP допитване (polling) на всеки 5 min и продължава да опитва WS във фонов режим.
Плик
{
"id": "01J...", // uuidv7, unique per message
"type": "job.assign", // message type
"ts": "2026-09-23T10:00:00Z",
"reply_to": "01J...", // optional: id of the message this responds to
"payload": { ... }
}
Съобщения на агента
Клиент → сървър
| type | payload | кога |
|---|---|---|
hello | {agent_version, os_build, capabilities: ["winget","run_as_user","remote_desktop"], config_version, pending_job_ids[]} | първото съобщение след свързване. Сървърът отговаря с hello.ack с {server_time, config, resend_job_ids[]}. pending_job_ids позволява на сървъра да съгласува задачите, изпратени преди прекъсването на връзката. |
heartbeat | {cpu_pct, mem_pct, disks:[{drive,free_bytes,size_bytes}], logged_on_user, uptime_seconds, pending_reboot, cpu_temp_c?} (cpu_temp_c: най-горещата термична зона в °C, -40..150, липсва, ако няма сензор) | на всеки 60 s |
inventory.report | {kind: "full"|"delta", collected_at, system?, software?, disks?, network?, services?, updates?, local_users?} | при стартиране, на всеки 24 h (пълна), на всеки 4 h (делта), при заявка. Преминава към HTTP, ако е >1 MB. |
job.ack | {job_id} | веднага след получаване на job.assign |
job.progress | {job_id, pct?, message, phase: "downloading"|"installing"|"running", output?, output_offset?} | най-често на всеки 2 s; run_script освен това изпраща поточно части от изхода (≤16 KiB, UTF-8, output_offset = отместване в байтове на частта) веднага щом бъдат генерирани |
job.result | {job_id, status: "succeeded"|"failed"|"timeout"|"cancelled", exit_code?, output_tail?, error_code?, error?, reboot_required?, detection_passed?, duration_ms} | при завършване |
event | {kind, data} — видове: reboot_started, user_logon, user_logoff, agent_updated, update_failed ({from, to, detail}: новата версия не е стартирала и е върната предишната), winget_missing | при настъпване; agent_updated/update_failed се изпращат след първото hello след самообновяване |
log | {level, message, fields} | препращане на диагностика с ограничена честота (изключено по подразбиране) |
session.report | {at, open:[{user, session_id, type: console|remote, client?, logon_at}], ended?:[{…, logoff_at}]} | при свързване, при всяко влизане или изход и поне на всеки 15 min. open съдържа всички текущи влизания; сървърът записва новите, задава времето на изход за тези в ended и затваря съхранените отворени влизания, които липсват в open, към момента at (приблизително). Само по WebSocket. |
Сървър → клиент
| type | payload | бележки |
|---|---|---|
hello.ack | {server_time, config, resend_job_ids[]} | |
config.update | {config_version, heartbeat_seconds, full_inventory_hours, delta_inventory_hours, log_level, features} | агентът я съхранява и прилага |
inventory.request | {kind} | |
job.assign | {job: {id, type, payload, timeout_seconds, expires_at, priority}} | агентът трябва да изпрати job.ack до 60 s, иначе сървърът изпраща отново |
job.cancel | {job_id, force?} | задача в опашката се премахва и се отчита като cancelled; изпълняваща се задача се спира само с force (дървото от процеси на инсталатора се прекратява), иначе тя се изпълнява докрай и отчита реалния си резултат |
ping | {} | проверка за активност на ниво приложение (в допълнение към WS ping) |
Раздели на инвентаризацията
inventory.report съдържа sections: {system: true, software: true, ...} със списък на събраното: JSON пропуска празните масиви, така че събран, но празен раздел (без услуги) се различава от раздел, който не е бил събран. Сървърът заменя точно изброените раздели; колектор, който е неуспешен, се отчита в errors[] и неговият раздел остава непроменен. Разделът за софтуер се изброява само когато колекторът за регистъра е успял (изходът на winget само допълва записите от регистъра с winget_id).
Типове задачи (агент)
| type | payload | поведение |
|---|---|---|
inventory | {kind} | изпълнява колекторите и изпраща отчет |
install_package | {package_id, kind: msi|exe|powershell|winget, download:{url?,sha256,size_bytes}?, file_name?, script_content?, install_args?, success_exit_codes[], detection?, winget:{id,version?,source?}?, reboot_policy, requires_reboot?, run_as: system|logged_on_user, timeout_seconds} | вижте последователността на изпълнение по-долу. download.url се попълва при доставката (нова предварително подписана връзка с валидност един час) и може да е празно в повторно изпратена задача; тогава агентът поисква такава. Пакетите за PowerShell съдържат или файл, или вграден script_content. |
uninstall_package | {package_id?, kind, uninstall_args?, uninstall_string?, product_code?, winget:{id}?, download?, file_name?, script_content?, success_exit_codes[], detection?, reboot_policy, run_as, timeout_seconds} | използва се точно един метод, в този ред: winget идентификатор → продуктов код на MSI (msiexec /x {GUID} /qn /norestart) → низът за деинсталиране от инвентарните данни на устройството (+ uninstall_args) → файлът на пакета с uninstall_args (exe/powershell). Сървърът избира метода при изграждането на задачата; без метод → целта се проваля с no_uninstall_method, без задачата да бъде изпратена. Ако правилото за откриване е изпълнено след деинсталирането → detection_failed. |
run_script | {script_run_id, language: powershell|pwsh|cmd, content, params, run_as, timeout_seconds} | вижте Скриптове по-долу |
reboot / shutdown | {delay_seconds, message?, force} | shutdown.exe /r|/s /t N /c <msg> [/f] /d p:0:0 (N е поне 5 s, за да стигне резултатът до сървъра; съобщението е един аргумент, никога не минава през обвивка (shell) и не може да съдържа кавички или нови редове); изпраща event reboot_started |
update_agent | {release_id, component: agent|connector, target: {version, url, sha256, size_bytes, signature}, rollback?: {…}} | вижте Самообновяване по-долу; същият тип задача се използва и за конекторите |
winget_search | {query} | използва се само когато няма кеширан индекс (рядко) |
remote_desktop | {session_id, mode: control|view, require_consent, requested_by, hide_banner?, profile?} (profile: wall: плочка от стената с екрани, само преглед, картина най-много 640×400, 1 кадър в секунда, качество на JPEG 40, 720p при уголемяване (large); агентите с възможността remote_wall го спазват) (hide_banner: без лента на сесията за потребителя; задава се само за сесии на администратори) | Само за Windows. Пита влезлия потребител, когато е зададено require_consent (отказ или липса на отговор до 60 s → remote_declined), стартира помощната програма за прихващане на екрана и отваря потока на сесията (вижте Потоци за отдалечен работен плот по-долу). succeeded, щом потокът е установен (remote session started); потокът продължава и след задачата. Други неуспехи: remote_unavailable. Без тайна: потокът се автентикира с ключа на агента. |
Последователност на изпълнение на install_package
- Ако има
detectionи то е изпълнено → резултатsucceededсdetection_passed=true, skipped=true(целта ставаskipped). run_as=logged_on_user(агенти ≥ 0.5, възможностrun_as_user): инсталаторът се изпълнява в сесията на потребителя на конзолата с неговия токен и среда; файловете се подготвят в%TEMP%на потребителя, а winget използва--scope user. Ако няма влязъл потребител →failedсno_logged_on_user. По-старите агенти отговарят сrun_as_unsupported.- Изтегляне (фаза
downloading, напредък сpct) в%ProgramData%\RMM\cache\<sha256>\<file_name>, освен ако файлът вече е кеширан и проверен. След прекъсване изтеглянето продължава сRange; изтекла връзка (403/401/400) или липсващurlсе опреснява еднократно чрезGET /api/agent/v1/packages/{id}/download-url. Първо се проверява свободното място (disk_full), след това се проверява SHA-256 (несъответствие →hash_mismatch, файлът се изтрива). - Изпълнение (фаза
installing):- msi:
msiexec.exe /i "<file>" /qn /norestart /l*v "<log>" <install_args> - exe:
"<file>" <install_args>(командният ред се подава дословно, без повторно поставяне на кавички) - powershell:
powershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File "<file>" <args> - winget:
winget install --id <id> [--version v] [--source s] --silent --scope machine --accept-package-agreements --accept-source-agreements --disable-interactivity; ако winget липсва → App Installer се инсталира от файловете, хоствани на сървъра (GET /api/agent/v1/releases/winget, инсталирани сAdd-AppxProvisionedPackage), в противен случайerror_code=winget_missing. Изходният код на winget „no package found“ се преобразува вwinget_not_found. - Изходен код
1618на msiexec (в ход е друга инсталация) се опитва отново локално 3× през една минута, след което се отчита катоinstall_in_progress.
- msi:
- Изходният код се проверява спрямо
success_exit_codes(по подразбиране0, 3010, 1641).3010/1641или ключове в регистъра за чакащо рестартиране →reboot_required=true. detectionсе изпълнява отново, ако е зададено; неуспех →failedсerror_code=detection_failed.- Прилага се
reboot_policy:never→ нищо;if_required→ рестартиране, когато еreboot_required;always→ рестартиране. - Отчита се
job.resultс последните 64 KB от изхода (за MSI – краят на подробния журнал, декодиран от UTF-16).
Отказ: job.cancel без force за изпълняваща се инсталация се игнорира (недовършените инсталатори причиняват повече вреди от закъснелия успех); с force дървото от процеси се прекратява (taskkill /T /F) и задачата отчита cancelled.
Възстановяване след срив: преди изпълнение агентът записва идентификатора на задачата с метаданни {action, detection} в state.json. При рестартиране всяка незавършена задача се отчита по HTTP (POST /jobs/{id}/result): ако правилото за откриване показва желаното състояние (инсталирано при инсталиране, липсващо при деинсталиране), задачата е succeeded, в противен случай е failed с agent_restarted (след това се прилага политиката за повторни опити на внедряването).
Кодове на грешки: download_failed, hash_mismatch, exec_failed, exit_code, timeout, detection_failed, winget_missing, winget_not_found, disk_full, cancelled, agent_restarted, run_as_unsupported (агенти преди 0.5), no_logged_on_user, signature_invalid, update_unsigned, no_uninstall_method, install_in_progress, unsupported, invalid_payload.
Типове правила за откриване (detection): msi_product_code {product_code}, registry {key, value?, op: exists\|==\|!=\|>=\|>\|<=\|<, expected?} (HKLM/HKCU, проверява се и в двата изгледа на регистъра), file {path, min_version?} (променливите на средата се разгръщат, сравнява се ресурсът за версия на файла), winget {id}.
Скриптове (run_script)
- Съдържанието се записва във временен файл (
.ps1с UTF-8 BOM или.cmd) и се изпълнява сpowershell.exe -NoProfile -NonInteractive -ExecutionPolicy Bypass -File(5.1),pwsh.exe(7,exec_failed, когато липсва) илиcmd.exe /d /c. - Параметрите (типизирани стойности, вече валидирани от сървъра спрямо схемата на скрипта) пристигат едновременно като променливи на средата
RMM_PARAM_<NAME>(булевите катоtrue/false) и, за PowerShell, подадени чрез splatting като именувани параметри от JSON файл от малка обвиваща програма, така че скриптът да може да декларираparam([string]$Name, [int]$Days, [switch]$Force). - stdout и stderr се сливат в реда на появата си и се изпращат поточно като части на
job.progress(output,output_offset); сървърът ги добавя към изпълнението и ги публикува отново като SSEscript_run.output. - Резултатът съдържа последните 64 KiB (
output_tail) иresult: {output_bytes, uploaded, truncated}. По-голям изход първо се качва сPUT /api/agent/v1/jobs/{id}/output(gzip текст, най-много 10 MiB; всичко отвъд това се отхвърля и изпълнението се маркира като съкратено), за да може порталът да го покаже изцяло. run_as=logged_on_userизпълнява скрипта в конзолната сесия с токена на потребителя (WTSQueryUserToken, среда отCreateEnvironmentBlock), като скриптът се подготвя в неговия%TEMP%; без потребител →no_logged_on_user.- При изтичане на времето дървото от процеси се прекратява (
timeout);job.cancelсforceправи същото (cancelled).
Самообновяване (update_agent)
targetв payload-а (и незадължителнотоrollback: MSI пакетът на текущата версия) съдържат Ed25519 подпис върху манифеста"rmm-release-v1\n<component>\n<version>\n<sha256 lower hex>\n<size>\n". Публичният ключ е вграден при компилиране (-X …/agentkit/update.PublicKey=); компилация без него отговаря сupdate_unsigned, а при невалиден подпис – сsignature_invalid. Нищо не се изтегля, преди подписът да бъде потвърден.- MSI пакетът се изтегля (нов предварително подписан URL, попълнен при доставката), размерът и SHA-256 се проверяват и той се съхранява като
%ProgramData%\RMM\update\<version>.msi(MSI пакетът за връщане към предишната версия – катоprevious.msi). - Агентът записва
update.ps1и регистрира еднократна планирана задачаRMMAgentUpdate/RMMConnectorUpdate(SYSTEM, стартира след минута), отчитаsucceededс{scheduled, from_version, to_version, rollback}и продължава да работи. - Задачата изпълнява
msiexec /i … /qn /norestart(WiXMajorUpgrade, който спира и заменя услугата), след което следва наблюдението (watchdog): до пет минути услугата трябва да работи и да продължава да работи 60 s по-късно. В противен случайprevious.msiсе инсталира отново (MSI пакетите позволяват връщане към по-стари версии) и услугата се стартира. - Резултатът се записва в
update\result.json; при следващото стартиране агентът го отчита катоevent agent_updatedилиupdate_failed.
Сървърът предлага обновяване при hello и от задача за поетапно пускане на всеки пет минути: на агенти (и конектори) на активни тенанти, които използват по-стара версия на изданието от най-новото публикувано издание в канала на тенанта (settings.update_channel, по подразбиране stable; beta вижда и предварителните издания), чиято група (FNV-1a на идентификатора, mod 100) е под rollout_pct на изданието и които нямат задача за обновяване в ход. Същата версия не се предлага отново в рамките на един час. Участват само инсталации, чиято версия е семантична (1.2.3 или със суфикс за предварително издание, например 0.0.42-dev.abc1234 от компилациите за разработка в CI); локалните компилации (dev или версии с метаданни за компилацията, например 1.0.0-dev+abc) никога не се обновяват.
HTTP крайни точки за пакети (/api/agent/v1, ключ на агента)
| метод и път | отговор |
|---|---|
GET /packages/{id}/download-url | {url, sha256, size_bytes, expires_at} — нова предварително подписана връзка с валидност един час за готов пакет на тенанта на агента или за глобален пакет; 404 в противен случай |
PUT /jobs/{id}/output | 204 — пълният изход на задача run_script на това устройство (Content-Encoding: gzip, текст, ≤ 10 MiB) |
GET /releases/winget | {files:[{name, url, size_bytes, role: bundle|dependency}]} — пакетът на App Installer и неговите зависимости, съхранени под releases/winget/ в bucket-а; 404, когато няма хоствани |
Състояние от страната на агента
%ProgramData%\RMM\
agent.dat DPAPI-encrypted {agent_id, agent_key, server_url}
config.json last config from server
state.json pending/in-progress job ids (+ detection metadata) for crash recovery
cache\ downloaded packages by sha256 (LRU, 2 GiB cap, `.verified` marker)
update\ self-update MSIs, update.ps1, result.json
logs\ rotating logs
Съобщения на конектора
Конекторът за обекта (site connector) (rmm-connector, Windows услуга
RMMConnector) използва същия плик, жизнен цикъл на задачите
(job.assign → job.ack → job.progress → job.result), изчакване при
повторно свързване и резервни HTTP варианти като агента; кодът се споделя в
entrosity-shared-go/agentkit (транспорт, изпълнител на задачи, DPAPI
хранилище за тайни, журналиране, обвивка на услугата). Типове:
entrosity-shared-go/proto/connector.go.
Регистриране и крайни точки (/api/connector/v1)
| метод + път | предназначение |
|---|---|
POST /enroll | {enrollment_token, hostname, domain, version} → {connector_id, connector_key, ws_url}. Токенът трябва да е от вид connector; при повторно регистриране на същата машина (тенант, име на хост, домейн) ключът ѝ се ротира и старата връзка се затваря. С ограничение на честотата на заявките по IP. |
GET /ws | WebSocket връзката (Authorization: Bearer <connector_key>) |
POST /heartbeat | резервен HTTP вариант на heartbeat |
GET /jobs/pending, `POST /jobs/{id}/ack | progress |
POST /adsync/runs/{run_id}/chunk | големи тела на adsync.chunk (над ограничението от 1 MiB за рамка; приема се gzip, максимум 16 MiB) |
POST /push/targets | резервен HTTP вариант на push.target |
POST /vertex/jobs/{job_id}/secrets, POST /vertex/jobs/{job_id}/chunks | задачи на Entrosity Vertex: тайните на задачата (еднократно) и частите с резултати, препращани към Vertex за активни задачи на Vertex на този конектор; само докато Vertex е настроен (Протокол на Vertex) |
Конекторът е онлайн от своето hello, докато сокетът му не се затвори (конекторите работят на сървъри, затова прекъсването се показва веднага) или докато не мълчи 3 min. Изтриването на конектор в портала отменя ключа му, отказва отворените му задачи, изтрива конфигурациите му за синхронизация с AD и затваря връзката му.
Клиент → сървър
| type | payload |
|---|---|
hello | както при агентите; capabilities ⊆ ["ldap","winrm","smb","wol","vertex"] (smb и vertex само в компилациите за Windows) |
heartbeat | {cpu_pct, mem_pct, active_jobs} на всеки 60 s |
job.ack / job.progress / job.result | същата структура като при агента; job.result.result съдържа структурирани резултати (ldap.test, ldap.ous, push_agent) |
adsync.chunk | {run_id, seq, computers:[{object_guid, object_sid, dn, name, dns_hostname, os, os_version, enabled, last_logon_at, when_created, ou, description}], complete, total} — най-много 1000 компютъра; последната част има complete:true и total (компютрите, изпратени при изпълнението). Частите са идемпотентни по seq и могат да пристигнат в разбъркан ред (големите минават по HTTP); изпълнението завършва, щом пристигнат total компютъра. |
push.target | {job_id, target:{ad_computer_id, hostname, fqdn}, status: "connecting"|"copying"|"installing"|"success"|"failed", error_code?, error?} напредък за всяка цел |
Сървър → клиент (payload-и на job.assign по тип задача)
Тайните (паролата за bind, идентификационните данни за push, токенът за
регистриране, връзката към MSI) се добавят в момента на доставката от
обогатители на задачите: таблицата jobs съхранява само препратки или
запечатан шифротекст, а API-тата за задачи никога не връщат payload-ите на
задачите за конектори.
| тип задача | payload | опашка |
|---|---|---|
adsync.run | {run_id, config:{ldap_host, ldap_port, tls_mode:"ldaps"|"starttls"|"none", skip_tls_verify, ca_pem?, base_dn, bind_dn, bind_password, computer_filter, ou_include[], ou_exclude[]}} | LDAP (последователно) |
ldap.test | {config} → резултат {ok, computers_found, server_info, default_naming_context}; неуспешен bind е job.result failed с кода на грешката | LDAP |
ldap.ous | {config} → резултат {ous:[{dn, name, parent_dn}]} | LDAP |
push_agent | {targets:[{ad_computer_id, hostname, fqdn}], msi:{url, sha256?}, enrollment_token, server_url, credential:{username, password}, concurrency} → резултат {succeeded, failed} | push (2 задачи паралелно, всяка с concurrency цели, по подразбиране 5) |
wake | {mac_addresses[] (≤16), broadcast?[]} → резултат {packets, targets[]}: magic пакети през всеки IPv4 интерфейс към ограничения и насочения broadcast адрес, UDP 9 и 7 (SO_BROADCAST). Сървърът избира онлайн конектор от обекта на устройството с възможност wol и MAC адресите на устройството от мрежовите му инвентарни данни (409 no_site, no_connector, no_mac_address). | wake |
update_agent | както при агентите (component: connector, задача RMMConnectorUpdate, услуга RMMConnector) | update |
vertex.op, vertex.read | OpJob {operation_id, op, managed_ous[], server?, params, expires_at}: операция с Active Directory на Entrosity Vertex, изпълнявана на домейн контролер; без тайни в payload-а (Протокол на Vertex) | vertex (последователно) / vertex-read (2) |
LDAP кодове на грешки: ldap_connect, ldap_bind, ldap_search, tls.
Синхронизация на конектора: свързване (LDAPS или StartTLS със системните
коренни сертификати плюс незадължителния CA; проверката се пропуска само
при skip_tls_verify), simple bind, търсене в поддървото на страници (по
500 на страница) с (&(objectCategory=computer)<computer_filter>),
включване/изключване на OU по суфикс на DN, части от по 1000, напредък на
всеки 1000 компютъра.
Push на конектора (за всяка цел, време за изпълнение 10 min): разрешаване на
името → connecting; първо SMB (компилации за Windows, порт 445):
\\host\ADMIN$ с акаунта за push и отдалечения мениджър на услуги;
съществуваща услуга RMMAgent → success с already_installed; копиране в
ADMIN$\Temp → copying; временна услуга RMMPush стартира
msiexec /i … /qn ENROLLMENT_TOKEN=… SERVER_URL=… → installing; крайното
състояние в журнала на инсталатора и услугата RMMAgent решават: изходен
код 0/3010/1641 → success, иначе msiexec_failed с края на журнала
(токените са скрити). WinRM (HTTPS 5986, иначе HTTP 5985 с NTLM шифроване на
съобщенията) се използва, когато порт 445 е затворен, или след SMB грешка
copy_failed/unreachable: една обвивка (shell), последователни команди,
MSI пакетът като base64 редове, декодирани от certutil, с проверка на
SHA-256. push_agent.msi е най-новото публикувано stable издание на агента
(обект с версия и записаният му SHA-256).
Кодове на грешки при push: dns_failed, unreachable, winrm_disabled, auth_failed, access_denied, copy_failed, msiexec_failed, already_installed, download_failed, timeout.
Потоци за отдалечен работен плот
Сесия за отдалечен работен плот използва две допълнителни WebSocket връзки, които бекендът препредава една към друга:
| Страна | Крайна точка | Автентикация |
|---|---|---|
| Агент | GET /api/agent/v1/remote/{session_id} | Ключ на агента (Authorization: Bearer). Сесията трябва да принадлежи на устройството на агента и все още да е в изчакване: иначе 404, 410 remote_session_ended, 409 remote_session_taken, когато агентът вече се е присъединил. Произходите (origins) от браузър се отказват. |
| Зрител | GET /api/remote/v1/sessions/{session_id}/viewer?ticket= | Еднократният билет от POST …/remote-sessions (60 s, еднократна употреба; съхранява се само неговият SHA-256). Произходи: собственият хост на сървъра и RMM_CORS_ORIGINS (останалите получават HTTP 403). Невалиден, използван или изтекъл билет затваря сокета с 1008. |
| Реплика към реплика | GET /api/remote/v1/internal/sessions/{session_id} | X-RMM-Relay: <unix expiry>.<hex HMAC-SHA256> върху <session_id>|<expiry>, с ключ, извлечен от RMM_JWT_SECRET (по време на ротация се приема и предишната тайна); токените са валидни 30 s. Отказва се на публичния край от Caddy. |
Съобщенията се препредават непроменени в двете посоки, с две изключения:
сървърът изпраща {"t":"status","state":"waiting"} на визуализатор, който
пристигне преди агента, и {"t":"status","state":"connected"}, щом двете
страни бъдат свързани, и препраща само съобщенията на визуализаторя, които
сесията позволява. Двоичните съобщения от визуализаторя, непознатите типове,
всичко, изпратено преди connected, и в сесиите само за преглед – целият
вход (mouse, wheel, key, type, cad) се отхвърлят. Ограничения при
четене: 8 MiB на съобщение от агента, 64 KiB на съобщение от визуализаторя.
Текстовите съобщения са JSON обекти с поле t:
t | Посока | Полета |
|---|---|---|
hello | агент → визуализатор | v (1), mode, displays[{id, name, x, y, width, height, primary}], display, width, height, user (празно на екрана за влизане). Изпраща се първо и отново, когато дисплеят или резолюцията се сменят. |
error | агент → визуализатор | message; след това агентът затваря потока. |
status | сървър → визуализатор | state: waiting | connected |
ack | визуализатор → агент | seq: кадърът, чиято последна плочка е изрисувана |
mouse | визуализатор → агент | x, y (пиксели на дисплея), a: move | down | up, b: 0 ляв, 1 среден, 2 десен |
wheel | визуализатор → агент | x, y, dx, dy в единици на колелцето (120 на стъпка, положително dy превърта надолу) |
key | визуализатор → агент | code (DOM KeyboardEvent.code, преобразуван в скан код), down |
type | визуализатор → агент | text (до 4096 знака, изпраща се като Unicode вход) |
cad | визуализатор → агент | Ctrl+Alt+Del (SendSAS) |
display | визуализатор → агент | id |
quality | визуализатор → агент | q: качество на JPEG 10–95 (по подразбиране 60) |
refresh | визуализатор → агент | изпраща отново целия екран |
lock | визуализатор → агент | locked: заключва (или отключва) собствените клавиатура и мишка на устройството; въвеждането от визуализатора продължава да работи. Предава се само в сесии за управление и за плочки от стената с екрани; отменя се при край на сесията. |
locked | агент → визуализатор | locked, error?: състоянието на заключването след lock (по-старите агенти не отговарят) |
large | визуализатор → агент | large: плочка от стената е уголемена (720p: най-много 1280×720, 5 кадъра в секунда, качество 60) или върната към малката картина; следва нов hello с новия размер. Само за плочки от стената. |
Двоичните съобщения (агент → визуализатор) са плочки от екрана: 14-байтова заглавка, последвана от JPEG изображение.
| Байтове | Поле |
|---|---|
| 0 | вид (1 = JPEG) |
| 1–4 | пореден номер на кадъра (uint32, big endian) |
| 5–6, 7–8 | x, y на плочката в пиксели на дисплея (uint16) |
| 9–10, 11–12 | ширина, височина (uint16) |
| 13 | флагове: бит 0 = последна плочка от кадъра |
Агентът прихваща до 15 кадъра в секунда, сравнява всеки кадър с предишния на плочки 64×64 и изпраща само променените плочки (съседните в един ред се обединяват в ивица); непроменен екран не изпраща нищо. Управление на потока: визуализаторят потвърждава всеки кадър, след като изрисува последната му плочка, а агентът държи най-много два непотвърдени кадъра, така че бавна връзка намалява честотата на кадрите, вместо да натрупва изоставане.
Кодове за затваряне (само за тези потоци; основната връзка на агента използва кодовете по-долу):
| Код | Значение |
|---|---|
4000 | Прекратена: от техник (причина ended by <name>), от затваряне на визуализаторя, от потребителя на устройството (the user ended the session), от устройството или поради промяна в достъпа (изведено от експлоатация устройство, отменен агент, спрян тенант, променен достъп на техника) |
4001 | Заменена от по-нова сесия на същото устройство |
4003 | Потребителят е отказал заявката за съгласие или не е отговорил |
4004 | Устройството не е могло да стартира сесията или връзката с устройството (или с репликата, която я държи) е прекъснала |
4008 | Устройството или визуализаторят не са се присъединили до 2 минути, времето на задачата е изтекло или сесията е достигнала 8 часа |
1008 | Невалиден, използван или изтекъл билет на визуализаторя |
При няколко реплики на бекенда агентът и визуализаторят може да попаднат на
различни реплики: репликата на агента записва своя RMM_NODE_URL в сесията,
а репликата на визуализаторя се свързва с нея през вътрешната крайна точка
(Мащабиране). Прекратяването на сесия се
разпространява до всички реплики по канала за известия remote_sessions.
Машина на състоянията на задачите (от страна на сървъра)
created ──send──► sent ──ack──► acked ──progress──► running ──result──► succeeded | failed | timeout | cancelled
▲ │ no ack in 60 s / disconnect
└────────────────┘
expires_at passed while not finished → timeout
Версии
- Пликът не съдържа версия; пътят на крайната точка (
/v1/) съдържа. Добавянето на полета в payload-а е разрешено в рамките наv1; премахването или преименуването на поле изисква/v2/и период на двойна поддръжка в бекенда. - Агентите и конекторите съобщават версията си в
hello. Самообновяването (update_agent, по-горе) се предлага на инсталации, по-стари от най-новото издание в канала на техния тенант, в рамките на процента на пускане на изданието. - На инсталациите, по-стари от
RMM_MIN_AGENT_VERSION, веднага се предлага най-новото издание, без да се взема предвид процентът на пускане. Те запазват връзката си, за да могат да получат обновяването; сървърът никога не отказва версия, защото това би оставило агента без канал за обновяване. - Сървър 1.x поддържа агенти и конектори от 1.0.0 (протокол
/v1).
Кодове за затваряне на връзката
| Код | Значение | Реакция на агента |
|---|---|---|
4003 | Отменен ключ: устройството е изведено от експлоатация, конекторът е изтрит или тенантът е спрян | Агентът спира (същото става и при 401 при свързване); преинсталирането с токен го регистрира отново |
4009 | По-нова връзка от същата инсталация е поела управлението | Повторно свързване с нарастващо изчакване |
1008 | Нарушение на политиката (например съобщение преди hello) | Повторно свързване с нарастващо изчакване |
Отмяната достига до всяка реплика на бекенда: връзката се затваря, а
кешираните ключове се изчистват. WebSocket, отворен от браузър (с чужда
заглавка Origin), се отказва с HTTP 403.