I have problem with solution that was working very good and suddenly it stopped to do so. I wrote server/client scripts and modules to make a SOAP connection type for my application.
Here is my server code :
import os
import rsglobal
import signal
import soaplib
from soaplib.core.service import rpc, DefinitionBase, soap
from soaplib.core.model.primitive import String, Integer
from soaplib.core.server import wsgi
from soaplib.core.model.clazz import Array
try:
import psycopg
except:
import psycopg2 as psycopg
import rssql
LogFile = "serwer_soap.log"
#-##############################################################################
#-- SOAP SERVER CLASS
#-##############################################################################
class AnakondaSOAPServer(DefinitionBase):
#-##############################################################################
#-- SOAP FUNCTIONS
#-##############################################################################
#soap(String,Integer,_returns=Array(String))
def say_hello(self,name,times):
results = []
for i in range(0,times):
results.append('Hello, %s'%name)
return results
#soap(String,String,_returns=String)
def ConnectToBase(self,name,passwd):
global PolSQL
try:
stat = 'OK'
dane=[]
PolSQL=rssql.RSSQL()
if PolSQL.ConnectToSQL(name,passwd,'127.0.0.1',5432,'','databasename')==1:
stat = u'Connection Error'
SQL='SELECT * FROM table1;'
stat,dane,dump,dump=PolSQL.Execute(SQL,3)
except Exception,e:
return u'Connection Error '+str(e)
return stat+' '+str(dane)
#soap(_returns=String)
def GiveData(self):
global PolSQL
try:
stat = 'OK'
dane=[]
SQL='SELECT * FROM table1;'
stat,dane,dump,dump=PolSQL.Execute(SQL,3)
except Exception,e:
return u'Data getting error '+str(e)
return stat+' '+str(dane)
#------------------------------------------
# ADMINISTRATIVE FUNCTIONS
#------------------------------------------
def SetDefaultData(self):
self._oldHupHandler = signal.SIG_DFL
self._oldAlarmHandler = signal.SIG_DFL
self._oldTermHandler = signal.SIG_DFL
self._childProcess = None
self.PolSQL = None
#-------------------------------------------------------------------------------
def _OnSIGALRM(self, sig, frame):
pass
#-------------------------------------------------------------------------------
def _OnSIGHUP(self, sig, frame):
if self._childProcess:
os.kill(self._childProcess, signal.SIGHUP)
else:
pass
#-------------------------------------------------------------------------------
def _OnSIGTERM(self, sig, frame):
pass
#-------------------------------------------------------------------------------
def _exit(self, status):
if self.PolSQL:
self.PolSQL.DisconnectSQL()
if status:
rsglobal.Log(u"SOAP - finishing : "+str(status), 1)
os._exit(status)
#-------------------------------------------------------------------------------
def StartSOAPServer(self, dbspec,HostSOAP,PortSOAP):
import os
self.dbspec = dbspec
childPID = os.fork()
if childPID:
self._childProcess = childPID
return childPID
else:
try:
signal.signal(signal.SIGUSR1, signal.SIG_DFL)
signal.signal(signal.SIGCHLD, signal.SIG_DFL)
if LogFile:
rsglobal.LogFile = LogFile
self._oldHupHandler = signal.signal(signal.SIGHUP, lambda x, y: self._OnSIGHUP(x, y))
self._oldAlarmHandler = signal.signal(signal.SIGALRM, lambda x, y: self._OnSIGALRM(x, y))
self._oldTermHandler = signal.signal(signal.SIGTERM, lambda x, y: self._OnSIGTERM(x, y))
self.PolSQL = SQLConnect(self.dbspec)
# running SOAP server
from wsgiref.simple_server import make_server
ServiceSoap = soaplib.core.Application([AnakondaSOAPServer],'AnakSOAP',name='AnakSOAP')
WSGI = wsgi.Application(ServiceSoap)
Serwer = make_server(HostSOAP, int(PortSOAP), WSGI)
Serwer.serve_forever()
except Exception, exc:
rsglobal.ZapiszDoLogow(u"Server SOAP Error : "+str(exc), 2)
self._exit(1)
#-------------------------------------------------------------------------------
def StopSOAPServer(self):
if self._childProcess:
os.kill(self._childProcess, signal.SIGTERM)
#-##################################################################
#-### - This is main SOAP server object used in other modules
SerwerSOAP = AnakondaSOAPServer()
SerwerSOAP.SetDefaultData()
#-##############################################################################
#-## ADDITIONAL FUNCTIONS
#-##############################################################################
def SQLConnect(dbspec):
# creates connection to database
PolSQL = rssql.RSSQL()
dbuser, dbpass, dbhost, dbport, dbase = dbspec
if PolSQL.PolaczZSQL(dbuser, dbpass, dbhost, dbport, None, Baza=dbase):
return False
else:
return PolSQL
My client code (which just tests server) is like this :
from suds.client import Client
hello_client = Client('http://128.1.2.3:1234/AnakondaSOAPServer?wsdl')
hello_client.options.cache.clear()
result = hello_client.service.ConnectToBase("username", "password")
print 'Result1',result
result = hello_client.service.GiveData()
print 'Result2',result
Earlier in my main application i use function StartSOAPServer with proper parameters and it's waiting for connections. I can see it with netstat on good adress and port.
After running client script i get :
Traceback (most recent call last):
File "./testsoapclient.py", line 8, in <module>
hello_client = Client('http://128.1.2.3:1234/AnakondaSOAPServer?wsdl')
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/client.py", line 112, in __init__
self.wsdl = reader.open(url)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/reader.py", line 152, in open
d = self.fn(url, self.options)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 158, in __init__
self.resolve()
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 207, in resolve
c.resolve(self)
File "/usr/local/lib/python2.6/dist-packages/suds-0.4-py2.6.egg/suds/wsdl.py", line 494, in resolve
raise Exception("msg '%s', not-found" % op.input)
Exception: msg 's0:ConnectToBase', not-found
Earlier i had problem with visibility of functions after creating a SOAP connection. Solution was to clear a cache. Now i can't even create it.
I use python 2.6, and lately my main app was transfered from 2.4 to 2.6. It's the only difference i can think of.
I tried manipulate with soaplib.core.Application definition, but it didn't work.
Please help :)
I managed to overcome the problems and it's working again.
First thing that repairs situation is splitting server into 2 classes - one to create object and run SOAPServer and second - SOAPServer which contains only definitions of functions.
Even after doing this changes i had bad results. I found out, that damaged structure of server definition hides in /tmp/suds directory (and that is why it was working while having damaged code before). Deleting this files allowed to refresh this structure and all scripts started to work again.
Related
I have the following issue with Python (2.7) socketserver:
import wx
import socket
from SocketServer import BaseRequestHandler, ThreadingTCPServer
from threading import Thread
from wx.lib.pubsub import pub
from GUI import GUI
class LogHandler(BaseRequestHandler):
def handle(self):
data = self.request.recv(1024)
wx.CallAfter(pub.sendMessage, 'logmsg', msg=data)
self.request.close()
class MyTestGUI(GUI):
def __init__(self):
super(MyTestGUI, self).__init__(None)
pub.subscribe(self.AppendLog, 'logmsg')
self.LogServer = ThreadingTCPServer(('', 10010), LogHandler)
self.LogServer.allow_reuse_address = True
self.thd = Thread(target=self.LogServer.serve_forever)
self.thd.daemon = True
self.thd.start()
def AppendLog(self, msg):
# Append the mesage
print(msg)
def AppClose(self, event):
self.LogServer.shutdown()
self.LogServer.server_close()
exit()
if __name__ == '__main__':
app = wx.App()
frame = MyTestGUI()
frame.Show(True)
app.MainLoop()
This server is supposed to receive messages from a device (which closes the socket upon message sent). On the first run the code works ok, but after restart I get the following exception:
self.LogServer = ThreadingTCPServer(('', 10010), LogHandler)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 420, in __init__
self.server_bind()
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/SocketServer.py", line 434, in server_bind
self.socket.bind(self.server_address)
File "/System/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/socket.py", line 228, in meth
return getattr(self._sock,name)(*args)
socket.error: [Errno 48] Address already in use
LogServer.allow_reuse_address = True / False, does not change a thing.
I had the same problem in Python 3.7.2 with a (non-threading) socketserver.TCPServer instance. ( I use anaconda on opensuse, in case it matters )
My solution:
during server initialization I set the third parameter of the __init__ function
false: bind_and_activate = False.
After initialization I set the .allow_reuse_address flag to True, and the .server_bind() and .server_activate() funs were called only after this flag setting.
I think that the important thing is to set the bind_and_activate flag before bindig and activating the server, since if the bind_and_activate parameter during TCPServer initialization is True or not set, then the TCPServer.__init__() calls both the server_bind() and server_activate() funtion. And in this case I could not change the value of the .allow_reuse_address flag - I could see it from the print() calls .
(Note that the code below does not work since the request handler definition is missing from it. I also use timeout, but that is independent of the problem )
def set_up_server_for_one_request(host, port, reqHandler, timeout = 600):
''' set up a server for one request. there is timeout as well.
'''
with socketserver.TCPServer((host, port), reqHandler, \
bind_and_activate= False) as serverInstance:
print('reuse adress attribute before flag setting: ',\
serverInstance.socket.getsockopt(socket.SOL_SOCKET,\
socket.SO_REUSEADDR))#print flagVal before setting
serverInstance.allow_reuse_address = True
print('reuse adress attribute after flag setting: ',\
serverInstance.socket.getsockopt(socket.SOL_SOCKET, \
socket.SO_REUSEADDR)) #print flagVal after setting
print('server adress: ', serverInstance. server_address)
serverInstance.server_bind()
serverInstance.server_activate()
serverInstance.timeout = timeout #set server's timeout
serverInstance.handle_request()
print('server finished, and exits')
if __name__ == '__main__':
set_up_server_for_one_request(host = 'localhost', port = 9998,\
reqHandler = My_EchoRH, timeout = 20)
Question
I am attempting to start a Python script as a Windows service using pywin32. I can properly install and remove the service, but while installed, its state never changes from "stopped." How can I fix my code so that the service actually runs?
Code
#!/bin/python
import winerror
import win32event
import win32service
import win32serviceutil
SVC_RUN = 1
SVC_REMOVE = 2
class TMP_Service(win32serviceutil.ServiceFramework):
_svc_name_ = "tmp_svc_name"
_svc_display_name_ = "tmp svc disp name"
_svc_reg_class = "tmp.reg_class"
_svc_description_ = "tmp description"
def __init__(self, dut_name):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.reportServiceStatus(win32service.SERVICE_STOP_PENDING)
# I will call reactor.callFromThread(reactor.stop) here to stop the
# FTP and SCP listeners
win32event.SetEvent(self.hWaitStop)
def SvcDoRun(self):
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# This infinite loop simulates future behavior of my service. It will
# run a Twisted reactor to handle FTP and TCP network connections.
while True:
pass
win32event.WaitforSingleObject(self.hWaitStop, win32event.INFINITE)
def install_svc():
try:
win32serviceutil.InstallService(
TMP_Service._svc_reg_class,
TMP_Service._svc_name_,
TMP_Service._svc_display_name_,
startType=win32service.SERVICE_AUTO_START)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_EXISTS:
pass # ignore install error if service is already installed
else:
raise
def handle_service(svc):
if svc == SVC_RUN:
try:
win32serviceutil.StartService(TMP_Service._svc_name_)
except win32service.error as e:
if ((e[0] == winerror.ERROR_SERVICE_ALREADY_RUNNING) or
(e[0] == winerror.ERROR_ALREADY_RUNNING_LKG)):
pass # ignore failed start if the service is already running
elif e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
# if the service is not installed, install it and try again
install_svc()
win32serviceutil.StartService(TMP_Service._svc_name_)
else:
# reraise any other start expection
raise
status = win32serviceutil.QueryServiceStatus(TMP_Service._svc_name_)
print("Service status: {}".format(status[1]))
else:
try:
win32serviceutil.RemoveService(TMP_Service._svc_name_)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
pass # ignore failed removal if service is not installed
else:
# reraise any other remove exception
raise
if __name__ == "__main__":
handle_service(SVC_RUN)
Other Details
When I look at the system event logs, I see this error:
Python could not import the service's module
ImportError: No module named tmp
%2: %3
The timestamp for these messages match the times that I tried to run this script.
I have seen this question: Can't start Windows service written in Python (win32serviceutil). Based on the advice there, I have made my code match the suggestion in the top answer there, and made sure that C:\Python27 is in my system path. Neither suggestion made a difference.
The status that is printed is always "2". According to MSDN, this is SERVICE_START_PENDING, which means the service should be starting.
Updated Details
If I change the value of the _svc_reg_class_ attribute to "tmp2.reg_class", then the name of the missing module, as reported in the Windows event log, changes to "tmp2", so this error is related to the _svc_reg_class_ attribute.
In reply to a comment below: I don't think I can capture the full traceback, because my service class is instantiated and used in the pywin32 library code. The offending import doesn't happen anywhere in my code, so there's nothing for me to wrap in a try/except block.
Change the _svc_reg_class = "tmp.reg_class" as shown below.
try:
module_path = modules[TMP_Service.__module__].__file__
except AttributeError:
# maybe py2exe went by
from sys import executable
module_path = executable
module_file = splitext(abspath(module_path))[0]
TMP_Service._svc_reg_class = '%s.%s' % (module_file, TMP_Service.__name__)
Below is the complete modified version of your original code.
#!/bin/python
import winerror
import win32event
import win32service
import win32serviceutil
from sys import modules
from os.path import splitext, abspath
SVC_RUN = 1
SVC_REMOVE = 2
class TMP_Service(win32serviceutil.ServiceFramework):
_svc_name_ = "tmp_svc_name"
_svc_display_name_ = "tmp svc disp name"
_svc_reg_class = "tmp.reg_class"
_svc_description_ = "tmp description"
def __init__(self, args):
win32serviceutil.ServiceFramework.__init__(self, args)
self.hWaitStop = win32event.CreateEvent(None, 0, 0, None)
def SvcStop(self):
self.ReportServiceStatus(win32service.SERVICE_STOP_PENDING)
self.Stop = True
# I will call reactor.callFromThread(reactor.stop) here to stop the
# FTP and SCP listeners
win32event.SetEvent(self.hWaitStop)
self.ReportServiceStatus(win32service.SERVICE_STOPPED)
def SvcDoRun(self):
self.Stop = False
self.ReportServiceStatus(win32service.SERVICE_RUNNING)
# This infinite loop simulates future behavior of my service. It will
# run a Twisted reactor to handle FTP and TCP network connections.
while self.Stop == False:
pass
win32event.WaitforSingleObject(self.hWaitStop, win32event.INFINITE)
def install_svc():
try:
module_path = modules[TMP_Service.__module__].__file__
except AttributeError:
# maybe py2exe went by
from sys import executable
module_path = executable
module_file = splitext(abspath(module_path))[0]
TMP_Service._svc_reg_class = '%s.%s' % (module_file, TMP_Service.__name__)
try:
win32serviceutil.InstallService(
TMP_Service._svc_reg_class,
TMP_Service._svc_name_,
TMP_Service._svc_display_name_,
startType=win32service.SERVICE_AUTO_START)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_EXISTS:
pass # ignore install error if service is already installed
else:
raise
def handle_service(svc):
if svc == SVC_RUN:
try:
win32serviceutil.StartService(TMP_Service._svc_name_)
except win32service.error as e:
if ((e[0] == winerror.ERROR_SERVICE_ALREADY_RUNNING) or
(e[0] == winerror.ERROR_ALREADY_RUNNING_LKG)):
pass # ignore failed start if the service is already running
elif e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
# if the service is not installed, install it and try again
install_svc()
win32serviceutil.StartService(TMP_Service._svc_name_)
else:
# reraise any other start expection
raise
status = win32serviceutil.QueryServiceStatus(TMP_Service._svc_name_)
print("Service status: {}".format(status[1]))
else:
try:
win32serviceutil.RemoveService(TMP_Service._svc_name_)
except win32service.error as e:
if e[0] == winerror.ERROR_SERVICE_DOES_NOT_EXIST:
pass # ignore failed removal if service is not installed
else:
# reraise any other remove exception
raise
if __name__ == "__main__":
handle_service(SVC_RUN)
Reference: here
I have not found any solution for my problem. I need to create a python application with two thread, each of which is connected to a WAMP Router using autobahn library.
Follow I write the code of my experiment:
wampAddress = 'ws://172.17.3.139:8181/ws'
wampRealm = 's4t'
from threading import Thread
from autobahn.twisted.wamp import ApplicationRunner
from autobahn.twisted.wamp import ApplicationSession
from twisted.internet.defer import inlineCallbacks
class AutobahnMRS(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
print("Sessio attached [Connect to WAMP Router]")
def onMessage(*args):
print args
try:
yield self.subscribe(onMessage, 'test')
print ("Subscribed to topic: test")
except Exception as e:
print("Exception:" +e)
class AutobahnIM(ApplicationSession):
#inlineCallbacks
def onJoin(self, details):
print("Sessio attached [Connect to WAMP Router]")
try:
yield self.publish('test','YOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOOO')
print ("Subscribed to topic: test")
except Exception as e:
print("Exception:" +e)
class ManageRemoteSystem:
def __init__(self):
self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)
def start(self):
self.runner.run(AutobahnMRS);
class InternalMessages:
def __init__(self):
self.runner = ApplicationRunner(url= wampAddress, realm = wampRealm)
def start(self):
self.runner.run(AutobahnIM);
#class S4tServer:
if __name__ == '__main__':
server = ManageRemoteSystem()
sendMessage = InternalMessages()
thread1 = Thread(target = server.start())
thread1.start()
thread1.join()
thread2 = Thread(target = sendMessage.start())
thread2.start()
thread2.join()
When I launch this python application only the thread1 is started and later when I kill the application (ctrl-c) the following error messages are shown:
Sessio attached [Connect to WAMP Router]
Subscribed to topic: test
^CTraceback (most recent call last):
File "test_pub.py", line 71, in <module>
p2 = multiprocessing.Process(target = server.start())
File "test_pub.py", line 50, in start
self.runner.run(AutobahnMRS);
File "/usr/local/lib/python2.7/dist-packages/autobahn/twisted/wamp.py", line 175, in run
reactor.run()
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1191, in run
self.startRunning(installSignalHandlers=installSignalHandlers)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 1171, in startRunning
ReactorBase.startRunning(self)
File "/usr/local/lib/python2.7/dist-packages/twisted/internet/base.py", line 683, in startRunning
raise error.ReactorNotRestartable()
twisted.internet.error.ReactorNotRestartable
I need to implement in one application that has its functionalities and also it must has a system for communicate to a WAMP router with autobahn python library.
In other words, I need a solution able to communicate with a WAMP router, but in the same time this application doesn't must be blocked with the autobahn part (I think that the solution is to start two thread, one thread manages some functions and second thread manages the autobahn part).
With the schema that I proposed before, there is another problem, the need to send message, in a specific topic on the WAMP router, from the application part in the 'no autobahn thread', this functionality should be called through with a specific function without blocking the other functionalities.
I hope I have given all the details.
Thanks a lot for any response
--------------------------------EDIT---------------------------------
After some research I have implemented what I need for websocket protocol, the code is the follow:
# ----- twisted ----------
class _WebSocketClientProtocol(WebSocketClientProtocol):
def __init__(self, factory):
self.factory = factory
def onOpen(self):
#log.debug("Client connected")
self.factory.protocol_instance = self
self.factory.base_client._connected_event.set()
class _WebSocketClientFactory(WebSocketClientFactory):
def __init__(self, *args, **kwargs):
WebSocketClientFactory.__init__(self, *args, **kwargs)
self.protocol_instance = None
self.base_client = None
def buildProtocol(self, addr):
return _WebSocketClientProtocol(self)
# ------ end twisted -------
lass BaseWBClient(object):
def __init__(self, websocket_settings):
#self.settings = websocket_settings
# instance to be set by the own factory
self.factory = None
# this event will be triggered on onOpen()
self._connected_event = threading.Event()
# queue to hold not yet dispatched messages
self._send_queue = Queue.Queue()
self._reactor_thread = None
def connect(self):
log.msg("Connecting to host:port")
self.factory = _WebSocketClientFactory(
"ws://host:port",
debug=True)
self.factory.base_client = self
c = connectWS(self.factory)
self._reactor_thread = threading.Thread(target=reactor.run,
args=(False,))
self._reactor_thread.daemon = True
self._reactor_thread.start()
def send_message(self, body):
if not self._check_connection():
return
log.msg("Queing send")
self._send_queue.put(body)
reactor.callFromThread(self._dispatch)
def _check_connection(self):
if not self._connected_event.wait(timeout=10):
log.err("Unable to connect to server")
self.close()
return False
return True
def _dispatch(self):
log.msg("Dispatching")
while True:
try:
body = self._send_queue.get(block=False)
except Queue.Empty:
break
self.factory.protocol_instance.sendMessage(body)
def close(self):
reactor.callFromThread(reactor.stop)
import time
def Ppippo(coda):
while True:
coda.send_message('YOOOOOOOO')
time.sleep(5)
if __name__ == '__main__':
ws_setting = {'host':'', 'port':}
client = BaseWBClient(ws_setting)
t1 = threading.Thread(client.connect())
t11 = threading.Thread(Ppippo(client))
t11.start()
t1.start()
The previous code work fine, but I need to translate this to operate on WAMP protocol insted websocket.
Does anyone know how I solve ?
The bad news is that Autobahn is using the Twisted main loop, so you can't run it in two threads at once.
The good news is that you don't need to run it in two threads to run two things, and two threads would be more complicated anyway.
The API to get started with multiple applications is a bit confusing, because you have two ApplicationRunner objects, and it looks at first glance that the way you run an application in autobahn is to call ApplicationRunner.run.
However, ApplicationRunner is simply a convenience that wraps up the stuff that sets up the application and the stuff that runs the main loop; the real meat of the work happens in WampWebSocketClientFactory.
In order to achieve what you want, you just need to get rid of the threads, and run the main loop yourself, making the ApplicationRunner instances simply set up their applications.
In order to achieve this, you'll need to change the last part of your program to do this:
class ManageRemoteSystem:
def __init__(self):
self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)
def start(self):
# Pass start_reactor=False to all runner.run() calls
self.runner.run(AutobahnMRS, start_reactor=False)
class InternalMessages:
def __init__(self):
self.runner = ApplicationRunner(url=wampAddress, realm=wampRealm)
def start(self):
# Same as above
self.runner.run(AutobahnIM, start_reactor=False)
if __name__ == '__main__':
server = ManageRemoteSystem()
sendMessage = InternalMessages()
server.start()
sendMessage.start()
from twisted.internet import reactor
reactor.run()
I'm developing a Python daemon responsible for converting multimedia files to .mp4 format.
The idea is to have the daemon running and, whenever the user requires, I add the desired video to a Queue and a thread eventually gets the video from the queue and calls Handbrake via Subprocess in order to do the conversion. For simplicity's sake, I'm using only one thread at the moment.
Here's my code.
First, the daemon (server.py, adapted from Kris Johnson's post here):
#!/usr/bin/env python
# -*- coding: utf-8 -*-
import os, sys
import os.path
import logging.config
import SocketServer
import optparse
import resource
import socket, tempfile
import time
from threadedqueue import QueueServer
version = '0.1'
SERVER_PORT=6666
SERVER_SOCKET='server_socket'
SERVER_TYPE=SocketServer.UnixStreamServer
ServerBase = SERVER_TYPE
if ServerBase == SocketServer.UnixStreamServer:
server_address = os.path.join(tempfile.gettempdir(), SERVER_SOCKET)
SERVER_LOG=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'convertCentral.log')
logging.basicConfig(format='[%(asctime)s.%(msecs).03d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S', filename=SERVER_LOG, level=logging.INFO)
class RequestHandler(SocketServer.StreamRequestHandler):
"""Request handler
An instance of this class is created for each connection made
by a client. The Server class invokes the instance's
setup(), handle(), and finish() methods.
The template implementation here simply reads a single line from
the client, breaks that up into whitespace-delimited words, and
then uses the first word as the name of a "command." If there is
a method called "do_COMMAND", where COMMAND matches the
commmand name, then that method is invoked. Otherwise, an error
message is returned to the client.
"""
def handle(self):
"""Service a newly connected client.
The socket can be accessed as 'self.connection'. 'self.rfile'
can be used to read from the socket using a file interface,
and 'self.wfile' can be used to write to the socket using a
file interface.
When this method returns, the connection will be closed.
"""
# Read a single request from the input stream and process it.
request = self.rfile.readline()
if request:
self.server.log('request %s: %s',
self.connection.getpeername(), request.rstrip())
try:
self.process_request(request)
except Exception, e:
self.server.log('exception: %s' % str(e))
self.wfile.write('Error: %s\n' % str(e))
else:
self.server.log('error: unable to read request')
self.wfile.write('Error: unable to read request')
def process_request(self, request):
"""Process a request.
This method is called by self.handle() for each request it
reads from the input stream.
This implementation simply breaks the request string into
words, and searches for a method named 'do_COMMAND',
where COMMAND is the first word. If found, that method is
invoked and remaining words are passed as arguments.
Otherwise, an error is returned to the client.
"""
words = request.split()
if len(words) == 0:
self.server.log('error: empty request')
self.wfile.write('Error: empty request\n')
return
command = words[0]
args = words[1:]
methodname = 'do_' + command
if not hasattr(self, methodname):
self.server.log('error: invalid command')
self.wfile.write('Error: "%s" is not a valid command\n' % command)
return
method = getattr(self, methodname)
method(*args)
def do_stop(self, *args):
self.wfile.write('Stopping server\n')
self.server.stop()
"""Process an 'echo' command"""
def do_echo(self, *args):
self.wfile.write(' '.join(args) + '\n')
"""Process a 'convert' command"""
def do_convert(self, video):
self.wfile.write('Converting %s\n' % (video))
try:
self.server.addVideo(video)
except Exception as e:
logging.info("ERROR: %s" % e)
class Server(ServerBase):
def __init__(self, server_address):
self.__daemonize()
self.pool = QueueServer()
if ServerBase == SocketServer.UnixStreamServer:
# Delete the socket file if it already exists
if os.access(server_address, 0):
os.remove(server_address)
ServerBase.__init__(self, server_address, RequestHandler)
def addVideo(self, video):
self.pool.add(video)
def log(self, format, *args):
try:
message = format % args
logging.info("%s" % message)
except Exception, e:
print str(e)
def serve_until_stopped(self):
self.log('started')
self.__stopped = False
while not self.__stopped:
self.handle_request()
self.log('stopped')
def stop(self):
self.__stopped = True
def __daemonize(self):
UMASK = 0
WORKDIR = '/'
MAXFD = 1024
if hasattr(os, 'devnull'):
REDIRECT_TO = os.devnull
else:
REDIRECT_TO = '/dev/null'
try :
if os.fork() != 0:
os._exit(0)
os.setsid()
if os.fork() != 0:
os._exit(0)
os.chdir(WORKDIR)
os.umask(UMASK)
except OSError, e:
self.log('exception: %s %s', e.strerror, e.errno)
raise Exception, "%s [%d]" % (e.strerror, e.errno)
except Exception, e:
self.log('exception: %s', str(e))
maxfd = resource.getrlimit(resource.RLIMIT_NOFILE)[1]
if maxfd == resource.RLIM_INFINITY:
maxfd = MAXFD
for fd in range(0, maxfd):
try:
os.close(fd)
except OSError:
pass
os.open(REDIRECT_TO, os.O_RDWR)
os.dup2(0, 1)
os.dup2(0, 2)
""" Run a server as a daemon """
def run_server(options, args):
print("convertCentral running on %s" % server_address)
svr = Server(server_address)
svr.serve_until_stopped()
svr.server_close()
"""Send request to the server and process response."""
def do_request(options, args):
if ServerBase == SocketServer.UnixStreamServer:
s = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
# Send request
s.connect(server_address)
s.sendall(' '.join(args) + '\n')
# Print response
sfile = s.makefile('rb')
line = sfile.readline()
while line:
print line,
line = sfile.readline()
#######################################################################
#######################################################################
if __name__ == '__main__':
optparser = optparse.OptionParser(usage=usage,
version=version)
(options, args) = optparser.parse_args()
if len(args) == 0:
optparser.print_help()
sys.exit(-1)
if args[0] == 'start':
run_server(options, args[1:])
else:
do_request(options, args)
Then, the queue (threadedqueue.py - sorry about the name, not feeling particularly creative):
#! /usr/bin/python
# -*- coding: utf-8 -*-
import os, time, threading, psutil, resource, logging, subprocess as sp, sys
from Queue import Queue
from threading import Thread
SERVER_LOG=os.path.join(os.path.dirname(os.path.realpath(__file__)), 'convertCentral.log')
logging.basicConfig(format='[%(asctime)s.%(msecs).03d] %(message)s', datefmt='%Y-%m-%d %H:%M:%S', filename=SERVER_LOG, level=logging.INFO)
class QueueServer(object):
current_video_queue = Queue(maxsize=0)
N_WORKER_THREADS = 1
counter = 0
def __init__(self):
logging.info("[QueueServer] Initializing the video conversion queue")
for i in range(self.N_WORKER_THREADS):
logging.info("Firing thread")
t = Thread(target=self.worker)
t.daemon = True
t.start()
''' Converts the video using Handbrake via subprocess'''
def convertVideo(self, video):
logging.info("Now converting %s" % video)
fileName, fileExtension = os.path.splitext(video)
payload = "nice -n 15 HandBrakeCLI -i %s -e x264 -q 15 -o %s.mp4" % (video, fileName)
pr = sp.Popen(payload, shell=True, stdout=open('/dev/null', 'w'), stderr=sp.STDOUT)
logging.info('Started handbrake')
pr.wait()
logging.info("EXIT CODE: %s " % pr.returncode)
self.counter = self.counter + 1
logging.info("Conversion's done. %d" % self.counter)
''' A worker thread '''
def worker(self):
while True:
logging.info("Getting one")
item = self.current_video_queue.get()
logging.info("Firing conversion: %s" % item)
self.convertVideo(item)
self.current_video_queue.task_done()
logging.info("All done")
''' Adds a video to the video conversion queue '''
def add(self, video):
logging.info("* Adding %s to the queue" % video)
self.current_video_queue.put(video)
logging.info("* Added %s to the queue" % video)
time.sleep(3)
Here's the deal: if I run the threadedqueue on its own, it works great.
However, if I run it using server.py, the conversion never happens because Handbrake crashes.
Here are the logs:
Hal#ubuntu:~/Desktop/convertCentral$ python server.py start
convertCentral running on /tmp/server_socket
Hal#ubuntu:~/Desktop/convertCentral$ python server.py convert UNKNOWN_PARAMETER_VALUE.WMV
[2014-04-17 18:05:44.793] request : convert UNKNOWN_PARAMETER_VALUE.WMV
Converting UNKNOWN_PARAMETER_VALUE.WMV
[2014-04-17 18:05:44.793] * Adding UNKNOWN_PARAMETER_VALUE.WMV to the queue
[2014-04-17 18:05:44.793] * Added UNKNOWN_PARAMETER_VALUE.WMV to the queue
[2014-04-17 18:05:44.793] Firing conversion: UNKNOWN_PARAMETER_VALUE.WMV
[2014-04-17 18:05:44.794] Now converting UNKNOWN_PARAMETER_VALUE.WMV
[2014-04-17 18:05:44.796] Started handbrake
[2014-04-17 18:05:45.046] Exit code: 0
[2014-04-17 18:05:45.046] Conversion's done. 1
[2014-04-17 18:05:45.046] All done
[2014-04-17 18:05:45.047] Getting one
I logged the subprocess's output to a file.
Here's what I got:
[18:05:44] hb_init: starting libhb thread
HandBrake 0.9.9 (2013051800) - Linux x86_64 - http://handbrake.fr
4 CPUs detected
Opening UNKNOWN_PARAMETER_VALUE.WMV...
[18:05:44] hb_scan: path=UNKNOWN_PARAMETER_VALUE.WMV, title_index=1
libbluray/bdnav/index_parse.c:162: indx_parse(): error opening UNKNOWN_PARAMETER_VALUE.WMV/BDMV/index.bdmv
libbluray/bdnav/index_parse.c:162: indx_parse(): error opening UNKNOWN_PARAMETER_VALUE.WMV/BDMV/BACKUP/index.bdmv
libbluray/bluray.c:1725: nav_get_title_list(UNKNOWN_PARAMETER_VALUE.WMV) failed (0x7fd44c000900)
[18:05:44] bd: not a bd - trying as a stream/file instead
libdvdnav: Using dvdnav version 4.1.3
libdvdread: Encrypted DVD support unavailable.
libdvdread: Can't stat UNKNOWN_PARAMETER_VALUE.WMV
No such file or directory
libdvdnav: vm: failed to open/read the DVD
[18:05:44] dvd: not a dvd - trying as a stream/file instead
[18:05:44] hb_stream_open: open UNKNOWN_PARAMETER_VALUE.WMV failed
[18:05:44] scan: unrecognized file type
[18:05:44] libhb: scan thread found 0 valid title(s)
No title found.
HandBrake has exited.
So, we can attest that the script can indeed fire up Handbrake, but the logs indicate that the Handbrake won't recognize the file format and dies on the spot. Again, this doesn't happen if I run the threadedqueue.py script on its own.
I'm guessing that Handbrake is not loading its libraries somehow.
Is this the reason the code won't work? How can I get Handbrake to work?
(darned browser lost my previous answer, hope this does not become a dup)
Both of these errors Can't stat UNKNOWN_PARAMETER_VALUE.WMV and
open UNKNOWN_PARAMETER_VALUE.WMV failed suggest file-not-found errors, BUT it does look like the file name is getting passed through to the handbrake command line.
So in order to be sure that the right files are being used: In the python code convert whatever filenames the user provides to server.py into absolute path names (see os.path.*). Use those absolute path names everywhere (esp. in the handbrake command/Popen)
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.