Merge branch 'pr310'

refs ticket:2804
This commit is contained in:
Brian Warner 2016-08-11 23:20:33 -07:00
commit 7182172fc7
6 changed files with 85 additions and 27 deletions

View File

@ -124,6 +124,7 @@ class Client(node.Node, pollmixin.PollMixin):
node.Node.__init__(self, basedir) node.Node.__init__(self, basedir)
# All tub.registerReference must happen *after* we upcall, since # All tub.registerReference must happen *after* we upcall, since
# that's what does tub.setLocation() # that's what does tub.setLocation()
self._magic_folder = None
self.started_timestamp = time.time() self.started_timestamp = time.time()
self.logSource="Client" self.logSource="Client"
self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy() self.encoding_params = self.DEFAULT_ENCODING_PARAMETERS.copy()

View File

@ -2,6 +2,7 @@
import sys, os import sys, os
import os.path import os.path
from collections import deque from collections import deque
from datetime import datetime
import time import time
from twisted.internet import defer, reactor, task from twisted.internet import defer, reactor, task
@ -22,6 +23,7 @@ from allmydata.util.progress import PercentProgress
from allmydata.util.encodingutil import listdir_filepath, to_filepath, \ from allmydata.util.encodingutil import listdir_filepath, to_filepath, \
extend_filepath, unicode_from_filepath, unicode_segments_from, \ extend_filepath, unicode_from_filepath, unicode_segments_from, \
quote_filepath, quote_local_unicode_path, quote_output, FilenameEncodingError quote_filepath, quote_local_unicode_path, quote_output, FilenameEncodingError
from allmydata.util.time_format import format_time
from allmydata.immutable.upload import FileName, Data from allmydata.immutable.upload import FileName, Data
from allmydata import magicfolderdb, magicpath from allmydata import magicfolderdb, magicpath
@ -80,7 +82,18 @@ class MagicFolder(service.MultiService):
self.uploader = Uploader(client, local_path_u, db, upload_dirnode, pending_delay, clock) self.uploader = Uploader(client, local_path_u, db, upload_dirnode, pending_delay, clock)
self.downloader = Downloader(client, local_path_u, db, collective_dirnode, self.downloader = Downloader(client, local_path_u, db, collective_dirnode,
upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending, umask) upload_dirnode.get_readonly_uri(), clock, self.uploader.is_pending, umask,
self.set_public_status)
self._public_status = (False, ['Magic folder has not yet started'])
def get_public_status(self):
"""
For the web UI, basically.
"""
return self._public_status
def set_public_status(self, status, *messages):
self._public_status = (status, messages)
def startService(self): def startService(self):
# TODO: why is this being called more than once? # TODO: why is this being called more than once?
@ -717,7 +730,8 @@ class Downloader(QueueMixin, WriteFileMixin):
scan_interval = 3 scan_interval = 3
def __init__(self, client, local_path_u, db, collective_dirnode, def __init__(self, client, local_path_u, db, collective_dirnode,
upload_readonly_dircap, clock, is_upload_pending, umask): upload_readonly_dircap, clock, is_upload_pending, umask,
status_reporter):
QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock, delay=self.scan_interval) QueueMixin.__init__(self, client, local_path_u, db, 'downloader', clock, delay=self.scan_interval)
if not IDirectoryNode.providedBy(collective_dirnode): if not IDirectoryNode.providedBy(collective_dirnode):
@ -731,6 +745,7 @@ class Downloader(QueueMixin, WriteFileMixin):
self._upload_readonly_dircap = upload_readonly_dircap self._upload_readonly_dircap = upload_readonly_dircap
self._is_upload_pending = is_upload_pending self._is_upload_pending = is_upload_pending
self._umask = umask self._umask = umask
self._status_reporter = status_reporter
@defer.inlineCallbacks @defer.inlineCallbacks
def start_downloading(self): def start_downloading(self):
@ -748,9 +763,16 @@ class Downloader(QueueMixin, WriteFileMixin):
break break
except Exception as e: except Exception as e:
self._status_reporter(
False, "Initial scan has failed",
"Last tried at %s" % self.nice_current_time(),
)
twlog.msg("Magic Folder failed initial scan: %s" % (e,)) twlog.msg("Magic Folder failed initial scan: %s" % (e,))
yield task.deferLater(self._clock, self.scan_interval, lambda: None) yield task.deferLater(self._clock, self.scan_interval, lambda: None)
def nice_current_time(self):
return format_time(datetime.fromtimestamp(self._clock.seconds()).timetuple())
def stop(self): def stop(self):
self._log("stop") self._log("stop")
self._stopped = True self._stopped = True
@ -837,6 +859,10 @@ class Downloader(QueueMixin, WriteFileMixin):
scan_batch[relpath_u] += [(file_node, metadata)] scan_batch[relpath_u] += [(file_node, metadata)]
else: else:
scan_batch[relpath_u] = [(file_node, metadata)] scan_batch[relpath_u] = [(file_node, metadata)]
self._status_reporter(
True, 'Magic folder is working',
'Last scan: %s' % self.nice_current_time(),
)
d.addCallback(scan_listing) d.addCallback(scan_listing)
d.addBoth(self._logcb, "end of _scan_remote_dmd") d.addBoth(self._logcb, "end of _scan_remote_dmd")
@ -892,9 +918,17 @@ class Downloader(QueueMixin, WriteFileMixin):
x = None x = None
try: try:
x = yield self._scan(None) x = yield self._scan(None)
self._status_reporter(
True, 'Magic folder is working',
'Last scan: %s' % self.nice_current_time(),
)
except Exception as e: except Exception as e:
twlog.msg("Remote scan failed: %s" % (e,)) twlog.msg("Remote scan failed: %s" % (e,))
self._log("_scan failed: %s" % (repr(e),)) self._log("_scan failed: %s" % (repr(e),))
self._status_reporter(
False, 'Remote scan has failed: %s' % str(e),
'Last attempted at %s' % self.nice_current_time(),
)
defer.returnValue(x) defer.returnValue(x)
def _scan(self, ign): def _scan(self, ign):

View File

@ -224,6 +224,7 @@ class FakeClient(Client):
# don't upcall to Client.__init__, since we only want to initialize a # don't upcall to Client.__init__, since we only want to initialize a
# minimal subset # minimal subset
service.MultiService.__init__(self) service.MultiService.__init__(self)
self._magic_folder = None
self.all_contents = {} self.all_contents = {}
self.nodeid = "fake_nodeid" self.nodeid = "fake_nodeid"
self.nickname = u"fake_nickname \u263A" self.nickname = u"fake_nickname \u263A"

View File

@ -16,31 +16,26 @@ class MagicFolderWebApi(TokenOnlyWebApi):
req.setHeader("content-type", "application/json") req.setHeader("content-type", "application/json")
data = [] data = []
try: for item in self.client._magic_folder.uploader.get_status():
for item in self.client._magic_folder.uploader.get_status(): d = dict(
d = dict( path=item.relpath_u,
path=item.relpath_u, status=item.status_history()[-1][0],
status=item.status_history()[-1][0], kind='upload',
kind='upload', )
) for (status, ts) in item.status_history():
for (status, ts) in item.status_history(): d[status + '_at'] = ts
d[status + '_at'] = ts d['percent_done'] = item.progress.progress
d['percent_done'] = item.progress.progress data.append(d)
data.append(d)
for item in self.client._magic_folder.downloader.get_status(): for item in self.client._magic_folder.downloader.get_status():
d = dict( d = dict(
path=item.relpath_u, path=item.relpath_u,
status=item.status_history()[-1][0], status=item.status_history()[-1][0],
kind='download', kind='download',
) )
for (status, ts) in item.status_history(): for (status, ts) in item.status_history():
d[status + '_at'] = ts d[status + '_at'] = ts
d['percent_done'] = item.progress.progress d['percent_done'] = item.progress.progress
data.append(d) data.append(d)
except Exception as e:
data.append({
"error": str(e),
})
return simplejson.dumps(data) return simplejson.dumps(data)

View File

@ -186,6 +186,25 @@ class Root(rend.Page):
def data_my_nickname(self, ctx, data): def data_my_nickname(self, ctx, data):
return self.client.nickname return self.client.nickname
def render_magic_folder(self, ctx, data):
if self.client._magic_folder is None:
return T.p()
(ok, messages) = self.client._magic_folder.get_public_status()
if ok:
ctx.fillSlots("magic_folder_status", "yes")
ctx.fillSlots("magic_folder_status_alt", "working")
else:
ctx.fillSlots("magic_folder_status", "no")
ctx.fillSlots("magic_folder_status_alt", "not working")
status = T.ul()
for msg in messages:
status[T.li[str(msg)]]
return ctx.tag[status]
def render_services(self, ctx, data): def render_services(self, ctx, data):
ul = T.ul() ul = T.ul()
try: try:

View File

@ -159,6 +159,14 @@
</div><!--/span--> </div><!--/span-->
</div><!--/row--> </div><!--/row-->
</div> </div>
<div n:render="magic_folder" class="row-fluid">
<h2>
<div class="status-indicator"><img><n:attr name="src">img/connected-<n:slot name="magic_folder_status" />.png</n:attr><n:attr name="alt"><n:slot name="magic_folder_status_alt" /></n:attr></img></div>
Magic Folder
</h2>
</div><!--/row-->
<div class="row-fluid"> <div class="row-fluid">
<h2> <h2>
Connected to <span n:render="string" n:data="connected_storage_servers" /> Connected to <span n:render="string" n:data="connected_storage_servers" />