Если бы дизайнером D-Bus был я...
Jul. 29th, 2008 11:37 am![[personal profile]](https://www.dreamwidth.org/img/silk/identity/user.png)
Общесистемная/общесессионная шина сообщений, по которой приложения могут общаться между собой - штука полезная.
К сожалению, существующий кандидат на роль такой шины - D-Bus обладает рядом недостатков, затрудняющих понимание и использование её авторами приложений, и делающих практически невозможным использование этой технологии пользователями, обустраивающими свою рабочую среду с помощью наколенных скриптов.
Я бы сделал немножко по-другому
Как принято в Unix, все есть файл. Поэтому шина сообщений с точки зрения программы представляет собой двунаправленный файловый дескриптор (например, сокет) куда посылаются сообщения и откуда они принимаются.
Шина имеет топологию "звезда" - есть некий процесс - менеджер шины, с которым соединяются все процессы, желающие по этой шине общаться, и который решает кому какие сообщения форвардить.
Каждый из процессов, пользующихся шиной идентифицируется уникальным именем. Имя имеет иерархическую структуру (somethig.something.else).
Имена бывают двух видов - уникальные, генерируемые менеджером шины в момент соединения клиента (uuid.ХХХХХХХ где XXXXХХ некая алфовитно-цифровая строка) и well-known, к которым можно обращаться, чтобы получить некий известный сервис.
Вообще говоря, если менеджер шины знает, что процесса, предоставляющего данный сервис в данный момент в системе/сессии нет, он имеет право этот процесс запустить, если знает как.
Сообщения представляют собой текстовые строки, завершающиеся символом newline. Синтаксис может быть любым - лисповские S-expression, Tcl-списки, аналог командной строки shell. Мне представляется наиболее разумным использование синтаксиса shell.
Во-первых, этот синтаксис наиболее понятен всем пользователям. Во-вторых, shell таки самый высокоуровневый из распространенных скриптовых языков, Парсить сообщение в таком синтаксисе в шелл-скрипте можно посредством
Естественно, никакой типизации. Все есть строка. А как эту строку интерпретировать - вопрос договоренности между клиентом и сервисом (опубликовнаного интерфейса). Причем на уровне семантики, а не синтаксиса.
Формат сообщения следующий
Если в качестве получателя указана звездочка, то это широковещательное сообщение, которое рассылается всем клиентам (если только они не попросили менеджер шины фильтровать широковещательные сообщения и данное сообщение под фильтр не попало.
Если клиент отправлеят менеджеру шины сообщение, не содержащее адреса отправителя, то менеджер, прежде чем отправить сообщение получателю подставляет туда уникальное имя клиента, присвоенное ему при соединении.
При коннекте к менеджеру клиент получает от него сообщение
т.е. клиенту сообщается какое уникальное имя ему присвоили.
Если клиент хочет зарегистрировать well-known имя, он посылает сообщение:
на которое может получить либо
либо
После успешной регистрации имени, все имена в иереархическом дереве имен, начинающиеся с этого имени, считаются принадлежащими данному клиенту.
Сообщения с конкретным получателем могут быть вызовами методов, или ответами на вызов. У ответа на вызов получателем, как правило, является uuid.XXXX (исключение см выше).
Любой клиент, зарегистрировавший имя должен поддерживать метод Help, который вызывается следующими способами
Возвращает текстовое описание того, что этот клиент делает (apropos)
Возвращает список вложенных объектов в данном поддереве имен, которые поддерживаются данным клиентом.
Возвращает список методов, которые можно вызывать
Возвращает список параметров указанного метода
Возвращает информацию о том, что данный метод возвращает
Список ошибок, которые может вернуть данный метод.
Сообщение, являющееся ответом на вызов метода выглядит как
или
Методы объекта manager (менеджера шины)
Hello (вызывается неявно при соединении)
RegisterName (см выше)
UnregisterName - отмена регистрации имени (при закрытии соединеия отменяются все имена, зарегистрированные данным клиентом)
Filter glob-patterns - установка фильтра на широковещательные сообщения. Шаблон предваренный восклицательным знаком означает "не посылать сообщения удовлетворяющей данному шаблону". Просто шаблон - "посылать только сообщения, удовлетворяющие данному шаблону".
Client имя - возвращает известную менеджеру информацию об указанном клиенте. По крайней мере пользователя-владельца соответствующего процесса.
Available имя - возвращает статус доступности указанного имени. Может быть либо active (процесс, зарегистрировавший такое имя, выполняется) startable - менеджер знает, как такой процесс запустить и unknown.
Monitor on/off- заправшивает/отменяет пересылку данному клиенту ВСЕХ сообщений, бегающих по шине, независимо от отправителя получателя.
Debug on/off - разрешает данному клиенту посылать сообщения от имени любого отправителя. Этот метод завершается успешно только если юзер-владелец клиента совпадает с юзером-владельцем процесса-менеджера.
Некоторые соглашения о пространстве имен:
hw.* такие имена должны использовать в качестве имен отправителей сообщения, которые сообщают о событиях с оборудованем.
net.* сервисы, работающие с сетевыми соединеиями и сообщения о событиях с сетью.
Запуск сервисов менеджером - для каждой шины (системной/сессионной) имеется некоторая директория, в которую помещаются скрипты, запускающие сервисы, запускаемые on-demand. Имя скрипта должно совпадать с именем, которое зарегистрирует запущенный сервис.
Процессы-гейты, обеспечивающие гейтование шины в другой транспорт (например, сообщения протокола X11) вписываются в эту систему совершенно прозрачным образом. Единственное что для каждого клиента, приконнектившегося к гейту, гейт должен вызвать
manager.Hello явным образом, чтобы получить для него uuid.
Назовем данную конструкцию мы E-Bus. Во-первых, это "неприлично" звучит, а я люблю аббревиатуры на грани фола. Во-вторых, это сокращение от easy bus, в третьих - E - следующая буква алфавита после D,
К сожалению, существующий кандидат на роль такой шины - D-Bus обладает рядом недостатков, затрудняющих понимание и использование её авторами приложений, и делающих практически невозможным использование этой технологии пользователями, обустраивающими свою рабочую среду с помощью наколенных скриптов.
Я бы сделал немножко по-другому
Как принято в Unix, все есть файл. Поэтому шина сообщений с точки зрения программы представляет собой двунаправленный файловый дескриптор (например, сокет) куда посылаются сообщения и откуда они принимаются.
Шина имеет топологию "звезда" - есть некий процесс - менеджер шины, с которым соединяются все процессы, желающие по этой шине общаться, и который решает кому какие сообщения форвардить.
Каждый из процессов, пользующихся шиной идентифицируется уникальным именем. Имя имеет иерархическую структуру (somethig.something.else).
Имена бывают двух видов - уникальные, генерируемые менеджером шины в момент соединения клиента (uuid.ХХХХХХХ где XXXXХХ некая алфовитно-цифровая строка) и well-known, к которым можно обращаться, чтобы получить некий известный сервис.
Вообще говоря, если менеджер шины знает, что процесса, предоставляющего данный сервис в данный момент в системе/сессии нет, он имеет право этот процесс запустить, если знает как.
Сообщения представляют собой текстовые строки, завершающиеся символом newline. Синтаксис может быть любым - лисповские S-expression, Tcl-списки, аналог командной строки shell. Мне представляется наиболее разумным использование синтаксиса shell.
Во-первых, этот синтаксис наиболее понятен всем пользователям. Во-вторых, shell таки самый высокоуровневый из распространенных скриптовых языков, Парсить сообщение в таком синтаксисе в шелл-скрипте можно посредством
read message set -- $message
Естественно, никакой типизации. Все есть строка. А как эту строку интерпретировать - вопрос договоренности между клиентом и сервисом (опубликовнаного интерфейса). Причем на уровне семантики, а не синтаксиса.
Формат сообщения следующий
отправитель:получатель параметры
Если в качестве получателя указана звездочка, то это широковещательное сообщение, которое рассылается всем клиентам (если только они не попросили менеджер шины фильтровать широковещательные сообщения и данное сообщение под фильтр не попало.
Если клиент отправлеят менеджеру шины сообщение, не содержащее адреса отправителя, то менеджер, прежде чем отправить сообщение получателю подставляет туда уникальное имя клиента, присвоенное ему при соединении.
При коннекте к менеджеру клиент получает от него сообщение
manager.Hello:uuid.XXXXXXX
т.е. клиенту сообщается какое уникальное имя ему присвоили.
Если клиент хочет зарегистрировать well-known имя, он посылает сообщение:
manager.RegisterName имя
на которое может получить либо
manager.RegisterName:имя ok
либо
manager.RegisterName:имя error "имя уже занято"
После успешной регистрации имени, все имена в иереархическом дереве имен, начинающиеся с этого имени, считаются принадлежащими данному клиенту.
Сообщения с конкретным получателем могут быть вызовами методов, или ответами на вызов. У ответа на вызов получателем, как правило, является uuid.XXXX (исключение см выше).
Любой клиент, зарегистрировавший имя должен поддерживать метод Help, который вызывается следующими способами
some.client.Help
Возвращает текстовое описание того, что этот клиент делает (apropos)
some.client.Help objects
Возвращает список вложенных объектов в данном поддереве имен, которые поддерживаются данным клиентом.
some.client.Help methods some.client.subobject.Help methods
Возвращает список методов, которые можно вызывать
some.client.Help parameters Имя
Возвращает список параметров указанного метода
some.client.Help retval Имя
Возвращает информацию о том, что данный метод возвращает
some.client.Help errors Имя
Список ошибок, которые может вернуть данный метод.
Сообщение, являющееся ответом на вызов метода выглядит как
some.client.Method:uuid.caller ok возвращаемые значения
или
some.client.Method:uuid.caller error сообщение об ошибке [машинно-читаемые данные об ошибке]
Методы объекта manager (менеджера шины)
Hello (вызывается неявно при соединении)
RegisterName (см выше)
UnregisterName - отмена регистрации имени (при закрытии соединеия отменяются все имена, зарегистрированные данным клиентом)
Filter glob-patterns - установка фильтра на широковещательные сообщения. Шаблон предваренный восклицательным знаком означает "не посылать сообщения удовлетворяющей данному шаблону". Просто шаблон - "посылать только сообщения, удовлетворяющие данному шаблону".
Client имя - возвращает известную менеджеру информацию об указанном клиенте. По крайней мере пользователя-владельца соответствующего процесса.
Available имя - возвращает статус доступности указанного имени. Может быть либо active (процесс, зарегистрировавший такое имя, выполняется) startable - менеджер знает, как такой процесс запустить и unknown.
Monitor on/off- заправшивает/отменяет пересылку данному клиенту ВСЕХ сообщений, бегающих по шине, независимо от отправителя получателя.
Debug on/off - разрешает данному клиенту посылать сообщения от имени любого отправителя. Этот метод завершается успешно только если юзер-владелец клиента совпадает с юзером-владельцем процесса-менеджера.
Некоторые соглашения о пространстве имен:
hw.* такие имена должны использовать в качестве имен отправителей сообщения, которые сообщают о событиях с оборудованем.
net.* сервисы, работающие с сетевыми соединеиями и сообщения о событиях с сетью.
Запуск сервисов менеджером - для каждой шины (системной/сессионной) имеется некоторая директория, в которую помещаются скрипты, запускающие сервисы, запускаемые on-demand. Имя скрипта должно совпадать с именем, которое зарегистрирует запущенный сервис.
Процессы-гейты, обеспечивающие гейтование шины в другой транспорт (например, сообщения протокола X11) вписываются в эту систему совершенно прозрачным образом. Единственное что для каждого клиента, приконнектившегося к гейту, гейт должен вызвать
manager.Hello явным образом, чтобы получить для него uuid.
Назовем данную конструкцию мы E-Bus. Во-первых, это "неприлично" звучит, а я люблю аббревиатуры на грани фола. Во-вторых, это сокращение от easy bus, в третьих - E - следующая буква алфавита после D,
no subject
Date: 2008-07-29 08:31 am (UTC)no subject
Date: 2008-07-29 08:37 am (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 08:41 am (UTC)no subject
Date: 2008-07-29 08:47 am (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 08:41 am (UTC)no subject
Date: 2008-07-29 08:53 am (UTC)(no subject)
From:(no subject)
From: (Anonymous) - Date: 2008-07-29 04:59 pm (UTC) - Expandno subject
Date: 2008-07-29 02:38 pm (UTC)Витус, я советую просто для вдохновения прочитать Plumbing and other utilities.
no subject
Date: 2008-07-29 08:44 am (UTC)no subject
Date: 2008-07-29 08:50 am (UTC)(no subject)
From:(no subject)
From: (Anonymous) - Date: 2008-07-29 09:07 am (UTC) - Expand(no subject)
From:(no subject)
From: (Anonymous) - Date: 2008-07-29 03:38 pm (UTC) - Expand(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 08:45 am (UTC)no subject
Date: 2008-07-29 08:48 am (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From: (Anonymous) - Date: 2008-07-29 08:58 am (UTC) - Expandno subject
Date: 2008-07-29 09:01 am (UTC)power.*
no subject
Date: 2008-07-29 09:09 am (UTC)Одно отличие, что там RPC с сериализованными типами данных.
no subject
Date: 2008-07-29 09:17 am (UTC)Основное отличие того, что я придумал - это именно ТЕКСТОВОЕ представление, плюс штатная возможность для юзера подключиться и это представление по ходу дела читать и даже писать (manager.Monitor и manager.Debug)
Это - главное - возможность легко и просто пощупать руками.
(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 10:02 am (UTC)От DCOP, не смотря на его удобства, всё же отказались, т.е. он уходит вместе 3-ми кедами
(no subject)
From:no subject
Date: 2008-07-29 09:38 am (UTC)Тогда недостает еще метода manager.GoodBye. Потому как сокет у гейта один, и закрывать его по отцеплении одного из клиентов он не будет.
no subject
Date: 2008-07-29 11:40 am (UTC)2) А чего точки, а не слэшы?
3) Добавь help aliases или help names, который бы возвращал список имён, под которым опубликован данный объект (some.server.subtree..., uuid.XXX.subtree, в таком духе).
4) Для некоторых приложэний очень жэлательно, чтобы иерархия подключений просматривалась. В смысле — кто чей родитель, кто с кем в одном дереве наследования и всё такое. По-моему, имеет смысл её сюда внедрить. Например, изменяя какое-нибудь значение в ENVIRONMENT, которое отвечает за подключение к сэссионному варианту менеджэра.
5) В связи с 4): имеет прямой смысл добавить концэпцыю параметров, указываемых при подключении. То есть что-то вроде ENV{SESS_CONNECT}="~/.ebus/sock-host COOKIE=abcdef BRANCH=uuid.123456".
Первая строка, с сокетом, эскейпиться, например, через \0xhex и \0oct для пробелов и остальных тильд. Можно, впрочем, вебовскую, как она бишь называется?
6) Большые буквы набирать муторно. То есть с этим надо что-то делать по-моему (или ignore case, или переделать имена на маленькие).
7) Предлагаю ограничить имена до us-ascii. Для передаваемых строк, которые могут буть локализованны — сделать стандартом rfc2047.
8) По-моему не нужно пользовательским приложэниям подключаться к общесистемной, если за них это можэт сделать сэссионный менеджэр. Опять жэ, толика контроля над криворукостью сисадмина появится.
no subject
Date: 2008-07-29 11:45 am (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 12:06 pm (UTC)Способ формирования uid на данный момент неспецифицирован. Может это и будет номер по порядку. 64 битный. Тогда от перезагрузки до перезагрузки точно хватит.
Почему бы и нет? Программистам на большинстве языков оно привычнее.
Не понял. Имен у объекта может быть ровно ОДНО. Потому что объект - это поддерево в пространстве имен. Не более того. Один и тот же клиентский процесс может зарегистрировать несколько несвязанных поддеревьев. Но вообще-то это уже клиентов не касается.
Какой родитель, какое наследование? Ты о чем? Единственное что из данной спецификации может представлять интерес, это какие n первых компонентов имени вызываемого метода зарегистрированы как сервис в менеджере шины, а какие m остальных - обрабатываются процессом сервиса.
Не имеет. Преумножение сущностей.
Купи книжку "Соло на клавиатуре" и потренируйся. Научишься работать с клавиатурой - будет пофигу.
Ограничение имен us-ascii - это стоит подумать. Оно так проще будет обеспечивать международную кооперацию разработчиков. Но вот RFC2047 - никогда и ни за что. Текст сообщения должен передаваться в читаемом виде. Utf-8 и только UTF-8. Благо уже скоро люди забудут что бывают другие локали.
Вообще говоря, система на которой выполняется программа, это не та система, на которой выполняется сессионный менеджер. И если у меня на экране ноутбука сидит окошко программы, выполнгяющейся на ноутбуке жены, а жена решила ноутбук в суспенд отправить, то программа должна получить сообщение о суспенде СВОЕЙ системы. А программы, выполняющиеся на моем ноутбуке локально - не должны получать сообщение о суспенде какой-то совершенно посторонней системы.
Правда, из этого следует, что основным транспортом сессионной шины должен быть X11, а не сокет, а гейт этого транспорта в сокетный должен быть встроен в эмулятор терминала.
(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:no subject
Date: 2008-07-29 04:36 pm (UTC)Т.е. у, получается, что у клиентов иерархии нет, все они на одном уровне?
Или вполне можно зарегистрировать имя my.clientA, а потом ещё и my.clientA.subclientX, т.е. при выборе предпочтение отдаётся самому длинному (по количеству слов) имени?
> Если в качестве получателя указана звездочка, то это широковещательное сообщение, которое рассылается всем клиентам
А если указано в виде "ptrfix.*" - широковещательный на данную ветвь дерева, ага?
no subject
Date: 2008-07-29 05:09 pm (UTC)Широковещательных сообщений на данную ветвь дерева я вообще-то не предполагал.
В простейшем случае well-known имена получателей - это имена сервисов. Нафига им широковещательные сообщения? Их дело свои собственные интерфейсы реализовывать. А в широковещательных сообщениях заинтересованы в первую очередь те клиенты, которые имен не регистрируют. А у тех, кто регистрирует - обработка широковещательных сообщений логически сильно отделена от обработки вызовов методов.
Впрочем, если придумаешь интересный use case, можно и реализовать.
no subject
Date: 2008-07-29 04:36 pm (UTC)no subject
Date: 2008-07-29 05:04 pm (UTC)Отсутствием возможности поиграться руками с сообщениями, бегающими по шине.
Переусложненностью адресации - ну нафига при вызове метода указывать и имя сервиса, и имя интерфейса и имя объекта? Имя объекта может быть производным от имени сервиса, а уж какие интерфейсы объект реализует - он сам разберется.
Типизацией параметров. Чай не двадцатый век на дворе, чтобы программист думал о типах переменных.
Сложностью интеграции в event loop произвольного GUI-тулкита.
маленькое замечание
Date: 2008-07-29 04:48 pm (UTC)имя
уже занято, то сообщение уйдёт не тому. Там должен стоять uuid. За исключением этого всё вроде логично.Re: маленькое замечание
Date: 2008-07-29 05:05 pm (UTC)Re: маленькое замечание
From:навскидку
Date: 2009-10-09 09:54 am (UTC)Отладка - не магия, в приличных инструментах даже дамп можно посмотреть в простом hex режиме.
А засада состоит в том, что как и с XML-ем, сначала придумали "нечто текстовое", а потом взялись за головы - на дворе-то 21 век, мультимедия заполонила весь винт - что, тоже в тексте держать? Не эффективно.
Я бы предложил всё же ориентироваться сразу на бинарное представление, но с гибким форматом сообщения - т.е. принимаем мы всегда чётко сформированный пакет (который уже точно не надо отлаживать), а данные могут быть какие угодно, наращиваемые по ходу дела. Далее...
> Как принято в Unix, все есть файл.
Как принято в ООП, всё есть объект. :) Ничего не напоминает? Так вот файлы юникса меня раздражают не меньше, чем вас - объекты. И тут я бы заложился сразу на сетевое представление. Скажем, так:
var session = open("host.russia.ru")
var service = session.getService("mail.send")
Есессно, при отсутствии хоста будет использоваться локальная машина без вообще какого-либо TCP/IP.
И тут мы приходим к не совсем стройной модели - ведь у нас есть как сервисы, так и "пространства имён". Но где разница между ними? Скажем, мне нужно послать сигнал shutdown всем сервисам. Как узнать их имена? Обратиться к сервис-менеджеру. Но он тоже в свою очередь - лишь один из обслуживающих менеджеров, помимо железо-менеджера и секурити-менеджера, которых тоже кто-то должен зарегистрировать при старте и выдать списком. Ничего пока не предлагаю, просто подумайте над моделью.
Re: навскидку
Date: 2009-10-09 10:04 am (UTC)Увы, с 70-х годов прошлого века ничего нового не изобретено.
Смысл - в первую очередь не отладка, а casual programming. Чтобы можно было легко и на любом языке (благо с файлами и строками умеют работать все) написать что-то, что с этой шиной работает. В считанные строчки.
Грамотность - это не способность написать роман-бестселлер. Это способность записать нужный адрес на любом клочке бумаги или даже губной помадой на зеркале. Вот от программирования мне требуется то же самое - не только и не столько возможность создать супермегаприложение, а возможность за пять минут заавтоматизировать какую-нибудь простую задачу. Причем используя тот инструмент, который мне сегодня больше всего для этого нравится.
А насчет сетевого представления - категорически не согласен. Система должна обладать полной сетевой прозрачностью. То есть, приложение запущенное на моем дисплее должно быть способно работать с сессионной шиной независимо от того, сколько NAT-ов, файрволлов и криптованных туннелей от того хоста, где оно исполняется до того, где окошки рисуются.
Поскольку если я его вижу, оно является частью сессии. Соответственно, сессионная шина должна уметь передаваться через X11 протокол. Любые другие способы её передачи по сети потребуют значительного усложнения инфраструктуры - придется не один порт форвардить, а два, да к тому же на втором обеспечивать аутентификацию и авторизацию, которые в X11 давно встроены.
Системная шина вообще не должна быть доступна по сети. Потому что security hole. Хочешь поуправлять машиной, залогинься на неё (по сети) и повыполняй команды локально. Благо протоколы удаленного выполнения команд существуют, в них уже все продумано с авторизацией и шифрованием, и нечего их дублировать.
Ну это с 70-х годов прошлого века реализуется через сигналы, а не через шину сообщений. И нечего это менять. Шина сообщений не заменяет, а дополняет существующие средства межпроцессной коммуникации.
Re: навскидку
From:Re: навскидку
From:до основанья - и никак иначе!
From:Интересует момент
Date: 2009-10-11 09:29 pm (UTC)Т.е. типа мы можем иметь глобальную шину /var/run/ebus.fifo и локальную ~/.ebus.fifo, обслуживающиеся двумя независимыми демонами. А что с глобальными событиями, например, "отключилась флешка", которое, по идее, должно исходить от системной шины.
Или по чтению, пользовательское приложение может вешаться на глобальную шину (0644 на /var/run/ebus.fifo), а по записи - только на локальную?
В плане реализации подвижек нету? У меня витают задумки для arm (мобильник htc), но хз, доберутся ли руки.
Re: Интересует момент
Date: 2009-10-12 06:40 am (UTC)А надо? Если речь идет о сессионной шине, то все запущенные в пределах сессии приложения запущены от имени одного и того же пользователя.
Поэтому при помощи механизма прав ничего разрулить нельзя.
В случае системной шины там могут быть разные права. Но не исключено что дешевле полагать все сообщения, ходящие по системной шине untrusted, чем пытаться разруливать права доступа.
no subject
Date: 2009-12-02 06:16 pm (UTC)Тогда help надо делать обязательной частью интерфейса, а не сервиса.
no subject
Date: 2009-12-02 06:25 pm (UTC)(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From:(no subject)
From: