Announcement

Collapse
No announcement yet.

Threading with PyQT4 for Webserver

Collapse
This topic is closed.
X
X
 
  • Filter
  • Time
  • Show
Clear All
new posts

    [SOLVED] Threading with PyQT4 for Webserver

    I have a Samsung Galaxy Tab 10.1 running a CM9 ICS rom. The tab lacks a removable micro sd card like most devices in the category and so I can't use UMS protocol and have to use the now default MTP. I know that an MTP KIO-slave is in the works and I know I can expect it in KDE 4.10 but in my experience I have never had a MTP implementation that works easily (MTP is an odd protocol) and I am also a little impatient. Anyhow, I decided to write a quick python app with GUI (in pyqt4) to make life easy.

    So the program is fairly simple. It basically allows drag-drop of files on to a QListWidget which then displays them and sets links up for the webserver to use. The webserver can be started and stopped as needed. The idea is then that I can just point my browser at the IP:Port combination and just download them. So ayways, I just can't get a way to set-up the threading so that I can actually stop and restart the thread. I've found some great articles on the web but I just find threads very confusing.

    I have a feeling that .serve_forever() is the problem because it causes an infinite loop but what else am I to use especially considering that I want to handle multiple requests.

    So here is my code:

    Program:

    *The commented out code is really just to show my different attempts. The uncommented bit is what currently threads and the server starts and doesn't block the UI but how do I start and stop/pause the thread.

    Code:
    import sys
    import os
    from fileshare import Ui_MainWindow
    from PyQt4 import QtGui, QtCore
    import SimpleHTTPServer
    import SocketServer
    import subprocess
    import threading
    
    class TestListView(QtGui.QListWidget):
        def __init__(self, type, parent=None):
            super(TestListView, self).__init__(parent)
            self.setAcceptDrops(True)
            self.setIconSize(QtCore.QSize(72, 72))
    
        def dragEnterEvent(self, event):
            if event.mimeData().hasUrls:
                event.accept()
            else:
                event.ignore()
    
        def dragMoveEvent(self, event):
            if event.mimeData().hasUrls:
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
            else:
                event.ignore()
    
        def dropEvent(self, event):
            if event.mimeData().hasUrls:
                event.setDropAction(QtCore.Qt.CopyAction)
                event.accept()
                links = []
                for url in event.mimeData().urls():
                    links.append(str(url.toLocalFile()))
                self.emit(QtCore.SIGNAL("dropped"), links)
            else:
                event.ignore()
    
    class MainForm(QtGui.QMainWindow):
    	def __init__(self, parent=None):
    		QtGui.QWidget.__init__(self, parent)
    		self.ui = Ui_MainWindow()
    		self.ui.setupUi(self)
    		self.view = TestListView(self)
    		self.connect(self.view, QtCore.SIGNAL("dropped"), self.itemDropped)
    		self.ui.pushButton_2.clicked.connect(self.addItem)
    		self.ui.gridLayout_2.addWidget(self.view,1,0,1,5)
    		os.system("mkdir fileshare")
    		
    
    
    	def itemDropped(self, l):
    		for url in l:
    			if os.path.exists(url):              
    				icon = QtGui.QIcon(url)
    				pixmap = icon.pixmap(72, 72)                
    				icon = QtGui.QIcon(pixmap)
    				item = QtGui.QListWidgetItem(url, self.view)
    				item.setIcon(icon)        
    				item.setStatusTip(url)
    				url2 = []
    				for i in range(len(url)):
    					if url[-i] == "/":
    						url2.append(url[-i+1:])
    				url2 = url2[1]
    		os.system("ln -s %s ~/fileshare/%s"%(url,url2))
    		
    	def addItem(self):
    		fileName = QtGui.QFileDialog()
    		url = fileName.getOpenFileName()
    		icon = QtGui.QIcon(url)
    		pixmap = icon.pixmap(72, 72)                
    		icon = QtGui.QIcon(pixmap)
    		item = QtGui.QListWidgetItem(url, self.view)
    		item.setIcon(icon)        
    		item.setStatusTip(url)
    		url2 = []
    		for i in range(len(url)):
    			if url[-i] == "/":
    				url2.append(url[-i+1:])
    		url2 = url2[1]
    		os.system("ln -s %s ~/fileshare/%s"%(url,url2))
    
    #class webServer(threading.Thread):
    	#def __init__(self,parent=None):
    		#threading.Thread.__init__(self, parent)
    		#self.port = 1800
    		#form.ui.pushButton_3.clicked.connect(self.exit)
    		#form.ui.pushButton.clicked.connect(self.run)
    		
    	#def run(self):
    		#proc=subprocess.Popen('echo ~', shell=True, stdout=subprocess.PIPE, )
    		#output=proc.communicate()[0].strip()
    		#os.chdir("%s/fileshare/"%(output))
    		#Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
    		#self.httpd = SocketServer.TCPServer(("", self.port), Handler)
    		#self.httpd.serve_forever()
    	
    	#def stopServer(self):
    		#self.httpd.shutdown()
    		
    #class webServer(QtCore.QThread):
    	#def __init__(self):
    		#QtCore.QThread.__init__(self)
    		#self.port = 1800
    		#form.ui.pushButton_3.clicked.connect(self.exit)
    		#form.ui.pushButton.clicked.connect(self.run)
    
    	#def run(self):
    		#proc=subprocess.Popen('echo ~', shell=True, stdout=subprocess.PIPE, )
    		#output=proc.communicate()[0].strip()
    		#os.chdir("%s/fileshare/"%(output))
    		#Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
    		#self.httpd = SocketServer.TCPServer(("", 1805), Handler)
    		#self.httpd.serve_forever()
    		
    class webServer(QtCore.QThread):
    
    	def __init__(self, parent = None):
    		QtCore.QThread.__init__(self, parent)
    		self.exiting = False
    		form.ui.pushButton_3.clicked.connect(self.stop)
            
    	def run(self):
    		while self.exiting == False:
    			proc=subprocess.Popen('echo ~', shell=True, stdout=subprocess.PIPE, )
    			output=proc.communicate()[0].strip()
    			os.chdir("%s/fileshare/"%(output))
    			Handler = SimpleHTTPServer.SimpleHTTPRequestHandler
    			self.httpd = SocketServer.TCPServer(("", 1805), Handler)
    			self.httpd.serve_forever()
    
    	def stop(self):
    		self.exiting = True
    
    
    if __name__ == '__main__':
    	app = QtGui.QApplication(sys.argv)
    	form = MainForm()
    	form.show()
    
    	web = webServer()
    	web.start()
    
    	sys.exit(app.exec_())
    UI:

    Code:
    # -*- coding: utf-8 -*-
    
    # Form implementation generated from reading ui file 'fileshare.ui'
    #
    # Created by: PyQt4 UI code generator 4.9.5
    #
    # WARNING! All changes made in this file will be lost!
    
    from PyQt4 import QtCore, QtGui
    
    try:
        _fromUtf8 = QtCore.QString.fromUtf8
    except AttributeError:
        _fromUtf8 = lambda s: s
    
    class Ui_MainWindow(object):
        def setupUi(self, MainWindow):
            MainWindow.setObjectName(_fromUtf8("MainWindow"))
            MainWindow.resize(800, 600)
            MainWindow.setAcceptDrops(False)
            self.centralwidget = QtGui.QWidget(MainWindow)
            self.centralwidget.setAcceptDrops(False)
            self.centralwidget.setObjectName(_fromUtf8("centralwidget"))
            self.gridLayout = QtGui.QGridLayout(self.centralwidget)
            self.gridLayout.setObjectName(_fromUtf8("gridLayout"))
            self.gridLayout_2 = QtGui.QGridLayout()
            self.gridLayout_2.setObjectName(_fromUtf8("gridLayout_2"))
            spacerItem = QtGui.QSpacerItem(40, 20, QtGui.QSizePolicy.Expanding, QtGui.QSizePolicy.Minimum)
            self.gridLayout_2.addItem(spacerItem, 0, 2, 1, 1)
            self.pushButton_4 = QtGui.QPushButton(self.centralwidget)
            self.pushButton_4.setText(_fromUtf8(""))
            icon = QtGui.QIcon()
            icon.addPixmap(QtGui.QPixmap(_fromUtf8("../../usr/share/icons/oxygen/32x32/actions/list-remove.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            self.pushButton_4.setIcon(icon)
            self.pushButton_4.setIconSize(QtCore.QSize(32, 32))
            self.pushButton_4.setObjectName(_fromUtf8("pushButton_4"))
            self.gridLayout_2.addWidget(self.pushButton_4, 0, 1, 1, 1)
            self.pushButton_2 = QtGui.QPushButton(self.centralwidget)
            self.pushButton_2.setText(_fromUtf8(""))
            icon1 = QtGui.QIcon()
            icon1.addPixmap(QtGui.QPixmap(_fromUtf8("../../usr/share/icons/oxygen/32x32/actions/list-add.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            self.pushButton_2.setIcon(icon1)
            self.pushButton_2.setIconSize(QtCore.QSize(32, 32))
            self.pushButton_2.setObjectName(_fromUtf8("pushButton_2"))
            self.gridLayout_2.addWidget(self.pushButton_2, 0, 0, 1, 1)
            self.pushButton = QtGui.QPushButton(self.centralwidget)
            self.pushButton.setText(_fromUtf8(""))
            icon2 = QtGui.QIcon()
            icon2.addPixmap(QtGui.QPixmap(_fromUtf8("../../usr/share/icons/oxygen/32x32/actions/media-playback-start.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            self.pushButton.setIcon(icon2)
            self.pushButton.setIconSize(QtCore.QSize(32, 32))
            self.pushButton.setObjectName(_fromUtf8("pushButton"))
            self.gridLayout_2.addWidget(self.pushButton, 0, 3, 1, 1)
            self.pushButton_3 = QtGui.QPushButton(self.centralwidget)
            self.pushButton_3.setText(_fromUtf8(""))
            icon3 = QtGui.QIcon()
            icon3.addPixmap(QtGui.QPixmap(_fromUtf8("../../usr/share/icons/oxygen/32x32/actions/media-playback-stop.png")), QtGui.QIcon.Normal, QtGui.QIcon.Off)
            self.pushButton_3.setIcon(icon3)
            self.pushButton_3.setIconSize(QtCore.QSize(32, 32))
            self.pushButton_3.setObjectName(_fromUtf8("pushButton_3"))
            self.gridLayout_2.addWidget(self.pushButton_3, 0, 4, 1, 1)
            self.gridLayout.addLayout(self.gridLayout_2, 1, 2, 1, 1)
            MainWindow.setCentralWidget(self.centralwidget)
            self.menubar = QtGui.QMenuBar(MainWindow)
            self.menubar.setGeometry(QtCore.QRect(0, 0, 800, 23))
            self.menubar.setObjectName(_fromUtf8("menubar"))
            self.menuFile = QtGui.QMenu(self.menubar)
            self.menuFile.setObjectName(_fromUtf8("menuFile"))
            self.menuHelp = QtGui.QMenu(self.menubar)
            self.menuHelp.setObjectName(_fromUtf8("menuHelp"))
            self.menuSettiings = QtGui.QMenu(self.menubar)
            self.menuSettiings.setObjectName(_fromUtf8("menuSettiings"))
            MainWindow.setMenuBar(self.menubar)
            self.statusbar = QtGui.QStatusBar(MainWindow)
            self.statusbar.setObjectName(_fromUtf8("statusbar"))
            MainWindow.setStatusBar(self.statusbar)
            self.actionExit = QtGui.QAction(MainWindow)
            self.actionExit.setObjectName(_fromUtf8("actionExit"))
            self.actionOpen = QtGui.QAction(MainWindow)
            self.actionOpen.setObjectName(_fromUtf8("actionOpen"))
            self.actionPreferences = QtGui.QAction(MainWindow)
            self.actionPreferences.setObjectName(_fromUtf8("actionPreferences"))
            self.actionAbout = QtGui.QAction(MainWindow)
            self.actionAbout.setObjectName(_fromUtf8("actionAbout"))
            self.menuFile.addAction(self.actionOpen)
            self.menuFile.addAction(self.actionExit)
            self.menuHelp.addAction(self.actionAbout)
            self.menuSettiings.addAction(self.actionPreferences)
            self.menubar.addAction(self.menuFile.menuAction())
            self.menubar.addAction(self.menuSettiings.menuAction())
            self.menubar.addAction(self.menuHelp.menuAction())
    
            self.retranslateUi(MainWindow)
            QtCore.QMetaObject.connectSlotsByName(MainWindow)
    
        def retranslateUi(self, MainWindow):
            MainWindow.setWindowTitle(QtGui.QApplication.translate("MainWindow", "MainWindow", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton_4.setToolTip(QtGui.QApplication.translate("MainWindow", "Remove files", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton_2.setToolTip(QtGui.QApplication.translate("MainWindow", "Add Files", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton.setToolTip(QtGui.QApplication.translate("MainWindow", "Start Server", None, QtGui.QApplication.UnicodeUTF8))
            self.pushButton_3.setToolTip(QtGui.QApplication.translate("MainWindow", "Stop Server", None, QtGui.QApplication.UnicodeUTF8))
            self.menuFile.setTitle(QtGui.QApplication.translate("MainWindow", "File", None, QtGui.QApplication.UnicodeUTF8))
            self.menuHelp.setTitle(QtGui.QApplication.translate("MainWindow", "Help", None, QtGui.QApplication.UnicodeUTF8))
            self.menuSettiings.setTitle(QtGui.QApplication.translate("MainWindow", "Settiings", None, QtGui.QApplication.UnicodeUTF8))
            self.actionExit.setText(QtGui.QApplication.translate("MainWindow", "Exit", None, QtGui.QApplication.UnicodeUTF8))
            self.actionOpen.setText(QtGui.QApplication.translate("MainWindow", "Open", None, QtGui.QApplication.UnicodeUTF8))
            self.actionPreferences.setText(QtGui.QApplication.translate("MainWindow", "Preferences", None, QtGui.QApplication.UnicodeUTF8))
            self.actionAbout.setText(QtGui.QApplication.translate("MainWindow", "About", None, QtGui.QApplication.UnicodeUTF8))
    Warning: This will create a folder in your home directory called fileshare. The self clean-up hasn't been implemented yet.

    I know this might not be the best place to ask but I've always found good assistance here when I have been at my wits end and don't feel like being berrated for poor coding style/being an imbecile etc. This isn't supposed to be a very powerful program, just a simple something that I can give people when they struggle with quickly and easily sending files and don't want to set-up a big file server etc. I'm going to make it show the needed URL to type into a browser to get the files.

    Thanks for any help you guys can give! Appreciate it a ton!

    P.S. I usually just invoke
    Code:
    python -m SimpleHTTPServer 1800
    and work with that. The limitation with this is that you have to run it in the folder you want to share and its difficult to to have multiple sources.

    #2
    See this. But basically it looks like you should subclass BaseHTTPServer and re-implement the server_forever function to have an exit condition.

    Comment


      #3
      So obvious! I can't believe I never thought of doing that. Hmm, I'll try to work multi-threading in for multiple simultaneous requests (shouldn't be difficult really.)

      This is why I am an embarrassingly awful programmer.

      Thanks so much!

      Comment

      Working...
      X