
Research
Two Malicious Rust Crates Impersonate Popular Logger to Steal Wallet Keys
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
@lad-tech/nsc-toolkit
Advanced tools
Содержание
nsc-toolkit (NATS service creator toolkit)
一 это набор инструментов для создания сервис-ориентированной архитектуры.
Основная идеология тулкита заключается в установке минимального количества зависимостей, что позволяет создавать сервисы с помощью инструментов кодогенерации на основе простого описания в JSON-формате.
Основным средством коммуникации между сервисами в обычном режиме работы является брокер сообщений NATS. Применяются четыре основных способа:
request
/reply
) через брокер сообщений. Используется, если одному сервису, чтобы продолжать выполнять свою логику, требуются данные из другого сервиса.pub
/sub
). События используются, когда сервису необходимо оповестить другие сервисы о произошедшем событии, но кто слушает и обрабатывает эти события, сервису неизвестно. Это дает возможность строить независимые между собой сервисы для создания архитектуры на основе событий 一 Event-driven architecture (EDA).HTTP 1.1
. Этот метод используется, если сервису требуется передать в другой сервис поток данных. Например, список из миллиона пользователей или любые другие объемные данные, включая бинарные. Тогда брокер выступает только как средство для балансировки нагрузки и не участвует в передаче данных напрямую. Данные передаются с помощью web-потока из одного сервиса в другой через прямое соединение. Метод сервиса в качестве входных параметров может принимать поток данных и отдавать его в качестве ответа.pub
/sub
, но предоставляют возможность хранить сообщения на самом брокере. Такой тип коммуникации позволяет реализовывать более безопасный способ общения между сервисами на основе событий. События, если на них нет подписчиков на текущий момент, не пропадут, а сохранятся на самом брокере.Все четыре способа коммуникации между сервисами реализуются средствами библиотеки и описываются в JSON.
request
/reply
pub
/sub
GET [host]/healthcheck HTTP/1.1
)npm i @lad-tech/nsc-toolkit
Для обзора возможностей библиотеки рекомендуется использовать пример из каталога examples
, который состоит из 3-х сервисов. Подробно реализация логики описана в пункте Пример использования.
Чтобы запустить пример, необходимо:
npm i
examples
с сервисом HttpGate
cd ./examples/HttpGate
и установить там зависимости, так как для реализации HTTP-API используется библиотека Fastify:
npm i
Список всех зависимостей можно посмотреть тут.
DEFAUL_RESPONSE_TIMEOUT
一 внешнее ограничение тайм-аута при запросе в секундах. Используется при первоначальном формировании времени тайм-аута в багаже по формуле Date.now() + DEFAULT_RESPONSE_TIMEOUT
;OTEL_AGENT
一 хост агента по сбору распределенных трассировок.Основные компоненты библиотеки хранятся в каталоге src
. То, что не перечисленно в описании ниже, недоступно для использования и применяется только во внутреннем устройстве библиотеки.
Для реализации сервисов используются следующие компоненты.
Файл service.schema.json
. Каждый сервис описывается в формате json.
Ниже представлена схема описания.
{
"$schema": "http://json-schema.org/draft-04/schema#",
"type": "object",
"properties": {
"name": {
"type": "string"
},
"description": {
"type": "string"
},
"methods": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"action": { "type": "string" },
"description": { "type": "string" },
"options": { "$ref": "#/$defs/options" },
"request": { "type": "object" },
"response": { "type": "object" }
},
"required": ["action", "description", "options"]
}
},
"events": {
"type": "object",
"properties": {
"list": {
"type": "object",
"additionalProperties": {
"type": "object",
"properties": {
"action": { "type": "string" },
"options": {
"type": "object",
"properties": {
"stream": { "type": "boolean" }
},
},
"description": { "type": "string" },
"event": { "type": "object" }
},
"required": ["action", "description", "event"]
},
},
"streamOptions": {
"type": "object",
"properties": {
"prefix": { "type": "string" },
"actions": {
"type": "array",
"items": {
"type": "object",
"properties": {
"action": { "type": "string" },
"storage": { "type": "string" },
"retentionPolicy": { "type": "string" },
"discardPolicy": { "type": "string" },
"messageTTL": { "type": "number" },
"duplicateTrackingTime": { "type": "number" },
"replication": { "type": "number" },
"rollUps": { "type": "boolean" }
},
"required": ["action"]
}
}
},
"required": ["prefix", "actions"]
}
},
"required": ["list"]
}
},
"required": ["name", "description", "methods"],
"$defs": {
"options": {
"type": "object",
"properties": {
"useStream": {
"type": "object",
"properties": {
"request": { "type": "boolean" },
"response": { "type": "boolean" }
}
},
"cache": { "type": "number" },
"runTimeValidation": {
"type": "object",
"properties": {
"request": { "type": "boolean" },
"response": { "type": "boolean" }
}
}
}
}
}
}
Пояснения к схеме:
name
一 название сервиса;description
一 описание сервиса;methods
一 набор методов для реализации схемы request
/reply
;
action
一 идентификатор запроса;description
一 описание метода;request
一 JSON Schema входных данных;response
一 JSON Schema выходных данных;options
一 настройки метода;
useStream
一 использование Web-стримов для входных и выходных данных;
request
一 Web-стрим на входе;response
一 Web-стрим на выходе;timeout
一 Таймаут в миллисекундахcache
一 кеширование запроса (задается в минутах);runTimeValidation
一 использование runtime для валидации параметров;
request
一 для входных данных;response
一 для выходных данных;events
一 набор событий, генерируемый сервисом для реализации схемы pub
/sub
;
list
一 массив объектов событий, генерируемых сервисом;
action
一 идентификатор события;description
一 описание события;options
一 необязательные настройки события;
stream
一 булевый флаг, маркирующий, что событие является стримом;event
一 JSON Schema события;name
一 идентификатор события;description
一 описание события;event
一 JSON Schema события;streamOptions
一 настройки стрима;
prefix
一 префикс ко всем темам, у которых включена опция stream: true
;actions
一 массив объектов настроек стримов;
action
一 паттерн для тем, на которые будут применяться данные настройки (если указана *
, то применяется ко всем событиям с опцией stream: true
);storage
一 хранилище для сообщений стрима (доступные варианты file
|memory
, по умолчанию file
);retentionPolicy
一 по каким правилам будут удаляться сообщения из стрима (доступные варианты limits
|interest
|workQueue
, по умолчанию limits
);discardPolicy
一 определяет, какие сообщения будут отброшены при достижении лимита (доступные варианты old
|new
, по умолчанию old
);messageTTL
一 срок жизни сообщения (задается в секундах, по умолчанию 2 недели);maxBytes
一 максимально возможный лимит стрима по его размеру (если не указывать ограничения по размеру не будет);duplicateTrackingTime
一 временной отрезок, на котором работает дедубликация сообщений (задается в секундах, по умолчанию 1 день);replication
一 количество реплик стрима (по умолчанию 1);rollUps
一 флаг, разрешающий удалить все сообщения из стрима (по умолчанию true
).Файл позволяет описать все возможности создаваемого сервиса:
Сервис предполагается создавать из описания с помощью кодогенерации. Используется библиотека для кодогенерации сервиса из описания nsc-cli.
Класс Service
. Чтобы создать сервис, необходимо создать экземпляр этого класса и вызвать метод start
.
Принимаемые параметры при создании экземпляра:
name
一 имя сервиса.brokerConnection
一 необязательный параметр для подключения к брокеру NATS. Если его не передать, то будет использоваться внутренняя реализация брокера, и приложение будет собираться в монолит.methods
一 массив методов. BaseMethod
это один из базовых классов библиотеки, который необходимо расширить, чтобы создать метод с бизнес-логикой.events
一 описание генерируемых событий. Следует передать весь блок events
из service.schema.json
.cache
一 настройки межмикросервисного кеширования.
service
一 реализация интерфейса для сервиса кеширования;timeout
一 время, в рамках которого необходимо ожидать ответа от кеша (задается в миллисекундах).loggerOutputFormatter
一 реализация класса форматера для логов. Для логирования используется библиотека @lad-tech/toolbelt.gracefulShutdown
一 настройки по завершению работы сервиса.
additional
一 массив дополнительных сервисов, которые могут завершать свою работу. Необходим, чтобы сервисы реализовывали нужный интерфейс.timeout
一 время, в рамках которого ожидается штатная остановка сервиса.Публичные методы:
getRootBaggage
一 получение корневого багажа для распределенной трассировки. Источником могут служить заголовки http-запроса. Если подобные источники отсутствуют, то создается новый корневой багаж.endRootSpan
一 завершение корневого Span
по id
трассировки. Необходим для внедрения распределенных трассировок.buildService
一 метод, чтобы создать экземпляр клиента. Все используемые при запросах клиенты (сервисы) должны создаваться через этот метод, если необходимо использовать полную функциональность библиотеки.start
一 запуск сервиса.stop
一 остановка сервиса.Класс Client
. Чтобы создать клиент для сервиса, необходимо расширить класс Client
и описать в нем все доступные извне вызовы методов. Для вызова метода используется приватный метод CLient.request
. Пример создания клиента можно посмотреть тут.
Публичные методы:
getListener
一 метод получения объекта EventEmitter
для подписки на события сервиса.Класс Container
. Реализует DI-контейнре. Сам класс не доступен для импорта, а доступен только его экземпляр, что позволяет реализовать шаблон Singleton. В микросервисном варианте контейнер один на сервис. В монолитном варианте использования контейнер один на все приложение. За счет использования объектов Symbol в качестве ключей для привязки зависимостей исключены коллизии при привязках зависимостей в разных частях приложения через один контейнер. Для привязки зависимости к ключу необходимо указать тип зависимости. Это нужно чтобы библиотека могла корректно создать экземпляр зависимости. Всего существуют 3 вида зависимостей:
service
一 сервис как зависимости.adapter
一 класс с набором синхронных или асинхронных методов. Например репозиторий или фасад от стороннего API. Этот тип зависимости можно настроить с помощью необязательного объекта настроек. У опций адаптера могут быть следующие настройки:
singleton
一 Булевое значение. Если передать true
то адаптер станет singleton'ом. Объект будет создан один раз и дальше будет всегда использоваться один экземпляр.init
一 Булевое значение. Для того что бы использовать этот флаг адаптер должен реализовывать следующий интерфейс{
init: () => Promise<any>;
close: () => Promise<any>;
}
Если адаптер реализует требуемые методы и при передачи флага init
при привязки адаптера адаптер можно будет инициализировать через контейнер использую метод контейнера init
. Если к контейнеру было привязано несколько адаптеров, которые необходимо инициализировать, то после вызова метода контейнера init
все адаптеры будут инициализированны последовательно. Метод инициализации вернет массив инициализированных экземпляров адаптеров. Каждый адаптер с настройкой init
также становится singleton'ом.constant
一 обычный объект. Например, объект с конфигурацией. // Простой адаптер
container.symbol(key).to.Adapter(InitializableService);
// константа
container.symbol(key2).to.Constant({ obj: 'value' });
// Синглтон
container.symbol(key).to.Singleton(mySingleton);
// Сервис с автоинициазлзацией
container.symbol(key).to.Initializable(InitializableService);
// Сервис
container.symbol(key).to.Service(MyService);
Публичные методы:
bind
一 привязать реализацию к ключу.unbind
一 отвязать реализацию от ключа.get
一 получить реализацию по ключу.getInstance
一 получить экземпляр реализации. Для зависимости с типом service
нельзя получить экземпляр через этот метод поскольку для создания экземпляра сервиса требуется контекст в рамках которого он будет работать. Для зависимости с типом constant
вернется привязанный объект.Декораторы. Применение декораторов:
@service
:
@service
, а к самому классу метода применить декоратор @related
. Тогда при вызове метода сервиса не пропадет контекст запроса и можно будет использовать распределенные трассировки.@service
позволяет использовать функциональность сборки приложения в монолит.@instance
:
Для передачи объектов в поток можно использовать встроенные классы JsonToBufferTransform
и BufferToJsonTransform
, с помощью которых склейка буфера при передаче и парсинг произойдет в автоматическом режиме
Библиотека задумана как инструмент, не диктующий жестких правил, однако предлагается следовать следующим рекомендациям.
Использовать кодогенерацию на основе описания сервиса в файле service.schema.json
с помощью библиотеки nsc-cli. На основе описания будут автоматически сгенерированы сервис, клиент, методы и все интерфейсы. В результате весь шаблонный код будет написан и можно сразу приступать к написанию бизнес-логики. Для изменения сервиса (например, добавления нового метода, события или параметров запроса) следует в первую очередь изменить файл описания service.schema.json
, а затем перегенерировать сервис на его основе. Уже написанная логика не пропадет, но все изменения будут учтены в коде.
Описывать структуру сервиса. Ниже представлена декларативная структура сервиса следующего вида.
Service/
├── domain/
│ ├── aggregates/
│ │ ├── Aggregate_1/
│ │ │ ├── fixtures/
│ │ │ │ ├── fixture_1.json
│ │ │ │ ├── fixture_1.json
│ │ │ │ └── ...
│ │ │ ├── Aggregate.ts
│ │ │ ├── Aggregate.interface.ts
│ │ │ ├── Aggregate.test.ts
│ │ │ └── index.ts
│ │ └── Aggregate_2/
│ │ ├── fixtures/
│ │ │ ├── fixture_1.json
│ │ │ ├── fixture_1.json
│ │ │ └── ...
│ │ ├── Aggregate.ts
│ │ ├── Aggregate.interface.ts
│ │ ├── Aggregate.test.ts
│ │ └── index.ts
│ └── ports/
│ ├── index.ts
│ └── repository.ts
├── methods/
│ ├── Method_1/
│ │ ├── index.ts
│ │ ├── index.test.ts
│ │ └── ...
│ ├── Method_2/
│ │ ├── index.ts
│ │ ├── index.test.ts
│ │ └── ...
│ └── ...
├── repository/
│ └── index.ts
├── index.ts
├── interfaces.ts
├── service.ts
├── start.ts
├── inversion.types
├── service.schema.json
├── package.json
├── package-lock.json
└── tsconfig.json
Пояснения к структуре:
domain
一 каталог, который содержит в себе все классы предметной области сервиса и интерфейсы портов, необходимых для ее работы;
aggregates
一 каталог с агрегатами предметной области;
Aggregate
一 каталог агрегата (например, User
);
Aggregate.ts
一 класс агрегата;Aggregate.interface.ts
一 интерфейсы агрегата (например, интерфейс параметров для создания экземпляра агрегата или интерфейс представления агрегата);Aggregate.test.ts
一 тесты для агрегата;fixtures
一 фикстуры для тестирования агрегата;index.ts
一 реэкспорт агрегата и его интерфейсов;ports
一 каталог, который содержит интерфейсы для всех необходимых логике портов;
repository.ts
一 файл с интерфейсом необходимого репозитория для хранения агрегатов (для примера);index.ts
一 реэкспорт портов и его интерфейсов;methods
一 каталог с синхронными методами сервиса (генерируется автоматически);
Method_1
一 каталог метода;
index.ts
一 класс метода;index.test.ts
一 тесты для метода;repository
一 реализация репозитория на основе порта;index.ts
一 файл клиента сервиса (генерируется автоматически);interfaces.ts
一 интерфейсы сервиса (генерируется автоматически);service.ts
一 реализация сервиса (генерируется автоматически);start.ts
一 точка входа для запуска сервиса (генерируется автоматически);inversion.types.ts
一 Типы зависимостей используемые в логике сервиса. Типы используются для получения зависимости. Реализация требуемой зависимости привязывается к контейнеру через тип в файле сервиса. Описание встроенных возможностей инверсии зависимостей.service.schema.json
一 описание сервиса.Вся бизнес-логика сконцентрирована в двух местах структуры:
Пример использования инструментов тулкита находится в каталоге examples
.
Все три сервиса созданы для реализации тестовой логики "Странная сумма":
a
и b
.examples
HttpGate
一 cервис предоставляет http api с одним маршрутом POST /math/weird/sum
. В качестве тела запроса необходимо передать json. Например:{
"a": 5,
"b": 5
}
После получения запроса сервис HttpGate
синхронно через брокер вызывает сервис Logic
и, получив от него ответ, возвращает результат в качестве ответа на запрос.
LogicService
一 сервис реализует логику "Странной суммы". Сам сервис ничего не вычисляет, а использует другой сервис MathService
:HttpGate
, LogicService
синхронно вызывает метод сервиса Math.sum
, который складывает два переданных числа.Math.Fibonnacci
, в который передает результат предыдущего действия и в качестве ответа получает поток с числами Фибоначчи.Math.SumStream
, который складывает все числа в потоке и в ответе возвращает одно число, которое и является "Странной суммой".Elapsed
, в которое передает затраченное на выполнение вычислений время.MathService
一 сервис реализует 3 метода: Sum
, Fibonacci
и SumStream
, описанные выше. Помимо этих методов, сервис генерирует также два события:SumStream
сервис генерирует обычное событие Notify
.Elapsed
, в которое передает затраченное на выполнение вычислений время. Событие Elapsed
описано как Jet-stream.В результате запросов к тестовым сервисам генерируются трассировки следующего вида:
Библиотека поддерживает возможность сворачивать микросервисы в одно монолитное приложение. Чтобы реализовать эту возможность, необходимо придерживаться рекомендаций.
Для сворачивания в монолит необходимо использовать отдельную точку входа в приложение. Она должна находиться в сервисе, предоставляющем внешнее API к методам приложения.
Логика точки входа в монолитную версию приложения:
EventEmitter
. Доступ в созданному брокеру можно получить через открытое свойство сервиса broker
.Пример точки входа для монолитного режима и скрипт сборки можно посмотреть в каталоге examples
: точка входа.
┌───────────┐
│ HTTP_GATE │
└─────┬─────┘
┌─────────┴─────────┐
┌───┴───┐ ┌─────┴─────┐
│ Logic │ │ Service_1 │
└───┬───┘ └─────┬─────┘
│ ┌──────┴───────┐
┌──┴───┐ ┌─────┴─────┐ ┌─────┴─────┐
│ Math │ │ Service_2 │ │ Service_3 │
└──────┘ └───────────┘ └───────────┘
Библиотека реализует возможности по инверсии зависимостей через DI-контейнер. Экземпляр контейнера можно получить импортировав его из библиотеки. Для описания существующих ключей зависимостей рекомендуется использовать отдельный файл inversion.types.ts
в корне сервиса. Пример файла. Для внедрения зависимостей используются свойства класса метода или параметры конструктора. Для описания зависимости используется декоратор inject
, который можно импортировать из библиотеки. В декоратор необходимо передать символьный ключ из файла inversion.types.ts
. Саму привязку реализаций к DI-контейнеру рекомендуется осуществлять в основном файле сервиса service.ts
. Пример с глубоко вложенными зависимостями разных типов можно посмотреть в методе. Цепочка внедряемых зависимостей.
┌---------┐ ┌───────────-┐ ┌───────────---┐ ┌---------┐
| GetUser |--->│ Repository |--->| Configurator |--->| Storage |
└---------┘ └─────-─────-┘ └─────-─────---┘ └---------┘
FAQs
Toolkit for create microservices around NATS
The npm package @lad-tech/nsc-toolkit receives a total of 7 weekly downloads. As such, @lad-tech/nsc-toolkit popularity was classified as not popular.
We found that @lad-tech/nsc-toolkit demonstrated a healthy version release cadence and project activity because the last version was released less than a year ago. It has 4 open source maintainers collaborating on the project.
Did you know?
Socket for GitHub automatically highlights issues in each pull request and monitors the health of all your open source dependencies. Discover the contents of your packages and block harmful activity before you install or update your dependencies.
Research
Socket uncovers malicious Rust crates impersonating fast_log to steal Solana and Ethereum wallet keys from source code.
Research
A malicious package uses a QR code as steganography in an innovative technique.
Research
/Security News
Socket identified 80 fake candidates targeting engineering roles, including suspected North Korean operators, exposing the new reality of hiring as a security function.