Hi, Since I cannot reproduce this (as I said, none of my 4.4 devices (Nexus 7, Moto G) have issues with permissions), could you please replace web_server.py in Mnemosyne/web_server with the attached version?
It will print out extra output, like name and path of the database loaded, the webrequests coming in, and the html that will be served. You will need to move back to the python console after launching requests from your webbrowser in order to see this debug info, though. Good luck! Peter > -----Original Message----- > From: [email protected] [mailto:mnemosyne-proj- > [email protected]] On Behalf Of Gnome > Sent: 05 May 2014 21:42 > To: [email protected] > Subject: Re: [mnemosyne-proj-users] Android 4.4 client problem (nothing > displayed) > > I tested deleting and resyncing the database again, same outcome. > > I then created a new database file in mnemosyne PC and added some cards. > I deleted the Mnemosyne database directory on android and started to > synch. > However, after the sync was finished, Mnemosyne PC had swiched back to > default.db and that database was synched, and the same outcome. > > -- > You received this message because you are subscribed to the Google Groups > "mnemosyne-proj-users" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to [email protected]. > To post to this group, send email to mnemosyne-proj- > [email protected]. > To view this discussion on the web visit > https://groups.google.com/d/msgid/mnemosyne-proj-users/1f6b4133-2dfa- > 41d8-affb-c54df0c6997d%40googlegroups.com > <https://groups.google.com/d/msgid/mnemosyne-proj-users/1f6b4133- > 2dfa-41d8-affb- > c54df0c6997d%40googlegroups.com?utm_medium=email&utm_source=foot > er> . > For more options, visit https://groups.google.com/d/optout. -- You received this message because you are subscribed to the Google Groups "mnemosyne-proj-users" group. To unsubscribe from this group and stop receiving emails from it, send an email to [email protected]. To post to this group, send email to [email protected]. To view this discussion on the web visit https://groups.google.com/d/msgid/mnemosyne-proj-users/002101cf691e%24688c8a50%2439a59ef0%24%40UGent.be. For more options, visit https://groups.google.com/d/optout.
# # web_server.py <[email protected]> # import os import cgi import sys import time import locale import httplib import threading from webob import Request from webob.static import FileApp from cherrypy import wsgiserver from mnemosyne.libmnemosyne import Mnemosyne from mnemosyne.libmnemosyne.utils import localhost_IP from mnemosyne.libmnemosyne.component import Component class ReleaseDatabaseAfterTimeout(threading.Thread): def __init__(self, port): threading.Thread.__init__(self) self.port = port self.ping() def ping(self): self.last_ping = time.time() def run(self): while time.time() < self.last_ping + 2*60: time.sleep(1) con = httplib.HTTPConnection("localhost", self.port) con.request("GET", "/release_database") response = con.getresponse() class StopServerAfterTimeout(threading.Thread): """Stop server after a certain timeout, so that it has enough time to serve the final page. """ def __init__(self, wsgi_server): threading.Thread.__init__(self) self.wsgi_server = wsgi_server def run(self): time.sleep(3) self.wsgi_server.stop() class WebServer(Component): def __init__(self, component_manager, port, data_dir, config_dir, filename, is_server_local=False): Component.__init__(self, component_manager) self.port = port self.data_dir = data_dir self.config_dir = config_dir self.filename = filename self.is_server_local = is_server_local # When restarting the server, make sure we discard info from the # browser resending the form from the previous session. self.is_just_started = True self.is_mnemosyne_loaded = False self.is_shutting_down = False self.wsgi_server = wsgiserver.CherryPyWSGIServer(\ ("0.0.0.0", port), self.wsgi_app, server_name="localhost", numthreads=1, timeout=5) # We need to set the timeout relatively low, otherwise it will take # too long for the server to process a 'stop' request. def serve_until_stopped(self): try: self.wsgi_server.start() # Sets self.wsgi_server.ready except KeyboardInterrupt: self.wsgi_server.stop() self.unload_mnemosyne() def stop(self): self.wsgi_server.stop() self.unload_mnemosyne() def load_mnemosyne(self): self.mnemosyne = Mnemosyne(upload_science_logs=True, interested_in_old_reps=True) self.mnemosyne.components.insert(0, ( ("mnemosyne.libmnemosyne.translators.gettext_translator", "GetTextTranslator"))) self.mnemosyne.components.append(\ ("mnemosyne.libmnemosyne.ui_components.main_widget", "MainWidget")) self.mnemosyne.components.append(\ ("mnemosyne.web_server.review_wdgt", "ReviewWdgt")) self.mnemosyne.components.append(\ ("mnemosyne.web_server.web_server_render_chain", "WebServerRenderChain")) self.mnemosyne.initialise(self.data_dir, config_dir=self.config_dir, filename=self.filename, automatic_upgrades=False) self.mnemosyne.review_controller().set_render_chain("web_server") self.save_after_n_reps = self.mnemosyne.config()["save_after_n_reps"] self.mnemosyne.config()["save_after_n_reps"] = 1 self.mnemosyne.start_review() self.mnemosyne.review_widget().set_is_server_local(\ self.is_server_local) self.is_mnemosyne_loaded = True self.release_database_after_timeout = \ ReleaseDatabaseAfterTimeout(self.port) self.release_database_after_timeout.start() print 'loaded', self.data_dir, self.filename def unload_mnemosyne(self): if not self.is_mnemosyne_loaded: return self.mnemosyne.config()["save_after_n_reps"] = self.save_after_n_reps self.mnemosyne.finalise() self.is_mnemosyne_loaded = False def wsgi_app(self, environ, start_response): filename = environ["PATH_INFO"].decode("utf-8") print filename if filename == "/status": response_headers = [("Content-type", "text/html")] start_response("200 OK", response_headers) return ["200 OK"] # Sometimes, even after the user has clicked 'exit' in the page, # a browser sends a request for e.g. an audio file. if self.is_shutting_down and filename != "/release_database": response_headers = [("Content-type", "text/html")] start_response("503 Service Unavailable", response_headers) return ["Server stopped"] # Load database if needed. if not self.is_mnemosyne_loaded and filename != "/release_database": self.load_mnemosyne() self.release_database_after_timeout.ping() # All our request return to the root page, so if the path is '/', # return the html of the review widget. if filename == "/": # Process clicked buttons in the form. form = cgi.FieldStorage(fp=environ["wsgi.input"], environ=environ) if "show_answer" in form and not self.is_just_started: self.mnemosyne.review_widget().show_answer() page = self.mnemosyne.review_widget().to_html() elif "grade" in form and not self.is_just_started: grade = int(form["grade"].value) self.mnemosyne.review_widget().grade_answer(grade) page = self.mnemosyne.review_widget().to_html() elif "star" in form: self.mnemosyne.controller().star_current_card() page = self.mnemosyne.review_widget().to_html() elif "exit" in form: self.unload_mnemosyne() page = "Server stopped" self.wsgi_server.stop() self.stop_server_after_timeout = \ StopServerAfterTimeout(self.wsgi_server) self.stop_server_after_timeout.start() self.is_shutting_down = True else: page = self.mnemosyne.review_widget().to_html() print page if self.is_just_started: self.is_just_started = False # Serve the web page. response_headers = [("Content-type", "text/html")] start_response("200 OK", response_headers) return [page] elif filename == "/release_database": self.unload_mnemosyne() response_headers = [("Content-type", "text/html")] start_response("200 OK", response_headers) return ["200 OK"] # We need to serve a media file. else: full_path = self.mnemosyne.database().media_dir() for word in filename.split("/"): full_path = os.path.join(full_path, word) request = Request(environ) # Check if file exists, but work around Android not reporting # the correct filesystem encoding. try: exists = os.path.exists(full_path) except (UnicodeEncodeError, UnicodeDecodeError): _ENCODING = sys.getfilesystemencoding() or \ locale.getdefaultlocale()[1] or "utf-8" full_path = full_path.encode(_ENCODING) if os.path.exists(full_path): etag = "%s-%s-%s" % (os.path.getmtime(full_path), os.path.getsize(full_path), hash(full_path)) else: etag = "none" app = FileApp(full_path, etag=etag) return app(request)(environ, start_response) class WebServerThread(threading.Thread, WebServer): """Basic threading implementation of the sync server, suitable for text- based UIs. A GUI-based client will want to override several functions in Server and ServerThread in view of the interaction between multiple threads and the GUI event loop. """ def __init__(self, component_manager, is_server_local=False): self.is_server_local = is_server_local threading.Thread.__init__(self) self.config = component_manager.current("config") WebServer.__init__(self, component_manager, self.config["web_server_port"], self.config.data_dir, self.config.config_dir, self.config["last_database"], self.is_server_local) def run(self): if not self.is_server_local: # Could fail if we are offline. print "Web server listening on http://" + \ localhost_IP() + ":" + str(self.config["web_server_port"]) self.serve_until_stopped()
