I've created a GUI using tkinter to send requests (from file) to a specific URL
everything worked great until I wanted to used threads...
so I used one thread to send the requests in order to keep the control over the GUI.
Now it's unstable, the application crashes almost everytime!
I tried using the 'threading.Thread' instead of 'thread.start_new_thread' but it did not work as a new thread (could not control GUI while requests are being sent)
I'm pretty sure the problem is related to the 'updateStatus' functions which writes a string into the status bar and either the results or the log tab because it works when i remove this option.
I would love to know how should I use the thread with the GUI and the status updater
also, the results tab sometime crashes the application - but only in random (to me) times...
here is the CODE:
from ftplib import FTP
from Tkinter import *
import threading
import thread
import Queue
import Tkinter, tkFileDialog, ttk
import os, base64, time, string, sys
import urllib2, telnetlib
class App:
def __init__(self, master):
self.selectedFileName = StringVar()
self.inProgress = 1.0
self.headers = {}
self.word_list = []
self.localPath = os.path.join(os.getcwd())
self.tabs = ttk.Notebook(root)
frame = Frame(self.tabs, width=750, height=300)
tab_log = ttk.Frame(self.tabs)
tab_results = ttk.Frame(self.tabs)
self.tabs.add(frame, text=" Main ")
self.tabs.add(tab_log, text=" Log ")
self.tabs.add(tab_results, text=" Results ")
self.tabs.pack()
######################
# Main TAB: #
######################
# Application URL: LABEL
self.label_url = Label(frame, text="URL (https://myApp:666/):", foreground="black")
self.label_url.pack(side=LEFT)
self.label_url.place(bordermode=OUTSIDE, x=5, y=40)
# App URL: TEXT
self.text_url = Entry(frame, width=66)
self.text_url.place(bordermode=OUTSIDE, x=200, y=40)
# Upload File: Button
self.upload_button = Button(frame, text="Upload File", command=self.browseFile, state=NORMAL)
self.upload_button.place(bordermode=OUTSIDE, x=5, y=100)
# Upload File: Label
self.upload_label = Label(frame, text="")
self.upload_label.place(bordermode=OUTSIDE, x=100, y=100)
########## Main Buttons ###########
# >> Run Button
self.button_run = Button(frame, text="Run", width=25, height=2, command=self.runPressed)
self.button_run.place(bordermode=OUTSIDE, x=300, y=325)
# >> Quit Button
self.quit_button = Button(frame, text="Quit", width=10, height=1, command=self.executeQuit)
self.quit_button.place(bordermode=OUTSIDE, x=666, y=335)
# Status bars
self.text_status = Text(frame, width=106, height=2, background="#DDDDDD", foreground="#990000")
self.text_status.insert(INSERT, "Status")
self.text_status.configure(state=DISABLED)
self.text_status.place(bordermode=OUTSIDE, x=0, y=260)
# Progress bar
self.progressBar = ttk.Progressbar(frame, orient="horizontal", length=748, mode="determinate")
#self.progressBar.pack()
self.progressBar.place(bordermode=OUTSIDE, x=1, y=300)
######################
# Log TAB: #
######################
self.log_text = Text(tab_log, width=104, state=DISABLED)
self.log_text.pack(side=LEFT, fill=BOTH)
self.button_toResults = Button(tab_log, text="Clear Log", command=self.clearLog)
self.button_toResults.place(bordermode=OUTSIDE, x=678, y=0)
# Scroll Bar
self.logScrollBar = Scrollbar(tab_log)
self.logScrollBar.pack(side=RIGHT, fill=Y)
self.logScrollBar.configure(command=self.log_text.yview)
self.log_text.configure(yscrollcommand=self.logScrollBar.set)
######################
# Results TAB: #
######################
self.results_text = Text(tab_results, width=104, state=NORMAL)
self.results_text.pack(side=LEFT, fill=BOTH)
# Scroll Bar
self.resScrollBar = Scrollbar(tab_results)
self.resScrollBar.pack(side=RIGHT, fill=Y)
self.resScrollBar.configure(command=self.log_text.yview)
self.results_text.configure(yscrollcommand=self.resScrollBar.set)
## functions... ##
# clears log in 'Log' tab
def clearLog(self):
self.log_text.configure(state=NORMAL)
self.log_text.delete(1.0, END)
self.log_text.configure(state=DISABLED)
# Browse file system to get file to use for requests
def browseFile(self):
self.selectedFileName = tkFileDialog.askopenfilename(filetypes = ( ("Text files", "*.txt"), ("All files", "*.*") ))
try:
tmpFile = open(self.selectedFileName, 'r')
self.editStatus('opened: %s' %self.selectedFileName, 1)
tmpFile.close()
selectedFileLength = len(self.selectedFileName)
if selectedFileLength > 75:
displayedFileName = '...' +self.selectedFileName[selectedFileLength -70:]
else:
displayedFileName = self.selectedFileName
self.upload_label.configure(text='Selected file: %s' %displayedFileName, foreground="darkblue")
tmpFile.close()
except:
'Error! file does not exist...'
## run() ##
def runPressed(self):
try:
self.executeRun()
"""self.lock = thread.allocate_lock()
thread.start_new_thread(self.executeRun, ())"""
except:
self.editStatus('Could not start! please try again...', 1)
def executeRun(self):
self.progressBar["value"] = 0
# is URL missing?
self.URL_TEXT = self.text_url.get().strip()
lenURL = len(self.URL_TEXT)
if lenURL < 1:
self.editStatus("Please fill in the URL and Press 'Run' again", 1)
return 0
if self.URL_TEXT[lenURL -1:] < '/':
self.URL_TEXT = self.URL_TEXT +'/'
try:
tmpFile = open(self.selectedFileName, 'r')
except:
self.editStatus("Please select file Press 'Run' again", 1)
return 0
tmpFile.close()
self.progressBar["value"] = 33
word_file = self.selectedFileName
myFile = open(word_file, 'r')
self.word_list = myFile.read().split('\n')
myFile.close()
self.progressBar["value"] = 66
# Create Results folder and files
self.resultsFolder = self.localPath +'\\' +'Results'
# Creates 'Results' folder
try:
os.makedirs(self.resultsFolder)
self.editStatus('folder created...', 1)
except:
self.editStatus('Folder already exists', 1)
self.result_file = open(self.resultsFolder +'\\results.txt', 'w')
self.result_file.close()
self.progressBar["value"] = 100
self.lineCounter = 1
self.totalLines = len(self.word_list)
self.editStatus('Total lines in file: %d' %self.totalLines, 1)
# number of reconnection times in case connection has been losts
timestoTry = 12
timesTried = 1
self.progressBar["value"] = 0
#self.myThread = threading.Thread(target=self.sendRequests())
thread.start_new_thread(self.sendRequests, ())
"""while self.lineCounter < self.totalLines and timesTried < timestoTry:
self.editStatus('Stopped @ line number: %d' %self.lineCounter, 1)
self.editStatus('connection lost, will try again(%s)...' %timesTried, 1)
time.sleep(5 +timesTried)
timesTried = timesTried +1
self.word_list = self.word_list[self.lineCounter -1:]
thread.start_new_thread(self.sendRequests, ())"""
# send requests from file
def sendRequests(self):
url = self.URL_TEXT
progress = self.inProgress
for word in self.word_list:
self.editStatus(str('Sending (%d): %s%s' %(self.lineCounter, url, word)),1)
self.lineCounter = self.lineCounter +1
progress = (self.lineCounter / float(self.totalLines)) * 100
self.progressBar["value"] = progress
try:
myRequest = urllib2.Request(url +word, data=None, headers=self.headers)
myResponse = urllib2.urlopen(myRequest, timeout=3)
res_html = myResponse.read()
myResponse.close()
if myResponse.getcode() == 200:
self.editStatus(url +word +'\n', 2)
resFile = open(self.resultsFolder +'\\results.txt', 'a')
resFile.write(url +word +'\n')
resFile.close()
except urllib2.HTTPError as e:
print 'could not reach: %s%s' %(url, word)
except urllib2.URLError as e:
self.editStatus(str(e), 1)
#thread.exit()
return 0
#thread.exit()
if self.lineCounter == self.totalLines +1:
self.finito()
return 1
else:
self.editStatus('something went wrong... finished but not done?!', 1)
return 0
# grand finale!
def finito(self):
self.editStatus(' ', 1)
self.editStatus(' ', 1)
self.editStatus('** !!! Mission accomplished !!! **', 1)
# 'Quit' button clicked
def executeQuit():
global root
root.destroy()
# writes passed string into Status-Bar
# if '1' is passed - will also write string to 'Log'
# if '2' is passed - will write to 'Results'
def editStatus(self, newStatus, toLog):
if toLog == 1:
self.text_status.configure(state=NORMAL)
self.text_status.delete(1.0, END)
self.text_status.insert(END, newStatus)
self.text_status.configure(state=DISABLED)
self.log_text.configure(state=NORMAL)
self.log_text.insert(END, newStatus +'\n')
self.log_text.configure(state=DISABLED)
elif toLog == 2:
self.results_text.configure(state=NORMAL)
self.results_text.insert(END, newStatus +'\n')
self.results_text.configure(state=DISABLED)
else:
print newStatus +'\n'
#print newStatus +'\n'
root = Tk()
app = App(root)
root.mainloop()