Add option verify_files to Site.update() to allow the real content verification check, not just the simple file size-based one
Add more informative updateWebsocket() notification in Site.update() and SiteStorage.verifyFiles()
This commit is contained in:
parent
75bba6ca1a
commit
5ec970adb8
3 changed files with 52 additions and 10 deletions
|
@ -689,18 +689,28 @@ class Site(object):
|
||||||
# Update content.json from peers and download changed files
|
# Update content.json from peers and download changed files
|
||||||
# Return: None
|
# Return: None
|
||||||
@util.Noparallel()
|
@util.Noparallel()
|
||||||
def update(self, announce=False, check_files=False, since=None):
|
def update(self, announce=False, check_files=False, verify_files=False, since=None):
|
||||||
self.content_manager.loadContent("content.json", load_includes=False) # Reload content.json
|
self.content_manager.loadContent("content.json", load_includes=False) # Reload content.json
|
||||||
self.content_updated = None # Reset content updated time
|
self.content_updated = None # Reset content updated time
|
||||||
|
|
||||||
if check_files:
|
if verify_files:
|
||||||
|
check_files = True
|
||||||
|
|
||||||
|
self.updateWebsocket(updating=True)
|
||||||
|
if verify_files:
|
||||||
|
self.updateWebsocket(verifying=True)
|
||||||
|
elif check_files:
|
||||||
|
self.updateWebsocket(checking=True)
|
||||||
|
|
||||||
|
if verify_files:
|
||||||
|
self.storage.updateBadFiles(quick_check=False)
|
||||||
|
elif check_files:
|
||||||
self.storage.updateBadFiles(quick_check=True) # Quick check and mark bad files based on file size
|
self.storage.updateBadFiles(quick_check=True) # Quick check and mark bad files based on file size
|
||||||
|
|
||||||
if not self.isServing():
|
if not self.isServing():
|
||||||
|
self.updateWebsocket(updated=True)
|
||||||
return False
|
return False
|
||||||
|
|
||||||
self.updateWebsocket(updating=True)
|
|
||||||
|
|
||||||
# Remove files that no longer in content.json
|
# Remove files that no longer in content.json
|
||||||
self.checkBadFiles()
|
self.checkBadFiles()
|
||||||
|
|
||||||
|
@ -1573,6 +1583,7 @@ class Site(object):
|
||||||
param = None
|
param = None
|
||||||
for ws in self.websockets:
|
for ws in self.websockets:
|
||||||
ws.event("siteChanged", self, param)
|
ws.event("siteChanged", self, param)
|
||||||
|
time.sleep(0.001)
|
||||||
|
|
||||||
def messageWebsocket(self, message, type="info", progress=None):
|
def messageWebsocket(self, message, type="info", progress=None):
|
||||||
for ws in self.websockets:
|
for ws in self.websockets:
|
||||||
|
|
|
@ -24,6 +24,25 @@ thread_pool_fs_read = ThreadPool.ThreadPool(config.threads_fs_read, name="FS rea
|
||||||
thread_pool_fs_write = ThreadPool.ThreadPool(config.threads_fs_write, name="FS write")
|
thread_pool_fs_write = ThreadPool.ThreadPool(config.threads_fs_write, name="FS write")
|
||||||
thread_pool_fs_batch = ThreadPool.ThreadPool(1, name="FS batch")
|
thread_pool_fs_batch = ThreadPool.ThreadPool(1, name="FS batch")
|
||||||
|
|
||||||
|
class VerifyFiles_Notificator(object):
|
||||||
|
def __init__(self, site, quick_check):
|
||||||
|
self.site = site
|
||||||
|
self.quick_check = quick_check
|
||||||
|
self.scanned_files = 0
|
||||||
|
self.websocket_update_interval = 0.25
|
||||||
|
self.websocket_update_time = time.time()
|
||||||
|
|
||||||
|
def inc(self):
|
||||||
|
self.scanned_files += 1
|
||||||
|
if self.websocket_update_time + self.websocket_update_interval < time.time():
|
||||||
|
self.send()
|
||||||
|
|
||||||
|
def send(self):
|
||||||
|
self.websocket_update_time = time.time()
|
||||||
|
if self.quick_check:
|
||||||
|
self.site.updateWebsocket(checking=self.scanned_files)
|
||||||
|
else:
|
||||||
|
self.site.updateWebsocket(verifying=self.scanned_files)
|
||||||
|
|
||||||
@PluginManager.acceptPlugins
|
@PluginManager.acceptPlugins
|
||||||
class SiteStorage(object):
|
class SiteStorage(object):
|
||||||
|
@ -427,11 +446,14 @@ class SiteStorage(object):
|
||||||
i = 0
|
i = 0
|
||||||
self.log.debug("Verifing files...")
|
self.log.debug("Verifing files...")
|
||||||
|
|
||||||
|
notificator = VerifyFiles_Notificator(self.site, quick_check)
|
||||||
|
|
||||||
if not self.site.content_manager.contents.get("content.json"): # No content.json, download it first
|
if not self.site.content_manager.contents.get("content.json"): # No content.json, download it first
|
||||||
self.log.debug("VerifyFile content.json not exists")
|
self.log.debug("VerifyFile content.json not exists")
|
||||||
self.site.needFile("content.json", update=True) # Force update to fix corrupt file
|
self.site.needFile("content.json", update=True) # Force update to fix corrupt file
|
||||||
self.site.content_manager.loadContent() # Reload content.json
|
self.site.content_manager.loadContent() # Reload content.json
|
||||||
for content_inner_path, content in list(self.site.content_manager.contents.items()):
|
for content_inner_path, content in self.site.content_manager.contents.iteritems():
|
||||||
|
notificator.inc()
|
||||||
back["num_content"] += 1
|
back["num_content"] += 1
|
||||||
i += 1
|
i += 1
|
||||||
if i % 50 == 0:
|
if i % 50 == 0:
|
||||||
|
@ -442,6 +464,7 @@ class SiteStorage(object):
|
||||||
bad_files.append(content_inner_path)
|
bad_files.append(content_inner_path)
|
||||||
|
|
||||||
for file_relative_path in list(content.get("files", {}).keys()):
|
for file_relative_path in list(content.get("files", {}).keys()):
|
||||||
|
notificator.inc()
|
||||||
back["num_file"] += 1
|
back["num_file"] += 1
|
||||||
file_inner_path = helper.getDirname(content_inner_path) + file_relative_path # Relative to site dir
|
file_inner_path = helper.getDirname(content_inner_path) + file_relative_path # Relative to site dir
|
||||||
file_inner_path = file_inner_path.strip("/") # Strip leading /
|
file_inner_path = file_inner_path.strip("/") # Strip leading /
|
||||||
|
@ -452,14 +475,19 @@ class SiteStorage(object):
|
||||||
bad_files.append(file_inner_path)
|
bad_files.append(file_inner_path)
|
||||||
continue
|
continue
|
||||||
|
|
||||||
|
err = None
|
||||||
|
|
||||||
if quick_check:
|
if quick_check:
|
||||||
ok = os.path.getsize(file_path) == content["files"][file_relative_path]["size"]
|
file_size = os.path.getsize(file_path)
|
||||||
|
expected_size = content["files"][file_relative_path]["size"]
|
||||||
|
ok = file_size == expected_size
|
||||||
if not ok:
|
if not ok:
|
||||||
err = "Invalid size"
|
err = "Invalid size: %s - actual, %s - expected" % (file_size, expected_size)
|
||||||
else:
|
else:
|
||||||
try:
|
try:
|
||||||
ok = self.site.content_manager.verifyFile(file_inner_path, open(file_path, "rb"))
|
ok = self.site.content_manager.verifyFile(file_inner_path, open(file_path, "rb"))
|
||||||
except Exception as err:
|
except Exception as err2:
|
||||||
|
err = err2
|
||||||
ok = False
|
ok = False
|
||||||
|
|
||||||
if not ok:
|
if not ok:
|
||||||
|
@ -472,6 +500,7 @@ class SiteStorage(object):
|
||||||
optional_added = 0
|
optional_added = 0
|
||||||
optional_removed = 0
|
optional_removed = 0
|
||||||
for file_relative_path in list(content.get("files_optional", {}).keys()):
|
for file_relative_path in list(content.get("files_optional", {}).keys()):
|
||||||
|
notificator.inc()
|
||||||
back["num_optional"] += 1
|
back["num_optional"] += 1
|
||||||
file_node = content["files_optional"][file_relative_path]
|
file_node = content["files_optional"][file_relative_path]
|
||||||
file_inner_path = helper.getDirname(content_inner_path) + file_relative_path # Relative to site dir
|
file_inner_path = helper.getDirname(content_inner_path) + file_relative_path # Relative to site dir
|
||||||
|
@ -516,6 +545,8 @@ class SiteStorage(object):
|
||||||
(content_inner_path, len(content["files"]), quick_check, optional_added, optional_removed)
|
(content_inner_path, len(content["files"]), quick_check, optional_added, optional_removed)
|
||||||
)
|
)
|
||||||
|
|
||||||
|
notificator.send()
|
||||||
|
|
||||||
self.site.content_manager.contents.db.processDelayed()
|
self.site.content_manager.contents.db.processDelayed()
|
||||||
time.sleep(0.001) # Context switch to avoid gevent hangs
|
time.sleep(0.001) # Context switch to avoid gevent hangs
|
||||||
return back
|
return back
|
||||||
|
|
|
@ -912,9 +912,9 @@ class UiWebsocket(object):
|
||||||
self.response(to, "ok")
|
self.response(to, "ok")
|
||||||
|
|
||||||
# Update site content.json
|
# Update site content.json
|
||||||
def actionSiteUpdate(self, to, address, check_files=False, since=None, announce=False):
|
def actionSiteUpdate(self, to, address, check_files=False, verify_files=False, since=None, announce=False):
|
||||||
def updateThread():
|
def updateThread():
|
||||||
site.update(announce=announce, check_files=check_files, since=since)
|
site.update(announce=announce, check_files=check_files, verify_files=verify_files, since=since)
|
||||||
self.response(to, "Updated")
|
self.response(to, "Updated")
|
||||||
|
|
||||||
site = self.server.sites.get(address)
|
site = self.server.sites.get(address)
|
||||||
|
|
Loading…
Reference in a new issue