% vim: set textwidth=64: \chapter{Сценарии} \section{Оракул} \subsubsection{Публикация <<фактов>>} Оракул стартует и обновляет стейт. Затем публикует набор <<фактов>>, отсутствующих в известном ему состоянии. \section{hbs2-browser} \subsection{Отображение списка ссылок} Предполагается, что \term{hbs2-browser}{hbs2-browser} будет отображать ссылки в виде списка с бесконечным скроллом, с возможностью поиска, с неким языком запросов. Для начала поисковой строкой будет являться просто подстрока из самой ссылки. В дальнейшем возможно расширение при помощи некоего DSL, где будут перечислены атрибуты. Если будут какие-либо специфические формы, с выбором опций --- то предпогается, что они просто будут добавлять некие термы в эту строку. На верхнем уровне отображется базовая информация для ссылки: её текстовое представление (обычно публичный ключ в base58), её тип. Возможно, некое описание. Например, название репозитория и список хэштегов. Предполагается оторбражение ссылок в порядке некоего веса, который вычисляется (TBD), возможно, формула для вычисление веса так или иначе определяется пользователем, например, возможностью редактирования весовых коэффициентов. Например, факторами могут быть время обновления и отношение к пользователю, которое может вычисляться исходя из встречаемости его ключей в данных ссылки (как пример). Данное требование предполагает наличие обязательных и дополнительных полей у отображаемой ссылки. \subsection{Отображение детализации ссылки} Понятно, что ссылок может быть произвольное количество и hbs2-browser не в состоянии знать их все, а тем более, осуществлять какую-то работу с ними. У нас не стоит цели разработать и запустить универсальную CMS. Мы не сможем встроить функции работы, например, с проектами в git в сам браузер, и вероятно, это было бы слишком. hbs2-browser может предоставить некоторый каркас отображения метаинформации; возможно несколько уровней. И предоставить возможность перенаправления на приложение, которое умеет работать со ссылкой (данными) такого типа. Рассмотрим примеры. \paragraph{git} Мы бы хотели видеть: название и описание репозитория, список авторов, README если есть, список бранчей и тегов. Еще бы мы хотели видеть структуру каталогов, и в переспективе --- просматривать каждый файл, как в онлайн-редакторе, так и raw виде. Однако, непонятно, как это сделать. Проекты могут иметь огромные размеры, как по количеству файлов, так и количеству коммитов. Если всё это делать метаданными, то размер метаданных сравняется или превысит размер изначальных данных, которые тоже могут иметь миллионы записей и гигабайты/десятки гигабайт размеров в предельных случаях (монорепозитории). Распаковка объектов на лету тоже малоприменима --- git~object~packs могут быть огромными, их может быть много, без полной распаковки объект не извлечь. Вероятно, на первом этапе стоит ограничиться списком ссылок и детализацией информации ссылки, например, нескольких уровней -- L1, L2. L2 подразумевает более подробную информацию о какой-то сущности ссылки, поэтому параметризуется этой сущностью. \paragraph{Пример:} \begin{verbatim} L1:репозиторий -> L2:список автров -> L3:автор \end{verbatim} С другой стороны, можно представить и таким образом: \begin{verbatim} L1:репозиторий -> L2:список авторов -> L2:автор \end{verbatim} Видно, что задача очень хорошо бы ложилась на XML/XSLT, если бы у нас была подобная опция. К сожалению, в современном мире такой опции нет и нам придётся изобретать некую замену, которая будет делать тоже самое, но не так. Таким образом, нам необходим способ преобразования из модели <<фактов>> в отображаемый формат (html). Мы не хотим, что бы этот способ был привязан к какому-то конкретному языку программирования. Мы не хотим, по возможности, встраивать эти преобразования в \term{hbs2-browser}{hbs2-browser}. Рассмотрим возможные варианты задания преобразований: \subsubsection{SQL+JSON} Пользователь задаёт в конфигурации SQL стейтмент, порождающий JSON + шаблон, который преобразует JSON в формат для отображения (html/htmx). Достаточно просто, доступный многим стек, возможны сложности с выполнением отображения в случае, если одного SQL запроса недостаточно, фиксируем СУБД (скорее всего, это будет sqlite, но это деталь реализации, которую не хотелось бы раскрывать), сколько-нибудь сложную логику писать в СУБД достаточно проблематично и способ зависит от БД. Отсутствие нормальной типизации. Слабые возможности абстракции. \subsubsection{Собственный EDSL} Требуется значительное время для разработки, необходима разработка средств разработки и отладки, высокий порог входа, возможное недовольство пользователей. \subsubsection{Биндинги в скриптовые ЯП + хост} Достаточно затратное встраивание, вопрос, какие именно ЯП выбрать из большого списка, необходимость принять множество решений при отсутствии достаточного количества объективных факторов для их оценки (какой язык <<лучше>>, какой <<хуже>> и множество еще) \subsubsection{Внешний процесс + некий IPC} К недостаткам относятся: необходимость в управлении этим процессом и его артефактами (сокеты, named pipes). Тем не менее, данный способ видится наиболее универсальным и простым относительно прочих. Способ в каком-то роде давно проверенный и доказанный: и cgi и fastcgi работают десятилетия уже, подход масштабируется. Внешним процессом может быть как некий сервер/сервант, так и запускаемый нашим процессом внешний процесс, обеспечивающий коммуникацию через pipe. При реализации Messaging через пайпы мы получаем такой же абсолютно RPC+Notifications, как во всех прочих частях системы: UDP, TCP, Unix sockets. Протокол может быть и бинарным и текстовым. Текстовый протокол может видеться, примерно похожим на HTTP: <<запросом>> является подобный HTTP заголовок, далее пустая строка <<\texttt{CR LF CR LF}>>, далее тело ответа, например, в JSON. Заголовки могут быть урезанным набором заголовков HTTP. При таком подходе мы можем интегрировать процессы, написанные на других языках, они получают достаточно простой текстовый интерфейс, при условии, что у них нет удобной реализации CBOR. Начать же мы можем с того, что просто реализуем \texttt{Messaging} c фреймингом, аналогичный TCP/ByPass --- но для pipes. Этот протокол может быть и синхронным и асинхронным, вероятно, лучше сразу же делать его асинхронным --- т.е потоки запросов и ответов являются независимыми, а на какой конкретно запрос поступает ответ --- зависит от специального поля в заголовке \texttt{REQID}. При асинхронном подходе нам не обязательно балансировать нагрузку внутри нашего хост-приложения --- балансировать может сам запущенный процесс. Почему нужно делать именно так: fork+RPC через pipes. \begin{enumerate} \item Имея механизм RPC через потоки ввода--вывода мы можем этот же механизм задействовать для named~pipes, то есть, для взаимодействия с внешним процессом, которым мы не управляем. \item Мы можем управлять нужным процессом и запускать его самостоятельно, не полагаясь на всякие системные вещи, типа systemd и внешних конфигурационных скриптов, снижая количество внешних факторов, влияющих на функционирование системы. \item Мы можем балансировать нагрузку, запуская нужное нам количество процессов и распределяя нагрузку между ними, если они имеют свойство блокироваться. \end{enumerate} Почему бинарный протокол в первую очередь: \begin{enumerate} \item Текстовый можно сделать позднее, для этого нужно просто подменить encode/decode в определении протокола. \item Это самое простое по реализации решение в данный момент, и отработанное на примере других протоколов/других транспортов. \item У нас всё уже для этого есть, и с примерами для других видов транспорта. Протокол для pipes будет почти полностью аналогичен протоколу для Unix sockets. \item Автор является и основным разработчиком системы, маловероятно, что на текущем этапе появятся какие-то другие разработчики, которые будут заинтересованы в разработке на других ЯП, кроме Haskell, а раз так, то все просто могут взять библиотеку и писать эти модули на Haskell. \end{enumerate} Почему асинхронный протокол: Потому, что синхронный --- его частный случай, как если бы асинхронный процесс просто затыкался после одного запроса. Это всё равно та ситуация, которую надо уметь обрабатывать. Так что сделав асинхронную обработку --- мы получим синхронную бесплатно. Механизмы ServiceProto уже умеют делать синхронные вызовы для асинхронных протоколов.