Эмуляторы
Эмулятор — это Signal Lab в роли API, устройства или сервиса, с которым говорит ваша система. Он слушает один адрес и отвечает по правилам: HTTP API — по маршрутам, OSC-, UDP- или TCP-устройство — по принципу «на это ответить тем-то», MQTT-брокер — как любой брокер, плюс собственные правила. Он умеет тормозить, сбоить и время от времени отключаться — так можно проверить, что делает ваша система, когда её зависимость ведёт себя плохо. Каждый обмен подсчитывается, попадает в список и отправляется в Инспектор.
Эмулятор — это один документ. Экран Эмуляторы хранит их библиотеку; тот же документ работает внутри эксперимента как узел Эмулятор, из командной строки через signallab emulate, через API и MCP — и везде отвечает одинаково.
Экран
Слева — библиотека (Библиотека): все эмуляторы с протоколом и адресом; у запущенных — пульсирующая точка и счётчик запросов. Справа — настройки и правила выбранного эмулятора, а под ними — то, что он получил (Сейчас).
Создание эмулятора
Нажмите одну из кнопок вверху библиотеки:
Кнопка Создаёт Слушает С одним правилом, которое сразу работает + HTTP API HTTP API 127.0.0.1:18080GET /health→ 200{"status":"ok"}+ OSC-устройство OSC-устройство 127.0.0.1:9100/ping→/pongсо счётчиком в виде int+ UDP-устройство UDP-устройство 127.0.0.1:7100датаграмма, содержащая PING→PONG 1,PONG 2, …+ TCP-устройство TCP-устройство 127.0.0.1:7200строка, содержащая PING→PONG+ MQTT-брокер MQTT-брокер 127.0.0.1:1883публикация в lab/<name>/set→ то же содержимое, retained, вlab/<name>/stateЕсли этот порт уже занят другим эмулятором библиотеки, берётся следующий свободный.
Заполните поле Название (не больше 120 символов).
В поле Слушать укажите
IP:port.127.0.0.1отвечает только этому компьютеру;0.0.0.0— ещё и сети.Измените правила (см. ниже) и напишите в поле Заметка, что этот эмулятор заменяет.
Изменения сохраняются сами. Кнопка Дублировать создаёт копию на следующем свободном порту. Кнопка Удалить переспрашивает (Удалить?), останавливает эмулятор, если он запущен, и удаляет его из библиотеки.
Правила перебираются по порядку, от первого к последнему; отвечает первое подошедшее. В заголовке каждого правила — его краткое описание в одну строку; щёлкните заголовок, чтобы раскрыть или свернуть правило. Кнопки ↑ и ↓ перемещают правило, × удаляет его.
Запуск
- Выберите эмулятор и нажмите Запустить. Его порт открывается раньше, чем кнопка снова станет доступна: занятый порт или эмулятор с ошибкой отклоняются тут же, с указанием причины.
- Направьте на него свою систему. Для HTTP API кнопка Скопировать URL копирует его адрес (
http://127.0.0.1:18080), а у каждого маршрута есть своя кнопка Скопировать URL (кроме маршрутов, путь которых содержит шаблон{{…}}). - Смотрите, как заполняется список Пришло.
- Нажмите Остановить или остановите задачу эмулятора на полосе консоли.
Рядом с кнопками показано состояние: Не запущен, адрес, на котором эмулятор отвечает, или то, что он отключён.
Эмулятор продолжает отвечать по тем правилам, с которыми был запущен. Если изменить его на ходу, появится кнопка Перезапустить: нажмите её, чтобы запустить эмулятор заново с текущими правилами. До тех пор счётчики срабатываний у правил скрыты — они относятся к старым правилам.
Кнопка Отключить делает запущенный эмулятор недоступным, пока вы не нажмёте Включить: HTTP-запрос получает 503, TCP-устройство и MQTT-брокер рвут соединения и отказывают новым, OSC- или UDP-устройство ничего не отвечает. См. Отключения.
Два эмулятора одного транспорта не могут делить порт: HTTP-, TCP- и MQTT-эмуляторы слушают TCP-порты, OSC- и UDP-эмуляторы — UDP-порты. HTTP API и OSC-устройство могут оба занять порт 8080; два HTTP API — нет. Второй эмулятор на занятом порту отклоняется при запуске.
TIP
В браузере, подключённом к серверу, эмулятор работает на сервере. До эмулятора, слушающего 0.0.0.0, добираются по имени сервера, и Скопировать URL копирует именно этот адрес; эмулятор на 127.0.0.1 отвечает только программам на самом сервере.
Что пришло
Пока эмулятор работает, панель Сейчас считает:
| Счётчик | Что считает |
|---|---|
| Запросы | Всё, что пришло: запросы, сообщения, строки. |
| Без правила | То, что не взяло ни одно правило. HTTP-запрос без маршрута всё равно получает ответ (см. Запросы без маршрута); остальные — нет. |
| С ошибкой | Обмены, в которых ответ не удалось составить или отправить. |
| Во время отключения | То, что пришло, пока эмулятор был отключён. Показывается, если у него задано отключение или что-то застало его отключённым. Никогда не попадает в Без правила. |
| Не доставлено | Только MQTT и только если такое случилось: сообщения, которые клиент не смог принять, слишком отстав. |
В заголовке каждого правила видно, сколько раз оно сработало с момента запуска.
Список Пришло показывает последние 300 обменов, новые сверху:
| Столбец | Что |
|---|---|
| Время | Когда пришло. |
| Откуда | Адрес клиента. |
| Запрос | Что пришло, в нотации протокола: GET /users/7, /ping 1, POWER?. |
| Правило | Правило, которое это взяло (#2), или —. |
| Ответ | Что ушло обратно: 200 OK · 37 B, /pong 3, содержимое; удержан или закрыто при сбое; ошибка, если ответить не удалось; отключён, если пришло во время отключения. |
| мс | От прихода до отправки ответа, включая задержку. |
Кнопка ⌕ в строке (Открыть в Инспекторе) открывает этот обмен в Инспекторе, если захват был включён. Если за пятую долю секунды приходит больше 200 обменов, список пропускает часть и пишет, сколько. Движок хранит последние 500 обменов каждого запущенного эмулятора вместе с тем, что пришло, — для командной строки, API и MCP.
HTTP API
Сервер HTTP/1.1. Каждому запросу отвечает первый маршрут, который его берёт.
Маршруты
Маршрут берёт запрос, когда совпадают его метод, путь и все условия.
| Поле | Что |
|---|---|
| Метод | GET, POST, PUT, PATCH, DELETE, HEAD, OPTIONS или Любой. Маршрут GET отвечает и на HEAD. |
| Путь | Начинается с /. Сегмент :name берёт любой один сегмент и читается как {{request.params.name}}; последний сегмент * берёт всё, что ниже. Завершающий / ничего не меняет; строка запроса в путь не входит. |
| Условия | Должны выполняться все. Добавьте условие кнопкой + Условие. |
Примеры путей:
| Путь | Берёт | Не берёт |
|---|---|---|
/health | /health, /health/ | /health/db, /Health |
/users/:id | /users/7 (params.id равен 7), /users/a%20b (a b) | /users, /users/7/orders |
/files/* | /files, /files/a, /files/a/b/c | /file, /other/files/a |
Условие читает одну часть запроса (Где) и сравнивает её:
| Где | Имя | Что читает |
|---|---|---|
| Заголовок | Имя заголовка, в любом регистре | Значение заголовка; если заголовок пришёл несколько раз — его значения через , . |
| Параметр запроса | Параметр запроса | Его значение, декодированное; если он повторяется — первое. |
| Тело | — | Всё тело как текст. |
| JSON | Путь JSON, например $.user.id | Это поле тела JSON. |
Сравнения: равно, не равно, меньше, не больше, больше, не меньше, содержит, соответствует regex, пусто и не пусто. Числа сравниваются как числа, текст — точно. Отсутствующий заголовок, параметр или поле считаются пустыми. Сравнение, которое невозможно выполнить, — текста с числом — считается невыполненным.
Ответы
У маршрута от одного до 16 ответов (Ответы).
| Поле | Что | По умолчанию |
|---|---|---|
| Статус | 100–599. | 200 |
| Сбой | Что-то иное, чем ответ; см. Сбои. | Нет — ответить |
| Задержка, мс | Сколько ждать перед ответом, 0–60 000 мс. | 0 |
| Разброс, мс | Случайная добавка к ожиданию, до этой величины, 0–60 000 мс. | 0 |
| Вес | Доля этого ответа, когда маршрут отвечает случайно. Показывается только в этом случае. | 1 |
| Заголовки | До 32. В именах можно использовать параметры; значения — шаблоны. | нет |
| Тело | Шаблон, до 256 КиБ в записанном виде. | пусто |
Без заголовка Content-Type тело, которое является корректным JSON, уходит как application/json, а любое другое — как text/plain; charset=utf-8.
Когда ответов два или больше, поле Какой ответ определяет, какой из них получит запрос:
| Какой ответ | Что получают запросы | Для чего |
|---|---|---|
| По очереди, дальше последний | Первый, второй, …, а затем всё время последний: 500, 500, 200, 200, 200… | Повторы: два сбоя, потом работает. |
| По кругу | После последнего снова первый: 200, 500, 200, 500… | Зависимость, которая регулярно сбоит время от времени. |
| Случайно, по весу | Каждый раз выбирается по весу. Веса 8 и 2 дают первый ответ примерно в 80 % случаев. Хотя бы один вес должен быть больше 0. | Реалистичная доля сбоев. |
В списке Добавить ответ можно добавить к маршруту готовый ответ:
| Пресет | Что добавляет |
|---|---|
| 200 JSON | 200, {"ok":true} |
| 201 Created | 201, {"id":"{{uuid}}"}, заголовок Location: {{request.path}}/{{counter}} |
| 404 Not found | 404, {"error":"not found"} |
| 500 Server error | 500, {"error":"internal"} |
| 503 Unavailable | 503, {"error":"unavailable"}, заголовок Retry-After: 1 |
| Медленно — 2 с | 200, {"ok":true} через 2000 мс |
| Без ответа | Сбой Без ответа |
| Обрыв соединения | Сбой Закрыть соединение |
| Битый JSON | 200, {"items":[{"id":1},{"id":2}]} со сбоем Битое тело |
Сбои
| Сбой | Что встречает клиент |
|---|---|
| Нет — ответить | Ответ. |
| Без ответа | Ничего. Запрос удерживается до 2 минут, затем соединение закрывается — так проверяется собственный тайм-аут клиента. Задержка не применяется. |
| Закрыть соединение | Соединение закрывается без ответа, после задержки. |
| Битое тело | Полный HTTP-ответ с заданными статусом и заголовками, тело которого обрывается на середине: JSON, который не разбирается. Если всё тело было JSON, тип содержимого по-прежнему application/json. |
Запросы без маршрута
Поле Запросы без маршрута определяет, что получает запрос, который не подошёл ни к одному маршруту:
- 404 Not found — 404 с телом
{"error":"no_route"}; - Этот ответ — заданный вами ответ со всем, что есть у ответа маршрута. Его
{{counter}}считает запросы, которые не взял ни один маршрут.
В обоих случаях запрос попадает в счётчик Без правила.
Что может прочитать HTTP-ответ
| Шаблон | Что это |
|---|---|
{{request.method}} | GET, POST, … |
{{request.path}} | Путь, без строки запроса. |
{{request.params.id}} | Сегмент пути с именем :id. |
{{request.query.page}} | Параметр запроса, декодированный. |
{{request.headers.x-key}} | Заголовок; имена в нижнем регистре. |
{{request.body}} | Тело как текст: его первые 64 КиБ. |
{{request.json.name}} | Поле тела JSON, если тело — JSON и не больше 64 КиБ. |
{{request.from}} | IP:port клиента. |
Запрос с телом больше 1 МиБ получает 413 и попадает в счётчик С ошибкой. Ответ, который не удалось составить, — шаблон ссылается на то, чего в запросе нет, — заменяется на 500 с ошибкой в теле и тоже попадает в счётчик С ошибкой.
OSC-устройство
Каждому пришедшему сообщению — и каждому сообщению бандла по отдельности — отвечает первое правило, к которому оно подходит. Датаграмма, которая не является OSC, попадает в счётчик Без правила.
| Поле | Что |
|---|---|
| Шаблон адреса | Шаблон адреса OSC 1.0: * — любые символы, ? — один символ, [a-z] — набор, {a,b} — любой из вариантов, каждый в пределах одного сегмента (см. OSC). |
| Условия на аргументы | До 16 условий на аргументы, как в узле Ждать OSC (см. Узлы). |
| Отвечать | Флажок снят: принять сообщение и ничего не отвечать. |
| Адрес ответа | Адрес ответа, шаблон. |
| Аргументы ответа | До 16 аргументов, у каждого Тип (int, float, str, long, double, bool, blob, nil) и Значение — шаблон. |
| Куда отвечать | Пусто: обратно на адрес и порт отправителя. Иначе IP:port. |
| Задержка, мс, Разброс, мс | По 0–60 000 мс. |
Значение аргумента читается как его тип после заполнения шаблона: {{request.args[0]}} возвращает первый аргумент числом, если тип числовой. bool принимает true, 1, yes, on или false, 0, no, off; blob — байты в hex; пустое значение — ноль этого типа.
Ответы уходят с собственного порта эмулятора, поэтому их слышит клиент, который слушает тот порт, с которого отправлял.
OSC-ответ может читать {{request.address}}, {{request.args[0]}} и {{request.from}}.
UDP-устройство
Каждой датаграмме отвечает первое правило, к которому она подходит.
| Поле | Что |
|---|---|
| Совпадение | Любая датаграмма, Содержит текст, Соответствует regex или Содержит байты (hex). |
| Шаблон | Текст, регулярное выражение или байты, которые нужно найти. |
| Ответ | Принять без ответа, Текст или Hex, а затем сам ответ — шаблон. |
| Куда отвечать | Пусто: обратно отправителю. Иначе IP:port. |
| Задержка, мс, Разброс, мс | По 0–60 000 мс. |
UDP- или TCP-ответ может читать:
| Шаблон | Что это |
|---|---|
{{request.text}} | Содержимое как текст. |
{{request.match}} | Что совпало: текст, первая группа регулярного выражения (или всё совпадение), байты. |
{{request.hex}} | Содержимое в виде hex-байтов, первые 1024. |
{{request.bytes}} | Размер содержимого. |
{{request.from}} | IP:port отправителя. |
Текстовый ответ — не больше 65 507 байт.
TCP-устройство
Устройство, которое обменивается строками по TCP-соединению, как проектор или матричный коммутатор. Каждому сообщению клиента отвечает первое правило, к которому оно подходит; ответ уходит обратно по тому же соединению.
| Поле | Что |
|---|---|
| Конец сообщения | Что завершает сообщение и добавляется после каждого ответа и приветствия: LF (\n) (\r перед ним отбрасывается), CR LF (\r\n), CR (\r) или Нет — каждый пришедший кусок. Пустые строки пропускаются. |
| Приветствие | Отправляется, когда клиент подключается; пусто — без приветствия. Может читать {{request.from}}. |
| Совпадение, Шаблон, Ответ | Как у UDP-устройства. |
| Затем закрыть соединение | Закрыть соединение после ответа этого правила — например, на QUIT. |
| Задержка, мс, Разброс, мс | По 0–60 000 мс. |
Сообщение длиннее 64 КиБ без разделителя берётся как есть.
MQTT-брокер
Небольшой брокер MQTT 3.1.1 поверх обычного TCP. Он делает то же, что любой брокер: клиенты подключаются, подписываются с + и #, публикуют с QoS 0, 1 и 2, retained-сообщения и завещания (last will) работают, а второе подключение с тем же id клиента вытесняет первое. Сессии всегда чистые: клиент, который просит сохранить сессию, получает новую, и для отсутствующего клиента ничего не копится.
Вдобавок каждое опубликованное на нём сообщение проверяется по правилам: первое подошедшее ещё и публикует ответ — как устройство, которое сообщает, что сделало.
| Поле | Что |
|---|---|
| Имя пользователя, Пароль | Если имя пользователя задано, клиент должен подключиться с ним и с паролем; пусто — подключиться может кто угодно. Пароль без имени пользователя отклоняется: MQTT 3.1.1 не может его передать. |
| Сохранённые | До 64 сообщений (Топик, Содержимое, QoS), которые хранятся с момента запуска, как будто опубликованы с retain: подписавшийся клиент получает их первыми. |
| Фильтр топика | Какие топики берёт правило: + — один уровень, # — все остальные, например lab/+/set. |
| Совпадение, Шаблон | Условие на содержимое, как у UDP-устройства. |
| Отвечать | Флажок снят: принять сообщение и больше ничего не публиковать. |
| Топик ответа, Содержимое ответа | Шаблоны. В топике не может быть + или #. |
| QoS, Сохранить (retain) | Для ответа. |
| Задержка, мс, Разброс, мс | По 0–60 000 мс. |
MQTT-ответ может читать {{request.topic}}, {{request.levels[1]}} (уровни топика, начиная с 0), {{request.payload}}, {{request.json.state}}, {{request.match}}, {{request.qos}}, {{request.retain}}, {{request.client}} (id клиента) и {{request.from}}.
Шаблоны в ответах
Ответы пишутся на том же языке шаблонов, что и эксперименты, поэтому поле значит одно и то же и здесь, и там. Ответ может читать:
request— то, что пришло, как перечислено выше для каждого протокола;{{counter}}— сколько сообщений взяло это правило с момента запуска эмулятора, включая текущее;- генераторы —
{{uuid}},{{now.iso}}, случайные значения и остальные; случайные значения берутся из seed эмулятора; - параметры — когда эмулятор работает в эксперименте или запущен через
signallab emulate --param.
Секреты ответ не читает никогда, а неизвестное имя — это ошибка, а не пустой текст.
Некоторые поля фиксируются при запуске эмулятора, ещё до того, как что-то придёт: путь, условие, шаблон адреса, шаблон содержимого, фильтр топика, Куда отвечать, имя заголовка, retained-сообщения и учётные данные брокера. Они принимают только текст и параметры — без request и без генераторов.
Seed управляет случайным порядком ответов, разбросом задержки и случайными генераторами. На экране Эмуляторы каждый запуск получает новый seed; эксперимент использует seed запуска, а signallab emulate --seed берёт тот, что вы укажете.
Отключения
Чтобы проверить, что делает ваша система, когда зависимость то пропадает, то появляется, установите флажок Время от времени отключается:
| Поле | Что | По умолчанию |
|---|---|---|
| Работает, мс | Сколько эмулятор отвечает, 10–3 600 000 мс. | 10 000 |
| Отключён, мс | Сколько он отключён, 10–3 600 000 мс. | 3000 |
| Пока отключён | Только HTTP: что встречает запрос, пока эмулятор отключён. | 503 Недоступен |
Расписание начинается с запуска эмулятора и повторяется: работает, отключён, работает, отключён… Пока он отключён:
| Эмулятор | Что встречает клиент |
|---|---|
| HTTP | 503 Недоступен: 503 с Retry-After, равным числу секунд до возвращения (не меньше 1). Закрыть соединение: соединение закрывается без ответа. Без ответа: запрос удерживается до 2 минут, затем соединение закрывается. |
| TCP-устройство | Открытые соединения рвутся в течение 0,1 с; новые закрываются сразу при подключении. |
| MQTT-брокер | Все соединения рвутся; новые отклоняются (код возврата CONNACK 3, сервер недоступен). |
| OSC-, UDP-устройство | Ничего не отвечает. |
То, что приходит во время отключения, попадает в счётчик Во время отключения, а не в Без правила, и правила при этом не опрашиваются.
Кнопка Отключить делает то же самое по требованию, что бы ни говорило расписание, пока вы не нажмёте Включить; HTTP тогда встречает 503 без Retry-After. В эксперименте то же самое на нужном шаге запуска делает узел Эмулятор: выкл./вкл. (см. Узлы и Сбои).
Ошибки в эмуляторе
Пока вы редактируете, эмулятор проверяется через мгновение после каждого изменения, и ошибка показывается под его кнопками ещё до того, как вы нажмёте Запустить. Ошибка указывает место — правило, ответ или retained-сообщение и поле — и что не так: путь без /, регулярное выражение, которое не компилируется, шаблон ответа, который ссылается на что-то кроме request, параметров и генераторов, значение вне допустимого диапазона. Кнопка Запустить не запустит эмулятор с ошибкой.
Ограничения
| Что | Ограничение | При достижении |
|---|---|---|
| Маршрутов или правил на эмулятор | 64 | Эмулятор отклоняется при проверке. |
| Ответов на маршрут | 16 | Отклоняется. |
| Условий на маршрут | 16 | Отклоняется. |
| Заголовков на ответ | 32 | Отклоняется. |
| Условий на аргументы, аргументов ответа (OSC) | по 16 | Отклоняется. |
| Retained-сообщений (MQTT) | 64 | Отклоняется. |
| Тело, ответ или приветствие в записанном виде | 256 КиБ | Отклоняется. |
| Задержка или разброс | 60 000 мс | Отклоняется. |
| Тело HTTP-запроса | 1 МиБ | 413. |
| HTTP-соединений одновременно | 512 | Лишние закрываются сразу при подключении. |
| Строка и заголовки HTTP-запроса | 30 с | Клиент должен прислать их за это время. |
| TCP-соединений одновременно | 256 | Лишние закрываются сразу при подключении. |
| OSC- и UDP-ответов, ожидающих своей задержки | 1024 | Лишние отбрасываются и попадают в счётчик С ошибкой. |
| MQTT-клиентов одновременно | 256 | Лишние закрываются сразу при подключении. |
| MQTT-пакет | 256 КиБ | Соединение клиента разрывается. |
| MQTT-подписок на клиента | 100 | Лишние отклоняются. |
| Retained-топиков MQTT | 1000 топиков, 16 МиБ | Новое retained-сообщение доставляется, но не сохраняется. |
| MQTT-сообщений в очереди одного медленного клиента | 1024 сообщения, 8 МиБ | Клиент их пропускает; они попадают в счётчик Не доставлено. |
Эмулятор из ответа
Чтобы сделать эмулятор из ответа, который сработал:
- На экране HTTP отправьте запрос и получите ответ — или нажмите Отправить сейчас на HTTP-узле эксперимента.
- Нажмите ⧉ Сымитировать рядом с ответом. Окно Сымитировать этот ответ покажет маршрут, который будет создан.
- В поле Добавить в выберите один из своих HTTP-эмуляторов или Новый эмулятор.
- Нажмите Добавить маршрут. Откроется экран Эмуляторы на этом эмуляторе.
Маршрут отвечает на метод и путь запроса (без строки запроса) статусом, заголовками и телом ответа. Заголовки, которые относятся только к тому обмену (Content-Length, Date, Server, ETag и подобные), не переносятся, а тело отправляется как было, даже если в нём есть {{. Новый эмулятор содержит только этот маршрут. При добавлении в существующий эмулятор маршрут встаёт первым, чтобы отвечать раньше более общего маршрута; запущенный эмулятор подхватит его, когда вы нажмёте Перезапустить.
Если ответ взят из эксперимента, URL, записанный с шаблонами, превращается в шаблон пути: его основа ({{api}}) отбрасывается, сегмент, который целиком является шаблоном (/orders/{{order_id}}), становится :order_id, а сегмент, лишь частично состоящий из шаблона, завершает путь звёздочкой *.
Стартовый набор
Впервые не найдя библиотеку эмуляторов, Signal Lab записывает пять эмуляторов, все на этом компьютере. Их названия и заметки пишутся на языке, выбранном в интерфейсе в этот момент.
| Эмулятор | Слушает | Что делает |
|---|---|---|
| Демо API | 127.0.0.1:8080 | GET /health → {"status":"ok","time":…}; GET /users/:id → пользователь с этим id; POST /users → 201 с Location; GET /slow → ответ через 1500 мс; /flaky → 503, 503, а дальше всё время 200. |
| Демо OSC-устройство | 127.0.0.1:9100 | /ping → /pong со счётчиком; /fader/* → /ack с полученным адресом; /cue/* принимается без ответа. |
| Демо UDP-устройство | 127.0.0.1:7100 | PING → PONG и счётчик; всё остальное → ACK и его размер в байтах. |
| Демо TCP-устройство | 127.0.0.1:7200 | Строки, оканчивающиеся на CR LF. Приветствует READY; POWER? → POWER=ON; POWER ON или POWER OFF → OK ON / OK OFF; QUIT → BYE, затем разрывает соединение. |
| Демо MQTT-брокер | 127.0.0.1:1883 | Хранит retained online в lab/status; ON или OFF, опубликованные в lab/<name>/set → то же самое, retained, в lab/<name>/state. |
Стартовый сигнал Сервис работает? из библиотеки сигналов запрашивает http://127.0.0.1:8080/ — адрес эмулятора Демо API: маршрута для / у того нет, поэтому сигнал получает 404.
Файл библиотеки
Библиотека — это файл emulators.json в папке данных (см. Файлы); наведите указатель на счётчик под списком, чтобы увидеть его путь. Файл записывается целиком через 0,7 с после последнего изменения, через временный файл, так что неудачная запись оставляет прежний. Если файл не читается, список показывает ошибку с путём, строкой и столбцом, а сам файл остаётся как есть: исправьте его и нажмите Перечитать файл. Нажмите Перечитать файл и после того, как отредактировали файл вручную. Если файла нет, стартовый набор записывается снова.
{
"version": 1,
"emulators": [
{
"id": "orders-api",
"note": "Stands in for the orders service.",
"emulator": {
"name": "Orders API",
"bind": "127.0.0.1:18080",
"protocol": "http",
"routes": [
{ "method": "GET", "path": "/orders/:id",
"responses": [{ "body": "{\"id\":\"{{request.params.id}}\",\"state\":\"open\"}" }] },
{ "method": "POST", "path": "/orders", "order": "sequence",
"responses": [{ "status": 503 }, { "status": 201, "body": "{\"id\":\"{{uuid}}\"}" }] }
],
"outage": { "up_ms": 20000, "down_ms": 2000, "fault": "unavailable" }
}
}
]
}Объект emulator сам по себе — тоже документ, который читает signallab emulate.
В экспериментах и скриптах
- В эксперименте узел Эмулятор открывает свой эмулятор до первого шага и отвечает, пока запуск не закончится; то, что он получил, подсчитывается в отчёте. HTTP-эмулятор там же — это и есть то, что слушает узел Ждать HTTP-запрос (Узлы), а OSC- или UDP-эмулятор делит свой порт с ожиданиями запуска. Два эмулятора одного транспорта в одном эксперименте не могут делить порт. См. Узлы и Сбои.
signallab emulateзапускает эмуляторы из файлов или из этой библиотеки до Ctrl+C или до истечения--forи печатает, что они отвечают; см. Командная строка.
См. также
- Инспектор — каждый обмен, декодированный.
- Помехи — плохая сеть между вашей системой и эмулятором.
- Данные и шаблоны