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

Протокол на агента и конектора

Описва съобщенията, които се обменят по 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": { ... }
}

Съобщения на агента​

Клиент → сървър​

typepayloadкога
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.

Сървър → клиент​

typepayloadбележки
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).

Типове задачи (агент)​

typepayloadповедение
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​

  1. Ако има detection и то е изпълнено → резултат succeeded с detection_passed=true, skipped=true (целта става skipped).
  2. run_as=logged_on_user (агенти ≥ 0.5, възможност run_as_user): инсталаторът се изпълнява в сесията на потребителя на конзолата с неговия токен и среда; файловете се подготвят в %TEMP% на потребителя, а winget използва --scope user. Ако няма влязъл потребител → failed с no_logged_on_user. По-старите агенти отговарят с run_as_unsupported.
  3. Изтегляне (фаза 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, файлът се изтрива).
  4. Изпълнение (фаза 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.
  5. Изходният код се проверява спрямо success_exit_codes (по подразбиране 0, 3010, 1641). 3010/1641 или ключове в регистъра за чакащо рестартиране → reboot_required=true.
  6. detection се изпълнява отново, ако е зададено; неуспех → failed с error_code=detection_failed.
  7. Прилага се reboot_policy: never → нищо; if_required → рестартиране, когато е reboot_required; always → рестартиране.
  8. Отчита се 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); сървърът ги добавя към изпълнението и ги публикува отново като SSE script_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)​

  1. 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. Нищо не се изтегля, преди подписът да бъде потвърден.
  2. MSI пакетът се изтегля (нов предварително подписан URL, попълнен при доставката), размерът и SHA-256 се проверяват и той се съхранява като %ProgramData%\RMM\update\<version>.msi (MSI пакетът за връщане към предишната версия – като previous.msi).
  3. Агентът записва update.ps1 и регистрира еднократна планирана задача RMMAgentUpdate / RMMConnectorUpdate (SYSTEM, стартира след минута), отчита succeeded с {scheduled, from_version, to_version, rollback} и продължава да работи.
  4. Задачата изпълнява msiexec /i … /qn /norestart (WiX MajorUpgrade, който спира и заменя услугата), след което следва наблюдението (watchdog): до пет минути услугата трябва да работи и да продължава да работи 60 s по-късно. В противен случай previous.msi се инсталира отново (MSI пакетите позволяват връщане към по-стари версии) и услугата се стартира.
  5. Резултатът се записва в 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}/output204 — пълният изход на задача 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 /wsWebSocket връзката (Authorization: Bearer <connector_key>)
POST /heartbeatрезервен HTTP вариант на heartbeat
GET /jobs/pending, `POST /jobs/{id}/ackprogress
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 и затваря връзката му.

Клиент → сървър​

typepayload
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.readOpJob {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–8x, 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.