Um pequeno serviço D-Bus em Python

Dentre os métodos para se fazer comunicação entre processos no Linux, o D-bus é provavelmente o que vem ganhando maior destaque recentemente. Aqui vou mostrar como implementar um serviço simples que poderá ser chamado de outros processos, demonstrando sua utilização a partir do Emacs; no entanto, nada impede que os métodos desse serviço sejam chamados de outra linguagem em que existam bindings para o D-Bus (o próprio Python, C/C++, C#, Perl, Ruby, PHP, Haskell, …). Aliás, é possível que em alguns casos seja mais simples fazer a integração entre processos escritos em linguagens diferentes através do D-Bus que usar foreign functions.

#!/usr/bin/env python2

import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
import gobject

class Greeter(dbus.service.Object):
    def __init__(self, Name=""):
        bus_name = dbus.service.BusName('org.local.greeter',\
                                            bus=dbus.SessionBus())
        dbus.service.Object.__init__(self, bus_name, '/%s' % Name)

    @dbus.service.method('org.local.greeter')
    def hello(self, Name="world"):
        print "Hello, %s!" % Name
        return "Hello, %s!" % Name 

DBusGMainLoop(set_as_default=True)
myGreeters = [Greeter("A"), Greeter("B")]

myLoop = gobject.MainLoop()

try:
    myLoop.run()
except KeyboardInterrupt:
    myLoop.quit()
    print "Bye!"

Começamos o arquivo importando os módulo necessários. Em vez de importar o módulo gobject, alguns tutoriais usam o módulo gtk. A função dos dois será a mesma: implementar o loop principal do serviço (tanto que o loop principal do gtk é implementado sobre o loop principal do gobject, apenas com alguns tratadores a mais). Como não iremos usar nenhum componente gráfico neste exemplo, não há a necessidade de se usar o gtk.

Em seguida criamos a classe que implementará o serviço, a classe Greeter. No construtor (__init__), definimos o nome do serviço — no caso, org.local.greeter —, e dizemos que ele é um Session Bus em vez de um System Bus (este reservado para serviços de mais baixo nível, como o HAL e o NetworkManager. No construtor também iniciamos o objeto, informando o nome que definimos anteriormente e lhe dando um caminho (path). O caminho é útil em casos onde se que o mesmo serviço dê acesso a vários objetos parecidos — por exemplo, o Emacs poderia dar acesso via D-Bus a cada um de seus buffers através do caminho /Emacs/Buffers/<Nome do Buffer>.

Depois, definimos um método. Note a presença do decorador (@dbus.service.method('org.local.greeter')). De certa forma, esse decorador estabelece que o método a seguir é “público”, ou seja, que pode ser acessado por processos externos. Para termos uma melhor organização do código, podemos criar outros métodos que não queremos que sejam acessíveis externamente; nesses casos, basta não usar o decorador. O método em si é bastante simples: ele imprime uma mensagem no terminal em que o serviço estiver rodando e retorna para o processo que o chamou essa mesma mensagem. Na prática, geralmente desejaremos que o serviço retorne alguma coisa em vez de imprimir, mas deixei assim para mostrar que existem as duas possibilidades.

Então temos o código para fazer o serviço executar. Criamos um novo DBusGMainLoop e o definimos como Loop padrão. Seguindo a documentação, atualmente não faz sentido criar mais de um loop, já que ainda não há suporte para isso (ao menos não no Python). Na linha seguinte são criados dois objetos da classe Greeter, cada um com um path diferente, /A e /B; fiz assim para demonstrar como isso é utilizado. E então criamos o loop principal e o executamos.

Do lado do cliente — no caso, o Emacs —, o código fica:

(require 'dbus)
(dbus-list-known-names :session)
(dbus-call-method :session "org.local.greeter"
                           "/A"
                           "org.local.greeter"
                           "hello"
                           "Emacs")

Caso se queira chamar o objeto /B, basta trocar o path na função dbus-call-methor.


Comparado ao COM do Windows, eu considero o D-Bus mais “limpo”. Mesmo quando se implementa um serviço COM em Python, sempre fico com a impressão de que certas coisas poderiam ser abstraídas de maneira melhor (CLSIDs, por exemplo).

Ainda assim, embora o D-Bus seja uma alternativa à altura (ou até melhor) que o COM, ele não substitui o DCOM. Nada impede que a comunicação entre processos seja feita entre diferentes máquinas, o problema é que, ao menos por enquanto, o D-Bus não implementa nenhum sistema de segurança — tanto de autenticação de usuário como de criptografia de dados.

Fonte

Publicidade

2 Respostas para “Um pequeno serviço D-Bus em Python

  1. Jack Benete julho 24, 2011 às 1:24 am

    Parou de atualizar o blog? Vai voltar um dia?

    Shalom!

Deixe um comentário

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair /  Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair /  Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair /  Alterar )

Conectando a %s

%d blogueiros gostam disto: