Use dbus to just send a message in Python - python

I have 2 Python programs. I just want to send a message (a long string) from the one to the other, and I want use dbus.
Now, is there an easy way to do this?
For example, if the message is very small, I have partially solved the problem putting the message in the path. But then I had to use the external program dbus-send:
Server (python):
import dbus,gtk
from dbus.mainloop.glib import DBusGMainLoop
DBusGMainLoop(set_as_default=True)
bus = dbus.SessionBus()
def msg_handler(*args,**keywords):
try:
msg=str(keywords['path'][8:])
#...do smthg with msg
print msg
except:
pass
bus.add_signal_receiver(handler_function=msg_handler, dbus_interface='my.app', path_keyword='path')
gtk.main()
Client (bash:( ):
dbus-send --session /my/app/this_is_the_message my.app.App
Is there a way to write the client in Python? or also, is there a better way to achieve the same result?

Here is an example that uses interface method calls:
Server:
#!/usr/bin/python3
#Python DBUS Test Server
#runs until the Quit() method is called via DBUS
import gi
gi.require_version('Gtk', '3.0')
from gi.repository import Gtk
import dbus
import dbus.service
from dbus.mainloop.glib import DBusGMainLoop
class MyDBUSService(dbus.service.Object):
def __init__(self):
bus_name = dbus.service.BusName('org.my.test', bus=dbus.SessionBus())
dbus.service.Object.__init__(self, bus_name, '/org/my/test')
#dbus.service.method('org.my.test')
def hello(self):
"""returns the string 'Hello, World!'"""
return "Hello, World!"
#dbus.service.method('org.my.test')
def string_echo(self, s):
"""returns whatever is passed to it"""
return s
#dbus.service.method('org.my.test')
def Quit(self):
"""removes this object from the DBUS connection and exits"""
self.remove_from_connection()
Gtk.main_quit()
return
DBusGMainLoop(set_as_default=True)
myservice = MyDBUSService()
Gtk.main()
Client:
#!/usr/bin/python3
#Python script to call the methods of the DBUS Test Server
import dbus
#get the session bus
bus = dbus.SessionBus()
#get the object
the_object = bus.get_object("org.my.test", "/org/my/test")
#get the interface
the_interface = dbus.Interface(the_object, "org.my.test")
#call the methods and print the results
reply = the_interface.hello()
print(reply)
reply = the_interface.string_echo("test 123")
print(reply)
the_interface.Quit()
Output:
$ ./dbus-test-server.py &
[1] 26241
$ ./dbus-server-tester.py
Hello, World!
test 123
Hope that helps.

Related

TypeError: 'module' object is not callable py 3

I'm trying to keep my discord bot online on replit. I made a new file called
keep_alive.py
Below is the code I input
import flask
import _thread
app = flask.Flask('Keep Alive')
#app.route('/')
def home():
return "I'm alive"
def run():
app.run(host='0.0.0.0',port=8080)
def keep_alive():
t = _thread(target=run)
t.start()
I'm not sure what I need to correct.
Replace
import _thread
#and
t = _thread(target=run)
with
from threading import Thread
#and
server = Thread(target=run)
The error is because you are trying to call the module itself.

Where are Gstreamer bus log messages?

I am trying to stream a .mp4 to a RTSP server using Gstreamer in python
import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
gi.require_version('GstRtsp', '1.0')
from gi.repository import Gst, GstRtspServer, GObject, GLib, GstRtsp
loop = GLib.MainLoop()
Gst.init(None)
file_path = "test.mp4"
class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self):
GstRtspServer.RTSPMediaFactory.__init__(self)
def do_create_element(self, url):
src_demux = f"filesrc location={file_path} ! qtdemux name=demux"
h264_transcode = "demux.video_0"
pipeline = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)
print ("Element created: " + pipeline)
self._pipeline = Gst.parse_launch(pipeline)
def bus_handler(bus, message):
print(message)
self.bus = self._pipeline.get_bus()
self.bus.connect('message', bus_handler)
self.bus.add_signal_watch_full(1)
return self._pipeline
class GstreamerRtspServer():
def __init__(self):
self.rtspServer = GstRtspServer.RTSPServer()
factory = TestRtspMediaFactory()
factory.set_shared(True)
mountPoints = self.rtspServer.get_mount_points()
self.address = '127.0.0.1' #my RPi's local IP
self.port = '8553'
self.rtspServer.set_address(self.address)
self.rtspServer.set_service(self.port)
urlstr = "/user=&password=.sdp"
url = GstRtsp.RTSPUrl.parse(urlstr)
mountPoints.add_factory(urlstr, factory)
self.rtspServer.attach(None)
if __name__ == '__main__':
s = GstreamerRtspServer()
loop.run()
However I am trying to understand how to use Gstreamer bus to log messages like eos or errors and warnings but I don't see any, even when I send eos events and the streaming effectively stops
s.rtspServer._pipeline._end_stream_event.set()
s.rtspServer._pipeline.send_event(Gst.Event.new_eos())
Am I using it properly? If not, what can I fix to properly log bus messages?
Following solution is based on this accepted but somehow incomplete answer.
I found out the way that does not require "manual" creation of pipeline elements but instead it keeps (in this scenario) convenient Gst.parse_launch(pipelineCmd) method and extends Gst.Bin to enable message debugging.
Here is full example source code (check out commented lines for some explanations):
#!/usr/bin/env python
import sys
import gi
gi.require_version('Gst', '1.0')
gi.require_version('GstRtspServer', '1.0')
from gi.repository import Gst, GstRtspServer, GObject, GLib
Gst.init(None)
loop = GLib.MainLoop()
# extended Gst.Bin that overrides do_handle_message and adds debugging
class ExtendedBin(Gst.Bin):
def do_handle_message(self,message):
if message.type == Gst.MessageType.ERROR:
error, debug = message.parse_error()
print("ERROR:", message.src.get_name(), ":", error.message)
if debug:
print ("Debug info: " + debug)
elif message.type == Gst.MessageType.EOS:
print ("End of stream")
elif message.type == Gst.MessageType.STATE_CHANGED:
oldState, newState, pendingState = message.parse_state_changed()
print ("State changed -> old:{}, new:{}, pending:{}".format(oldState,newState,pendingState))
else :
print("Some other message type: " + str(message.type))
#call base handler to enable message propagation
Gst.Bin.do_handle_message(self,message)
class TestRtspMediaFactory(GstRtspServer.RTSPMediaFactory):
def __init__(self):
GstRtspServer.RTSPMediaFactory.__init__(self)
def do_create_element(self, url):
#set mp4 file path to filesrc's location property
src_demux = "filesrc location=/path/to/dir/test.mp4 ! qtdemux name=demux"
h264_transcode = "demux.video_0"
#uncomment following line if video transcoding is necessary
#h264_transcode = "demux.video_0 ! decodebin ! queue ! x264enc"
pipelineCmd = "{0} {1} ! queue ! rtph264pay name=pay0 config-interval=1 pt=96".format(src_demux, h264_transcode)
self.pipeline = Gst.parse_launch(pipelineCmd)
print ("Pipeline created: " + pipelineCmd)
# creates extended Gst.Bin with message debugging enabled
extendedBin = ExtendedBin("extendedBin")
# Gst.pipeline inherits Gst.Bin and Gst.Element so following is possible
extendedBin.add(self.pipeline)
# creates new Pipeline and adds extended Bin to it
self.extendedPipeline = Gst.Pipeline.new("extendedPipeline")
self.extendedPipeline.add(extendedBin)
return self.extendedPipeline
class GstreamerRtspServer(GstRtspServer.RTSPServer):
def __init__(self):
self.rtspServer = GstRtspServer.RTSPServer()
self.factory = TestRtspMediaFactory()
self.factory.set_shared(True)
mountPoints = self.rtspServer.get_mount_points()
mountPoints.add_factory("/stream", self.factory)
self.rtspServer.attach(None)
print ("RTSP server is ready")
if __name__ == '__main__':
s = GstreamerRtspServer()
loop.run()
Please note that Gst.Pipeline actually inherists/extends Gst.Bin (and Gst.Element) so it is possible (no matter how strange it sounds) to add pipeline to bin.
This little "trick" saves time for us "lazy" programmers to keep using parsing of command line syntax to create pipeline elements.
In some more complex scenarios, where parsing of command line syntax is not applicable, solution would be following:
create ExtendedBin,
"manually" create elements with Gst.ElementFactory.make method (and set necessary properties)
add created elements to ExtendedBean
link elements
create new pipeline and add bin to it
use pipeline where it is needed.

DBus python unwanted blocked threads

I write a simple dbus service which create several threads. But when a service starts all threads became blocked. More or less this is my service:
import time
import threading
import gobject
import dbus
import dbus.service
import dbus.mainloop.glib
dbus.mainloop.glib.threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
class DummyThread(threading.Thread):
def __init__(self):
super(DummyThread, self).__init__()
self.__running = True
def run(self):
while self.__running:
print "I'm a running thread..."
time.sleep(1.0)
def stop(self):
self.__running = False
class Service(dbus.service.Object):
def __init__(self):
super(Service, self).__init__(
dbus.service.BusName('example.service', bus.SessionBus()),
'/example/service')
self.__loop = gobject.MainLoop(is_running=True)
#dbus.service.method('example.service.Interface')
def echo(self, data):
print 'Received: {}'.format(str(data))
return data
def run(self):
self.__loop.run()
def quit(self):
if self.__loop.is_running():
self.__loop.stop()
if __name__ == '__main__':
service = Service()
print 'Starting dummy thread...'
dummy = DummyThread()
dummy.start()
print 'Starting echo service...'
try:
service.run()
except KeyboardInterrupt:
print '\nUser want to quit!'
print 'Stopping services and threads...'
dummy.stop()
dummy.join()
service.quit()
And also this is a little client:
import sys
import dbus
class Client(object):
def __init__(self):
service = dbus.SessionBus().get_object('example.service',
'/example/service')
self.echo = service.get_dbus_method('echo', 'example.service.Interface')
if __name__ == '__main__':
client = Client()
recv = client.echo(' '.join(sys.argv[1:]))
print 'Received: {}'.format(recv)
If you run the server, no messages of the thread are showed until any client make requests to service. So my question is: is it possible to make threads independent of the gMainLoop() used by DBus?
Thank you in advance!

python: simple dbus example- os.fork() in service routine?

I am trying to write dbus server where I want to run some external shell program (grep here) to do the job.
when I do:
prompt$ server.py
then:
prompt$ client.py # works fine, ie. runs grep command in child process.
prompt$ client.py # ..., but second invocation produces following error message:
DBusException: org.freedesktop.DBus.Error.ServiceUnknown: The name org.example.ExampleService was not provided by any .service files
I am stuck. Are You able to help me?
here is server.py (client.py thereafter):
import gtk, glib
import os
import dbus
import dbus.service
import dbus.mainloop.glib
import subprocess
messages_queue=list()
grep_pid=0
def queue_msg(message):
global messages_queue
messages_queue.append(message)
return
def dequeue_msg():
global messages_queue,grep_pid
if grep_pid != 0:
try:
pid=os.waitpid(grep_pid,os.P_NOWAIT)
except:
return True
if pid[0] == 0:
return True
grep_pid=0
if len(messages_queue) == 0:
return True
else:
tekst=messages_queue.pop(0)
cmd="grep 'pp'"
print cmd
#works fine, when I do return here
#return True
grep_pid=os.fork()
if grep_pid != 0:
return True
os.setpgid(0,0)
pop=subprocess.Popen(cmd,shell=True,stdin=subprocess.PIPE)
pop.stdin.write(tekst)
pop.stdin.close()
pop.wait()
exit(0)
class DemoException(dbus.DBusException):
_dbus_error_name = 'org.example.Exception'
class MyServer(dbus.service.Object):
#dbus.service.method("org.example.ExampleInterface",
in_signature='', out_signature='')
def QueueMsg(self):
queue_msg("ppppp")
#dbus.service.method("org.example.ExampleInterface",
in_signature='', out_signature='')
def Exit(self):
mainloop.quit()
from dbus.mainloop.glib import threads_init
if __name__ == '__main__':
glib.threads_init()
threads_init()
dbus.mainloop.glib.DBusGMainLoop(set_as_default=True)
session_bus = dbus.SessionBus()
name = dbus.service.BusName("org.example.ExampleService", session_bus)
object = MyServer(session_bus, '/My')
glib.timeout_add_seconds(1, dequeue_msg)
mainloop = glib.MainLoop()
print "Running example service."
mainloop.run()
now client.py:
import sys
from traceback import print_exc
import dbus
def main():
bus = dbus.SessionBus()
try:
remote_object = bus.get_object("org.example.ExampleService",
"/My")
except dbus.DBusException:
print_exc()
sys.exit(1)
iface = dbus.Interface(remote_object, "org.example.ExampleInterface")
iface.QueueMsg()
if sys.argv[1:] == ['--exit-service']:
iface.Exit()
if __name__ == '__main__':
main()
You usually get this error message when you try to access a service that is no longer available. Check if your server is still running.
You can use d-feet to debug your dbus connections.
The error message about the missing .service file means that you need to create a service file in dbus-1/services.
For example:
# /usr/local/share/dbus-1/services/org.example.ExampleService.service
[D-BUS Service]
Name=org.example.ExampleService
Exec=/home/user1401567/service.py
A lot of tutorials don't include this detail (maybe .service files didn't use to be required?) But, at least on Ubuntu 12.04, dbus services can't be connected to without it.

how to deal with Python BaseHTTPServer killed,but the port is still be occupied?

I use python BaseHTTPServer,it can handle do_GET,do_POST methods,in do_POST method,i execute linux shell using os.system,when i kill the python script,but the listening port still occupied,so i can't run the script again, the netstat -antp|grep 80 show that the bash/tail is occupied the port 80
import sys
import os
import traceback
import time
import logging.handlers
import logging
from threading import *
from datetime import datetime
import urllib2
reload(sys)
sys.setdefaultencoding('utf-8')
class WebRequestHandler(BaseHTTPServer.BaseHTTPRequestHandler):
server_version = 'python httpserver'
sys_version = 'b'
backup_dir = None
def do_HEAD(s):
s.send_response(200)
s.send_header("Content-type", "text/html")
s.end_headers()
def do_GET(self):
if self.path == '/foo':
self.send_response(200)
os.system('nohup tail -f a.log &')
else:
self.send_error(404)
if __name__ == "__main__":
try:
server = BaseHTTPServer.HTTPServer(('',80), WebRequestHandler)
server.serve_forever()
except KeyboardInterrupt:
server.socket.close()
File descriptors are inherited by default by child processes, so the socket listening on port 80 is inherited by the command you have launched using your system() call.
To avoid that, you should set the FD_CLOEXEC flag on the listening socket. This can be done by adding (and using) a specific HTTPServer class.
class WebServer(BaseHTTPServer.HTTPServer):
def __init__(self, *args, **kwargs):
BaseHTTPServer.HTTPServer.__init__(self, *args, **kwargs)
# Set FD_CLOEXEC flag
flags = fcntl.fcntl(self.socket.fileno(), fcntl.F_GETFD)
flags |= fcntl.FD_CLOEXEC
fcntl.fcntl(self.socket.fileno(), fcntl.F_SETFD, flags)
Related :
Process started from system command in C inherits parent fd's

Categories