Архитектура платформы¶
NodaLogic - это распределенная система, которая может быть как централизованной с сервером и клиентами- мобильными устройствами и веб клиентами, так и децентрализованной, в том плане что логика «узлов», основных кирпичиков системы, может выполняться как на сервере, так и на устройствах-клиентах, серверов может быть много, а каждый клиент в свою очередь может быть также сервером.
Основа решений – «узел». Это объект, который одновременно является хранилищем данных и имеет исполняемые методы. Это такой самостоятельный микросервис, хранящий данные и готовый взаимодействовать с другими узлами. Из узлов строится фронтовое решение и бекенд (границы фронт/бек размыты в NodaLogic, так как «сервер там, где в данный момент выполняется узел») . В каком-то смысле, это как нейрон, имеющий вход/выход и веса.
Узлом может быть такие сущности как «задача», «документ», «строка документа», любая другая бизнес сущность – склад, товар, ячейка. И виртуальные сущности – «остаток товара в ячейке», например.
Данные узла хранятся в _data – это и оперативная и долговременная память. _data – это JSON-совместимая структура данных. Узел имеет ссылку на класс. Сам класс задает поведение узла, его обложку, описывает события (связь событий и методов).
Данные из интерфейса и обработчиков попадают в _data, и наоборот хранимые в _data данные отображаются в интерфейсе. По сути - это обычная JSON-ориентированная NoSQL.
На клиенте(мобильном устройстве или веб-клиенте) при пользовательском вводе возникает событие onInput/onInputWeb и если на него есть какой то метод-обработчик, то он обработает эти данные, сохранит, возможно вызовет другие методы или отправит другим узлам (путем вызова их методов). На картинке ниже ситуация: пользователь нажал на кнопку - сработало событие onInput, на которое есть подписка в виде метода Input (python) - метод python (на мобильном устройстве) выводит тост(сообщение) с переменной input1, в которой хранится ввод из поля ввода.
На сервере (если узел имеет серверные методы) узел можно представить как микросервис. Когда вы создаете класс, автоматически создается REST API класса по которому можно обратиться как к классу так и к его объектам - узлам посредством HTTP-запросов. Если при этом узел имеет серверные методы, то их также можно выполнять удаленно как из внешней системы так и с мобильных клиентов.
Таким образом, формально узел – это данные _data + класс (описывающий методы и поведение узла в системе). С одной стороны узел - это единица данных, как запись в NoSQL, с другой стороны - микросервис.
Вот пример класса узла в python (для мобильного клиента). Видно что он наследуется от Node и имеет какие-то свои методы. Метод Open отвечает за отрисовку, в Input - за обработку ввода.
class MyClass(Node):
def __init__(self, modules, jNode, modulename, uid, _data):
super().__init__(modules, jNode, modulename, uid, _data)
"""Class MyClass"""
def Open(self, input_data=None):
self.Show(
[
[{"type":"Input","id":"input1","caption":"input 1","value":"@input1"}],
[{"type":"Button","id":"button1","caption":"Get result"}]
]
)
return True,{}
def Input(self, input_data=None):
toast(self._data["input1"])
return True,{}
В данный момент доступны 2 типа узлов:
Обычный узел (Узел данных) с поведением, описанным выше
Пользовательский процесс – узел, существующий в одном экземпляре, который создается в интерфейсе клиента для выполнения каких то пользовательских задач. В отличии от узла – его не надо создавать или передавать, он создается при загрузке конфигурации
Классы, в свою очередь хранятся в конфигурации – JSON структуре или файле. Таким образом конфигурация – это набор классов узлов. Но не только – в конфигурации также задается настройка решения в целом – общие события, разделы и так далее. Т.е. конфигурация - это JSON-хранилище классов узлов, обработчиков (в виде base64-кодированного python-файла) и общих настроек. Подробнее о структуре этого файла в разделе «Структура конфигурации»
На клиенте может быть загружено одновременно любое число конфигураций в «репозиторий конфигураций» и все они активны одновременно, как для пользователя так и друг для друга. Просто классы размещаются к правило в своих разделах и не мешают друг другу. На сервере такой же принцип – каждая конфигурация существует сама по себе, каждый класс имеет свой API, каждый узел живет сам по себе.
Узел может работать на сервере и на клиенте или и там и там одновременно. При этом как правило, он работает локально – на той машине где выполняется, но может обращаться к узлу на сервере, о чем далее
Вот сценарий пассивного использования узла в оффлайновом решении (как объекта данных)
Узлы сбрасываются HTTP-запросом на сервер. Класс в конфигурации на сервере автоматически имеет свой REST-API. По нему можно создавать узлы, запрашивать данные, выполнять методы.
Узлы отправляются клиентам через механизм комнат (Rooms) Устройства объединяются в rooms через WebSocket и всегда готовы принять изменения по узлам как мессенджеры принимают сообщения
Узел на устройстве работает самостоятельно оффлайн. Связь с сервером не нужна. На клиенте выполняется UI/UX, накапливаются данные
По необходимости данные отправляются в узлы на сервере, путем вызова их методов либо просто _data в таком же узле на сервере замещается _data узла с клиента
Внешняя система через тот же REST-API забирает данные.
Сценарий, где сервер играет свою роль почти такой же, но имеет важное отличие – бизнес логика выполняется на сервере. Разберем это на примере WMS-решения:
Учетная система отправляет распоряжения на сервер NodaLogic – допустим это какие то накладные системы – заказы клиентов, накладные от поставщиков.
Узлы на сервере, которые являются генераторами задач, порождают узлы-задачи для клиентов-устройств и регистрируют их в Room, они попадают на устройство
На устройстве пользователь выполняет задачи, данные о фактическом выполнении сразу поступают на сервер (по сути онлайн-режим). На сервере выполняются учетные процессы, такие как вычисление остатков товаров например.
По выполнению либо сервер шлет HTTP-запрос во внешнюю систему, либо система обращается к узлу-генератору задач и забирает выполненные задачи (по сути-фактические данные). Также она может обратиться к учетному узлу и запросить например остатки в ячейках
И также могут быть сценарии вообще без сервера, где просто создается мобильное решение, в котором узлы отправляются на сервер через rooms либо вообще через файлы. Либо вообще не используются узлы данных и это просто мобильное решение. Таким образом, система может быть просто конструктором мобильного клиента - фронта.
Резюмируя все вышесказанное, можно сказать что узел – это некий самостоятельный объект, решение – это набор классов, а система будь то сервер или клиент - рой объектов, которые могут взаимодействовать между собой. А клиентское приложение – это «плеер» узлов, в то время как узлы доставляются в него в режиме мессенджера (или например просто через файлы через почту или другие мессенджеры), порождаются пользователем или другим узлами. Это своеобразное развитие идеи suip-файлов в SimpleUI https://uitxt.readthedocs.io/ru/latest/suip.html