Skip to content

Commit

Permalink
Refs #1, download or pick a local image is done.
Browse files Browse the repository at this point in the history
  • Loading branch information
stdevPavelmc committed Jan 5, 2019
1 parent 68428b4 commit e0c3a1f
Show file tree
Hide file tree
Showing 2 changed files with 203 additions and 68 deletions.
208 changes: 162 additions & 46 deletions skyflash.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
import subprocess
import webbrowser
from urllib.request import Request, urlopen
import time

# GUI imports
from PyQt5.QtGui import QGuiApplication
Expand All @@ -14,7 +15,7 @@

# environment vars
# TODO, set final real URLS
skybianUrl = "http://127.0.0.1:8080/d.big"
skybianUrl = "http://192.168.200.1:8080/d.big"
manualUrl = "http://github.com/simelo/skyflash"

# utils class
Expand All @@ -25,20 +26,81 @@ def __init__(self):
def shortenPath(self, fullpath, ccount):
# TODO OS dependent FS char
fpath = fullpath.split("/")
spath = fpath[-1]
if len(spath) > ccount:
spath = ".../" + spath[-ccount:]
else:
spath = ".../" + spath
fpath.reverse()
spath = fpath[0]
count = len(spath)

# cycle from back to start to fit on ccount
for item in fpath:
if item == fpath[0]:
# filename
spath = item
else:
# folders
# TODO OS dependant FS char
tspath = item + "/" + spath
if len(tspath) > ccount:
spath = ".../" + spath
break
else:
spath = tspath

# spath has the final shorted path
return spath

def eta(self, secs):
# takes int seconds to complete a task
# return str like this
# < 10 seconds: a few seconds
# > 10 seconds & < 1 minute: 45 seconds
# > 1 minute & < 59 minutes: 45 minutes
# > 1 hour: 1 hour 23 minutes

# minutes to decide
mins = int(secs / 60)
hours = int(mins / 60)
out = ""

if mins < 1:
if secs < 10:
out = "a few secs"
else:
out = "{} secs".format(secs)
elif mins < 59:
out = "{} min".format(mins)
else:
if hours > 1:
out = "{} hours {} min".format(hours, int(mins % 60))
else:
out = "{} hour {} min".format(hours, int(mins % 60))

return out

def speed(self, speed):
# takes speeds in bytes per second
# return str like this
# < 1 kb/s: 256 b/s
# > 1 kb/s & < 1 Mb/s: 23 kb/s
# > 1 Mb/s: 2.1 Mb/s

k = speed / 1000
M = k / 1000
out = ""

if M > 1:
out = "{:0.1f} Mb/s".format(M)
elif k > 1:
out = "{:0.1f} kb/s".format(k)
else:
out = "{} b/s".format(int(speed))

return out

# signals class, to be used on threads; for all major tasks
class WorkerSignals(QObject):
data = pyqtSignal(str)
error = pyqtSignal(tuple)
progress = pyqtSignal(float)
progress = pyqtSignal(float, str)
result = pyqtSignal(str)
finished = pyqtSignal(str)

Expand Down Expand Up @@ -77,7 +139,7 @@ def run(self):
self.signals.result.emit(result)
finally:
# Done
self.signals.finished.emit()
self.signals.finished.emit("Done")


# main object definition
Expand All @@ -88,9 +150,21 @@ class skyFlash(QObject):
setStatus = pyqtSignal(str, arguments=["msg"])

# download signals
# target is download label
dData = pyqtSignal(str, arguments=["data"])
# target is proogress bar
dProg = pyqtSignal(float, arguments=["percent"])
dDone = pyqtSignal(str, arguments=["result"])
# target is hide download buttons
dDone = pyqtSignal()
# target is download button text: Download
dDown = pyqtSignal()

# download flags
downloadActive = False
downloadOk = False

# network signals
netConfig = pyqtSignal()

# thread pool
threadpool = QThreadPool()
Expand All @@ -103,24 +177,41 @@ def __init__(self, parent=None):
def downloadSkybianData(self, data):
self.dData.emit(data)

def downloadSkybianProg(self, percent):
self.dProg.emit(percent)
def downloadSkybianProg(self, percent, data):
self.dProg.emit(int(percent))
self.setStatus.emit(data)

def downloadSkybianError(self, error):
print("Error: " + error)

# result is the path to the local file
def downloadSkybianFile(self, file):
self.skybianFile = file
if self.downloadOk:
self.skybianFile = file
# TODO adjust the size of the path
self.dData.emit("Skybian image is: " + utils.shortenPath(file, 32))
self.setStatus.emit("Choose your network configuration")
else:
self.dData.emit("")
self.setStatus.emit("Download canceled or error happened")
self.dDown.emit()

# download finished, good or bad?
def downloadSkybianDone(self, result):
self.dDone.emit(result)
# check status of download
if self.downloadOk:
self.dDone.emit()
self.netConfig.emit()

# Download main trigger
@pyqtSlot()
def downloadSkybian(self):
# check if there is a thread already working there
downCount = self.threadpool.activeThreadCount()
if downCount < 1:
# rise flag
self.downloadActive = True

# init download process
self.down = Worker(self.skyDown)
self.down.signals.data.connect(self.downloadSkybianData)
Expand All @@ -131,10 +222,12 @@ def downloadSkybian(self):
# init worker
self.threadpool.start(self.down)
else:
# TODO, emit status bar warning or modal box
print("There is a download in progress, please wait...")
# if you clicked it during a download, then you want to cancel
# just rise the flag an the thread will catch it and stop
self.downloadActive = False
self.downloadOk = False

# download skybian, will be instantiated in thread
# download skybian, will be instantiated in a thread
def skyDown(self, data_callback, progress_callback):
# take url for skybian from upper
url = skybianUrl
Expand All @@ -146,48 +239,70 @@ def skyDown(self, data_callback, progress_callback):
fileName = url.split("/")[-1]

# emit data of the download
data_callback.emit("There is {:04.1f}MB to download...".format(self.size/1000/1000))
data_callback.emit("Downloading {:04.1f} MB".format(self.size/1000/1000))

# start download
downloadedChunk = 0

# chuck size @ 20kb
blockSize = 20480
localFile = os.getcwd() + fileName
# chuck size @ 100kb
blockSize = 102400
# TODO folder separator can be os depenndent, review
filePath = os.getcwd() + "/" + fileName
startTime = 0
elapsedTime = 0

# DEBUG
print("Downloading to: {}".format(localFile))

with open(localFile, "wb") as finalImg:
while True:
chunk = req.read(blockSize)
if not chunk:
print("\nDownload Complete.")
break
downloadedChunk += len(chunk)
finalImg.write(chunk)
progress = float(downloadedChunk) / self.size

# emit percent
progress_callback.emit(progress * 100)
print("Downloading to: {}".format(filePath))

# final emit
print("Done")
try:
with open(filePath, "wb") as finalImg:
startTime = time.time()
while True:
chunk = req.read(blockSize)
if not chunk:
print("\nDownload Complete.")
break
downloadedChunk += len(chunk)
finalImg.write(chunk)
progress = (float(downloadedChunk) / self.size) * 100

# calc speed and ETA
elapsedTime = time.time() - startTime
bps = int(downloadedChunk/elapsedTime) # b/s
etas = int((self.size - downloadedChunk)/bps) # seconds
# emit progress
prog = "{:.1%}, {}, {} to go.".format(progress/100, utils.speed(bps), utils.eta(etas))
progress_callback.emit(progress, prog)

# check if the terminate flag is raised
if not self.downloadActive:
finalImg.close()
return "canceled"

# close the file handle
finalImg.close()
self.downloadOk = True

# return the local filename
return filePath

# close the file handle
finalImg.close()
except:
self.downloadOk = False
if finalImg:
finalImg.close()
os.unlink(finalImg)

# return the local filename
return localFile
return "Abnormal termination"

# load skybian from a local file
@pyqtSlot()
@pyqtSlot(str)
def localFile(self, file):
if file is "":
self.setStatus.emit("You selected nothing, plase try again")
self.setStatus.emit("You selected nothing, please try again")
return

if file.startswith("file://"):
# TODO, check on windows
if file.startswith("file:///"):
file = file.replace("file://", "")

print("Selected file is " + file)
Expand All @@ -203,9 +318,10 @@ def localFile(self, file):
self.setStatus.emit("Selected file is not readable.")
return

# shorten the filename to fit on the label
filename = utils.shortenPath(file, 26)
self.downloadFinished.emit(filename)
# all seems good, emit ans go on
self.downloadOk = True
self.downloadSkybianFile(file)
self.downloadSkybianDone("Ok")

# open the manual in the browser
@pyqtSlot()
Expand Down
Loading

0 comments on commit e0c3a1f

Please sign in to comment.